diff --git a/examples/dice.js b/examples/dice.js index ee48d59617..f313e606b8 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -32,7 +32,7 @@ var BUTTON_SIZE = 32; var PADDING = 3; var offButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE, + x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y- (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, height: BUTTON_SIZE, @@ -40,6 +40,17 @@ var offButton = Overlays.addOverlay("image", { color: { red: 255, green: 255, blue: 255}, alpha: 1 }); + +var deleteButton = Overlays.addOverlay("image", { + x: screenSize.x / 2 - BUTTON_SIZE, + y: screenSize.y- (BUTTON_SIZE + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); + var diceButton = Overlays.addOverlay("image", { x: screenSize.x / 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING), @@ -108,6 +119,8 @@ function mousePressEvent(event) { if (clickedOverlay == offButton) { deleteDice(); Script.stop(); + } else if (clickedOverlay == deleteButton) { + deleteDice(); } else if (clickedOverlay == diceButton) { var HOW_HARD = 2.0; var position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); @@ -120,6 +133,7 @@ function mousePressEvent(event) { function scriptEnding() { Overlays.deleteOverlay(offButton); Overlays.deleteOverlay(diceButton); + Overlays.deleteOverlay(deleteButton); } Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity); diff --git a/examples/grab.js b/examples/grab.js index 5d2ae13cde..df2042350e 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -179,7 +179,7 @@ function update(deltaTime) { if (distanceToTarget > CLOSE_ENOUGH) { // compute current velocity in the direction we want to move velocityTowardTarget = Vec3.dot(currentVelocity, Vec3.normalize(dPosition)); - velocityTowardTarget = Vec3.multiply(dPosition, velocityTowardTarget); + velocityTowardTarget = Vec3.multiply(Vec3.normalize(dPosition), velocityTowardTarget); // compute the speed we would like to be going toward the target position desiredVelocity = Vec3.multiply(dPosition, (1.0 / deltaTime) * SPRING_RATE); @@ -193,12 +193,15 @@ function update(deltaTime) { // Add Damping newVelocity = Vec3.subtract(newVelocity, Vec3.multiply(newVelocity, DAMPING_RATE)); // Update entity - - //add damping to angular velocity: + } else { + newVelocity = entityProps.velocity; } if (shouldRotate) { angularVelocity = Vec3.subtract(angularVelocity, Vec3.multiply(angularVelocity, ANGULAR_DAMPING_RATE)); + } else { + angularVelocity = entityProps.angularVelocity; } + Entities.editEntity(grabbedEntity, { velocity: newVelocity, angularVelocity: angularVelocity diff --git a/examples/harmonicOscillator.js b/examples/harmonicOscillator.js index 0ffbce8beb..653c2db939 100644 --- a/examples/harmonicOscillator.js +++ b/examples/harmonicOscillator.js @@ -16,8 +16,7 @@ var ball, disc; var time = 0.0; var range = 1.0; -var speed = 0.5; - +var omega = 2.0 * Math.PI / 32.0; var basePosition = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); @@ -25,35 +24,44 @@ ball = Entities.addEntity( { type: "Box", position: basePosition, dimensions: { x: 0.1, y: 0.1, z: 0.1 }, - color: { red: 255, green: 0, blue: 255 } + color: { red: 255, green: 0, blue: 255 }, + collisionsWillMove: false, + ignoreForCollisions: true }); disc = Entities.addEntity( { type: "Sphere", position: basePosition, - dimensions: { x: range, y: range / 20.0, z: range }, + dimensions: { x: range * 0.8, y: range / 20.0, z: range * 0.8}, color: { red: 128, green: 128, blue: 128 } }); +function randomColor() { + return { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 }; +} + function update(deltaTime) { - time += deltaTime * speed; + time += deltaTime; if (!ball.isKnownID) { ball = Entities.identifyEntity(ball); } - rotation = Quat.angleAxis(time/Math.PI * 180.0, { x: 0, y: 1, z: 0 }); + rotation = Quat.angleAxis(time * omega /Math.PI * 180.0, { x: 0, y: 1, z: 0 }); Entities.editEntity(ball, { - color: { red: 255 * (Math.sin(time)/2.0 + 0.5), - green: 255 - 255 * (Math.sin(time)/2.0 + 0.5), + color: { red: 255 * (Math.sin(time * omega)/2.0 + 0.5), + green: 255 - 255 * (Math.sin(time * omega)/2.0 + 0.5), blue: 0 }, - position: { x: basePosition.x + Math.sin(time) / 2.0 * range, + position: { x: basePosition.x + Math.sin(time * omega) / 2.0 * range, y: basePosition.y, - z: basePosition.z + Math.cos(time) / 2.0 * range }, - velocity: { x: Math.cos(time)/2.0 * range, + z: basePosition.z + Math.cos(time * omega) / 2.0 * range }, + velocity: { x: Math.cos(time * omega)/2.0 * range * omega, y: 0.0, - z: -Math.sin(time)/2.0 * range }, + z: -Math.sin(time * omega)/2.0 * range * omega}, rotation: rotation }); + if (Math.random() < 0.007) { + Entities.editEntity(disc, { color: randomColor() }); + } } function scriptEnding() { diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index e525818e51..26bcc63f15 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -26,6 +26,20 @@ ); }; } + function createEmitGroupCheckedPropertyUpdateFunction(group, propertyName) { + return function() { + var properties = {}; + properties[group] = {}; + properties[group][propertyName] = this.checked; + EventBridge.emitWebEvent( + JSON.stringify({ + type: "update", + properties: properties + }) + ); + }; + } + function createEmitNumberPropertyUpdateFunction(propertyName) { return function() { EventBridge.emitWebEvent( @@ -286,6 +300,8 @@ var elZoneAtmosphereScatteringWavelengthsX = document.getElementById("property-zone-atmosphere-scattering-wavelengths-x"); var elZoneAtmosphereScatteringWavelengthsY = document.getElementById("property-zone-atmosphere-scattering-wavelengths-y"); var elZoneAtmosphereScatteringWavelengthsZ = document.getElementById("property-zone-atmosphere-scattering-wavelengths-z"); + var elZoneAtmosphereHasStars = document.getElementById("property-zone-atmosphere-has-stars"); + if (window.EventBridge !== undefined) { EventBridge.scriptEventReceived.connect(function(data) { @@ -486,7 +502,7 @@ elZoneAtmosphereScatteringWavelengthsX.value = properties.atmosphere.scatteringWavelengths.x; elZoneAtmosphereScatteringWavelengthsY.value = properties.atmosphere.scatteringWavelengths.y; elZoneAtmosphereScatteringWavelengthsZ.value = properties.atmosphere.scatteringWavelengths.z; - + elZoneAtmosphereHasStars.checked = properties.atmosphere.hasStars; } @@ -650,6 +666,8 @@ elZoneAtmosphereScatteringWavelengthsX.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); elZoneAtmosphereScatteringWavelengthsY.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); elZoneAtmosphereScatteringWavelengthsZ.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); + elZoneAtmosphereHasStars.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('atmosphere','hasStars')); + elMoveSelectionToGrid.addEventListener("click", function() { EventBridge.emitWebEvent(JSON.stringify({ @@ -1136,23 +1154,29 @@
Atmosphere Mie Scattering
- +
Atmosphere Rayleigh Scattering
- +
Atmosphere Scattering Wavelenghts
-
X
-
Y
-
Z
+
X
+
Y
+
Z
+
+ Atmosphere Has Stars + + + +
diff --git a/examples/html/style.css b/examples/html/style.css index 8be9b92a51..c87201da4b 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -121,6 +121,14 @@ input.coord { display: block; } +input.no-spin::-webkit-outer-spin-button, +input.no-spin::-webkit-inner-spin-button { + display: none; + -webkit-appearance: none; + -moz-appearance: none; + margin: 0; /* <-- Apparently some margin are still there even though it's hidden */ +} + table#entity-table { border-collapse: collapse; font-family: Sans-Serif; diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 70af987243..f3ea18aef3 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -203,7 +203,7 @@ SelectionManager = (function() { try { listeners[i](); } catch (e) { - print("got exception"); + print("EntitySelectionTool got exception: " + JSON.stringify(e)); } } }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8d660848f2..cc62490b64 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -692,6 +692,9 @@ Application::~Application() { nodeThread->quit(); nodeThread->wait(); + Leapmotion::destroy(); + RealSense::destroy(); + qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages } @@ -809,8 +812,7 @@ void Application::initializeUi() { if (devicePixelRatio != oldDevicePixelRatio) { oldDevicePixelRatio = devicePixelRatio; qDebug() << "Device pixel ratio changed, triggering GL resize"; - resizeGL(_glWidget->width(), - _glWidget->height()); + resizeGL(); } }); } @@ -827,15 +829,7 @@ void Application::paintGL() { PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::paintGL()"); - - // Set the desired FBO texture size. If it hasn't changed, this does nothing. - // Otherwise, it must rebuild the FBOs - if (OculusManager::isConnected()) { - DependencyManager::get()->setFrameBufferSize(OculusManager::getRenderTargetSize()); - } else { - QSize fbSize = _glWidget->getDeviceSize() * getRenderResolutionScale(); - DependencyManager::get()->setFrameBufferSize(fbSize); - } + resizeGL(); glEnable(GL_LINE_SMOOTH); @@ -912,7 +906,14 @@ void Application::paintGL() { renderRearViewMirror(_mirrorViewRect); } - DependencyManager::get()->render(); + auto finalFbo = DependencyManager::get()->render(); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); + glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y, + 0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height(), + GL_COLOR_BUFFER_BIT, GL_NEAREST); + { PerformanceTimer perfTimer("renderOverlay"); @@ -957,33 +958,47 @@ void Application::showEditEntitiesHelp() { InfoView::show(INFO_EDIT_ENTITIES_PATH); } -void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height) { +void Application::resetCamerasOnResizeGL(Camera& camera, const glm::uvec2& size) { if (OculusManager::isConnected()) { - OculusManager::configureCamera(camera, width, height); + OculusManager::configureCamera(camera, size.x, size.y); } else if (TV3DManager::isConnected()) { - TV3DManager::configureCamera(camera, width, height); + TV3DManager::configureCamera(camera, size.x, size.y); } else { - camera.setAspectRatio((float)width / height); + camera.setAspectRatio((float)size.x / size.y); camera.setFieldOfView(_fieldOfView.get()); } } -void Application::resizeGL(int width, int height) { - DependencyManager::get()->setFrameBufferSize(QSize(width, height)); - resetCamerasOnResizeGL(_myCamera, width, height); +void Application::resizeGL() { + // Set the desired FBO texture size. If it hasn't changed, this does nothing. + // Otherwise, it must rebuild the FBOs + QSize renderSize; + if (OculusManager::isConnected()) { + renderSize = OculusManager::getRenderTargetSize(); + } else { + renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale(); + } + if (_renderResolution == toGlm(renderSize)) { + return; + } - glViewport(0, 0, width, height); // shouldn't this account for the menu??? + _renderResolution = toGlm(renderSize); + DependencyManager::get()->setFrameBufferSize(renderSize); + resetCamerasOnResizeGL(_myCamera, _renderResolution); + + glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu??? updateProjectionMatrix(); glLoadIdentity(); auto offscreenUi = DependencyManager::get(); offscreenUi->resize(_glWidget->size()); + _glWidget->makeCurrent(); // update Stats width // let's set horizontal offset to give stats some margin to mirror int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; - Stats::getInstance()->resetWidth(width, horizontalOffset); + Stats::getInstance()->resetWidth(_renderResolution.x, horizontalOffset); } void Application::updateProjectionMatrix() { @@ -1821,7 +1836,7 @@ void Application::setFullscreen(bool fullscreen) { } void Application::setEnable3DTVMode(bool enable3DTVMode) { - resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); + resizeGL(); } void Application::setEnableVRMode(bool enableVRMode) { @@ -1846,7 +1861,7 @@ void Application::setEnableVRMode(bool enableVRMode) { _myCamera.setHmdRotation(glm::quat()); } - resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); + resizeGL(); updateCursorVisibility(); } @@ -1931,6 +1946,7 @@ void Application::setActiveFaceTracker() { bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::UseCamera); Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE); Menu::getInstance()->getActionForOption(MenuOption::VelocityFilter)->setVisible(isUsingDDE); + Menu::getInstance()->getActionForOption(MenuOption::CalibrateCamera)->setVisible(isUsingDDE); auto ddeTracker = DependencyManager::get(); ddeTracker->setIsMuted(isMuted); ddeTracker->setEnabled(isUsingDDE && !isMuted); @@ -2644,7 +2660,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node if (rootCode) { VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, + rootDetails.y * TREE_SCALE, + rootDetails.z * TREE_SCALE), + rootDetails.s * TREE_SCALE); ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds); @@ -2685,7 +2704,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // only send to the NodeTypes that are serverType if (node->getActiveSocket() && node->getType() == serverType) { - // get the server bounds for this server QUuid nodeUUID = node->getUUID(); @@ -2707,7 +2725,12 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node if (rootCode) { VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, + rootDetails.y * TREE_SCALE, + rootDetails.z * TREE_SCALE), + rootDetails.s * TREE_SCALE); + + ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds); if (serverFrustumLocation != ViewFrustum::OUTSIDE) { @@ -2753,7 +2776,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node } // set up the packet for sending... unsigned char* endOfQueryPacket = queryPacket; - + // insert packet type/version and node UUID endOfQueryPacket += populatePacketHeader(reinterpret_cast(endOfQueryPacket), packetType); @@ -3217,12 +3240,12 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs _stars.render(theCamera.getFieldOfView(), theCamera.getAspectRatio(), theCamera.getNearClip(), alpha); } - // draw the sky dome - if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { - PerformanceTimer perfTimer("atmosphere"); - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... atmosphere..."); - _environment.renderAtmospheres(theCamera); + // draw the sky dome + if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { + PerformanceTimer perfTimer("atmosphere"); + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... atmosphere..."); + _environment.renderAtmospheres(theCamera); } } @@ -4625,7 +4648,3 @@ PickRay Application::computePickRay() const { bool Application::hasFocus() const { return _glWidget->hasFocus(); } - -void Application::resizeGL() { - this->resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); -} diff --git a/interface/src/Application.h b/interface/src/Application.h index 10df094c2e..5a3756e768 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -163,7 +163,7 @@ public: void initializeGL(); void initializeUi(); void paintGL(); - void resizeGL(int width, int height); + void resizeGL(); void resizeEvent(QResizeEvent * size); @@ -194,7 +194,6 @@ public: bool hasFocus() const; PickRay computePickRay() const; PickRay computeViewPickRay(float xRatio, float yRatio) const; - void resizeGL(); bool isThrottleRendering() const; @@ -463,7 +462,7 @@ private slots: void setCursorVisible(bool visible); private: - void resetCamerasOnResizeGL(Camera& camera, int width, int height); + void resetCamerasOnResizeGL(Camera& camera, const glm::uvec2& size); void updateProjectionMatrix(); void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true); @@ -662,6 +661,7 @@ private: QHash _acceptedExtensions; QList _domainConnectionRefusals; + glm::uvec2 _renderResolution; }; #endif // hifi_Application_h diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 2cbec1b258..995e1908a9 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -64,7 +64,7 @@ void GLCanvas::paintGL() { } void GLCanvas::resizeGL(int width, int height) { - Application::getInstance()->resizeGL(width, height); + Application::getInstance()->resizeGL(); } void GLCanvas::activeChanged(Qt::ApplicationState state) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 425f9d13d9..61213e7334 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -392,6 +392,9 @@ Menu::Menu() { useAudioForMouth->setVisible(false); QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true); ddeFiltering->setVisible(false); + QAction* ddeCalibrate = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::CalibrateCamera, 0, + DependencyManager::get().data(), SLOT(calibrate())); + ddeCalibrate->setVisible(false); #endif #if defined(HAVE_FACESHIFT) || defined(HAVE_DDE) faceTrackingMenu->addSeparator(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b15607df8f..96c8fedf0d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -154,6 +154,7 @@ namespace MenuOption { const QString Bookmarks = "Bookmarks"; const QString CascadedShadows = "Cascaded"; const QString CachesSize = "RAM Caches Size"; + const QString CalibrateCamera = "Calibrate Camera"; const QString Chat = "Chat..."; const QString Collisions = "Collisions"; const QString Console = "Console..."; @@ -181,7 +182,7 @@ namespace MenuOption { const QString EditEntitiesHelp = "Edit Entities Help..."; const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString EnableCharacterController = "Enable avatar collisions"; - const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; + const QString EnableGlowEffect = "Enable Glow Effect"; const QString EnableVRMode = "Enable VR Mode"; const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; const QString ExpandMyAvatarTiming = "Expand /myAvatar"; diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 59d2b42a51..6ed253c1ec 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -20,6 +20,7 @@ #include #include +#include "Application.h" #include "DdeFaceTracker.h" #include "FaceshiftConstants.h" #include "InterfaceLogging.h" @@ -86,16 +87,16 @@ static const float DDE_COEFFICIENT_SCALES[] = { 3.0f, // BrowsU_L 3.0f, // BrowsU_R 1.0f, // JawFwd - 1.5f, // JawLeft + 2.0f, // JawLeft 1.8f, // JawOpen 1.0f, // JawChew - 1.5f, // JawRight + 2.0f, // JawRight 1.5f, // MouthLeft 1.5f, // MouthRight 1.5f, // MouthFrown_L 1.5f, // MouthFrown_R - 1.5f, // MouthSmile_L - 1.5f, // MouthSmile_R + 2.5f, // MouthSmile_L + 2.5f, // MouthSmile_R 1.0f, // MouthDimple_L 1.0f, // MouthDimple_R 1.0f, // LipsStretch_L @@ -106,8 +107,8 @@ static const float DDE_COEFFICIENT_SCALES[] = { 1.0f, // LipsLowerDown 1.0f, // LipsUpperOpen 1.0f, // LipsLowerOpen - 2.5f, // LipsFunnel - 2.0f, // LipsPucker + 1.5f, // LipsFunnel + 2.5f, // LipsPucker 1.5f, // ChinLowerRaise 1.5f, // ChinUpperRaise 1.0f, // Sneer @@ -135,7 +136,9 @@ struct Packet { char name[MAX_NAME_SIZE + 1]; }; -const float STARTING_DDE_MESSAGE_TIME = 0.033f; +static const float STARTING_DDE_MESSAGE_TIME = 0.033f; + +static const int CALIBRATION_SAMPLES = 150; #ifdef WIN32 // warning C4351: new behavior: elements of array 'DdeFaceTracker::_lastEyeBlinks' will be default initialized @@ -178,11 +181,18 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui _filteredBrowUp(0.0f), _lastEyeBlinks(), _filteredEyeBlinks(), - _lastEyeCoefficients() + _lastEyeCoefficients(), + _isCalibrating(false), + _calibrationValues(), + _calibrationCount(0), + _calibrationBillboard(NULL), + _calibrationBillboardID(0), + _calibrationMessage(QString()) { _coefficients.resize(NUM_FACESHIFT_BLENDSHAPES); - _blendshapeCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES); + _coefficientAverages.resize(NUM_FACESHIFT_BLENDSHAPES); + _calibrationValues.resize(NUM_FACESHIFT_BLENDSHAPES); _eyeStates[0] = EYE_OPEN; _eyeStates[1] = EYE_OPEN; @@ -195,6 +205,10 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui DdeFaceTracker::~DdeFaceTracker() { setEnabled(false); + + if (_isCalibrating) { + cancelCalibration(); + } } #ifdef WIN32 @@ -212,6 +226,12 @@ void DdeFaceTracker::setEnabled(bool enabled) { return; } #ifdef HAVE_DDE + + if (_isCalibrating) { + cancelCalibration(); + } + + // isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket. _udpSocket.close(); if (enabled) { @@ -382,10 +402,18 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _coefficients[DDE_TO_FACESHIFT_MAPPING[i]] = packet.expressions[i]; } + // Calibration + if (_isCalibrating) { + addCalibrationDatum(); + } + for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { + _coefficients[i] -= _coefficientAverages[i]; + } + // Use BrowsU_C to control both brows' up and down float browUp = _coefficients[_browUpCenterIndex]; if (isFiltering) { - const float BROW_VELOCITY_FILTER_STRENGTH = 0.75f; + const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f; float velocity = fabs(browUp - _lastBrowUp) / _averageMessageTime; float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp; @@ -399,11 +427,11 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { _coefficients[_browDownRightIndex] = -browUp; // Offset jaw open coefficient - static const float JAW_OPEN_THRESHOLD = 0.16f; + static const float JAW_OPEN_THRESHOLD = 0.1f; _coefficients[_jawOpenIndex] = _coefficients[_jawOpenIndex] - JAW_OPEN_THRESHOLD; // Offset smile coefficients - static const float SMILE_THRESHOLD = 0.18f; + static const float SMILE_THRESHOLD = 0.5f; _coefficients[_mouthSmileLeftIndex] = _coefficients[_mouthSmileLeftIndex] - SMILE_THRESHOLD; _coefficients[_mouthSmileRightIndex] = _coefficients[_mouthSmileRightIndex] - SMILE_THRESHOLD; @@ -430,7 +458,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { // Change to closing or opening states const float EYE_CONTROL_HYSTERISIS = 0.25f; - const float EYE_CLOSING_THRESHOLD = 0.95f; + const float EYE_CLOSING_THRESHOLD = 0.8f; const float EYE_OPENING_THRESHOLD = EYE_CONTROL_THRESHOLD - EYE_CONTROL_HYSTERISIS; if ((_eyeStates[i] == EYE_OPEN || _eyeStates[i] == EYE_OPENING) && eyeCoefficients[i] > EYE_CLOSING_THRESHOLD) { _eyeStates[i] = EYE_CLOSING; @@ -510,4 +538,81 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { } else { qCWarning(interfaceapp) << "DDE Face Tracker: Decode error"; } + + if (_isCalibrating && _calibrationCount > CALIBRATION_SAMPLES) { + finishCalibration(); + } +} + +static const int CALIBRATION_BILLBOARD_WIDTH = 240; +static const int CALIBRATION_BILLBOARD_HEIGHT = 180; +static const int CALIBRATION_BILLBOARD_TOP_MARGIN = 60; +static const int CALIBRATION_BILLBOARD_LEFT_MARGIN = 30; +static const int CALIBRATION_BILLBOARD_FONT_SIZE = 16; +static const float CALIBRATION_BILLBOARD_ALPHA = 0.5f; +static QString CALIBRATION_INSTRUCTION_MESSAGE = "Hold still to calibrate"; + +void DdeFaceTracker::calibrate() { + if (!_isCalibrating) { + qCDebug(interfaceapp) << "DDE Face Tracker: Calibration started"; + + _isCalibrating = true; + _calibrationCount = 0; + _calibrationMessage = CALIBRATION_INSTRUCTION_MESSAGE + "\n\n"; + + _calibrationBillboard = new TextOverlay(); + _calibrationBillboard->setTopMargin(CALIBRATION_BILLBOARD_TOP_MARGIN); + _calibrationBillboard->setLeftMargin(CALIBRATION_BILLBOARD_LEFT_MARGIN); + _calibrationBillboard->setFontSize(CALIBRATION_BILLBOARD_FONT_SIZE); + _calibrationBillboard->setText(CALIBRATION_INSTRUCTION_MESSAGE); + _calibrationBillboard->setAlpha(CALIBRATION_BILLBOARD_ALPHA); + glm::vec2 viewport = qApp->getCanvasSize(); + _calibrationBillboard->setX((viewport.x - CALIBRATION_BILLBOARD_WIDTH) / 2); + _calibrationBillboard->setY((viewport.y - CALIBRATION_BILLBOARD_HEIGHT) / 2); + _calibrationBillboard->setWidth(CALIBRATION_BILLBOARD_WIDTH); + _calibrationBillboard->setHeight(CALIBRATION_BILLBOARD_HEIGHT); + _calibrationBillboardID = qApp->getOverlays().addOverlay(_calibrationBillboard); + + for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { + _calibrationValues[i] = 0.0f; + } + } +} + +void DdeFaceTracker::addCalibrationDatum() { + const int LARGE_TICK_INTERVAL = 30; + const int SMALL_TICK_INTERVAL = 6; + int samplesLeft = CALIBRATION_SAMPLES - _calibrationCount; + if (samplesLeft % LARGE_TICK_INTERVAL == 0) { + _calibrationMessage += QString::number(samplesLeft / LARGE_TICK_INTERVAL); + _calibrationBillboard->setText(_calibrationMessage); + } else if (samplesLeft % SMALL_TICK_INTERVAL == 0) { + _calibrationMessage += "."; + _calibrationBillboard->setText(_calibrationMessage); + } + + for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { + _calibrationValues[i] += _coefficients[i]; + } + + _calibrationCount += 1; +} + +void DdeFaceTracker::cancelCalibration() { + qApp->getOverlays().deleteOverlay(_calibrationBillboardID); + _calibrationBillboard = NULL; + _isCalibrating = false; + qCDebug(interfaceapp) << "DDE Face Tracker: Calibration cancelled"; +} + +void DdeFaceTracker::finishCalibration() { + qApp->getOverlays().deleteOverlay(_calibrationBillboardID); + _calibrationBillboard = NULL; + _isCalibrating = false; + + for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) { + _coefficientAverages[i] = _calibrationValues[i] / (float)CALIBRATION_SAMPLES; + } + + qCDebug(interfaceapp) << "DDE Face Tracker: Calibration finished"; } diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index 9edbd4df58..7019802603 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -20,6 +20,7 @@ #include #include +#include #include "FaceTracker.h" @@ -51,6 +52,7 @@ public: public slots: void setEnabled(bool enabled); + void calibrate(); private slots: void processFinished(int exitCode, QProcess::ExitStatus exitStatus); @@ -121,6 +123,17 @@ private: float _lastEyeBlinks[2]; float _filteredEyeBlinks[2]; float _lastEyeCoefficients[2]; + QVector _coefficientAverages; + + bool _isCalibrating; + int _calibrationCount; + QVector _calibrationValues; + TextOverlay* _calibrationBillboard; + int _calibrationBillboardID; + QString _calibrationMessage; + void addCalibrationDatum(); + void cancelCalibration(); + void finishCalibration(); }; #endif // hifi_DdeFaceTracker_h diff --git a/interface/src/devices/DeviceTracker.cpp b/interface/src/devices/DeviceTracker.cpp index 265a77b362..2a956a42de 100644 --- a/interface/src/devices/DeviceTracker.cpp +++ b/interface/src/devices/DeviceTracker.cpp @@ -66,6 +66,14 @@ DeviceTracker::ID DeviceTracker::registerDevice(const Name& name, DeviceTracker* return deviceID; } +void DeviceTracker::destroyDevice(const Name& name) { + DeviceTracker::ID deviceID = getDeviceID(name); + if (deviceID != INVALID_DEVICE) { + delete Singleton::get()->_devicesVector[getDeviceID(name)]; + Singleton::get()->_devicesVector[getDeviceID(name)] = nullptr; + } +} + void DeviceTracker::updateAll() { //TODO C++11 for (auto deviceIt = Singleton::get()->_devicesVector.begin(); deviceIt != Singleton::get()->_devicesVector.end(); deviceIt++) { for (Vector::iterator deviceIt = Singleton::get()->_devicesVector.begin(); deviceIt != Singleton::get()->_devicesVector.end(); deviceIt++) { diff --git a/interface/src/devices/DeviceTracker.h b/interface/src/devices/DeviceTracker.h index 2e0f69b371..b28e22b06d 100644 --- a/interface/src/devices/DeviceTracker.h +++ b/interface/src/devices/DeviceTracker.h @@ -79,6 +79,8 @@ public: /// INVALID_DEVICE_NAME if the name is already taken static ID registerDevice(const Name& name, DeviceTracker* tracker); + static void destroyDevice(const Name& name); + // DeviceTracker interface virtual void update(); diff --git a/interface/src/devices/Leapmotion.cpp b/interface/src/devices/Leapmotion.cpp index 04cd51a484..cb99cf324d 100644 --- a/interface/src/devices/Leapmotion.cpp +++ b/interface/src/devices/Leapmotion.cpp @@ -50,6 +50,11 @@ void Leapmotion::init() { } } +// static +void Leapmotion::destroy() { + DeviceTracker::destroyDevice(NAME); +} + // static Leapmotion* Leapmotion::getInstance() { DeviceTracker* device = DeviceTracker::getDevice(NAME); diff --git a/interface/src/devices/Leapmotion.h b/interface/src/devices/Leapmotion.h index a0c75da38f..266b9beb87 100644 --- a/interface/src/devices/Leapmotion.h +++ b/interface/src/devices/Leapmotion.h @@ -26,6 +26,7 @@ public: static const Name NAME; static void init(); + static void destroy(); /// Leapmotion MotionTracker factory static Leapmotion* getInstance(); diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 065b7499d3..f4693d3c08 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -627,7 +627,7 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { //Full texture viewport for glow effect glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); - finalFbo = DependencyManager::get()->render(true); + finalFbo = DependencyManager::get()->render(); } else { finalFbo = DependencyManager::get()->getPrimaryFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, 0); diff --git a/interface/src/devices/RealSense.cpp b/interface/src/devices/RealSense.cpp index 8e9cd85451..d9b1486f09 100644 --- a/interface/src/devices/RealSense.cpp +++ b/interface/src/devices/RealSense.cpp @@ -54,6 +54,11 @@ void RealSense::init() { } } +// static +void RealSense::destroy() { + DeviceTracker::destroyDevice(NAME); +} + // static RealSense* RealSense::getInstance() { DeviceTracker* device = DeviceTracker::getDevice(NAME); diff --git a/interface/src/devices/RealSense.h b/interface/src/devices/RealSense.h index 20111365d0..c958ab1e53 100644 --- a/interface/src/devices/RealSense.h +++ b/interface/src/devices/RealSense.h @@ -32,6 +32,7 @@ public: static const Name NAME; static void init(); + static void destroy(); /// RealSense MotionTracker factory static RealSense* getInstance(); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index 9d5dd2faae..5d60bf7e19 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -14,7 +14,7 @@ #include #include - +#include "gpu/GLBackend.h" #include "Application.h" #include "TV3DManager.h" @@ -163,10 +163,18 @@ void TV3DManager::display(Camera& whichCamera) { glPopMatrix(); glDisable(GL_SCISSOR_TEST); + auto finalFbo = DependencyManager::get()->render(); + auto fboSize = finalFbo->getSize(); + // Get the ACTUAL device size for the BLIT + deviceSize = qApp->getDeviceSize(); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); + glBlitFramebuffer(0, 0, fboSize.x, fboSize.y, + 0, 0, deviceSize.width(), deviceSize.height(), + GL_COLOR_BUFFER_BIT, GL_NEAREST); + // reset the viewport to how we started glViewport(0, 0, deviceSize.width(), deviceSize.height()); - - DependencyManager::get()->render(); } void TV3DManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 5c878b484c..1bfdf88032 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -190,8 +190,8 @@ void ApplicationOverlay::renderOverlay() { Overlays& overlays = qApp->getOverlays(); _textureFov = glm::radians(_hmdUIAngularSize); - glm::vec2 deviceSize = qApp->getCanvasSize(); - _textureAspectRatio = (float)deviceSize.x / (float)deviceSize.y; + glm::vec2 size = qApp->getCanvasSize(); + _textureAspectRatio = aspect(size); //Handle fading and deactivation/activation of UI @@ -204,12 +204,13 @@ void ApplicationOverlay::renderOverlay() { _overlays.buildFramebufferObject(); _overlays.bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, size.x, size.y); glPushMatrix(); { const float NEAR_CLIP = -10000; const float FAR_CLIP = 10000; glLoadIdentity(); - glOrtho(0, deviceSize.x, deviceSize.y, 0, NEAR_CLIP, FAR_CLIP); + glOrtho(0, size.x, size.y, 0, NEAR_CLIP, FAR_CLIP); glMatrixMode(GL_MODELVIEW); @@ -269,6 +270,7 @@ void ApplicationOverlay::displayOverlayTexture() { if (_alpha < 1.0) { glEnable(GL_BLEND); } + glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height()); static const glm::vec2 topLeft(-1, 1); static const glm::vec2 bottomRight(1, -1); @@ -1129,8 +1131,9 @@ void ApplicationOverlay::TexturedHemisphere::cleanupVBO() { } void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { - auto deviceSize = qApp->getDeviceSize(); - if (_framebufferObject != NULL && deviceSize == _framebufferObject->size()) { + auto canvasSize = qApp->getCanvasSize(); + QSize fboSize = QSize(canvasSize.x, canvasSize.y); + if (_framebufferObject != NULL && fboSize == _framebufferObject->size()) { // Already build return; } @@ -1139,7 +1142,7 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { delete _framebufferObject; } - _framebufferObject = new QOpenGLFramebufferObject(deviceSize, QOpenGLFramebufferObject::Depth); + _framebufferObject = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); glBindTexture(GL_TEXTURE_2D, getTexture()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 0fb9296b64..e4c476c6f7 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "EntityTreeRenderer.h" @@ -449,15 +450,19 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, } else { _viewState->endOverrideEnvironmentData(); + auto stage = scene->getSkyStage(); if (_bestZone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) { - auto stage = scene->getSkyStage(); stage->getSkybox()->setColor(_bestZone->getSkyboxProperties().getColorVec3()); if (_bestZone->getSkyboxProperties().getURL().isEmpty()) { stage->getSkybox()->clearCubemap(); } else { - stage->getSkybox()->clearCubemap(); // NOTE: this should be changed to do something to set the cubemap + // Update the Texture of the Skybox with the one pointed by this zone + auto cubeMap = DependencyManager::get()->getTexture(_bestZone->getSkyboxProperties().getURL(), CUBE_TEXTURE); + stage->getSkybox()->setCubemap(cubeMap->getGPUTexture()); } stage->setBackgroundMode(model::SunSkyStage::SKY_BOX); + } else { + stage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through } } @@ -475,7 +480,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, _hasPreviousZone = false; } _viewState->endOverrideEnvironmentData(); - scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); + scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through } // we must call endScene while we still have the tree locked so that no one deletes a model diff --git a/libraries/entities/src/AtmospherePropertyGroup.cpp b/libraries/entities/src/AtmospherePropertyGroup.cpp index c1210be24e..2e0a043749 100644 --- a/libraries/entities/src/AtmospherePropertyGroup.cpp +++ b/libraries/entities/src/AtmospherePropertyGroup.cpp @@ -16,12 +16,19 @@ #include "EntityItemPropertiesMacros.h" AtmospherePropertyGroup::AtmospherePropertyGroup() { - _center = glm::vec3(0.0f); - _innerRadius = 0.0f; - _outerRadius = 0.0f; - _mieScattering = 0.0f; - _rayleighScattering = 0.0f; - _scatteringWavelengths = glm::vec3(0.0f); + const glm::vec3 DEFAULT_CENTER = glm::vec3(0.0f, -1000.0f, 0.0f); + const float DEFAULT_INNER_RADIUS = 1000.0f; + const float DEFAULT_OUTER_RADIUS = 1025.0f; + const float DEFAULT_RAYLEIGH_SCATTERING = 0.0025f; + const float DEFAULT_MIE_SCATTERING = 0.0010f; + const glm::vec3 DEFAULT_SCATTERING_WAVELENGTHS = glm::vec3(0.650f, 0.570f, 0.475f); + + _center = DEFAULT_CENTER; + _innerRadius = DEFAULT_INNER_RADIUS; + _outerRadius = DEFAULT_OUTER_RADIUS; + _mieScattering = DEFAULT_MIE_SCATTERING; + _rayleighScattering = DEFAULT_RAYLEIGH_SCATTERING; + _scatteringWavelengths = DEFAULT_SCATTERING_WAVELENGTHS; _hasStars = true; } diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c26dcacd4c..4a8a2fc53d 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -386,8 +386,9 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi done: if (faces.count() == 0) { // empty mesh mesh.parts.pop_back(); + } else { + faceGroups.append(faces); // We're done with this group. Add the faces. } - faceGroups.append(faces); // We're done with this group. Add the faces. //qCDebug(modelformat) << "end group:" << meshPart.materialID << " original faces:" << originalFaceCountForDebugging << " triangles:" << faces.count() << " keep going:" << result; return result; } diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 23cfef7764..ef272bb708 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -479,6 +479,7 @@ void GLBackend::getCurrentGLState(State::Data& state) { void GLBackend::syncPipelineStateCache() { State::Data state; + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); getCurrentGLState(state); State::Signature signature = State::evalSignature(state); diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 4387821cfd..69f2b33d1b 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -373,7 +373,6 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; - if (needUpdate) { if (texture.isStoredMipAvailable(0)) { Texture::PixelsPointer mip = texture.accessStoredMip(0); diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 883b7c7098..19add9a47e 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -68,11 +68,11 @@ public: uint8 _maxMip = MAX_MIP_LEVEL; Desc() {} - Desc(const Filter filter) : _filter(filter) {} + Desc(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _filter(filter), _wrapModeU(wrap), _wrapModeV(wrap), _wrapModeW(wrap) {} }; Sampler() {} - Sampler(const Filter filter) : _desc(filter) {} + Sampler(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _desc(filter, wrap) {} Sampler(const Desc& desc) : _desc(desc) {} ~Sampler() {} diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index d27bdd4372..55572a5122 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -92,15 +92,3 @@ void Material::setTextureView(MapChannel channel, const gpu::TextureView& view) _textureMap[channel] = view; } -// TextureStorage -TextureStorage::TextureStorage(const QUrl& url) : gpu::Texture::Storage(), _url(url) { - init(); -} - -TextureStorage::~TextureStorage() { -} - -void TextureStorage::init() { - _gpuTexture = TexturePointer(Texture::createFromStorage(this)); -} - diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 7e4417b55b..ea0ab808e9 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -23,27 +23,6 @@ namespace model { -typedef glm::vec3 Color; - -// TextureStorage is a specialized version of the gpu::Texture::Storage -// It adds the URL and the notion that it owns the gpu::Texture -class TextureStorage : public gpu::Texture::Storage { -public: - TextureStorage(const QUrl& url); - ~TextureStorage(); - - const QUrl& getUrl() const { return _url; } - const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } - -protected: - gpu::TexturePointer _gpuTexture; - QUrl _url; - void init(); -}; -typedef std::shared_ptr< TextureStorage > TextureStoragePointer; - - - class Material { public: typedef gpu::BufferView UniformBufferView; @@ -62,6 +41,7 @@ public: NUM_MAPS, }; typedef std::map TextureMap; + typedef std::bitset MapFlags; enum FlagBit { DIFFUSE_BIT = 0, diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index d10b97a455..00a64c9606 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -21,6 +21,7 @@ using namespace model; Skybox::Skybox() { +/* // PLease create a default engineer skybox _cubemap.reset( gpu::Texture::createCube(gpu::Element::COLOR_RGBA_32, 1)); unsigned char texels[] = { 255, 0, 0, 255, @@ -30,7 +31,7 @@ Skybox::Skybox() { 0, 255, 0, 255, 255, 0, 255, 255, }; - _cubemap->assignStoredMip(0, gpu::Element::COLOR_RGBA_32, sizeof(texels), texels); + _cubemap->assignStoredMip(0, gpu::Element::COLOR_RGBA_32, sizeof(texels), texels);*/ } void Skybox::setColor(const Color& color) { @@ -47,7 +48,7 @@ void Skybox::clearCubemap() { void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) { - if (skybox.getCubemap()) { + if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { static gpu::PipelinePointer thePipeline; static gpu::BufferPointer theBuffer; static gpu::Stream::FormatPointer theFormat; diff --git a/libraries/model/src/model/Skybox.slf b/libraries/model/src/model/Skybox.slf index 452b9daebe..03f7a5ef8a 100755 --- a/libraries/model/src/model/Skybox.slf +++ b/libraries/model/src/model/Skybox.slf @@ -18,7 +18,8 @@ varying vec3 color; void main(void) { - vec4 texel = textureCube(cubeMap, normalize(normal)); - gl_FragData[0] = texel; - // gl_FragData[0] = vec4(normal, 1.0); + vec3 coord = normalize(normal); + vec4 texel = textureCube(cubeMap, coord); + // gl_FragData[0] = vec4(texel.xyz * color, texel.w); + gl_FragData[0] = vec4(texel.xyz, 1.0); } diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index c29ebfe83e..e5d23e9191 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -190,7 +190,8 @@ const float NUM_HOURS_PER_DAY = 24.0f; const float NUM_HOURS_PER_HALF_DAY = NUM_HOURS_PER_DAY * 0.5f; SunSkyStage::SunSkyStage() : - _sunLight(new Light()) + _sunLight(new Light()), + _skybox(new Skybox()) { _sunLight->setType(Light::SUN); @@ -290,6 +291,19 @@ void SunSkyStage::updateGraphicsObject() const { _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); } + // Background + switch (getBackgroundMode()) { + case NO_BACKGROUND: { + break; + } + case SKY_DOME: { + break; + } + case SKY_BOX: { + break; + } + }; + static int firstTime = 0; if (firstTime == 0) { firstTime++; diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index b6a19b49cd..a5f39cb825 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -223,11 +223,11 @@ public: const SkyboxPointer& getSkybox() const { valid(); return _skybox; } protected: - BackgroundMode _backgroundMode = SKY_DOME; + BackgroundMode _backgroundMode = SKY_BOX; LightPointer _sunLight; AtmospherePointer _atmosphere; - SkyboxPointer _skybox; + mutable SkyboxPointer _skybox; gpu::PipelinePointer _skyPipeline; diff --git a/libraries/model/src/model/TextureStorage.cpp b/libraries/model/src/model/TextureStorage.cpp new file mode 100755 index 0000000000..499054c34b --- /dev/null +++ b/libraries/model/src/model/TextureStorage.cpp @@ -0,0 +1,28 @@ +// +// TextureStorage.cpp +// libraries/model/src/model +// +// Created by Sam Gateau on 5/6/2015. +// 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 "TextureStorage.h" + +using namespace model; +using namespace gpu; + +// TextureStorage +TextureStorage::TextureStorage() : Texture::Storage(), + _gpuTexture(Texture::createFromStorage(this)) +{} + +TextureStorage::~TextureStorage() { +} + +void TextureStorage::reset(const QUrl& url, const TextureUsage& usage) { + _url = url; + _usage = usage; +} + diff --git a/libraries/model/src/model/TextureStorage.h b/libraries/model/src/model/TextureStorage.h new file mode 100755 index 0000000000..2b19a6cc1d --- /dev/null +++ b/libraries/model/src/model/TextureStorage.h @@ -0,0 +1,56 @@ +// +// TextureStorage.h +// libraries/model/src/model +// +// Created by Sam Gateau on 5/6/2015. +// 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_model_TextureStorage_h +#define hifi_model_TextureStorage_h + +#include "gpu/Texture.h" + +#include "Material.h" + +#include + +namespace model { + +typedef glm::vec3 Color; + +class TextureUsage { +public: + gpu::Texture::Type _type{ gpu::Texture::TEX_2D }; + Material::MapFlags _materialUsage{ Material::DIFFUSE_MAP }; + + int _environmentUsage = 0; +}; + +// TextureStorage is a specialized version of the gpu::Texture::Storage +// It provides the mechanism to create a texture from a Url and the intended usage +// that guides the internal format used +class TextureStorage : public gpu::Texture::Storage { +public: + TextureStorage(); + ~TextureStorage(); + + const QUrl& getUrl() const { return _url; } + const gpu::Texture::Type getType() const { return _usage._type; } + const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } + + void reset(const QUrl& url, const TextureUsage& usage); + +protected: + gpu::TexturePointer _gpuTexture; + TextureUsage _usage; + QUrl _url; +}; +typedef std::shared_ptr< TextureStorage > TextureStoragePointer; + +}; + +#endif // hifi_model_TextureStorage_h + diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c897da3ef9..b5d14e4814 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -151,10 +151,10 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _movingStepsWithoutSimulationOwner = 0; } - int ownershipClaimDelay = 50; // TODO -- how to pick this? based on meters from our characterController? + uint32_t ownershipClaimDelay = 50; // TODO -- how to pick this? based on meters from our characterController? if (_movingStepsWithoutSimulationOwner > ownershipClaimDelay) { - qDebug() << "Warning -- claiming something I saw moving." << getName(); + //qDebug() << "Warning -- claiming something I saw moving." << getName(); setShouldClaimSimulationOwnership(true); } @@ -178,7 +178,7 @@ void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) { const int MAX_NUM_NON_MOVING_UPDATES = 5; bool EntityMotionState::doesNotNeedToSendUpdate() const { - return !_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES; + return !_body || (_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES); } bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { @@ -232,6 +232,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _serverPosition += dt * _serverVelocity; } + // TODO: compensate for simulation offset here btTransform worldTrans = _body->getWorldTransform(); glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); @@ -310,86 +311,60 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ return; // never update entities that are unknown } + bool active = _body->isActive(); + if (!active) { + if (_sentMoving) { + // make sure all derivatives are zero + glm::vec3 zero(0.0f); + _entity->setVelocity(zero); + _entity->setAngularVelocity(zero); + _entity->setAcceleration(zero); + } + + } else { + float gravityLength = glm::length(_entity->getGravity()); + float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); + if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { + // acceleration measured during the most recent simulation step was close to gravity. + if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet. this is to avoid + // overflowing the counter. + incrementAccelerationNearlyGravityCount(); + } + } else { + // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter + resetAccelerationNearlyGravityCount(); + } + + // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let + // the entity server's estimates include gravity. + if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { + _entity->setAcceleration(_entity->getGravity()); + } else { + _entity->setAcceleration(glm::vec3(0.0f)); + } + } + + // remember properties for local server prediction + _serverPosition = _entity->getPosition(); + _serverRotation = _entity->getRotation(); + _serverVelocity = _entity->getVelocity(); + _serverAcceleration = _entity->getAcceleration(); + _serverAngularVelocity = _entity->getAngularVelocity(); + + _sentMoving = _serverVelocity != glm::vec3(0.0f) || _serverAngularVelocity != glm::vec3(0.0f); + EntityItemProperties properties = _entity->getProperties(); - float gravityLength = glm::length(_entity->getGravity()); - float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); - if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { - // acceleration measured during the most recent simulation step was close to gravity. - if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { - // only increment this if we haven't reached the threshold yet. this is to avoid - // overflowing the counter. - incrementAccelerationNearlyGravityCount(); - } - } else { - // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter - resetAccelerationNearlyGravityCount(); - } - - // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let - // the entity server's estimates include gravity. - if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { - _entity->setAcceleration(_entity->getGravity()); - } else { - _entity->setAcceleration(glm::vec3(0.0f)); - } - - btTransform worldTrans = _body->getWorldTransform(); - _serverPosition = bulletToGLM(worldTrans.getOrigin()); - properties.setPosition(_serverPosition + ObjectMotionState::getWorldOffset()); - - _serverRotation = bulletToGLM(worldTrans.getRotation()); + // explicitly set the properties that changed + properties.setPosition(_serverPosition); properties.setRotation(_serverRotation); - - bool zeroSpeed = true; - bool zeroSpin = true; - - if (_body->isActive()) { - _serverVelocity = bulletToGLM(_body->getLinearVelocity()); - _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); - - // if the speeds are very small we zero them out - const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec - zeroSpeed = (glm::length2(_serverVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); - if (zeroSpeed) { - _serverVelocity = glm::vec3(0.0f); - } - const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec - zeroSpin = glm::length2(_serverAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; - if (zeroSpin) { - _serverAngularVelocity = glm::vec3(0.0f); - } - - _sentMoving = ! (zeroSpeed && zeroSpin); - } else { - _serverVelocity = _serverAngularVelocity = glm::vec3(0.0f); - _sentMoving = false; - } properties.setVelocity(_serverVelocity); - _serverGravity = _entity->getGravity(); - properties.setGravity(_entity->getGravity()); - _serverAcceleration = _entity->getAcceleration(); properties.setAcceleration(_serverAcceleration); properties.setAngularVelocity(_serverAngularVelocity); - auto nodeList = DependencyManager::get(); - QUuid myNodeID = nodeList->getSessionUUID(); - QUuid simulatorID = _entity->getSimulatorID(); - - if (getShouldClaimSimulationOwnership()) { - properties.setSimulatorID(myNodeID); - setShouldClaimSimulationOwnership(false); - } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { - // we are the simulator and the entity has stopped. give up "simulator" status - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); - } else if (simulatorID == myNodeID && !_body->isActive()) { - // it's not active. don't keep simulation ownership. - _entity->setSimulatorID(QUuid()); - properties.setSimulatorID(QUuid()); - } - - // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. + // RELIABLE_SEND_HACK: count number of updates for entities at rest + // so we can stop sending them after some limit. if (_sentMoving) { _numNonMovingUpdates = 0; } else { @@ -397,8 +372,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } if (_numNonMovingUpdates <= 1) { // we only update lastEdited when we're sending new physics data - // (i.e. NOT when we just simulate the positions forward, nor when we resend non-moving data) - // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly quint64 lastSimulated = _entity->getLastSimulated(); _entity->setLastEdited(lastSimulated); properties.setLastEdited(lastSimulated); @@ -415,6 +388,25 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setLastEdited(_entity->getLastEdited()); } + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); + QUuid simulatorID = _entity->getSimulatorID(); + + if (getShouldClaimSimulationOwnership()) { + // we think we should own it, so we tell the server that we do, + // but we don't remember that we own it... + // instead we expect the sever to tell us later whose ownership it has accepted + properties.setSimulatorID(myNodeID); + setShouldClaimSimulationOwnership(false); + } else if (simulatorID == myNodeID + && !_sentMoving + && _numNonMovingUpdates == MAX_NUM_NON_MOVING_UPDATES) { + // we own it, the entity has stopped, and we're sending the last non-moving update + // --> give up ownership + _entity->setSimulatorID(QUuid()); + properties.setSimulatorID(QUuid()); + } + if (EntityItem::getSendPhysicsUpdates()) { EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index ed7b986800..50e81b4788 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -167,7 +167,8 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() { _tempVector.push_back(motionState); entityItr = _pendingAdds.erase(entityItr); } else { - qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName(); + // TODO: Seth to look into why this case is hit. + //qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName(); ++entityItr; } } else { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index ea74a87286..bfd0b6cb28 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -147,6 +147,7 @@ void PhysicsEngine::deleteObjects(VectorOfMotionStates& objects) { // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. btRigidBody* body = object->getRigidBody(); object->setRigidBody(nullptr); + body->setMotionState(nullptr); delete body; object->releaseShape(); delete object; @@ -161,6 +162,7 @@ void PhysicsEngine::deleteObjects(SetOfMotionStates& objects) { // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); + body->setMotionState(nullptr); delete body; object->releaseShape(); delete object; diff --git a/libraries/render-utils/src/FboCache.cpp b/libraries/render-utils/src/FboCache.cpp index de2b483573..b6cca8116b 100644 --- a/libraries/render-utils/src/FboCache.cpp +++ b/libraries/render-utils/src/FboCache.cpp @@ -95,4 +95,7 @@ void FboCache::setSize(const QSize& newSize) { }); } +const QSize& FboCache::getSize() { + return _size; +} diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h index 30278470fd..78c3194eb5 100644 --- a/libraries/render-utils/src/FboCache.h +++ b/libraries/render-utils/src/FboCache.h @@ -37,6 +37,8 @@ public: // internal locks and pointers but execute no OpenGL opreations. void lockTexture(int texture); void releaseTexture(int texture); + + const QSize& getSize(); protected: QMap> _fboMap; diff --git a/libraries/render-utils/src/GlowEffect.cpp b/libraries/render-utils/src/GlowEffect.cpp index 3040088ce5..bb18729f12 100644 --- a/libraries/render-utils/src/GlowEffect.cpp +++ b/libraries/render-utils/src/GlowEffect.cpp @@ -129,7 +129,7 @@ static void maybeRelease(const gpu::FramebufferPointer& fbo) { } } -gpu::FramebufferPointer GlowEffect::render(bool toTexture) { +gpu::FramebufferPointer GlowEffect::render() { PerformanceTimer perfTimer("glowEffect"); auto textureCache = DependencyManager::get(); @@ -151,26 +151,24 @@ gpu::FramebufferPointer GlowEffect::render(bool toTexture) { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); - gpu::FramebufferPointer destFBO = toTexture ? - textureCache->getSecondaryFramebuffer() : nullptr; + gpu::FramebufferPointer destFBO = textureCache->getSecondaryFramebuffer(); if (!_enabled || _isEmpty) { // copy the primary to the screen - if (destFBO && QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO); + if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO)); - glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(), 0, 0, framebufferSize.width(), framebufferSize.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO); + glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(), + 0, 0, framebufferSize.width(), framebufferSize.height(), + GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { - maybeBind(destFBO); - if (!destFBO) { - //destFBO->getSize(); - glViewport(0, 0, framebufferSize.width(), framebufferSize.height()); - } + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO)); + glViewport(0, 0, framebufferSize.width(), framebufferSize.height()); glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); renderFullscreenQuad(); glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); - maybeRelease(destFBO); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } } else { // diffuse into the secondary/tertiary (alternating between frames) @@ -199,22 +197,18 @@ gpu::FramebufferPointer GlowEffect::render(bool toTexture) { _diffuseProgram->release(); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + destFBO = oldDiffusedFBO; + glBindFramebuffer(GL_FRAMEBUFFER, 0); // add diffused texture to the primary glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(newDiffusedFBO->getRenderBuffer(0))); - if (toTexture) { - destFBO = oldDiffusedFBO; - } - maybeBind(destFBO); - if (!destFBO) { - glViewport(0, 0, framebufferSize.width(), framebufferSize.height()); - } + glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO)); + glViewport(0, 0, framebufferSize.width(), framebufferSize.height()); _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); - maybeRelease(destFBO); + glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); diff --git a/libraries/render-utils/src/GlowEffect.h b/libraries/render-utils/src/GlowEffect.h index 1cee7b2e9d..73c512ecf5 100644 --- a/libraries/render-utils/src/GlowEffect.h +++ b/libraries/render-utils/src/GlowEffect.h @@ -52,7 +52,7 @@ public: /// Renders the glow effect. To be called after rendering the scene. /// \param toTexture whether to render to a texture, rather than to the frame buffer /// \return the framebuffer object to which we rendered, or NULL if to the frame buffer - gpu::FramebufferPointer render(bool toTexture = false); + gpu::FramebufferPointer render(); public slots: void toggleGlowEffect(bool enabled); diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index bd243cbe88..c88050f7fb 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -417,17 +417,23 @@ void ImageReader::run() { return; } - // enforce a fixed maximum area (1024 * 2048) - const int MAXIMUM_AREA_SIZE = 2097152; int imageArea = image.width() * image.height(); - if (imageArea > MAXIMUM_AREA_SIZE) { - float scaleRatio = sqrtf((float)MAXIMUM_AREA_SIZE) / sqrtf((float)imageArea); - int resizeWidth = static_cast(std::floor(scaleRatio * static_cast(image.width()))); - int resizeHeight = static_cast(std::floor(scaleRatio * static_cast(image.height()))); - qCDebug(renderutils) << "Image greater than maximum size:" << _url << image.width() << image.height() << - " scaled to:" << resizeWidth << resizeHeight; - image = image.scaled(resizeWidth, resizeHeight, Qt::IgnoreAspectRatio); - imageArea = image.width() * image.height(); + auto ntex = dynamic_cast(&*texture); + if (ntex && (ntex->getType() == CUBE_TEXTURE)) { + qCDebug(renderutils) << "Cube map size:" << _url << image.width() << image.height(); + } else { + + // enforce a fixed maximum area (1024 * 2048) + const int MAXIMUM_AREA_SIZE = 2097152; + if (imageArea > MAXIMUM_AREA_SIZE) { + float scaleRatio = sqrtf((float)MAXIMUM_AREA_SIZE) / sqrtf((float)imageArea); + int resizeWidth = static_cast(std::floor(scaleRatio * static_cast(image.width()))); + int resizeHeight = static_cast(std::floor(scaleRatio * static_cast(image.height()))); + qCDebug(renderutils) << "Image greater than maximum size:" << _url << image.width() << image.height() << + " scaled to:" << resizeWidth << resizeHeight; + image = image.scaled(resizeWidth, resizeHeight, Qt::IgnoreAspectRatio); + imageArea = image.width() * image.height(); + } } const int EIGHT_BIT_MAXIMUM = 255; @@ -507,6 +513,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo imageLoaded(image); if ((_width > 0) && (_height > 0)) { + bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); @@ -515,9 +522,18 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } - _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); - _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); - _gpuTexture->autoGenerateMips(-1); + + if (_type == CUBE_TEXTURE) { + if (_height >= (6 * _width)) { + _gpuTexture = gpu::TexturePointer(gpu::Texture::createCube(formatGPU, image.width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP))); + _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); + _gpuTexture->autoGenerateMips(-1); + } + } else { + _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); + _gpuTexture->autoGenerateMips(-1); + } } } diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index e25a640ae7..3ff184c621 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -27,7 +27,7 @@ class NetworkTexture; typedef QSharedPointer NetworkTexturePointer; -enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE }; +enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE }; /// Stores cached textures, including render-to-texture targets. class TextureCache : public ResourceCache, public Dependency { @@ -164,7 +164,7 @@ public: int getOriginalHeight() const { return _originalHeight; } int getWidth() const { return _width; } int getHeight() const { return _height; } - + TextureType getType() const { return _type; } protected: virtual void downloadFinished(QNetworkReply* reply); diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 2461487414..ad76dbcc38 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -13,6 +13,9 @@ #include "SceneScriptingInterface.h" +#include "SceneScriptingInterface.h" + + void SceneScriptingInterface::setStageOrientation(const glm::quat& orientation) { _skyStage->setOriginOrientation(orientation); } @@ -86,6 +89,29 @@ bool SceneScriptingInterface::isStageSunModelEnabled() const { return _skyStage->isSunModelEnabled(); } +void SceneScriptingInterface::setBackgroundMode(const QString& mode) { + if (mode == QString("inherit")) { + _skyStage->setBackgroundMode(model::SunSkyStage::NO_BACKGROUND); + } else if (mode == QString("atmosphere")) { + _skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); + } else if (mode == QString("skybox")) { + _skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); + } +} + +QString SceneScriptingInterface::getBackgroundMode() const { + switch (_skyStage->getBackgroundMode()) { + case model::SunSkyStage::NO_BACKGROUND: + return QString("inherit"); + case model::SunSkyStage::SKY_DOME: + return QString("atmosphere"); + case model::SunSkyStage::SKY_BOX: + return QString("skybox"); + default: + return QString("inherit"); + }; +} + model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { return _skyStage; } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index c384153a0f..50aaae83ff 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -57,7 +57,8 @@ public: Q_INVOKABLE glm::vec3 getKeyLightDirection() const; - + Q_INVOKABLE void setBackgroundMode(const QString& mode); + Q_INVOKABLE QString getBackgroundMode() const; model::SunSkyStagePointer getSkyStage() const; diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index a06f6f26cf..9b7cca70ee 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -117,6 +117,11 @@ QMatrix4x4 fromGlm(const glm::mat4 & m); QRectF glmToRect(const glm::vec2 & pos, const glm::vec2 & size); +template +float aspect(const T& t) { + return (float)t.x / (float)t.y; +} + #define YAW(euler) euler.y #define PITCH(euler) euler.x #define ROLL(euler) euler.z diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 9b32aca96f..7d13a00324 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -117,8 +117,13 @@ void OffscreenUi::addImportPath(const QString& path) { void OffscreenUi::resize(const QSize& newSize) { makeCurrent(); - // Clear out any fbos with the old size qreal pixelRatio = _renderControl->_renderWindow ? _renderControl->_renderWindow->devicePixelRatio() : 1.0; + QSize newOffscreenSize = newSize * pixelRatio; + if (newOffscreenSize == _fboCache.getSize()) { + return; + } + + // Clear out any fbos with the old size qDebug() << "Offscreen UI resizing to " << newSize.width() << "x" << newSize.height() << " with pixel ratio " << pixelRatio; _fboCache.setSize(newSize * pixelRatio);