diff --git a/assignment-client/src/AssignmentActionFactory.cpp b/assignment-client/src/AssignmentActionFactory.cpp index e1c5d3adff..7c404cbd97 100644 --- a/assignment-client/src/AssignmentActionFactory.cpp +++ b/assignment-client/src/AssignmentActionFactory.cpp @@ -17,8 +17,7 @@ EntityActionPointer assignmentActionFactory(EntityActionType type, const QUuid& } -EntityActionPointer AssignmentActionFactory::factory(EntitySimulation* simulation, - EntityActionType type, +EntityActionPointer AssignmentActionFactory::factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments) { @@ -33,9 +32,7 @@ EntityActionPointer AssignmentActionFactory::factory(EntitySimulation* simulatio } -EntityActionPointer AssignmentActionFactory::factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, - QByteArray data) { +EntityActionPointer AssignmentActionFactory::factoryBA(EntityItemPointer ownerEntity, QByteArray data) { QDataStream serializedActionDataStream(data); EntityActionType type; QUuid id; diff --git a/assignment-client/src/AssignmentActionFactory.h b/assignment-client/src/AssignmentActionFactory.h index 41245dac68..e2d58f3e6a 100644 --- a/assignment-client/src/AssignmentActionFactory.h +++ b/assignment-client/src/AssignmentActionFactory.h @@ -19,14 +19,11 @@ class AssignmentActionFactory : public EntityActionFactoryInterface { public: AssignmentActionFactory() : EntityActionFactoryInterface() { } virtual ~AssignmentActionFactory() { } - virtual EntityActionPointer factory(EntitySimulation* simulation, - EntityActionType type, + virtual EntityActionPointer factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments); - virtual EntityActionPointer factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, - QByteArray data); + virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data); }; #endif // hifi_AssignmentActionFactory_h diff --git a/examples/animationPerfTest.js b/examples/animationPerfTest.js index 6bf310db23..b832d2e61f 100644 --- a/examples/animationPerfTest.js +++ b/examples/animationPerfTest.js @@ -9,9 +9,7 @@ var NUM_MOONS = 20; // 1 = 60Hz, 2 = 30Hz, 3 = 20Hz, etc var UPDATE_FREQUENCY_DIVISOR = 2; - var MAX_RANGE = 75.0; -var LIFETIME = 600; var SCALE = 0.1; var center = Vec3.sum(MyAvatar.position, @@ -22,44 +20,47 @@ var PARTICLE_MIN_SIZE = 2.50; var PARTICLE_MAX_SIZE = 2.50; -var planet = Entities.addEntity({ - type: "Sphere", - position: center, - dimensions: { x: 10 * SCALE, y: 10 * SCALE, z: 10 * SCALE }, - color: { red: 0, green: 0, blue: 255 }, - ignoreCollisions: true, - collisionsWillMove: false, - lifetime: LIFETIME -}); +function deleteAnimationTestEntitites() { + var ids = Entities.findEntities(MyAvatar.position, 50); + for (var i = 0; i < ids.length; i++) { + var id = ids[i]; + var properties = Entities.getEntityProperties(id); + if (properties.name == "AnimationTest") { + Entities.deleteEntity(id); + } + } +} + +deleteAnimationTestEntitites(); var moons = []; // Create initial test particles that will move according to gravity from the planets for (var i = 0; i < NUM_MOONS; i++) { - var radius = PARTICLE_MIN_SIZE + Math.random() * PARTICLE_MAX_SIZE; - radius *= SCALE; - var gray = Math.random() * 155; - var position = { x: 10 , y: i * 3, z: 0 }; - var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray }; - if (i == 0) { - color = { red: 255, green: 0, blue: 0 }; - radius = 6 * SCALE - } - moons.push(Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(center, position), - dimensions: { x: radius, y: radius, z: radius }, - color: color, - ignoreCollisions: true, - lifetime: LIFETIME, - collisionsWillMove: false - })); + var radius = PARTICLE_MIN_SIZE + Math.random() * PARTICLE_MAX_SIZE; + radius *= SCALE; + var gray = Math.random() * 155; + var position = { x: 10 , y: i * 3, z: 0 }; + var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray }; + if (i == 0) { + color = { red: 255, green: 0, blue: 0 }; + radius = 6 * SCALE + } + moons.push(Entities.addEntity({ + type: "Sphere", + name: "AnimationTest", + position: Vec3.sum(center, position), + dimensions: { x: radius, y: radius, z: radius }, + color: color, + ignoreCollisions: true, + collisionsWillMove: false + + })); } Script.update.connect(update); function scriptEnding() { - Entities.deleteEntity(planet); for (var i = 0; i < moons.length; i++) { Entities.deleteEntity(moons[i]); } @@ -70,22 +71,20 @@ var updateCount = 0; function update(deltaTime) { // Apply gravitational force from planets totalTime += deltaTime; - updateCount++; - if (0 != updateCount % UPDATE_FREQUENCY_DIVISOR) { - return; - } - - var planetProperties = Entities.getEntityProperties(planet); - var center = planetProperties.position; + updateCount++; + if (0 != updateCount % UPDATE_FREQUENCY_DIVISOR) { + return; + } + var particlePos = Entities.getEntityProperties(moons[0]).position; var relativePos = Vec3.subtract(particlePos.position, center); for (var t = 0; t < moons.length; t++) { - var thetaDelta = (Math.PI * 2.0 / NUM_MOONS) * t; - var y = Math.sin(totalTime + thetaDelta) * 10.0 * SCALE; - var x = Math.cos(totalTime + thetaDelta) * 10.0 * SCALE; + var thetaDelta = (Math.PI * 2.0 / NUM_MOONS) * t; + var y = Math.sin(totalTime + thetaDelta) * 10.0 * SCALE; + var x = Math.cos(totalTime + thetaDelta) * 10.0 * SCALE; var newBasePos = Vec3.sum({ x: 0, y: y, z: x }, center); Entities.editEntity(moons[t], { position: newBasePos}); } } -Script.scriptEnding.connect(scriptEnding); +Script.scriptEnding.connect(deleteAnimationTestEntitites); diff --git a/examples/cubePerfTest.js b/examples/cubePerfTest.js new file mode 100644 index 0000000000..e349b7add7 --- /dev/null +++ b/examples/cubePerfTest.js @@ -0,0 +1,58 @@ +// +// Created by Bradley Austin Davis on 2015/07/01 +// 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 +// + +var SIDE_SIZE = 10; + +var center = { x: 0, y: 0, z: 0 }; + +var DEGREES_TO_RADIANS = Math.PI / 180.0; +var PARTICLE_MIN_SIZE = 2.50; +var PARTICLE_MAX_SIZE = 2.50; +var LIFETIME = 600; +var boxes = []; + +var ids = Entities.findEntities({ x: 512, y: 512, z: 512 }, 50); +for (var i = 0; i < ids.length; i++) { + var id = ids[i]; + var properties = Entities.getEntityProperties(id); + if (properties.name == "PerfTest") { + Entities.deleteEntity(id); + } +} + + +// Create initial test particles that will move according to gravity from the planets +for (var x = 0; x < SIDE_SIZE; x++) { + for (var y = 0; y < SIDE_SIZE; y++) { + for (var z = 0; z < SIDE_SIZE; z++) { + var gray = Math.random() * 155; + var cube = Math.random() > 0.5; + var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray }; + var position = { x: 512 + x * 0.2, y: 512 + y * 0.2, z: 512 + z * 0.2}; + var radius = Math.random() * 0.1; + boxes.push(Entities.addEntity({ + type: cube ? "Box" : "Sphere", + name: "PerfTest", + position: position, + dimensions: { x: radius, y: radius, z: radius }, + color: color, + ignoreCollisions: true, + collisionsWillMove: false, + lifetime: LIFETIME + })); + } + } +} + + +function scriptEnding() { + for (var i = 0; i < boxes.length; i++) { + //Entities.deleteEntity(boxes[i]); + } +} +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/stick-hydra.js b/examples/stick-hydra.js new file mode 100644 index 0000000000..a74f7954bb --- /dev/null +++ b/examples/stick-hydra.js @@ -0,0 +1,73 @@ +// stick-hydra.js +// examples +// +// Created by Seth Alves on 2015-7-9 +// Copyright 2015 High Fidelity, Inc. +// +// Allow avatar to hold a stick and control it with a hand-tracker +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var hand = "left"; +var nullActionID = "00000000-0000-0000-0000-000000000000"; +var controllerID; +var controllerActive; +var stickID = null; +var actionID = nullActionID; +var makingNewStick = false; + +function makeNewStick() { + if (makingNewStick) { + return; + } + makingNewStick = true; + cleanUp(); + // sometimes if this is run immediately the stick doesn't get created? use a timer. + Script.setTimeout(function() { + stickID = Entities.addEntity({ + type: "Model", + name: "stick", + modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx", + compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj", + dimensions: {x: .11, y: .11, z: 1.0}, + position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close + rotation: MyAvatar.orientation, + damping: .1, + collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav", + restitution: 0.01, + collisionsWillMove: true + }); + actionID = Entities.addAction("hold", stickID, + {relativePosition: {x: 0.0, y: 0.0, z: -0.5}, + relativeRotation: Quat.fromVec3Degrees({x: 0.0, y: 90.0, z: 0.0}), + hand: hand, + timeScale: 0.15}); + if (actionID == nullActionID) { + cleanUp(); + } + makingNewStick = false; + }, 3000); +} + + +function cleanUp() { + if (stickID) { + Entities.deleteEntity(stickID); + stickID = null; + } +} + + +function initControls(){ + if (hand == "right") { + controllerID = 3; // right handed + } else { + controllerID = 4; // left handed + } +} + + +Script.scriptEnding.connect(cleanUp); +makeNewStick(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 76d95ede8f..140656bc16 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -394,6 +394,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : static_cast(dependency)->deleteLater(); }); + // setup a timer for domain-server check ins + QTimer* domainCheckInTimer = new QTimer(nodeList.data()); + connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn); + domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); + // put the NodeList and datagram processing on the node thread nodeList->moveToThread(nodeThread); @@ -895,12 +900,6 @@ void Application::paintGL() { { PerformanceTimer perfTimer("renderOverlay"); - /* - gpu::Context context(new gpu::GLBackend()); - RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(), - lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, - RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); - */ _applicationOverlay.renderOverlay(&renderArgs); } @@ -976,6 +975,8 @@ void Application::paintGL() { } else if (TV3DManager::isConnected()) { TV3DManager::display(&renderArgs, _myCamera); } else { + PROFILE_RANGE(__FUNCTION__ "/mainRender"); + DependencyManager::get()->prepare(&renderArgs); // Viewport is assigned to the size of the framebuffer @@ -990,7 +991,7 @@ void Application::paintGL() { renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - renderRearViewMirror(&renderArgs, _mirrorViewRect); + renderRearViewMirror(&renderArgs, _mirrorViewRect); } renderArgs._renderMode = RenderArgs::NORMAL_RENDER_MODE; @@ -1010,6 +1011,7 @@ void Application::paintGL() { if (!OculusManager::isConnected() || OculusManager::allowSwap()) { + PROFILE_RANGE(__FUNCTION__ "/bufferSwap"); _glWidget->swapBuffers(); } @@ -1059,6 +1061,7 @@ void Application::resetCameras(Camera& camera, const glm::uvec2& size) { } void Application::resizeGL() { + PROFILE_RANGE(__FUNCTION__); // Set the desired FBO texture size. If it hasn't changed, this does nothing. // Otherwise, it must rebuild the FBOs QSize renderSize; @@ -1534,6 +1537,7 @@ void Application::focusOutEvent(QFocusEvent* event) { } void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { + PROFILE_RANGE(__FUNCTION__); // Used by application overlay to determine how to draw cursor(s) _lastMouseMoveWasSimulated = deviceID > 0; if (!_lastMouseMoveWasSimulated) { @@ -1789,9 +1793,6 @@ void Application::checkFPS() { _frameCount = 0; _datagramProcessor->resetCounters(); _timerStart.start(); - - // ask the node list to check in with the domain server - DependencyManager::get()->sendDomainServerCheckIn(); } void Application::idle() { @@ -1837,6 +1838,7 @@ void Application::idle() { PerformanceTimer perfTimer("update"); PerformanceWarning warn(showWarnings, "Application::idle()... update()"); const float BIGGEST_DELTA_TIME_SECS = 0.25f; + PROFILE_RANGE(__FUNCTION__ "/idleUpdate"); update(glm::clamp((float)timeSinceLastUpdate / 1000.0f, 0.0f, BIGGEST_DELTA_TIME_SECS)); } { @@ -1860,7 +1862,7 @@ void Application::idle() { // After finishing all of the above work, ensure the idle timer is set to the proper interval, // depending on whether we're throttling or not idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : 0); - } + } // check for any requested background downloads. emit checkBackgroundDownloads(); @@ -2971,6 +2973,7 @@ QRect Application::getDesirableApplicationGeometry() { // or the "myCamera". // void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { + PROFILE_RANGE(__FUNCTION__); // We will use these below, from either the camera or head vectors calculated above viewFrustum.setProjection(camera.getProjection()); @@ -3327,7 +3330,7 @@ namespace render { const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f; const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f; - glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation()) + glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation()) / closestData.getAtmosphereOuterRadius(); float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter()); if (height < closestData.getAtmosphereInnerRadius()) { @@ -3335,8 +3338,8 @@ namespace render { alpha = 0.0f; if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) { - float directionY = glm::clamp(sunDirection.y, - -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + float directionY = glm::clamp(sunDirection.y, + -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + APPROXIMATE_DISTANCE_FROM_HORIZON; alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON); } @@ -3347,8 +3350,8 @@ namespace render { (closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius()); if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) { - float directionY = glm::clamp(sunDirection.y, - -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + float directionY = glm::clamp(sunDirection.y, + -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + APPROXIMATE_DISTANCE_FROM_HORIZON; alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON); } @@ -3475,9 +3478,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // Assuming nothing get's rendered through that if (!selfAvatarOnly) { - - // render models... if (DependencyManager::get()->shouldRenderEntities()) { + // render models... PerformanceTimer perfTimer("entities"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... entities..."); @@ -3485,11 +3487,11 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { - renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_HULLS); + 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 | (int)RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP); } renderArgs->_debugFlags = renderDebugFlags; _entities.render(renderArgs); @@ -3514,8 +3516,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se pendingChanges.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload); } else { - pendingChanges.updateItem(WorldBoxRenderData::_item, - [](WorldBoxRenderData& payload) { + pendingChanges.updateItem(WorldBoxRenderData::_item, + [](WorldBoxRenderData& payload) { payload._val++; }); } @@ -3534,7 +3536,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se } { - PerformanceTimer perfTimer("SceneProcessPendingChanges"); + PerformanceTimer perfTimer("SceneProcessPendingChanges"); _main3DScene->enqueuePendingChanges(pendingChanges); _main3DScene->processPendingChangesQueue(); @@ -4843,7 +4845,7 @@ qreal Application::getDevicePixelRatio() { mat4 Application::getEyeProjection(int eye) const { if (isHMDMode()) { return OculusManager::getEyeProjection(eye); - } + } return _viewFrustum.getProjection(); } diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index f691527186..99308a922f 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -29,12 +29,13 @@ DatagramProcessor::DatagramProcessor(QObject* parent) : } void DatagramProcessor::processDatagrams() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "DatagramProcessor::processDatagrams()"); if (_isShuttingDown) { return; // bail early... we're shutting down. } + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "DatagramProcessor::processDatagrams()"); + HifiSockAddr senderSockAddr; diff --git a/interface/src/InterfaceActionFactory.cpp b/interface/src/InterfaceActionFactory.cpp index 363fb66e76..dca1015ecc 100644 --- a/interface/src/InterfaceActionFactory.cpp +++ b/interface/src/InterfaceActionFactory.cpp @@ -35,8 +35,7 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i } -EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation, - EntityActionType type, +EntityActionPointer InterfaceActionFactory::factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments) { @@ -51,9 +50,7 @@ EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation } -EntityActionPointer InterfaceActionFactory::factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, - QByteArray data) { +EntityActionPointer InterfaceActionFactory::factoryBA(EntityItemPointer ownerEntity, QByteArray data) { QDataStream serializedArgumentStream(data); EntityActionType type; QUuid id; diff --git a/interface/src/InterfaceActionFactory.h b/interface/src/InterfaceActionFactory.h index 004c24163f..2031f5c57a 100644 --- a/interface/src/InterfaceActionFactory.h +++ b/interface/src/InterfaceActionFactory.h @@ -18,13 +18,11 @@ class InterfaceActionFactory : public EntityActionFactoryInterface { public: InterfaceActionFactory() : EntityActionFactoryInterface() { } virtual ~InterfaceActionFactory() { } - virtual EntityActionPointer factory(EntitySimulation* simulation, - EntityActionType type, + virtual EntityActionPointer factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments); - virtual EntityActionPointer factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, + virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data); }; diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index 8cc27341d6..7a93be80f1 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include "AudioScope.h" @@ -104,7 +107,7 @@ void AudioScope::freeScope() { } } -void AudioScope::render(int width, int height) { +void AudioScope::render(RenderArgs* renderArgs, int width, int height) { if (!_isEnabled) { return; @@ -122,24 +125,26 @@ void AudioScope::render(int width, int height) { int y = (height - (int)SCOPE_HEIGHT) / 2; int w = (int)SCOPE_WIDTH; int h = (int)SCOPE_HEIGHT; - - renderBackground(backgroundColor, x, y, w, h); - renderGrid(gridColor, x, y, w, h, gridRows, gridCols); - - renderLineStrip(_inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput); - renderLineStrip(_outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft); - renderLineStrip(_outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight); + + gpu::Batch batch; + auto geometryCache = DependencyManager::get(); + geometryCache->useSimpleDrawPipeline(batch); + auto textureCache = DependencyManager::get(); + batch.setUniformTexture(0, textureCache->getWhiteTexture()); + mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000); + batch.setProjectionTransform(legacyProjection); + batch.setModelTransform(Transform()); + batch.setViewTransform(Transform()); + geometryCache->renderQuad(batch, x, y, w, h, backgroundColor); + geometryCache->renderGrid(batch, x, y, w, h, gridRows, gridCols, gridColor, _audioScopeGrid); + renderLineStrip(batch, _inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput); + renderLineStrip(batch, _outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft); + renderLineStrip(batch, _outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight); + renderArgs->_context->syncCache(); + renderArgs->_context->render(batch); } -void AudioScope::renderBackground(const glm::vec4& color, int x, int y, int width, int height) { - DependencyManager::get()->renderQuad(x, y, width, height, color); -} - -void AudioScope::renderGrid(const glm::vec4& color, int x, int y, int width, int height, int rows, int cols) { - DependencyManager::get()->renderGrid(x, y, width, height, rows, cols, color, _audioScopeGrid); -} - -void AudioScope::renderLineStrip(int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray) { +void AudioScope::renderLineStrip(gpu::Batch& batch, int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray) { int16_t sample; int16_t* samples = ((int16_t*) byteArray->data()) + offset; @@ -194,7 +199,7 @@ void AudioScope::renderLineStrip(int id, const glm::vec4& color, int x, int y, i geometryCache->updateVertices(id, points, color); - geometryCache->renderVertices(gpu::LINE_STRIP, id); + geometryCache->renderVertices(batch, gpu::LINE_STRIP, id); } int AudioScope::addBufferToScope(QByteArray* byteArray, int frameOffset, const int16_t* source, int sourceSamplesPerChannel, diff --git a/interface/src/audio/AudioScope.h b/interface/src/audio/AudioScope.h index cc9367e2d5..4ff4b55c29 100644 --- a/interface/src/audio/AudioScope.h +++ b/interface/src/audio/AudioScope.h @@ -14,11 +14,14 @@ #include -#include - #include #include +#include +#include +#include + + class AudioScope : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -28,7 +31,7 @@ public: void freeScope(); void reallocateScope(int frames); - void render(int width, int height); + void render(RenderArgs* renderArgs, int width, int height); public slots: void toggle(); @@ -48,9 +51,7 @@ private slots: private: // Audio scope methods for rendering - static void renderBackground(const glm::vec4& color, int x, int y, int width, int height); - void renderGrid(const glm::vec4& color, int x, int y, int width, int height, int rows, int cols); - void renderLineStrip(int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray); + void renderLineStrip(gpu::Batch& batch, int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray); // Audio scope methods for data acquisition int addBufferToScope(QByteArray* byteArray, int frameOffset, const int16_t* source, int sourceSamples, diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index ca903a9771..ba37112fe1 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -52,16 +52,18 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { } glm::vec3 palmPosition; + glm::quat palmRotation; if (_hand == "right") { palmPosition = myAvatar->getRightPalmPosition(); + palmRotation = myAvatar->getRightPalmRotation(); } else { palmPosition = myAvatar->getLeftPalmPosition(); + palmRotation = myAvatar->getLeftPalmRotation(); } - auto rotation = myAvatar->getWorldAlignedOrientation(); + auto rotation = palmRotation * _relativeRotation; auto offset = rotation * _relativePosition; auto position = palmPosition + offset; - rotation *= _relativeRotation; unlock(); if (!tryLockForWrite()) { @@ -83,6 +85,13 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { return; } + if (_positionalTarget != position || _rotationalTarget != rotation) { + auto ownerEntity = _ownerEntity.lock(); + if (ownerEntity) { + ownerEntity->setActionDataDirty(true); + } + } + _positionalTarget = position; _rotationalTarget = rotation; unlock(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index aa6b6afc66..79c600b7ec 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -371,6 +371,12 @@ glm::vec3 MyAvatar::getLeftPalmPosition() { return leftHandPosition; } +glm::quat MyAvatar::getLeftPalmRotation() { + glm::quat leftRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation); + return leftRotation; +} + glm::vec3 MyAvatar::getRightPalmPosition() { glm::vec3 rightHandPosition; getSkeletonModel().getRightHandPosition(rightHandPosition); @@ -380,6 +386,12 @@ glm::vec3 MyAvatar::getRightPalmPosition() { return rightHandPosition; } +glm::quat MyAvatar::getRightPalmRotation() { + glm::quat rightRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); + return rightRotation; +} + void MyAvatar::clearReferential() { changeReferential(NULL); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4e76143774..34dfcad2ad 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -195,10 +195,12 @@ public slots: void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } void updateMotionBehavior(); - + glm::vec3 getLeftPalmPosition(); + glm::quat getLeftPalmRotation(); glm::vec3 getRightPalmPosition(); - + glm::quat getRightPalmRotation(); + void clearReferential(); bool setModelReferential(const QUuid& id); bool setJointReferential(const QUuid& id, int jointIndex); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index dafa332d53..2c1c800f94 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -184,6 +184,7 @@ void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorI // Draws the FBO texture for the screen void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); if (_alpha == 0.0f) { return; } @@ -252,6 +253,7 @@ vec2 getPolarCoordinates(const PalmData& palm) { // Draws the FBO texture for Oculus rift. void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int eye) { + PROFILE_RANGE(__FUNCTION__); if (_alpha == 0.0f) { return; } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index e7d220893f..01e581399c 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -74,6 +74,7 @@ ApplicationOverlay::~ApplicationOverlay() { // Renders the overlays either to a texture or to the screen void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); CHECK_GL_ERROR(); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); @@ -98,6 +99,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { } void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); if (_uiTexture) { gpu::Batch batch; auto geometryCache = DependencyManager::get(); @@ -112,6 +114,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { } void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); glm::vec2 size = qApp->getCanvasSize(); mat4 legacyProjection = glm::ortho(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP); @@ -129,11 +132,12 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { emit qApp->renderingOverlay(); qApp->getOverlays().renderHUD(renderArgs); + DependencyManager::get()->render(renderArgs, _overlayFramebuffer->size().width(), _overlayFramebuffer->size().height()); + glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - renderArgs->_context->syncCache(); fboViewport(_overlayFramebuffer); } @@ -219,6 +223,7 @@ GLuint ApplicationOverlay::getOverlayTexture() { } void ApplicationOverlay::buildFramebufferObject() { + PROFILE_RANGE(__FUNCTION__); QSize fboSize = qApp->getDeviceSize(); if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) { // Already built diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index 399e8a459a..7a0c3c00c3 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -75,44 +75,44 @@ void ImageOverlay::render(RenderArgs* args) { glm::vec2 topLeft(left, top); glm::vec2 bottomRight(right, bottom); - float imageWidth = _texture->getWidth(); - float imageHeight = _texture->getHeight(); - // if for some reason our image is not over 0 width or height, don't attempt to render the image - if (_renderImage && imageWidth > 0 && imageHeight > 0) { + if (_renderImage) { + float imageWidth = _texture->getWidth(); + float imageHeight = _texture->getHeight(); + if (imageWidth > 0 && imageHeight > 0) { + QRect fromImage; + if (_wantClipFromImage) { + float scaleX = imageWidth / _texture->getOriginalWidth(); + float scaleY = imageHeight / _texture->getOriginalHeight(); - QRect fromImage; - if (_wantClipFromImage) { - float scaleX = imageWidth / _texture->getOriginalWidth(); - float scaleY = imageHeight / _texture->getOriginalHeight(); + fromImage.setX(scaleX * _fromImage.x()); + fromImage.setY(scaleY * _fromImage.y()); + fromImage.setWidth(scaleX * _fromImage.width()); + fromImage.setHeight(scaleY * _fromImage.height()); + } + else { + fromImage.setX(0); + fromImage.setY(0); + fromImage.setWidth(imageWidth); + fromImage.setHeight(imageHeight); + } - fromImage.setX(scaleX * _fromImage.x()); - fromImage.setY(scaleY * _fromImage.y()); - fromImage.setWidth(scaleX * _fromImage.width()); - fromImage.setHeight(scaleY * _fromImage.height()); + float x = fromImage.x() / imageWidth; + float y = fromImage.y() / imageHeight; + float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure + float h = fromImage.height() / imageHeight; + + glm::vec2 texCoordTopLeft(x, y); + glm::vec2 texCoordBottomRight(x + w, y + h); + + DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); } else { - fromImage.setX(0); - fromImage.setY(0); - fromImage.setWidth(imageWidth); - fromImage.setHeight(imageHeight); + DependencyManager::get()->renderQuad(topLeft, bottomRight, quadColor); } - - float x = fromImage.x() / imageWidth; - float y = fromImage.y() / imageHeight; - float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure - float h = fromImage.height() / imageHeight; - - glm::vec2 texCoordTopLeft(x, y); - glm::vec2 texCoordBottomRight(x + w, y + h); - - DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); + glDisable(GL_TEXTURE_2D); } else { DependencyManager::get()->renderQuad(topLeft, bottomRight, quadColor); } - - if (_renderImage) { - glDisable(GL_TEXTURE_2D); - } } void ImageOverlay::setProperties(const QScriptValue& properties) { diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index fb0a095e13..db1bc2185a 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -96,6 +96,7 @@ void Overlays::cleanupOverlaysToDelete() { } void Overlays::renderHUD(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); QReadLocker lock(&_lock); gpu::Batch batch; renderArgs->_batch = &batch; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 03d88200c5..11d24c6d9d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -802,6 +802,8 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity); connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity); connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity); + + connect(&(*DependencyManager::get()), &SceneScriptingInterface::shouldRenderEntitiesChanged, this, &EntityTreeRenderer::updateEntityRenderStatus, Qt::QueuedConnection); } QScriptValueList EntityTreeRenderer::createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID) { @@ -1152,3 +1154,17 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons entityScriptB.property("collisionWithEntity").call(entityScriptA, args); } } + +void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) { + if (DependencyManager::get()->shouldRenderEntities()) { + for (auto entityID : _entityIDsLastInScene) { + addingEntity(entityID); + } + _entityIDsLastInScene.clear(); + } else { + _entityIDsLastInScene = _entitiesInScene.keys(); + for (auto entityID : _entityIDsLastInScene) { + deletingEntity(entityID); + } + } +} diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index bd6044516f..28a6a3172c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -90,6 +90,9 @@ public: virtual void scriptContentsAvailable(const QUrl& url, const QString& scriptContents); virtual void errorInLoadingScript(const QUrl& url); + // For Scene.shouldRenderEntities + QList& getEntitiesLastInScene() { return _entityIDsLastInScene; } + signals: void mousePressOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); void mouseMoveOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); @@ -112,6 +115,7 @@ public slots: void deletingEntity(const EntityItemID& entityID); void entitySciptChanging(const EntityItemID& entityID, const bool reload); void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); + void updateEntityRenderStatus(bool shouldRenderEntities); // optional slots that can be wired to menu items void setDisplayElementChildProxies(bool value) { _displayElementChildProxies = value; } @@ -188,6 +192,8 @@ private: int _previousStageDay; QHash _entitiesInScene; + // For Scene.shouldRenderEntities + QList _entityIDsLastInScene; }; diff --git a/libraries/entities/src/EntityActionFactoryInterface.h b/libraries/entities/src/EntityActionFactoryInterface.h index 9f4056cdff..adff1a53ba 100644 --- a/libraries/entities/src/EntityActionFactoryInterface.h +++ b/libraries/entities/src/EntityActionFactoryInterface.h @@ -23,13 +23,11 @@ class EntityActionFactoryInterface : public QObject, public Dependency { public: EntityActionFactoryInterface() { } virtual ~EntityActionFactoryInterface() { } - virtual EntityActionPointer factory(EntitySimulation* simulation, - EntityActionType type, + virtual EntityActionPointer factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments) { assert(false); return nullptr; } - virtual EntityActionPointer factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, + virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data) { assert(false); return nullptr; } }; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1165518097..794d0752a1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1489,20 +1489,22 @@ void EntityItem::clearSimulationOwnership() { } + bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer action) { + lockForWrite(); checkWaitingToRemove(simulation); - if (!checkWaitingActionData(simulation)) { - return false; - } bool result = addActionInternal(simulation, action); if (!result) { removeAction(simulation, action->getID()); } + + unlock(); return result; } bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPointer action) { + assertLocked(); assert(action); assert(simulation); auto actionOwnerEntity = action->getOwnerEntity().lock(); @@ -1523,36 +1525,37 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi } bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionID, const QVariantMap& arguments) { + lockForWrite(); checkWaitingToRemove(simulation); - if (!checkWaitingActionData(simulation)) { - return false; - } if (!_objectActions.contains(actionID)) { + unlock(); return false; } EntityActionPointer action = _objectActions[actionID]; - bool success = action->updateArguments(arguments); + bool success = action->updateArguments(arguments); if (success) { _allActionsDataCache = serializeActions(success); } else { qDebug() << "EntityItem::updateAction failed"; } + unlock(); return success; } bool EntityItem::removeAction(EntitySimulation* simulation, const QUuid& actionID) { + lockForWrite(); checkWaitingToRemove(simulation); - if (!checkWaitingActionData(simulation)) { - return false;; - } - return removeActionInternal(actionID); + bool success = removeActionInternal(actionID); + unlock(); + return success; } bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* simulation) { + assertWriteLocked(); if (_objectActions.contains(actionID)) { if (!simulation) { EntityTree* entityTree = _element ? _element->getTree() : nullptr; @@ -1575,7 +1578,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s } bool EntityItem::clearActions(EntitySimulation* simulation) { - _waitingActionData.clear(); + lockForWrite(); QHash::iterator i = _objectActions.begin(); while (i != _objectActions.end()) { const QUuid id = i.key(); @@ -1584,85 +1587,84 @@ bool EntityItem::clearActions(EntitySimulation* simulation) { action->setOwnerEntity(nullptr); action->removeFromSimulation(simulation); } + // empty _serializedActions means no actions for the EntityItem _actionsToRemove.clear(); _allActionsDataCache.clear(); + unlock(); return true; } -bool EntityItem::deserializeActions(QByteArray allActionsData, EntitySimulation* simulation) const { - bool success = true; - QVector serializedActions; - if (allActionsData.size() > 0) { - QDataStream serializedActionsStream(allActionsData); - serializedActionsStream >> serializedActions; + +void EntityItem::deserializeActions() { + assertUnlocked(); + lockForWrite(); + deserializeActionsInternal(); + unlock(); +} + + +void EntityItem::deserializeActionsInternal() { + assertWriteLocked(); + + if (!_element) { + return; } // Keep track of which actions got added or updated by the new actionData - QSet updated; EntityTree* entityTree = _element ? _element->getTree() : nullptr; - if (!simulation) { - simulation = entityTree ? entityTree->getSimulation() : nullptr; + assert(entityTree); + EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr; + assert(simulation); + + QVector serializedActions; + if (_allActionsDataCache.size() > 0) { + QDataStream serializedActionsStream(_allActionsDataCache); + serializedActionsStream >> serializedActions; } - if (simulation && entityTree) { - foreach(QByteArray serializedAction, serializedActions) { - QDataStream serializedActionStream(serializedAction); - EntityActionType actionType; - QUuid actionID; - serializedActionStream >> actionType; - serializedActionStream >> actionID; - updated << actionID; + QSet updated; - if (_objectActions.contains(actionID)) { - EntityActionPointer action = _objectActions[actionID]; - // TODO: make sure types match? there isn't currently a way to - // change the type of an existing action. - action->deserialize(serializedAction); - } else { - auto actionFactory = DependencyManager::get(); - if (simulation) { - EntityItemPointer entity = entityTree->findEntityByEntityItemID(_id); - EntityActionPointer action = actionFactory->factoryBA(simulation, entity, serializedAction); - if (action) { - entity->addActionInternal(simulation, action); - } - } else { - // we can't yet add the action. This method will be called later. - success = false; - } + foreach(QByteArray serializedAction, serializedActions) { + QDataStream serializedActionStream(serializedAction); + EntityActionType actionType; + QUuid actionID; + serializedActionStream >> actionType; + serializedActionStream >> actionID; + updated << actionID; + + if (_objectActions.contains(actionID)) { + EntityActionPointer action = _objectActions[actionID]; + // TODO: make sure types match? there isn't currently a way to + // change the type of an existing action. + action->deserialize(serializedAction); + } else { + auto actionFactory = DependencyManager::get(); + + // EntityItemPointer entity = entityTree->findEntityByEntityItemID(_id, false); + EntityItemPointer entity = shared_from_this(); + EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); + if (action) { + entity->addActionInternal(simulation, action); } } + } - // remove any actions that weren't included in the new data. - QHash::const_iterator i = _objectActions.begin(); - while (i != _objectActions.end()) { - const QUuid id = i.key(); - if (!updated.contains(id)) { - _actionsToRemove << id; - } - i++; + // remove any actions that weren't included in the new data. + QHash::const_iterator i = _objectActions.begin(); + while (i != _objectActions.end()) { + QUuid id = i.key(); + if (!updated.contains(id)) { + _actionsToRemove << id; } - } else { - // no simulation - success = false; + i++; } - return success; -} - -bool EntityItem::checkWaitingActionData(EntitySimulation* simulation) const { - if (_waitingActionData.size() == 0) { - return true; - } - bool success = deserializeActions(_waitingActionData, simulation); - if (success) { - _waitingActionData.clear(); - } - return success; + return; } void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { + assertLocked(); foreach(QUuid actionID, _actionsToRemove) { removeActionInternal(actionID, simulation); } @@ -1670,21 +1672,22 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { } void EntityItem::setActionData(QByteArray actionData) { + assertUnlocked(); + lockForWrite(); + setActionDataInternal(actionData); + unlock(); +} + +void EntityItem::setActionDataInternal(QByteArray actionData) { + assertWriteLocked(); checkWaitingToRemove(); - bool success = deserializeActions(actionData); _allActionsDataCache = actionData; - if (success) { - _waitingActionData.clear(); - } else { - _waitingActionData = actionData; - } + deserializeActionsInternal(); } QByteArray EntityItem::serializeActions(bool& success) const { + assertLocked(); QByteArray result; - if (!checkWaitingActionData()) { - return _waitingActionData; - } if (_objectActions.size() == 0) { success = true; @@ -1713,21 +1716,132 @@ QByteArray EntityItem::serializeActions(bool& success) const { return result; } -const QByteArray EntityItem::getActionData() const { +const QByteArray EntityItem::getActionDataInternal() const { + if (_actionDataDirty) { + bool success; + QByteArray newDataCache = serializeActions(success); + if (success) { + _allActionsDataCache = newDataCache; + } + _actionDataDirty = false; + } return _allActionsDataCache; } +const QByteArray EntityItem::getActionData() const { + assertUnlocked(); + lockForRead(); + auto result = getActionDataInternal(); + unlock(); + return result; +} + QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const { QVariantMap result; - - if (!checkWaitingActionData()) { - return result; - } + lockForRead(); if (_objectActions.contains(actionID)) { EntityActionPointer action = _objectActions[actionID]; result = action->getArguments(); result["type"] = EntityActionInterface::actionTypeToString(action->getType()); } + unlock(); return result; } + + + +#define ENABLE_LOCKING 1 + +#ifdef ENABLE_LOCKING +void EntityItem::lockForRead() const { + _lock.lockForRead(); +} + +bool EntityItem::tryLockForRead() const { + return _lock.tryLockForRead(); +} + +void EntityItem::lockForWrite() const { + _lock.lockForWrite(); +} + +bool EntityItem::tryLockForWrite() const { + return _lock.tryLockForWrite(); +} + +void EntityItem::unlock() const { + _lock.unlock(); +} + +bool EntityItem::isLocked() const { + bool readSuccess = tryLockForRead(); + if (readSuccess) { + unlock(); + } + bool writeSuccess = tryLockForWrite(); + if (writeSuccess) { + unlock(); + } + if (readSuccess && writeSuccess) { + return false; // if we can take both kinds of lock, there was no previous lock + } + return true; // either read or write failed, so there is some lock in place. +} + + +bool EntityItem::isWriteLocked() const { + bool readSuccess = tryLockForRead(); + if (readSuccess) { + unlock(); + return false; + } + bool writeSuccess = tryLockForWrite(); + if (writeSuccess) { + unlock(); + return false; + } + return true; // either read or write failed, so there is some lock in place. +} + + +bool EntityItem::isUnlocked() const { + // this can't be sure -- this may get unlucky and hit locks from other threads. what we're actually trying + // to discover is if *this* thread hasn't locked the EntityItem. Try repeatedly to take both kinds of lock. + bool readSuccess = false; + for (int i=0; i<80; i++) { + readSuccess = tryLockForRead(); + if (readSuccess) { + unlock(); + break; + } + QThread::usleep(200); + } + + bool writeSuccess = false; + if (readSuccess) { + for (int i=0; i<80; i++) { + writeSuccess = tryLockForWrite(); + if (writeSuccess) { + unlock(); + break; + } + QThread::usleep(300); + } + } + + if (readSuccess && writeSuccess) { + return true; // if we can take both kinds of lock, there was no previous lock + } + return false; +} +#else +void EntityItem::lockForRead() const { } +bool EntityItem::tryLockForRead() const { return true; } +void EntityItem::lockForWrite() const { } +bool EntityItem::tryLockForWrite() const { return true; } +void EntityItem::unlock() const { } +bool EntityItem::isLocked() const { return true; } +bool EntityItem::isWriteLocked() const { return true; } +bool EntityItem::isUnlocked() const { return true; } +#endif diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index bc8901c6b1..de431446e8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -68,10 +68,28 @@ const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) #define debugTreeVector(V) V << "[" << V << " in meters ]" +#if DEBUG + #define assertLocked() assert(isLocked()) +#else + #define assertLocked() +#endif + +#if DEBUG + #define assertWriteLocked() assert(isWriteLocked()) +#else + #define assertWriteLocked() +#endif + +#if DEBUG + #define assertUnlocked() assert(isUnlocked()) +#else + #define assertUnlocked() +#endif + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. -class EntityItem { +class EntityItem : public std::enable_shared_from_this { // These two classes manage lists of EntityItem pointers and must be able to cleanup pointers when an EntityItem is deleted. // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by // the managers themselves, hence they are fiends) whose NULL status can be used to determine which managers still need to @@ -395,9 +413,14 @@ public: bool hasActions() { return !_objectActions.empty(); } QList getActionIDs() { return _objectActions.keys(); } QVariantMap getActionArguments(const QUuid& actionID) const; + void deserializeActions(); + void setActionDataDirty(bool value) const { _actionDataDirty = value; } protected: + const QByteArray getActionDataInternal() const; + void setActionDataInternal(QByteArray actionData); + static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; QUuid _id; @@ -470,18 +493,28 @@ protected: bool addActionInternal(EntitySimulation* simulation, EntityActionPointer action); bool removeActionInternal(const QUuid& actionID, EntitySimulation* simulation = nullptr); - bool deserializeActions(QByteArray allActionsData, EntitySimulation* simulation = nullptr) const; + void deserializeActionsInternal(); QByteArray serializeActions(bool& success) const; QHash _objectActions; + static int _maxActionsDataSize; mutable QByteArray _allActionsDataCache; // when an entity-server starts up, EntityItem::setActionData is called before the entity-tree is // ready. This means we can't find our EntityItemPointer or add the action to the simulation. These // are used to keep track of and work around this situation. - bool checkWaitingActionData(EntitySimulation* simulation = nullptr) const; void checkWaitingToRemove(EntitySimulation* simulation = nullptr); - mutable QByteArray _waitingActionData; mutable QSet _actionsToRemove; + mutable bool _actionDataDirty = false; + + mutable QReadWriteLock _lock; + void lockForRead() const; + bool tryLockForRead() const; + void lockForWrite() const; + bool tryLockForWrite() const; + void unlock() const; + bool isLocked() const; + bool isWriteLocked() const; + bool isUnlocked() const; }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7cc2c03dfc..f1c6157694 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -574,7 +574,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, if (actionType == ACTION_TYPE_NONE) { return false; } - EntityActionPointer action = actionFactory->factory(simulation, actionType, actionID, entity, arguments); + EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments); if (action) { entity->addAction(simulation, action); auto nodeList = DependencyManager::get(); diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index a2d20fe5d5..f2bd1e873e 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -146,6 +146,7 @@ void EntitySimulation::sortEntitiesThatMoved() { void EntitySimulation::addEntity(EntityItemPointer entity) { assert(entity); + entity->deserializeActions(); if (entity->isMortal()) { _mortalEntities.insert(entity); quint64 expiry = entity->getExpiry(); diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 5f4d5f4af6..48a42fe5f1 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -117,7 +117,7 @@ void GLBackend::updateTransform() { if (_transform._invalidView || _transform._invalidProj || _transform._invalidViewport) { glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0); glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_transform._transformCamera), (const void*)&_transform._transformCamera); glBindBuffer(GL_ARRAY_BUFFER, 0); CHECK_GL_ERROR(); } @@ -125,7 +125,7 @@ void GLBackend::updateTransform() { if (_transform._invalidModel) { glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0); glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_transform._transformObject), (const void*) &_transform._transformObject); glBindBuffer(GL_ARRAY_BUFFER, 0); CHECK_GL_ERROR(); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8d77f815b7..b06c6f264b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -287,6 +287,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { } if (_serverActionData != _entity->getActionData()) { + setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY); return true; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a721e0cad3..9bda5b8048 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL #include #include @@ -24,7 +23,7 @@ #include "TextureCache.h" #include "gpu/Batch.h" -#include "gpu/GLBackend.h" +#include "gpu/Context.h" #include "gpu/StandardShaderLib.h" #include "simple_vert.h" @@ -269,7 +268,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { // Fetch the ViewMatrix; glm::mat4 invViewMat; - _viewState->getViewTransform().getMatrix(invViewMat); + invViewMat = args->_viewFrustum->getView(); auto& program = _directionalLight; const LightLocations* locations = &_directionalLightLocations; @@ -344,7 +343,8 @@ void DeferredLightingEffect::render(RenderArgs* args) { float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; - _viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + args->_viewFrustum->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + batch._glUniform1f(locations->nearLocation, nearVal); float depthScale = (farVal - nearVal) / farVal; @@ -394,9 +394,9 @@ void DeferredLightingEffect::render(RenderArgs* args) { // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; - - const glm::vec3& eyePoint = _viewState->getCurrentViewFrustum()->getPosition(); - float nearRadius = glm::distance(eyePoint, _viewState->getCurrentViewFrustum()->getNearTopLeft()); + + auto eyePoint = args->_viewFrustum->getPosition(); + float nearRadius = glm::distance(eyePoint, args->_viewFrustum->getNearTopLeft()); auto geometryCache = DependencyManager::get(); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 35f946c55c..02e59bfa3a 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -279,14 +279,21 @@ void GeometryCache::renderSphere(gpu::Batch& batch, float radius, int slices, in const int VERTICES_SLOT = 0; const int NORMALS_SLOT = 1; const int COLOR_SLOT = 2; - gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); + static gpu::Stream::FormatPointer streamFormat; + static gpu::Element positionElement, normalElement, colorElement; + if (!streamFormat) { + streamFormat.reset(new gpu::Stream::Format()); // 1 for everyone + streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); + positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element; + normalElement = streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element; + colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element; + } - gpu::BufferView verticesView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); - gpu::BufferView normalsView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element); - gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); + gpu::BufferView verticesView(verticesBuffer, positionElement); + gpu::BufferView normalsView(verticesBuffer, normalElement); + gpu::BufferView colorView(colorBuffer, colorElement); batch.setInputFormat(streamFormat); batch.setInputBuffer(VERTICES_SLOT, verticesView); @@ -899,14 +906,21 @@ void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::ve const int VERTICES_SLOT = 0; const int NORMALS_SLOT = 1; const int COLOR_SLOT = 2; - gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone + static gpu::Stream::FormatPointer streamFormat; + static gpu::Element positionElement, normalElement, colorElement; + if (!streamFormat) { + streamFormat.reset(new gpu::Stream::Format()); // 1 for everyone + streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); + positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element; + normalElement = streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element; + colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element; + } - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); - - gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); - gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element); + + gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, positionElement); + gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, normalElement); gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); batch.setInputFormat(streamFormat); @@ -986,12 +1000,18 @@ void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec const int VERTICES_SLOT = 0; const int COLOR_SLOT = 1; - gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); - - gpu::BufferView verticesView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); - gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); + static gpu::Stream::FormatPointer streamFormat; + static gpu::Element positionElement, colorElement; + if (!streamFormat) { + streamFormat.reset(new gpu::Stream::Format()); // 1 for everyone + streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); + positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element; + colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element; + } + + gpu::BufferView verticesView(verticesBuffer, positionElement); + gpu::BufferView colorView(colorBuffer, colorElement); batch.setInputFormat(streamFormat); batch.setInputBuffer(VERTICES_SLOT, verticesView);