From b35134e325aceb22adc6ec0836dc9e29057f38d2 Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Sat, 17 May 2014 20:38:43 +0530 Subject: [PATCH 01/41] Fix the chat widget's visibility when not logged in --- interface/src/Menu.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index bff08d5221..c79d4618e5 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -34,6 +34,7 @@ #include #include "Application.h" +#include "AccountManager.h" #include "Menu.h" #include "scripting/MenuScriptingInterface.h" #include "Util.h" @@ -193,10 +194,10 @@ Menu::Menu() : QAction::PreferencesRole); addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0, this, SLOT(editAttachments())); - + addDisabledActionAndSeparator(editMenu, "Physics"); QObject* avatar = appInstance->getAvatar(); - addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, + addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, avatar, SLOT(updateMotionBehaviorsFromMenu())); @@ -1013,24 +1014,24 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson void Menu::muteEnvironment() { int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment); int packetSize = headerSize + sizeof(glm::vec3) + sizeof(float); - + glm::vec3 position = Application::getInstance()->getAvatar()->getPosition(); - + char* packet = (char*)malloc(packetSize); populatePacketHeader(packet, PacketTypeMuteEnvironment); memcpy(packet + headerSize, &position, sizeof(glm::vec3)); memcpy(packet + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); - + QByteArray mutePacket(packet, packetSize); - + // grab our audio mixer from the NodeList, if it exists SharedNodePointer audioMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AudioMixer); - + if (audioMixer) { // send off this mute packet NodeList::getInstance()->writeDatagram(mutePacket, audioMixer); } - + free(packet); } @@ -1188,19 +1189,22 @@ void Menu::showScriptEditor() { } void Menu::showChat() { - QMainWindow* mainWindow = Application::getInstance()->getWindow(); - if (!_chatWindow) { - _chatWindow = new ChatWindow(mainWindow); - } - if (_chatWindow->isHidden()) { - _chatWindow->show(); + if (AccountManager::getInstance().isLoggedIn()) { + QMainWindow* mainWindow = Application::getInstance()->getWindow(); + if (!_chatWindow) { + _chatWindow = new ChatWindow(mainWindow); + } + + if (_chatWindow->isHidden()) { + _chatWindow->show(); + } } } void Menu::toggleChat() { #ifdef HAVE_QXMPP _chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected()); - if (!_chatAction->isEnabled() && _chatWindow) { + if (!_chatAction->isEnabled() && _chatWindow && AccountManager::getInstance().isLoggedIn()) { if (_chatWindow->isHidden()) { _chatWindow->show(); } else { From ad49b5c2e15846ab4d5178e1cff88e81c8783beb Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Thu, 22 May 2014 16:53:07 +0530 Subject: [PATCH 02/41] Show OS notification when user is not logged in --- interface/src/Application.cpp | 109 +++++++++++++++++----------------- interface/src/Application.h | 6 +- interface/src/Menu.cpp | 3 + 3 files changed, 64 insertions(+), 54 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 17443b3cb0..79015185c6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -172,11 +172,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _previousScriptLocation(), _nodeBoundsDisplay(this), _runningScriptsWidget(new RunningScriptsWidget(_window)), - _runningScriptsWidgetWasVisible(false) + _runningScriptsWidgetWasVisible(false), + _trayIcon(new QSystemTrayIcon(_window)) { // init GnuTLS for DTLS with domain-servers DTLSClientSession::globalInit(); - + // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); @@ -238,10 +239,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); - + // update our location every 5 seconds in the data-server, assuming that we are authenticated with one const float DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5.0f * 1000.0f; - + QTimer* locationUpdateTimer = new QTimer(this); connect(locationUpdateTimer, &QTimer::timeout, this, &Application::updateLocationInServer); locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); @@ -337,7 +338,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // when -url in command line, teleport to location urlGoTo(argc, constArgv); - + // For now we're going to set the PPS for outbound packets to be super high, this is // probably not the right long term solution. But for now, we're going to do this to // allow you to move a particle around in your hand @@ -364,27 +365,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // clear the scripts, and set out script to our default scripts clearScriptsBeforeRunning(); loadScript("http://public.highfidelity.io/scripts/defaultScripts.js"); - + QMutexLocker locker(&_settingsMutex); _settings->setValue("firstRun",QVariant(false)); } else { // do this as late as possible so that all required subsystems are inialized loadScripts(); - + QMutexLocker locker(&_settingsMutex); _previousScriptLocation = _settings->value("LastScriptLocation", QVariant("")).toString(); } - + connect(_window, &MainWindow::windowGeometryChanged, _runningScriptsWidget, &RunningScriptsWidget::setBoundary); - - //When -url in command line, teleport to location - urlGoTo(argc, constArgv); - + + //When -url in command line, teleport to location + urlGoTo(argc, constArgv); + // call the OAuthWebviewHandler static getter so that its instance lives in our thread OAuthWebViewHandler::getInstance(); // make sure the High Fidelity root CA is in our list of trusted certs OAuthWebViewHandler::addHighFidelityRootCAToSSLConfig(); + + _trayIcon->show(); } Application::~Application() { @@ -393,11 +396,11 @@ Application::~Application() { // make sure we don't call the idle timer any more delete idleTimer; - + _sharedVoxelSystem.changeTree(new VoxelTree); - + saveSettings(); - + delete _voxelImporter; // let the avatar mixer know we're out @@ -431,14 +434,14 @@ Application::~Application() { delete _glWidget; AccountManager::getInstance().destroy(); - + DTLSClientSession::globalDeinit(); } void Application::saveSettings() { Menu::getInstance()->saveSettings(); _rearMirrorTools->saveSettings(_settings); - + if (_voxelImporter) { _voxelImporter->saveSettings(_settings); } @@ -520,7 +523,7 @@ void Application::initializeGL() { _voxelHideShowThread.initialize(_enableProcessVoxelsThread); _particleEditSender.initialize(_enableProcessVoxelsThread); _modelEditSender.initialize(_enableProcessVoxelsThread); - + if (_enableProcessVoxelsThread) { qDebug("Voxel parsing thread created."); } @@ -585,7 +588,7 @@ void Application::paintGL() { _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale() * _scaleMirror); _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - + // if the head would intersect the near clip plane, we must push the camera out glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * (eyePosition - _myCamera.getTargetPosition()); @@ -594,7 +597,7 @@ void Application::paintGL() { pushback = relativePosition.z + pushbackRadius - _myCamera.getDistance(); pushbackFocalLength = _myCamera.getDistance(); } - + // handle pushback, if any if (pushbackFocalLength > 0.0f) { const float PUSHBACK_DECAY = 0.5f; @@ -1279,7 +1282,7 @@ void Application::dropEvent(QDropEvent *event) { void Application::sendPingPackets() { QByteArray pingPacket = NodeList::getInstance()->constructPingPacket(); - controlledBroadcastToNodes(pingPacket, NodeSet() + controlledBroadcastToNodes(pingPacket, NodeSet() << NodeType::VoxelServer << NodeType::ParticleServer << NodeType::ModelServer << NodeType::AudioMixer << NodeType::AvatarMixer << NodeType::MetavoxelServer); @@ -1290,7 +1293,7 @@ void Application::timer() { if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { sendPingPackets(); } - + float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f; _fps = (float)_frameCount / diffTime; @@ -1694,7 +1697,7 @@ void Application::init() { connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView())); connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView())); connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors())); - + // set up our audio reflector _audioReflector.setMyAvatar(getAvatar()); _audioReflector.setVoxels(_voxels.getTree()); @@ -1703,7 +1706,7 @@ void Application::init() { connect(getAudio(), &Audio::processInboundAudio, &_audioReflector, &AudioReflector::processInboundAudio,Qt::DirectConnection); connect(getAudio(), &Audio::processLocalAudio, &_audioReflector, &AudioReflector::processLocalAudio,Qt::DirectConnection); - connect(getAudio(), &Audio::preProcessOriginalInboundAudio, &_audioReflector, + connect(getAudio(), &Audio::preProcessOriginalInboundAudio, &_audioReflector, &AudioReflector::preProcessOriginalInboundAudio,Qt::DirectConnection); // save settings when avatar changes @@ -1818,7 +1821,7 @@ void Application::updateMyAvatarLookAtPosition() { PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); FaceTracker* tracker = getActiveFaceTracker(); - + bool isLookingAtSomeone = false; glm::vec3 lookAtSpot; if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { @@ -1853,7 +1856,7 @@ void Application::updateMyAvatarLookAtPosition() { glm::distance(_mouseRayOrigin, _myAvatar->getHead()->calculateAverageEyePosition())); lookAtSpot = _mouseRayOrigin + _mouseRayDirection * qMax(minEyeDistance, distance); */ - + } // // Deflect the eyes a bit to match the detected Gaze from 3D camera if active @@ -1873,7 +1876,7 @@ void Application::updateMyAvatarLookAtPosition() { eyePitch * pitchSign * deflection, eyeYaw * deflection, 0.0f))) * glm::inverse(_myCamera.getRotation()) * (lookAtSpot - origin); } - + _myAvatar->getHead()->setLookAtPosition(lookAtSpot); } @@ -1925,7 +1928,7 @@ void Application::updateCamera(float deltaTime) { PerformanceWarning warn(showWarnings, "Application::updateCamera()"); if (!OculusManager::isConnected() && !TV3DManager::isConnected() && - Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { + Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { FaceTracker* tracker = getActiveFaceTracker(); if (tracker) { const float EYE_OFFSET_SCALE = 0.025f; @@ -2481,7 +2484,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // disable specular lighting for ground and voxels glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR); - + // draw the audio reflector overlay _audioReflector.render(); @@ -2649,7 +2652,7 @@ void Application::displayOverlay() { const float LOG2_LOUDNESS_FLOOR = 11.f; float audioLevel = 0.f; float loudness = _audio.getLastInputLoudness() + 1.f; - + _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness; float log2loudness = log(_trailingAudioLoudness) / LOG2; @@ -2662,7 +2665,7 @@ void Application::displayOverlay() { audioLevel = AUDIO_METER_SCALE_WIDTH; } bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)); - + if ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) { const float MAX_MAGNITUDE = 0.7f; float magnitude = MAX_MAGNITUDE * (1 - _audio.getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME); @@ -2768,7 +2771,7 @@ void Application::displayOverlay() { // give external parties a change to hook in emit renderingOverlay(); - + _overlays.render2D(); glPopMatrix(); @@ -2844,7 +2847,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { // save absolute translations glm::vec3 absoluteSkeletonTranslation = _myAvatar->getSkeletonModel().getTranslation(); glm::vec3 absoluteFaceTranslation = _myAvatar->getHead()->getFaceModel().getTranslation(); - + // get the eye positions relative to the neck and use them to set the face translation glm::vec3 leftEyePosition, rightEyePosition; _myAvatar->getHead()->getFaceModel().setTranslation(glm::vec3()); @@ -3110,7 +3113,7 @@ void Application::uploadModel(ModelType modelType) { thread->connect(uploader, SIGNAL(destroyed()), SLOT(quit())); thread->connect(thread, SIGNAL(finished()), SLOT(deleteLater())); uploader->connect(thread, SIGNAL(started()), SLOT(send())); - + thread->start(); } @@ -3127,28 +3130,28 @@ void Application::updateWindowTitle(){ } void Application::updateLocationInServer() { - + AccountManager& accountManager = AccountManager::getInstance(); - + if (accountManager.isLoggedIn()) { - + static QJsonObject lastLocationObject; - + // construct a QJsonObject given the user's current address information QJsonObject updatedLocationObject; - + QJsonObject addressObject; addressObject.insert("position", QString(createByteArray(_myAvatar->getPosition()))); addressObject.insert("orientation", QString(createByteArray(glm::degrees(safeEulerAngles(_myAvatar->getOrientation()))))); addressObject.insert("domain", NodeList::getInstance()->getDomainHandler().getHostname()); - + updatedLocationObject.insert("address", addressObject); - + if (updatedLocationObject != lastLocationObject) { - + accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation, JSONCallbackParameters(), QJsonDocument(updatedLocationObject).toJson()); - + lastLocationObject = updatedLocationObject; } } @@ -3173,7 +3176,7 @@ void Application::domainChanged(const QString& domainHostname) { // reset the voxels renderer _voxels.killLocalVoxels(); - + // reset the auth URL for OAuth web view handler OAuthWebViewHandler::getInstance().clearLastAuthorizationURL(); } @@ -3394,7 +3397,7 @@ void Application::loadScripts() { loadScript(string); } } - + QMutexLocker locker(&_settingsMutex); _settings->endArray(); } @@ -3655,7 +3658,7 @@ void Application::parseVersionXml() { QObject* sender = QObject::sender(); QXmlStreamReader xml(qobject_cast(sender)); - + while (!xml.atEnd() && !xml.hasError()) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) { while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == operatingSystem)) { @@ -3672,7 +3675,7 @@ void Application::parseVersionXml() { } xml.readNext(); } - + if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) { new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl); } @@ -3724,24 +3727,24 @@ void Application::urlGoTo(int argc, const char * constArgv[]) { } else if (urlParts.count() > 1) { // if url has 2 or more parts, the first one is domain name QString domain = urlParts[0]; - + // second part is either a destination coordinate or // a place name QString destination = urlParts[1]; - + // any third part is an avatar orientation. QString orientation = urlParts.count() > 2 ? urlParts[2] : QString(); - + Menu::goToDomain(domain); - + // goto either @user, #place, or x-xx,y-yy,z-zz // style co-ordinate. Menu::goTo(destination); - + if (!orientation.isEmpty()) { // location orientation Menu::goToOrientation(orientation); } - } + } } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 5460093cbd..36076218b1 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -203,6 +204,7 @@ public: JoystickManager* getJoystickManager() { return &_joystickManager; } BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; } QUndoStack* getUndoStack() { return &_undoStack; } + QSystemTrayIcon* getTrayIcon() { return _trayIcon; } /// if you need to access the application settings, use lockSettings()/unlockSettings() QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } @@ -466,7 +468,7 @@ private: glm::mat4 _untranslatedViewMatrix; glm::vec3 _viewMatrixTranslation; glm::mat4 _projectionMatrix; - + float _scaleMirror; float _rotateMirror; float _raiseMirror; @@ -553,6 +555,8 @@ private: RunningScriptsWidget* _runningScriptsWidget; QHash _scriptEnginesHash; bool _runningScriptsWidgetWasVisible; + + QSystemTrayIcon* _trayIcon; }; #endif // hifi_Application_h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c79d4618e5..8021816db9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -1198,6 +1199,8 @@ void Menu::showChat() { if (_chatWindow->isHidden()) { _chatWindow->show(); } + } else { + Application::getInstance()->getTrayIcon()->showMessage("Interface", "You need to login to be able to chat with others on this domain."); } } From c4b17963e2d78c2ce9c6002d7f76aa77392a1a38 Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Thu, 22 May 2014 16:55:24 +0530 Subject: [PATCH 03/41] Remove unnecessory header file inclusion in Menu.cpp --- interface/src/Menu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8021816db9..c40058f89b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include From 08b525ef91e3301069cc414085bc2a1e2435311b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 22 May 2014 17:54:32 -0700 Subject: [PATCH 04/41] prevent walking avatar from bouncing on floor --- interface/src/avatar/MyAvatar.cpp | 113 ++++++++++++++++++------------ interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 71 insertions(+), 44 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 85c1734e56..6a4ababa25 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -134,45 +134,7 @@ void MyAvatar::simulate(float deltaTime) { _handState = HAND_STATE_NULL; updateOrientation(deltaTime); - - float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + - fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT]) + - fabsf(_driveKeys[UP] - _driveKeys[DOWN]); - - bool walkingOnFloor = false; - float gravityLength = glm::length(_gravity); - if (gravityLength > EPSILON) { - const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); - glm::vec3 startCap; - boundingShape.getStartPoint(startCap); - glm::vec3 bottomOfBoundingCapsule = startCap + (boundingShape.getRadius() / gravityLength) * _gravity; - - float fallThreshold = 2.0f * deltaTime * gravityLength; - walkingOnFloor = (glm::distance(bottomOfBoundingCapsule, _lastFloorContactPoint) < fallThreshold); - } - - if (keyboardInput > 0.0f || glm::length2(_velocity) > 0.0f || glm::length2(_thrust) > 0.0f || - ! walkingOnFloor) { - // apply gravity - _velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime); - - // update motor and thrust - updateMotorFromKeyboard(deltaTime, walkingOnFloor); - applyMotor(deltaTime); - applyThrust(deltaTime); - - // update position - if (glm::length2(_velocity) < EPSILON) { - _velocity = glm::vec3(0.0f); - } else { - _position += _velocity * deltaTime; - } - } - - // update moving flag based on speed - const float MOVING_SPEED_THRESHOLD = 0.01f; - _moving = glm::length(_velocity) > MOVING_SPEED_THRESHOLD; - updateChatCircle(deltaTime); + updatePosition(deltaTime); // update avatar skeleton and simulate hand and head getHand()->collideAgainstOurself(); @@ -833,8 +795,7 @@ void MyAvatar::updateOrientation(float deltaTime) { // We must adjust the body orientation using a delta rotation (rather than // doing yaw math) because the body's yaw ranges are not the same // as what the Oculus API provides. - glm::vec3 UP_AXIS = glm::vec3(0.0f, 1.0f, 0.0f); - glm::quat bodyCorrection = glm::angleAxis(glm::radians(delta), UP_AXIS); + glm::quat bodyCorrection = glm::angleAxis(glm::radians(delta), _worldUpDirection); orientation = orientation * bodyCorrection; } Head* head = getHead(); @@ -848,6 +809,62 @@ void MyAvatar::updateOrientation(float deltaTime) { setOrientation(orientation); } +void MyAvatar::updatePosition(float deltaTime) { + float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + + fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT]) + + fabsf(_driveKeys[UP] - _driveKeys[DOWN]); + + bool walkingOnFloor = false; + float gravityLength = glm::length(_gravity) * GRAVITY_EARTH; + if (gravityLength > EPSILON) { + const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); + glm::vec3 startCap; + boundingShape.getStartPoint(startCap); + glm::vec3 bottomOfBoundingCapsule = startCap - boundingShape.getRadius() * _worldUpDirection; + + float speedFromGravity = _scale * deltaTime * gravityLength; + float distanceToFall = glm::distance(bottomOfBoundingCapsule, _lastFloorContactPoint); + walkingOnFloor = (distanceToFall < 2.0f * deltaTime * speedFromGravity); + + if (walkingOnFloor) { + // BEGIN HACK: to prevent the avatar from bouncing on a floor surface + if (distanceToFall < deltaTime * speedFromGravity) { + float verticalSpeed = glm::dot(_velocity, _worldUpDirection); + if (fabs(verticalSpeed) < speedFromGravity) { + // we're standing on a floor, and nearly at rest so we zero the vertical velocity component + _velocity -= verticalSpeed * _worldUpDirection; + } + } else { + // fall with gravity against floor + _velocity -= speedFromGravity * _worldUpDirection; + } + // END HACK + } else { + _velocity -= speedFromGravity * _worldUpDirection; + } + } + + if (keyboardInput > 0.0f || glm::length2(_velocity) > 0.0f || glm::length2(_thrust) > 0.0f || ! walkingOnFloor) { + // update motor and thrust + updateMotorFromKeyboard(deltaTime, walkingOnFloor); + applyMotor(deltaTime); + applyThrust(deltaTime); + + // update position + if (glm::length2(_velocity) < EPSILON) { + _velocity = glm::vec3(0.0f); + } else { + _position += _velocity * deltaTime; + } + } + + // update moving flag based on speed + const float MOVING_SPEED_THRESHOLD = 0.01f; + _moving = glm::length(_velocity) > MOVING_SPEED_THRESHOLD; + + updateChatCircle(deltaTime); +} + void MyAvatar::updateMotorFromKeyboard(float deltaTime, bool walking) { // Increase motor velocity until its length is equal to _maxMotorSpeed. if (!(_motionBehaviors & AVATAR_MOTION_MOTOR_KEYBOARD_ENABLED)) { @@ -1121,6 +1138,8 @@ void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { const float MIN_STEP_HEIGHT = 0.0f; glm::vec3 footBase = boundingShape.getPosition() - (capsuleRadius + capsuleHalfHeight) * _worldUpDirection; float highestStep = 0.0f; + float lowestStep = MAX_STEP_HEIGHT; + glm::vec3 floorPoint; glm::vec3 stepPenetration(0.0f); glm::vec3 totalPenetration(0.0f); @@ -1154,8 +1173,15 @@ void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { highestStep = stepHeight; stepPenetration = collision->_penetration; } + if (stepHeight < lowestStep) { + lowestStep = stepHeight; + floorPoint = collision->_contactPoint - collision->_penetration; + } } } + if (lowestStep < MAX_STEP_HEIGHT) { + _lastFloorContactPoint = floorPoint; + } float penetrationLength = glm::length(totalPenetration); if (penetrationLength < EPSILON) { @@ -1194,8 +1220,9 @@ void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } - const float VOXEL_COLLISION_FREQUENCY = 0.5f; - updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); + // Don't make a collision sound against voxlels by default -- too annoying when walking + //const float VOXEL_COLLISION_FREQUENCY = 0.5f; + //updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); } _trapDuration = isTrapped ? _trapDuration + deltaTime : 0.0f; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9d6f22264f..89606858e6 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -141,7 +141,6 @@ private: bool _shouldJump; float _driveKeys[MAX_DRIVE_KEYS]; glm::vec3 _gravity; - glm::vec3 _environmentGravity; float _distanceToNearestAvatar; // How close is the nearest avatar? bool _wasPushing; @@ -166,6 +165,7 @@ private: // private methods void updateOrientation(float deltaTime); + void updatePosition(float deltaTime); void updateMotorFromKeyboard(float deltaTime, bool walking); float computeMotorTimescale(); void applyMotor(float deltaTime); From b875144e2d4cb68581a75b02c1d39e2b06e2cd21 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 May 2014 09:55:45 -0700 Subject: [PATCH 05/41] Don't repeat check for non-zero collision groups --- interface/src/avatar/MyAvatar.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6a4ababa25..43f577d878 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -168,19 +168,17 @@ void MyAvatar::simulate(float deltaTime) { radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.0f)); radius *= COLLISION_RADIUS_SCALAR; } - if (_collisionGroups) { - updateShapePositions(); - if (_collisionGroups & COLLISION_GROUP_ENVIRONMENT) { - updateCollisionWithEnvironment(deltaTime, radius); - } - if (_collisionGroups & COLLISION_GROUP_VOXELS) { - updateCollisionWithVoxels(deltaTime, radius); - } else { - _trapDuration = 0.0f; - } - if (_collisionGroups & COLLISION_GROUP_AVATARS) { - updateCollisionWithAvatars(deltaTime); - } + updateShapePositions(); + if (_collisionGroups & COLLISION_GROUP_ENVIRONMENT) { + updateCollisionWithEnvironment(deltaTime, radius); + } + if (_collisionGroups & COLLISION_GROUP_VOXELS) { + updateCollisionWithVoxels(deltaTime, radius); + } else { + _trapDuration = 0.0f; + } + if (_collisionGroups & COLLISION_GROUP_AVATARS) { + updateCollisionWithAvatars(deltaTime); } } From df68082705e0a02266fadee65d9db6cd44fab9a8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 May 2014 11:02:07 -0700 Subject: [PATCH 06/41] Added local glow to models --- interface/src/models/ModelTreeRenderer.cpp | 6 ++++- libraries/models/src/ModelItem.cpp | 28 +++++++++++++++++++--- libraries/models/src/ModelItem.h | 8 +++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 0f9da86887..d29303ab79 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -203,7 +203,11 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) // TODO: should we allow modelItems to have alpha on their models? Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - model->render(alpha, modelRenderMode); + + { // Sets the glower scope + Glower glower(modelItem.getGlowLevel()); + model->render(alpha, modelRenderMode); + } if (!isShadowMode && displayModelBounds) { glColor3f(0.0f, 1.0f, 0.0f); diff --git a/libraries/models/src/ModelItem.cpp b/libraries/models/src/ModelItem.cpp index 3dd1c99e60..b6f4fe6c1d 100644 --- a/libraries/models/src/ModelItem.cpp +++ b/libraries/models/src/ModelItem.cpp @@ -85,12 +85,13 @@ ModelItem::ModelItem(const ModelItemID& modelItemID, const ModelItemProperties& _shouldDie = false; _modelURL = MODEL_DEFAULT_MODEL_URL; _modelRotation = MODEL_DEFAULT_MODEL_ROTATION; - + // animation related _animationURL = MODEL_DEFAULT_ANIMATION_URL; _animationIsPlaying = false; _animationFrameIndex = 0.0f; _animationFPS = MODEL_DEFAULT_ANIMATION_FPS; + _glowLevel = 0.0f; _jointMappingCompleted = false; _lastAnimated = now; @@ -125,6 +126,7 @@ void ModelItem::init(glm::vec3 position, float radius, rgbColor color, uint32_t _animationIsPlaying = false; _animationFrameIndex = 0.0f; _animationFPS = MODEL_DEFAULT_ANIMATION_FPS; + _glowLevel = 0.0f; _jointMappingCompleted = false; _lastAnimated = now; } @@ -802,6 +804,7 @@ ModelItemProperties::ModelItemProperties() : _animationIsPlaying(false), _animationFrameIndex(0.0), _animationFPS(MODEL_DEFAULT_ANIMATION_FPS), + _glowLevel(0.0f), _id(UNKNOWN_MODEL_ID), _idSet(false), @@ -817,6 +820,7 @@ ModelItemProperties::ModelItemProperties() : _animationIsPlayingChanged(false), _animationFrameIndexChanged(false), _animationFPSChanged(false), + _glowLevelChanged(false), _defaultSettings(true) { } @@ -890,6 +894,7 @@ QScriptValue ModelItemProperties::copyToScriptValue(QScriptEngine* engine) const properties.setProperty("animationIsPlaying", _animationIsPlaying); properties.setProperty("animationFrameIndex", _animationFrameIndex); properties.setProperty("animationFPS", _animationFPS); + properties.setProperty("glowLevel", _glowLevel); if (_idSet) { properties.setProperty("id", _id); @@ -1015,7 +1020,7 @@ void ModelItemProperties::copyFromScriptValue(const QScriptValue &object) { _animationFrameIndexChanged = true; } } - + QScriptValue animationFPS = object.property("animationFPS"); if (animationFPS.isValid()) { float newFPS; @@ -1025,6 +1030,16 @@ void ModelItemProperties::copyFromScriptValue(const QScriptValue &object) { _animationFPSChanged = true; } } + + QScriptValue glowLevel = object.property("glowLevel"); + if (glowLevel.isValid()) { + float newGlowLevel; + newGlowLevel = glowLevel.toVariant().toFloat(); + if (_defaultSettings || newGlowLevel != _glowLevel) { + _glowLevel = newGlowLevel; + _glowLevelChanged = true; + } + } _lastEdited = usecTimestampNow(); } @@ -1075,11 +1090,16 @@ void ModelItemProperties::copyToModelItem(ModelItem& modelItem) const { modelItem.setAnimationFrameIndex(_animationFrameIndex); somethingChanged = true; } - + if (_animationFPSChanged) { modelItem.setAnimationFPS(_animationFPS); somethingChanged = true; } + + if (_glowLevelChanged) { + modelItem.setGlowLevel(_glowLevel); + somethingChanged = true; + } if (somethingChanged) { bool wantDebug = false; @@ -1104,6 +1124,7 @@ void ModelItemProperties::copyFromModelItem(const ModelItem& modelItem) { _animationIsPlaying = modelItem.getAnimationIsPlaying(); _animationFrameIndex = modelItem.getAnimationFrameIndex(); _animationFPS = modelItem.getAnimationFPS(); + _glowLevel = modelItem.getGlowLevel(); _id = modelItem.getID(); _idSet = true; @@ -1119,6 +1140,7 @@ void ModelItemProperties::copyFromModelItem(const ModelItem& modelItem) { _animationIsPlayingChanged = false; _animationFrameIndexChanged = false; _animationFPSChanged = false; + _glowLevelChanged = false; _defaultSettings = false; } diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 838dbc0fc8..63adae48fa 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -83,6 +83,7 @@ public: float getAnimationFrameIndex() const { return _animationFrameIndex; } bool getAnimationIsPlaying() const { return _animationIsPlaying; } float getAnimationFPS() const { return _animationFPS; } + float getGlowLevel() const { return _glowLevel; } quint64 getLastEdited() const { return _lastEdited; } uint16_t getChangedBits() const; @@ -100,6 +101,7 @@ public: void setAnimationFrameIndex(float value) { _animationFrameIndex = value; _animationFrameIndexChanged = true; } void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; _animationIsPlayingChanged = true; } void setAnimationFPS(float value) { _animationFPS = value; _animationFPSChanged = true; } + void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; } /// used by ModelScriptingInterface to return ModelItemProperties for unknown models void setIsUnknownID() { _id = UNKNOWN_MODEL_ID; _idSet = true; } @@ -119,6 +121,7 @@ private: bool _animationIsPlaying; float _animationFrameIndex; float _animationFPS; + float _glowLevel; uint32_t _id; bool _idSet; @@ -135,6 +138,7 @@ private: bool _animationIsPlayingChanged; bool _animationFrameIndexChanged; bool _animationFPSChanged; + bool _glowLevelChanged; bool _defaultSettings; }; Q_DECLARE_METATYPE(ModelItemProperties); @@ -206,6 +210,7 @@ public: const glm::quat& getModelRotation() const { return _modelRotation; } bool hasAnimation() const { return !_animationURL.isEmpty(); } const QString& getAnimationURL() const { return _animationURL; } + float getGlowLevel() const { return _glowLevel; } ModelItemID getModelItemID() const { return ModelItemID(getID(), getCreatorTokenID(), getID() != UNKNOWN_MODEL_ID); } ModelItemProperties getProperties() const; @@ -248,6 +253,7 @@ public: void setAnimationFrameIndex(float value) { _animationFrameIndex = value; } void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; } void setAnimationFPS(float value) { _animationFPS = value; } + void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; } void setProperties(const ModelItemProperties& properties); @@ -293,6 +299,8 @@ protected: // model related items QString _modelURL; glm::quat _modelRotation; + + float _glowLevel; uint32_t _creatorTokenID; bool _newlyCreated; From 53141ff1c11b4bcf9329fb2e419ed29c3c4acad2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 May 2014 11:10:56 -0700 Subject: [PATCH 07/41] Glow when grabbed with the mouse (for now) --- examples/editModels.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 55c79cbc1d..394e9aa783 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -517,7 +517,7 @@ function mousePressEvent(event) { modelSelected = true; selectedModelID = foundModels[i]; selectedModelProperties = properties; - + selectedModelProperties.oldRadius = selectedModelProperties.radius; selectedModelProperties.oldPosition = { x: selectedModelProperties.position.x, @@ -534,7 +534,11 @@ function mousePressEvent(event) { orientation = MyAvatar.orientation; intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); - + + + selectedModelProperties.glowLevel = 0.1; + Models.editModel(selectedModelID, { glowLevel: selectedModelProperties.glowLevel}); + print("Clicked on " + selectedModelID.id + " " + modelSelected); return; } @@ -543,6 +547,13 @@ function mousePressEvent(event) { } } +Controller.mouseReleaseEvent.connect(function() { + if (modelSelected) { + Models.editModel(selectedModelID, { glowLevel: 0.0 }); + modelSelected = false; + } + }); + var oldModifier = 0; var modifier = 0; var wasShifted = false; From 107c142532e9b6fc231e22e8e491cc06301e88ed Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Fri, 23 May 2014 20:21:00 +0200 Subject: [PATCH 08/41] _voxelFades needs locking. --- interface/src/Application.cpp | 10 ++++++++++ interface/src/Application.h | 1 + 2 files changed, 11 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2b552de0ee..95a3c87494 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2525,6 +2525,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { if (_voxelFades.size() > 0) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxel fades..."); + _voxelFadesLock.lockForWrite(); for(std::vector::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) { fade->render(); if(fade->isDone()) { @@ -2533,6 +2534,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { ++fade; } } + _voxelFadesLock.unlock(); } // give external parties a change to hook in @@ -3188,7 +3190,9 @@ void Application::nodeKilled(SharedNodePointer node) { fade.voxelDetails = rootDetails; const float slightly_smaller = 0.99f; fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; + _voxelFadesLock.lockForWrite(); _voxelFades.push_back(fade); + _voxelFadesLock.unlock(); } // If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server @@ -3219,7 +3223,9 @@ void Application::nodeKilled(SharedNodePointer node) { fade.voxelDetails = rootDetails; const float slightly_smaller = 0.99f; fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; + _voxelFadesLock.lockForWrite(); _voxelFades.push_back(fade); + _voxelFadesLock.unlock(); } // If the particle server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server @@ -3251,7 +3257,9 @@ void Application::nodeKilled(SharedNodePointer node) { fade.voxelDetails = rootDetails; const float slightly_smaller = 0.99f; fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; + _voxelFadesLock.lockForWrite(); _voxelFades.push_back(fade); + _voxelFadesLock.unlock(); } // If the model server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server @@ -3336,7 +3344,9 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin fade.voxelDetails = rootDetails; const float slightly_smaller = 0.99f; fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; + _voxelFadesLock.lockForWrite(); _voxelFades.push_back(fade); + _voxelFadesLock.unlock(); } } // store jurisdiction details for later use diff --git a/interface/src/Application.h b/interface/src/Application.h index 1968ef4fee..77d948e708 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -533,6 +533,7 @@ private: NodeBounds _nodeBoundsDisplay; std::vector _voxelFades; + QReadWriteLock _voxelFadesLock; ControllerScriptingInterface _controllerScriptingInterface; QPointer _logDialog; QPointer _snapshotShareDialog; From 7fb9e3a7e616b84133e6e1718111d63898872e9b Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Fri, 23 May 2014 20:25:20 +0200 Subject: [PATCH 09/41] spaces instead of tabs. --- interface/src/Application.cpp | 20 ++++++++++---------- interface/src/Application.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 95a3c87494..ad6c7ebc54 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2525,7 +2525,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { if (_voxelFades.size() > 0) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxel fades..."); - _voxelFadesLock.lockForWrite(); + _voxelFadesLock.lockForWrite(); for(std::vector::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) { fade->render(); if(fade->isDone()) { @@ -2534,7 +2534,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { ++fade; } } - _voxelFadesLock.unlock(); + _voxelFadesLock.unlock(); } // give external parties a change to hook in @@ -3190,9 +3190,9 @@ void Application::nodeKilled(SharedNodePointer node) { fade.voxelDetails = rootDetails; const float slightly_smaller = 0.99f; fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; - _voxelFadesLock.lockForWrite(); + _voxelFadesLock.lockForWrite(); _voxelFades.push_back(fade); - _voxelFadesLock.unlock(); + _voxelFadesLock.unlock(); } // If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server @@ -3223,9 +3223,9 @@ void Application::nodeKilled(SharedNodePointer node) { fade.voxelDetails = rootDetails; const float slightly_smaller = 0.99f; fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; - _voxelFadesLock.lockForWrite(); + _voxelFadesLock.lockForWrite(); _voxelFades.push_back(fade); - _voxelFadesLock.unlock(); + _voxelFadesLock.unlock(); } // If the particle server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server @@ -3257,9 +3257,9 @@ void Application::nodeKilled(SharedNodePointer node) { fade.voxelDetails = rootDetails; const float slightly_smaller = 0.99f; fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; - _voxelFadesLock.lockForWrite(); + _voxelFadesLock.lockForWrite(); _voxelFades.push_back(fade); - _voxelFadesLock.unlock(); + _voxelFadesLock.unlock(); } // If the model server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server @@ -3344,9 +3344,9 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin fade.voxelDetails = rootDetails; const float slightly_smaller = 0.99f; fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; - _voxelFadesLock.lockForWrite(); + _voxelFadesLock.lockForWrite(); _voxelFades.push_back(fade); - _voxelFadesLock.unlock(); + _voxelFadesLock.unlock(); } } // store jurisdiction details for later use diff --git a/interface/src/Application.h b/interface/src/Application.h index 77d948e708..9c03dccd0f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -533,7 +533,7 @@ private: NodeBounds _nodeBoundsDisplay; std::vector _voxelFades; - QReadWriteLock _voxelFadesLock; + QReadWriteLock _voxelFadesLock; ControllerScriptingInterface _controllerScriptingInterface; QPointer _logDialog; QPointer _snapshotShareDialog; From 37a939588f543b4fb9769ccad6746fbc962be82d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 May 2014 11:28:48 -0700 Subject: [PATCH 10/41] Mode sure the closest model is always selected --- examples/editModels.js | 58 +++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 394e9aa783..d53b854003 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -479,6 +479,7 @@ function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); Vec3.print("[Mouse] Looking at: ", pickRay.origin); var foundModels = Models.findModels(pickRay.origin, LASER_LENGTH_FACTOR); + var closest = -1.0; for (var i = 0; i < foundModels.length; i++) { if (!foundModels[i].isKnownID) { var identify = Models.identifyModel(foundModels[i]); @@ -514,36 +515,41 @@ function mousePressEvent(event) { var d = Vec3.length(Vec3.subtract(P, X)); if (d < properties.radius && 0 < x && x < LASER_LENGTH_FACTOR) { - modelSelected = true; - selectedModelID = foundModels[i]; - selectedModelProperties = properties; + if (closest < 0.0) { + closest = x; + } - selectedModelProperties.oldRadius = selectedModelProperties.radius; - selectedModelProperties.oldPosition = { - x: selectedModelProperties.position.x, - y: selectedModelProperties.position.y, - z: selectedModelProperties.position.z, - }; - selectedModelProperties.oldRotation = { - x: selectedModelProperties.modelRotation.x, - y: selectedModelProperties.modelRotation.y, - z: selectedModelProperties.modelRotation.z, - w: selectedModelProperties.modelRotation.w, - }; - - - orientation = MyAvatar.orientation; - intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); - - - selectedModelProperties.glowLevel = 0.1; - Models.editModel(selectedModelID, { glowLevel: selectedModelProperties.glowLevel}); - - print("Clicked on " + selectedModelID.id + " " + modelSelected); - return; + if (x <= closest) { + modelSelected = true; + selectedModelID = foundModels[i]; + selectedModelProperties = properties; + + orientation = MyAvatar.orientation; + intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); + } } } } + + if (modelSelected) { + selectedModelProperties.oldRadius = selectedModelProperties.radius; + selectedModelProperties.oldPosition = { + x: selectedModelProperties.position.x, + y: selectedModelProperties.position.y, + z: selectedModelProperties.position.z, + }; + selectedModelProperties.oldRotation = { + x: selectedModelProperties.modelRotation.x, + y: selectedModelProperties.modelRotation.y, + z: selectedModelProperties.modelRotation.z, + w: selectedModelProperties.modelRotation.w, + }; + + selectedModelProperties.glowLevel = 0.1; + Models.editModel(selectedModelID, { glowLevel: selectedModelProperties.glowLevel}); + + print("Clicked on " + selectedModelID.id + " " + modelSelected); + } } } From f0f62ced6b07e0ef0a016ad867abac078fe2986d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 May 2014 11:41:42 -0700 Subject: [PATCH 11/41] Don't create a glower if no glow --- interface/src/models/ModelTreeRenderer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index d29303ab79..3f32f7f5ad 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -204,9 +204,11 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - { // Sets the glower scope + if (modelItem.getGlowLevel() > 0) { Glower glower(modelItem.getGlowLevel()); model->render(alpha, modelRenderMode); + } else { + model->render(alpha, modelRenderMode); } if (!isShadowMode && displayModelBounds) { From be9aac08ee5635b7e58728756ff127ff049e11d1 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski Date: Fri, 23 May 2014 20:49:48 +0200 Subject: [PATCH 12/41] add `disabled` state to Share button on click --- interface/src/ui/SnapshotShareDialog.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/interface/src/ui/SnapshotShareDialog.cpp b/interface/src/ui/SnapshotShareDialog.cpp index b5694b3e48..617d5e7101 100644 --- a/interface/src/ui/SnapshotShareDialog.cpp +++ b/interface/src/ui/SnapshotShareDialog.cpp @@ -31,6 +31,10 @@ const QString FORUM_REPLY_TO_TOPIC = "244"; const QString FORUM_POST_TEMPLATE = "

%2

"; const QString SHARE_DEFAULT_ERROR = "The server isn't responding. Please try again in a few minutes."; const QString SUCCESS_LABEL_TEMPLATE = "Success!!! Go check out your image ...
%1"; +const QString SHARE_BUTTON_STYLE = "border-width:0;border-radius:9px;border-radius:9px;font-family:Arial;font-size:18px;" + "font-weight:100;color:#FFFFFF;width: 120px;height: 50px;"; +const QString SHARE_BUTTON_ENABLED_STYLE = "background-color: #333;"; +const QString SHARE_BUTTON_DISABLED_STYLE = "background-color: #999;"; Q_DECLARE_METATYPE(QNetworkAccessManager::Operation) @@ -73,6 +77,10 @@ SnapshotShareDialog::SnapshotShareDialog(QString fileName, QWidget* parent) : } void SnapshotShareDialog::accept() { + // prevent multiple clicks on share button + _ui.shareButton->setEnabled(false); + // gray out share button + _ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_DISABLED_STYLE); uploadSnapshot(); } @@ -179,6 +187,8 @@ void SnapshotShareDialog::postRequestFinished() { } } QMessageBox::warning(this, "", errorMessage); + _ui.shareButton->setEnabled(true); + _ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_ENABLED_STYLE); } } @@ -192,6 +202,8 @@ void SnapshotShareDialog::uploadRequestFinished() { sendForumPost(responseObject["url"].toString()); } else { QMessageBox::warning(this, "", SHARE_DEFAULT_ERROR); + _ui.shareButton->setEnabled(true); + _ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_ENABLED_STYLE); } delete requestReply; From 9acf377573111beb1f76afbe90fc0639203cd1d4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 11:52:39 -0700 Subject: [PATCH 13/41] balances are 64-bit unsigned ints --- libraries/networking/src/AccountManager.cpp | 2 +- libraries/networking/src/AccountManager.h | 4 ++-- libraries/networking/src/DataServerAccountInfo.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 7d27332a57..96292d7baf 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -98,7 +98,7 @@ void AccountManager::updateBalance() { } } -void AccountManager::accountInfoBalanceChanged(qint64 newBalance) { +void AccountManager::accountInfoBalanceChanged(quint64 newBalance) { emit balanceChanged(newBalance); } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 628b084ea8..b761b50610 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -64,7 +64,7 @@ public slots: void requestError(QNetworkReply::NetworkError error); void logout(); void updateBalance(); - void accountInfoBalanceChanged(qint64 newBalance); + void accountInfoBalanceChanged(quint64 newBalance); signals: void authRequired(); void authEndpointChanged(); @@ -73,7 +73,7 @@ signals: void loginComplete(const QUrl& authURL); void loginFailed(); void logoutComplete(); - void balanceChanged(qint64 newBalance); + void balanceChanged(quint64 newBalance); private slots: void processReply(); private: diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index fd135f922b..2777bec4be 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -44,7 +44,7 @@ public: friend QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info); friend QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info); signals: - qint64 balanceChanged(qint64 newBalance); + quint64 balanceChanged(quint64 newBalance); private: void swap(DataServerAccountInfo& otherInfo); From 28536eaef29245b223f1371cc244c0a3c6d51200 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 May 2014 11:53:34 -0700 Subject: [PATCH 14/41] CR --- interface/src/models/ModelTreeRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 3f32f7f5ad..2ab8a1a7d3 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -204,7 +204,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - if (modelItem.getGlowLevel() > 0) { + if (modelItem.getGlowLevel() > 0.0f) { Glower glower(modelItem.getGlowLevel()); model->render(alpha, modelRenderMode); } else { From f4292fd29c332ecde41e37ba426f7a2907cf11d9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 12:33:39 -0700 Subject: [PATCH 15/41] handle serving of scripts at temp unique UUIDs --- assignment-client/src/Agent.cpp | 2 + domain-server/src/DomainServer.cpp | 37 +++++++++++++++++++ .../embedded-webserver/src/HTTPConnection.cpp | 1 + .../embedded-webserver/src/HTTPConnection.h | 1 + 4 files changed, 41 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index e6c14d06da..fcc2288356 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -213,6 +213,8 @@ void Agent::run() { loop.exec(); + + // let the AvatarData and ResourceCache classes use our QNetworkAccessManager AvatarData::setNetworkAccessManager(networkManager); ResourceCache::setNetworkAccessManager(networkManager); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index f979de64c0..28258d59b7 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1004,6 +1004,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return true; } else { + // check if this is for json stats for a node const QString NODE_JSON_REGEX_STRING = QString("\\%1\\/(%2).json\\/?$").arg(URI_NODES).arg(UUID_REGEX_STRING); QRegExp nodeShowRegex(NODE_JSON_REGEX_STRING); @@ -1028,6 +1029,42 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url // tell the caller we processed the request return true; } + + return false; + } + + // check if this is a request for a scripted assignment (with a temp unique UUID) + const QString ASSIGNMENT_REGEX_STRING = QString("\\%1\\/(%2)\\/?$").arg(URI_ASSIGNMENT).arg(UUID_REGEX_STRING); + QRegExp assignmentRegex(ASSIGNMENT_REGEX_STRING); + + if (assignmentRegex.indexIn(url.path()) != -1) { + QUuid matchingUUID = QUuid(assignmentRegex.cap(1)); + + SharedAssignmentPointer matchingAssignment = _allAssignments.value(matchingUUID); + if (!matchingAssignment) { + // check if we have a pending assignment that matches this temp UUID, and it is a scripted assignment + PendingAssignedNodeData* pendingData = _pendingAssignedNodes.value(matchingUUID); + if (pendingData) { + matchingAssignment = _allAssignments.value(pendingData->getAssignmentUUID()); + + if (matchingAssignment && matchingAssignment->getType() == Assignment::AgentType) { + // we have a matching assignment and it is for the right type, send a temp re-direct to the + // URL for the script so the client can download + + QUrl scriptURL = url; + scriptURL.setPath(URI_ASSIGNMENT + "/" + + uuidStringWithoutCurlyBraces(pendingData->getAssignmentUUID())); + + // have the HTTPManager serve the appropriate script file + return _httpManager.handleHTTPRequest(connection, scriptURL); + } + } else { + return false; + } + } + + // request not handled + return false; } } } else if (connection->requestOperation() == QNetworkAccessManager::PostOperation) { diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index a6eb391138..beb107c4cf 100755 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -19,6 +19,7 @@ const char* HTTPConnection::StatusCode200 = "200 OK"; const char* HTTPConnection::StatusCode301 = "301 Moved Permanently"; +const char* HTTPConnection::StatusCode302 = "302 Found"; const char* HTTPConnection::StatusCode400 = "400 Bad Request"; const char* HTTPConnection::StatusCode404 = "404 Not Found"; const char* HTTPConnection::DefaultContentType = "text/plain; charset=ISO-8859-1"; diff --git a/libraries/embedded-webserver/src/HTTPConnection.h b/libraries/embedded-webserver/src/HTTPConnection.h index d5214ee3a8..e2352ed250 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.h +++ b/libraries/embedded-webserver/src/HTTPConnection.h @@ -44,6 +44,7 @@ class HTTPConnection : public QObject { public: static const char* StatusCode200; static const char* StatusCode301; + static const char* StatusCode302; static const char* StatusCode400; static const char* StatusCode404; static const char* DefaultContentType; From 7e78fc788a1b46714afe29efe416a262ca356332 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 12:35:16 -0700 Subject: [PATCH 16/41] fix double return false --- domain-server/src/DomainServer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 28258d59b7..c814f81313 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1058,8 +1058,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url // have the HTTPManager serve the appropriate script file return _httpManager.handleHTTPRequest(connection, scriptURL); } - } else { - return false; } } From e7e19e87143f3991de50bcbb33177bb76c63aa97 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 12:37:27 -0700 Subject: [PATCH 17/41] fix a comment in script handling --- domain-server/src/DomainServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index c814f81313..a530be5dad 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1048,8 +1048,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url matchingAssignment = _allAssignments.value(pendingData->getAssignmentUUID()); if (matchingAssignment && matchingAssignment->getType() == Assignment::AgentType) { - // we have a matching assignment and it is for the right type, send a temp re-direct to the - // URL for the script so the client can download + // we have a matching assignment and it is for the right type, have the HTTP manager handle it + // via correct URL for the script so the client can download QUrl scriptURL = url; scriptURL.setPath(URI_ASSIGNMENT + "/" From 34eb0f9f431d6c7f944f19cd821d77fda0d83966 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 15:34:34 -0700 Subject: [PATCH 18/41] make transaction amounts and balances signed 64-bit --- domain-server/src/WalletTransaction.cpp | 6 +++--- domain-server/src/WalletTransaction.h | 10 +++++----- libraries/networking/src/AccountManager.cpp | 2 +- libraries/networking/src/AccountManager.h | 4 ++-- libraries/networking/src/DataServerAccountInfo.cpp | 2 +- libraries/networking/src/DataServerAccountInfo.h | 8 ++++---- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/domain-server/src/WalletTransaction.cpp b/domain-server/src/WalletTransaction.cpp index 6ff57f063c..9c8226a908 100644 --- a/domain-server/src/WalletTransaction.cpp +++ b/domain-server/src/WalletTransaction.cpp @@ -18,13 +18,13 @@ WalletTransaction::WalletTransaction() : _uuid(), _destinationUUID(), - _amount(), + _amount(0), _isFinalized(false) { } -WalletTransaction::WalletTransaction(const QUuid& destinationUUID, double amount) : +WalletTransaction::WalletTransaction(const QUuid& destinationUUID, qint64 amount) : _uuid(QUuid::createUuid()), _destinationUUID(destinationUUID), _amount(amount), @@ -63,5 +63,5 @@ void WalletTransaction::loadFromJson(const QJsonObject& jsonObject) { _uuid = QUuid(transactionObject.value(TRANSACTION_ID_KEY).toString()); _destinationUUID = QUuid(transactionObject.value(TRANSACTION_DESTINATION_WALLET_ID_KEY).toString()); - _amount = transactionObject.value(TRANSACTION_AMOUNT_KEY).toDouble(); + _amount = transactionObject.value(TRANSACTION_AMOUNT_KEY).toInt(); } \ No newline at end of file diff --git a/domain-server/src/WalletTransaction.h b/domain-server/src/WalletTransaction.h index 8f36d10302..5e05f9f549 100644 --- a/domain-server/src/WalletTransaction.h +++ b/domain-server/src/WalletTransaction.h @@ -19,16 +19,16 @@ class WalletTransaction : public QObject { public: WalletTransaction(); - WalletTransaction(const QUuid& destinationUUID, double amount); + WalletTransaction(const QUuid& destinationUUID, qint64 amount); const QUuid& getUUID() const { return _uuid; } void setDestinationUUID(const QUuid& destinationUUID) { _destinationUUID = destinationUUID; } const QUuid& getDestinationUUID() const { return _destinationUUID; } - double getAmount() const { return _amount; } - void setAmount(double amount) { _amount = amount; } - void incrementAmount(double increment) { _amount += increment; } + qint64 getAmount() const { return _amount; } + void setAmount(qint64 amount) { _amount = amount; } + void incrementAmount(qint64 increment) { _amount += increment; } bool isFinalized() const { return _isFinalized; } void setIsFinalized(bool isFinalized) { _isFinalized = isFinalized; } @@ -39,7 +39,7 @@ public: private: QUuid _uuid; QUuid _destinationUUID; - double _amount; + qint64 _amount; bool _isFinalized; }; diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 96292d7baf..7d27332a57 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -98,7 +98,7 @@ void AccountManager::updateBalance() { } } -void AccountManager::accountInfoBalanceChanged(quint64 newBalance) { +void AccountManager::accountInfoBalanceChanged(qint64 newBalance) { emit balanceChanged(newBalance); } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index b761b50610..628b084ea8 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -64,7 +64,7 @@ public slots: void requestError(QNetworkReply::NetworkError error); void logout(); void updateBalance(); - void accountInfoBalanceChanged(quint64 newBalance); + void accountInfoBalanceChanged(qint64 newBalance); signals: void authRequired(); void authEndpointChanged(); @@ -73,7 +73,7 @@ signals: void loginComplete(const QUrl& authURL); void loginFailed(); void logoutComplete(); - void balanceChanged(quint64 newBalance); + void balanceChanged(qint64 newBalance); private slots: void processReply(); private: diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index b3607200fe..809f083e35 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -83,7 +83,7 @@ void DataServerAccountInfo::setDiscourseApiKey(const QString& discourseApiKey) { } } -void DataServerAccountInfo::setBalance(quint64 balance) { +void DataServerAccountInfo::setBalance(qint64 balance) { if (!_hasBalance || _balance != balance) { _balance = balance; _hasBalance = true; diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index 2777bec4be..9bc4fbb37c 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -35,8 +35,8 @@ public: const QString& getDiscourseApiKey() const { return _discourseApiKey; } void setDiscourseApiKey(const QString& discourseApiKey); - quint64 getBalance() const { return _balance; } - void setBalance(quint64 balance); + qint64 getBalance() const { return _balance; } + void setBalance(qint64 balance); bool hasBalance() const { return _hasBalance; } void setHasBalance(bool hasBalance) { _hasBalance = hasBalance; } Q_INVOKABLE void setBalanceFromJSON(const QJsonObject& jsonObject); @@ -44,7 +44,7 @@ public: friend QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info); friend QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info); signals: - quint64 balanceChanged(quint64 newBalance); + qint64 balanceChanged(qint64 newBalance); private: void swap(DataServerAccountInfo& otherInfo); @@ -52,7 +52,7 @@ private: QString _username; QString _xmppPassword; QString _discourseApiKey; - quint64 _balance; + qint64 _balance; bool _hasBalance; }; From 15a8272286c31fee047acde7855820e02c2dff55 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 15:43:02 -0700 Subject: [PATCH 19/41] fix domain-server pending credits to actually be in credits --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index a530be5dad..7224f9eec8 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -887,7 +887,7 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { double pendingCreditAmount = 0; while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) { - pendingCreditAmount += i.value()->getAmount(); + pendingCreditAmount += i.value()->getAmount() * powf(10.0f, -8.0f); ++i; } From d425b5b322bbc5140652606394d66e472fc220ea Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 May 2014 15:59:27 -0700 Subject: [PATCH 20/41] Enable local gravity when there is a floor nearby. --- interface/src/Menu.cpp | 3 +- interface/src/Menu.h | 1 + interface/src/avatar/MyAvatar.cpp | 63 ++++++++++++++++++++++++------ libraries/avatars/src/AvatarData.h | 20 ++++++---- 4 files changed, 67 insertions(+), 20 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 96bfa106f4..856e1efae7 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -200,7 +200,8 @@ Menu::Menu() : QObject* avatar = appInstance->getAvatar(); addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, avatar, SLOT(updateMotionBehaviorsFromMenu())); - + addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::StandOnNearbyFloors, 0, true, + avatar, SLOT(updateMotionBehaviorsFromMenu())); addAvatarCollisionSubMenu(editMenu); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b12f989ed6..279d2151c9 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -376,6 +376,7 @@ namespace MenuOption { const QString ShowBordersModelNodes = "Show Model Nodes"; const QString ShowBordersParticleNodes = "Show Particle Nodes"; const QString ShowIKConstraints = "Show IK Constraints"; + const QString StandOnNearbyFloors = "Stand on nearby floors"; const QString Stars = "Stars"; const QString Stats = "Stats"; const QString StopAllScripts = "Stop All Scripts"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 43f577d878..79c721e896 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -383,9 +383,9 @@ void MyAvatar::setGravity(const glm::vec3& gravity) { float gravityLength = glm::length(gravity); if (gravityLength > EPSILON) { _worldUpDirection = _gravity / -gravityLength; - } else { - _worldUpDirection = DEFAULT_UP_DIRECTION; } + // NOTE: the else case here it to leave _worldUpDirection unchanged + // so it continues to point opposite to the previous gravity setting. } AnimationHandlePointer MyAvatar::addAnimationHandle() { @@ -814,12 +814,13 @@ void MyAvatar::updatePosition(float deltaTime) { bool walkingOnFloor = false; float gravityLength = glm::length(_gravity) * GRAVITY_EARTH; - if (gravityLength > EPSILON) { - const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); - glm::vec3 startCap; - boundingShape.getStartPoint(startCap); - glm::vec3 bottomOfBoundingCapsule = startCap - boundingShape.getRadius() * _worldUpDirection; + const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); + glm::vec3 startCap; + boundingShape.getStartPoint(startCap); + glm::vec3 bottomOfBoundingCapsule = startCap - boundingShape.getRadius() * _worldUpDirection; + + if (gravityLength > EPSILON) { float speedFromGravity = _scale * deltaTime * gravityLength; float distanceToFall = glm::distance(bottomOfBoundingCapsule, _lastFloorContactPoint); walkingOnFloor = (distanceToFall < 2.0f * deltaTime * speedFromGravity); @@ -840,6 +841,32 @@ void MyAvatar::updatePosition(float deltaTime) { } else { _velocity -= speedFromGravity * _worldUpDirection; } + if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) { + const float MAX_VERTICAL_FLOOR_DETECTION_SPEED = _scale * MAX_WALKING_SPEED; + if (keyboardInput && glm::dot(_motorVelocity, _worldUpDirection) > 0.0f && + glm::dot(_velocity, _worldUpDirection) > MAX_VERTICAL_FLOOR_DETECTION_SPEED) { + // disable gravity because we're pushing with keyboard + setLocalGravity(glm::vec3(0.0f)); + } + } + } else { + if ((_collisionGroups & COLLISION_GROUP_VOXELS) && + _motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) { + const float MIN_FLOOR_DETECTION_SPEED = _scale * 1.0f; + if (glm::length(_velocity) < MIN_FLOOR_DETECTION_SPEED ) { + // scan for floor + glm::vec3 direction = -_worldUpDirection; + OctreeElement* elementHit; // output from findRayIntersection + float distance; // output from findRayIntersection + BoxFace face; // output from findRayIntersection + Application::getInstance()->getVoxelTree()->findRayIntersection(bottomOfBoundingCapsule, direction, elementHit, distance, face); + const float NEARBY_FLOOR_THRESHOLD = _scale * 2.0f; + if (elementHit && distance < NEARBY_FLOOR_THRESHOLD) { + // turn on local gravity + setLocalGravity(-_worldUpDirection); + } + } + } } if (keyboardInput > 0.0f || glm::length2(_velocity) > 0.0f || glm::length2(_thrust) > 0.0f || ! walkingOnFloor) { @@ -888,12 +915,12 @@ void MyAvatar::updateMotorFromKeyboard(float deltaTime, bool walking) { if (directionLength > EPSILON) { direction /= directionLength; // the finalMotorSpeed depends on whether we are walking or not - float finalMaxMotorSpeed = walking ? MAX_WALKING_SPEED : _maxMotorSpeed; + float finalMaxMotorSpeed = walking ? _scale * MAX_WALKING_SPEED : _scale * _maxMotorSpeed; float motorLength = glm::length(_motorVelocity); - if (motorLength < MIN_KEYBOARD_CONTROL_SPEED) { + if (motorLength < _scale * MIN_KEYBOARD_CONTROL_SPEED) { // an active keyboard motor should never be slower than this - _motorVelocity = MIN_KEYBOARD_CONTROL_SPEED * direction; + _motorVelocity = _scale * MIN_KEYBOARD_CONTROL_SPEED * direction; } else { float MOTOR_LENGTH_TIMESCALE = 1.5f; float tau = glm::clamp(deltaTime / MOTOR_LENGTH_TIMESCALE, 0.0f, 1.0f); @@ -1566,7 +1593,8 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) { } void MyAvatar::updateMotionBehaviorsFromMenu() { - if (Menu::getInstance()->isOptionChecked(MenuOption::ObeyEnvironmentalGravity)) { + Menu* menu = Menu::getInstance(); + if (menu->isOptionChecked(MenuOption::ObeyEnvironmentalGravity)) { _motionBehaviors |= AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; // Environmental and Local gravities are incompatible. Environmental setting trumps local. _motionBehaviors &= ~AVATAR_MOTION_OBEY_LOCAL_GRAVITY; @@ -1576,6 +1604,14 @@ void MyAvatar::updateMotionBehaviorsFromMenu() { if (! (_motionBehaviors & (AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | AVATAR_MOTION_OBEY_LOCAL_GRAVITY))) { setGravity(glm::vec3(0.0f)); } + if (menu->isOptionChecked(MenuOption::StandOnNearbyFloors)) { + _motionBehaviors |= AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + // standing on floors requires collision with voxels + _collisionGroups |= COLLISION_GROUP_VOXELS; + menu->setIsOptionChecked(MenuOption::CollideWithVoxels, true); + } else { + _motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + } } void MyAvatar::renderAttachments(RenderMode renderMode) { @@ -1602,6 +1638,11 @@ void MyAvatar::setCollisionGroups(quint32 collisionGroups) { menu->setIsOptionChecked(MenuOption::CollideWithAvatars, (bool)(_collisionGroups & COLLISION_GROUP_AVATARS)); menu->setIsOptionChecked(MenuOption::CollideWithVoxels, (bool)(_collisionGroups & COLLISION_GROUP_VOXELS)); menu->setIsOptionChecked(MenuOption::CollideWithParticles, (bool)(_collisionGroups & COLLISION_GROUP_PARTICLES)); + if (! (_collisionGroups & COLLISION_GROUP_VOXELS)) { + // no collision with voxels --> disable standing on floors + _motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + menu->setIsOptionChecked(MenuOption::StandOnNearbyFloors, false); + } } void MyAvatar::setMotionBehaviorsByScript(quint32 flags) { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 072070e98c..8f658678b5 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -53,23 +53,27 @@ typedef unsigned long long quint64; #include "HandData.h" // avatar motion behaviors -const quint32 AVATAR_MOTION_MOTOR_ENABLED = 1U << 0; -const quint32 AVATAR_MOTION_MOTOR_KEYBOARD_ENABLED = 1U << 1; -const quint32 AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME = 1U << 2; -const quint32 AVATAR_MOTION_MOTOR_COLLISION_SURFACE_ONLY = 1U << 3; +const quint32 AVATAR_MOTION_MOTOR_ENABLED = 1U << 0; +const quint32 AVATAR_MOTION_MOTOR_KEYBOARD_ENABLED = 1U << 1; +const quint32 AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME = 1U << 2; +const quint32 AVATAR_MOTION_MOTOR_COLLISION_SURFACE_ONLY = 1U << 3; -const quint32 AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY = 1U << 4; -const quint32 AVATAR_MOTION_OBEY_LOCAL_GRAVITY = 1U << 5; +const quint32 AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY = 1U << 4; +const quint32 AVATAR_MOTION_OBEY_LOCAL_GRAVITY = 1U << 5; + +const quint32 AVATAR_MOTION_STAND_ON_NEARBY_FLOORS = 1U << 6; const quint32 AVATAR_MOTION_DEFAULTS = AVATAR_MOTION_MOTOR_ENABLED | AVATAR_MOTION_MOTOR_KEYBOARD_ENABLED | - AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME; + AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME | + AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; // these bits will be expanded as features are exposed const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | - AVATAR_MOTION_OBEY_LOCAL_GRAVITY; + AVATAR_MOTION_OBEY_LOCAL_GRAVITY | + AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; // First bitset From 1b00cda068a02744277bb227f6e384a87baeff6b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 16:12:34 -0700 Subject: [PATCH 21/41] don't use powf for credit conversions --- domain-server/src/DomainServer.cpp | 4 ++-- interface/src/Application.cpp | 2 +- libraries/networking/src/DataServerAccountInfo.h | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 7224f9eec8..d83ba5772b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -735,7 +735,7 @@ void DomainServer::setupPendingAssignmentCredits() { const float CREDITS_PER_HOUR = 0.10f; const float CREDITS_PER_MSEC = CREDITS_PER_HOUR / (60 * 60 * 1000); - const int SATOSHIS_PER_MSEC = CREDITS_PER_MSEC * powf(10.0f, 8.0f); + const int SATOSHIS_PER_MSEC = CREDITS_PER_MSEC * SATOSHIS_PER_UNIT; float pendingCredits = elapsedMsecsSinceLastPayment * SATOSHIS_PER_MSEC; @@ -887,7 +887,7 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { double pendingCreditAmount = 0; while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) { - pendingCreditAmount += i.value()->getAmount() * powf(10.0f, -8.0f); + pendingCreditAmount += i.value()->getAmount() / SATOSHIS_PER_CREDIT; ++i; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1bf284a00f..8d8c098fe0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3108,7 +3108,7 @@ void Application::updateWindowTitle(){ AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.getAccountInfo().hasBalance()) { - float creditBalance = accountManager.getAccountInfo().getBalance() * pow(10.0f, -8.0f); + float creditBalance = accountManager.getAccountInfo().getBalance() / SATOSHIS_PER_CREDIT; QString creditBalanceString; creditBalanceString.sprintf("%.8f", creditBalance); diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index 9bc4fbb37c..f37e05ff63 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -16,6 +16,8 @@ #include "OAuthAccessToken.h" +const float SATOSHIS_PER_CREDIT = 10.0e8f; + class DataServerAccountInfo : public QObject { Q_OBJECT public: From 831b0faa20faa3a20806f256e452c74b6fd5a451 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 16:15:11 -0700 Subject: [PATCH 22/41] fix a mistyped constant --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d83ba5772b..2eb92ff24c 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -735,7 +735,7 @@ void DomainServer::setupPendingAssignmentCredits() { const float CREDITS_PER_HOUR = 0.10f; const float CREDITS_PER_MSEC = CREDITS_PER_HOUR / (60 * 60 * 1000); - const int SATOSHIS_PER_MSEC = CREDITS_PER_MSEC * SATOSHIS_PER_UNIT; + const int SATOSHIS_PER_MSEC = CREDITS_PER_MSEC * SATOSHIS_PER_CREDIT; float pendingCredits = elapsedMsecsSinceLastPayment * SATOSHIS_PER_MSEC; From 1e9589c19e77df226c1655f019854f6c30a3f01b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 16:18:21 -0700 Subject: [PATCH 23/41] fix an implicit cast to float --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8d8c098fe0..83568998b6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3108,7 +3108,7 @@ void Application::updateWindowTitle(){ AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.getAccountInfo().hasBalance()) { - float creditBalance = accountManager.getAccountInfo().getBalance() / SATOSHIS_PER_CREDIT; + float creditBalance = accountManager.getAccountInfo().getBalance() / (float) SATOSHIS_PER_CREDIT; QString creditBalanceString; creditBalanceString.sprintf("%.8f", creditBalance); From 45ab8145a46a741287b0e74122468a5f63b8bddc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 16:22:08 -0700 Subject: [PATCH 24/41] fix another implicit float cast --- domain-server/src/DomainServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2eb92ff24c..9cd7080347 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -884,10 +884,10 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { if (!nodeData->getWalletUUID().isNull()) { TransactionHash::iterator i = _pendingAssignmentCredits.find(nodeData->getWalletUUID()); - double pendingCreditAmount = 0; + float pendingCreditAmount = 0; while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) { - pendingCreditAmount += i.value()->getAmount() / SATOSHIS_PER_CREDIT; + pendingCreditAmount += i.value()->getAmount() / (float) SATOSHIS_PER_CREDIT; ++i; } From d341e7314defd042622ef1fc6a4e05ee3b1e1099 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 23 May 2014 16:25:19 -0700 Subject: [PATCH 25/41] squared force on thrust controller --- examples/hydraMove.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/examples/hydraMove.js b/examples/hydraMove.js index ed6a5a4f44..f211a450a3 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -78,7 +78,7 @@ function createDebugOverlay() { position: defaultPosition, size: RADIUS, color: GRAY_COLOR, - alpha: 1, + alpha: 0.75, visible: true, solid: true, anchor: "MyAvatar" @@ -87,7 +87,7 @@ function createDebugOverlay() { position: defaultPosition, size: RADIUS, color: RED_COLOR, - alpha: 1, + alpha: 0.5, visible: true, solid: true, anchor: "MyAvatar" @@ -111,7 +111,7 @@ function displayDebug() { } } else { // update debug indicator - if (greenSphere == -1) { + if (greenSphere == -1) { createDebugOverlay(); } @@ -149,8 +149,8 @@ function getGrabRotation() { // When move button is pressed, process results function handleGrabBehavior(deltaTime) { // check for and handle grab behaviors - grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_FWD) || Controller.isButtonPressed(RIGHT_BUTTON_4); - grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_FWD) || Controller.isButtonPressed(LEFT_BUTTON_4); + grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4); + grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_4); stoppedGrabbingWithLeftHand = false; stoppedGrabbingWithRightHand = false; @@ -201,20 +201,22 @@ function handleGrabBehavior(deltaTime) { printVector("grabDelta: ", grabDelta, 3); } - var THRUST_GRAB_SCALING = 300000.0; + var thrust = Vec3.multiply(grabDelta, Math.abs(Vec3.length(grabDelta))); + + var THRUST_GRAB_SCALING = 100000.0; - var thrustFront = Vec3.multiply(front, MyAvatar.scale * -grabDelta.z * THRUST_GRAB_SCALING * deltaTime); + var thrustFront = Vec3.multiply(front, MyAvatar.scale * -thrust.z * THRUST_GRAB_SCALING * deltaTime); MyAvatar.addThrust(thrustFront); - var thrustRight = Vec3.multiply(right, MyAvatar.scale * grabDelta.x * THRUST_GRAB_SCALING * deltaTime); + var thrustRight = Vec3.multiply(right, MyAvatar.scale * thrust.x * THRUST_GRAB_SCALING * deltaTime); MyAvatar.addThrust(thrustRight); - var thrustUp = Vec3.multiply(up, MyAvatar.scale * grabDelta.y * THRUST_GRAB_SCALING * deltaTime); + var thrustUp = Vec3.multiply(up, MyAvatar.scale * thrust.y * THRUST_GRAB_SCALING * deltaTime); MyAvatar.addThrust(thrustUp); // add some rotation... var deltaRotation = getGrabRotation(); - var PITCH_SCALING = 2.0; + var PITCH_SCALING = 2.5; var PITCH_DEAD_ZONE = 2.0; - var YAW_SCALING = 2.0; + var YAW_SCALING = 2.5; var ROLL_SCALING = 2.0; var euler = Quat.safeEulerAngles(deltaRotation); From 0baf757c0de13dc6742c1259bfb98251a1a5db8f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 23 May 2014 16:35:51 -0700 Subject: [PATCH 26/41] Basic support for shadows on models. --- interface/resources/shaders/model.vert | 3 + .../resources/shaders/model_normal_map.vert | 4 + interface/resources/shaders/skin_model.vert | 3 + .../shaders/skin_model_normal_map.vert | 4 + interface/src/renderer/Model.cpp | 173 ++++++++++++++++-- interface/src/renderer/Model.h | 24 ++- 6 files changed, 199 insertions(+), 12 deletions(-) diff --git a/interface/resources/shaders/model.vert b/interface/resources/shaders/model.vert index f78ed5045b..da7e9640d9 100644 --- a/interface/resources/shaders/model.vert +++ b/interface/resources/shaders/model.vert @@ -31,6 +31,9 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; + // and the shadow texture coordinates + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0); + // use standard pipeline transform gl_Position = ftransform(); } diff --git a/interface/resources/shaders/model_normal_map.vert b/interface/resources/shaders/model_normal_map.vert index b013a0a736..2a2f4156f0 100644 --- a/interface/resources/shaders/model_normal_map.vert +++ b/interface/resources/shaders/model_normal_map.vert @@ -36,6 +36,10 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; + // and the shadow texture coordinates + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], interpolatedPosition), dot(gl_EyePlaneT[0], interpolatedPosition), + dot(gl_EyePlaneR[0], interpolatedPosition), 1.0); + // use standard pipeline transform gl_Position = ftransform(); } diff --git a/interface/resources/shaders/skin_model.vert b/interface/resources/shaders/skin_model.vert index f743609dc3..d68347d33d 100644 --- a/interface/resources/shaders/skin_model.vert +++ b/interface/resources/shaders/skin_model.vert @@ -43,5 +43,8 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; + // and the shadow texture coordinates + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0); + gl_Position = gl_ProjectionMatrix * position; } diff --git a/interface/resources/shaders/skin_model_normal_map.vert b/interface/resources/shaders/skin_model_normal_map.vert index 5dbc32626a..66cc7c0f58 100644 --- a/interface/resources/shaders/skin_model_normal_map.vert +++ b/interface/resources/shaders/skin_model_normal_map.vert @@ -52,5 +52,9 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; + // and the shadow texture coordinates + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], interpolatedPosition), dot(gl_EyePlaneT[0], interpolatedPosition), + dot(gl_EyePlaneR[0], interpolatedPosition), 1.0); + gl_Position = gl_ProjectionMatrix * interpolatedPosition; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d18abce677..d1a0a3ec7c 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -59,18 +59,39 @@ ProgramObject Model::_program; ProgramObject Model::_normalMapProgram; ProgramObject Model::_specularMapProgram; ProgramObject Model::_normalSpecularMapProgram; + +ProgramObject Model::_shadowMapProgram; +ProgramObject Model::_shadowNormalMapProgram; +ProgramObject Model::_shadowSpecularMapProgram; +ProgramObject Model::_shadowNormalSpecularMapProgram; + ProgramObject Model::_shadowProgram; + ProgramObject Model::_skinProgram; ProgramObject Model::_skinNormalMapProgram; ProgramObject Model::_skinSpecularMapProgram; ProgramObject Model::_skinNormalSpecularMapProgram; + +ProgramObject Model::_skinShadowMapProgram; +ProgramObject Model::_skinShadowNormalMapProgram; +ProgramObject Model::_skinShadowSpecularMapProgram; +ProgramObject Model::_skinShadowNormalSpecularMapProgram; + ProgramObject Model::_skinShadowProgram; + int Model::_normalMapTangentLocation; int Model::_normalSpecularMapTangentLocation; +int Model::_shadowNormalMapTangentLocation; +int Model::_shadowNormalSpecularMapTangentLocation; + Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; Model::SkinLocations Model::_skinSpecularMapLocations; Model::SkinLocations Model::_skinNormalSpecularMapLocations; +Model::SkinLocations Model::_skinShadowMapLocations; +Model::SkinLocations Model::_skinShadowNormalMapLocations; +Model::SkinLocations Model::_skinShadowSpecularMapLocations; +Model::SkinLocations Model::_skinShadowNormalSpecularMapLocations; Model::SkinLocations Model::_skinShadowLocations; void Model::setScale(const glm::vec3& scale) { @@ -100,7 +121,8 @@ void Model::setOffset(const glm::vec3& offset) { } -void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit) { +void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, + int specularTextureUnit, int shadowTextureUnit) { program.bind(); locations.clusterMatrices = program.uniformLocation("clusterMatrices"); locations.clusterIndices = program.attributeLocation("clusterIndices"); @@ -109,6 +131,7 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati program.setUniformValue("diffuseMap", 0); program.setUniformValue("normalMap", 1); program.setUniformValue("specularMap", specularTextureUnit); + program.setUniformValue("shadowMap", shadowTextureUnit); program.release(); } @@ -170,7 +193,7 @@ void Model::init() { _program.link(); _program.bind(); - _program.setUniformValue("texture", 0); + _program.setUniformValue("diffuseMap", 0); _program.release(); _normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, @@ -209,11 +232,63 @@ void Model::init() { _normalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); _normalSpecularMapProgram.release(); + + _shadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); + _shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/model_shadow_map.frag"); + _shadowMapProgram.link(); + + _shadowMapProgram.bind(); + _shadowMapProgram.setUniformValue("diffuseMap", 0); + _shadowMapProgram.setUniformValue("shadowMap", 1); + _shadowMapProgram.release(); + + _shadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model_normal_map.vert"); + _shadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_shadow_normal_map.frag"); + _shadowNormalMapProgram.link(); + + _shadowNormalMapProgram.bind(); + _shadowNormalMapProgram.setUniformValue("diffuseMap", 0); + _shadowNormalMapProgram.setUniformValue("normalMap", 1); + _shadowNormalMapProgram.setUniformValue("shadowMap", 2); + _shadowNormalMapTangentLocation = _shadowNormalMapProgram.attributeLocation("tangent"); + _shadowNormalMapProgram.release(); + + _shadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model.vert"); + _shadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_shadow_specular_map.frag"); + _shadowSpecularMapProgram.link(); + + _shadowSpecularMapProgram.bind(); + _shadowSpecularMapProgram.setUniformValue("diffuseMap", 0); + _shadowSpecularMapProgram.setUniformValue("specularMap", 1); + _shadowSpecularMapProgram.setUniformValue("shadowMap", 2); + _shadowSpecularMapProgram.release(); + + _shadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model_normal_map.vert"); + _shadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag"); + _shadowNormalSpecularMapProgram.link(); + + _shadowNormalSpecularMapProgram.bind(); + _shadowNormalSpecularMapProgram.setUniformValue("diffuseMap", 0); + _shadowNormalSpecularMapProgram.setUniformValue("normalMap", 1); + _shadowNormalSpecularMapProgram.setUniformValue("specularMap", 2); + _shadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3); + _shadowNormalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); + _shadowNormalSpecularMapProgram.release(); + + _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); _shadowProgram.link(); + _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); _skinProgram.link(); @@ -244,6 +319,40 @@ void Model::init() { initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations, 2); + + _skinShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/skin_model.vert"); + _skinShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/model_shadow_map.frag"); + _skinShadowMapProgram.link(); + + initSkinProgram(_skinShadowMapProgram, _skinShadowMapLocations); + + _skinShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); + _skinShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_shadow_normal_map.frag"); + _skinShadowNormalMapProgram.link(); + + initSkinProgram(_skinShadowNormalMapProgram, _skinShadowNormalMapLocations, 1, 2); + + _skinShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model.vert"); + _skinShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_shadow_specular_map.frag"); + _skinShadowSpecularMapProgram.link(); + + initSkinProgram(_skinShadowSpecularMapProgram, _skinShadowSpecularMapLocations, 1, 2); + + _skinShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); + _skinShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag"); + _skinShadowNormalSpecularMapProgram.link(); + + initSkinProgram(_skinNormalSpecularMapProgram, _skinShadowNormalSpecularMapLocations, 2, 3); + + _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_shadow.vert"); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, @@ -1485,6 +1594,12 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); + bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::Shadows); + if (receiveShadows) { + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]); + glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]); + } for (int i = 0; i < networkMeshes.size(); i++) { // exit early if the translucency doesn't match what we're drawing const NetworkMesh& networkMesh = networkMeshes.at(i); @@ -1507,6 +1622,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; GLenum specularTextureUnit = 0; + GLenum shadowTextureUnit = 0; if (mode == SHADOW_RENDER_MODE) { program = &_shadowProgram; skinProgram = &_skinShadowProgram; @@ -1514,21 +1630,45 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { } else if (!mesh.tangents.isEmpty()) { if (mesh.hasSpecularTexture()) { - program = &_normalSpecularMapProgram; - skinProgram = &_skinNormalSpecularMapProgram; - skinLocations = &_skinNormalSpecularMapLocations; + if (receiveShadows) { + program = &_shadowNormalSpecularMapProgram; + skinProgram = &_skinShadowNormalSpecularMapProgram; + skinLocations = &_skinShadowNormalSpecularMapLocations; + shadowTextureUnit = GL_TEXTURE3; + } else { + program = &_normalSpecularMapProgram; + skinProgram = &_skinNormalSpecularMapProgram; + skinLocations = &_skinNormalSpecularMapLocations; + } specularTextureUnit = GL_TEXTURE2; + } else if (receiveShadows) { + program = &_shadowNormalMapProgram; + skinProgram = &_skinShadowNormalMapProgram; + skinLocations = &_skinShadowNormalMapLocations; } else { program = &_normalMapProgram; skinProgram = &_skinNormalMapProgram; skinLocations = &_skinNormalMapLocations; } } else if (mesh.hasSpecularTexture()) { - program = &_specularMapProgram; - skinProgram = &_skinSpecularMapProgram; - skinLocations = &_skinSpecularMapLocations; - specularTextureUnit = GL_TEXTURE1; + if (receiveShadows) { + program = &_shadowSpecularMapProgram; + skinProgram = &_skinShadowSpecularMapProgram; + skinLocations = &_skinShadowSpecularMapLocations; + specularTextureUnit = GL_TEXTURE1; + shadowTextureUnit = GL_TEXTURE2; + } else { + program = &_specularMapProgram; + skinProgram = &_skinSpecularMapProgram; + skinLocations = &_skinSpecularMapLocations; + specularTextureUnit = GL_TEXTURE1; + } + } else if (receiveShadows) { + program = &_shadowMapProgram; + skinProgram = &_skinShadowMapProgram; + skinLocations = &_skinShadowMapLocations; + shadowTextureUnit = GL_TEXTURE1; } const MeshState& state = _meshStates.at(i); @@ -1617,8 +1757,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); - if (!mesh.tangents.isEmpty()) { - specularTextureUnit = GL_TEXTURE2; + if (!mesh.tangents.isEmpty()) { glActiveTexture(GL_TEXTURE1); Texture* normalMap = networkPart.normalTexture.data(); glBindTexture(GL_TEXTURE_2D, !normalMap ? @@ -1633,6 +1772,12 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { Application::getInstance()->getTextureCache()->getWhiteTextureID() : specularMap->getID()); glActiveTexture(GL_TEXTURE0); } + + if (shadowTextureUnit) { + glActiveTexture(shadowTextureUnit); + glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); + glActiveTexture(GL_TEXTURE0); + } } glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset); offset += part.quadIndices.size() * sizeof(int); @@ -1662,6 +1807,12 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { glActiveTexture(GL_TEXTURE0); } + if (shadowTextureUnit) { + glActiveTexture(shadowTextureUnit); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + } + if (state.clusterMatrices.size() > 1) { skinProgram->disableAttributeArray(skinLocations->clusterIndices); skinProgram->disableAttributeArray(skinLocations->clusterWeights); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 1a6642dfc6..1c9145139b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -340,19 +340,36 @@ private: QList _runningAnimations; + bool _receivesShadows; + static ProgramObject _program; static ProgramObject _normalMapProgram; static ProgramObject _specularMapProgram; static ProgramObject _normalSpecularMapProgram; + + static ProgramObject _shadowMapProgram; + static ProgramObject _shadowNormalMapProgram; + static ProgramObject _shadowSpecularMapProgram; + static ProgramObject _shadowNormalSpecularMapProgram; + static ProgramObject _shadowProgram; + static ProgramObject _skinProgram; static ProgramObject _skinNormalMapProgram; static ProgramObject _skinSpecularMapProgram; static ProgramObject _skinNormalSpecularMapProgram; + + static ProgramObject _skinShadowMapProgram; + static ProgramObject _skinShadowNormalMapProgram; + static ProgramObject _skinShadowSpecularMapProgram; + static ProgramObject _skinShadowNormalSpecularMapProgram; + static ProgramObject _skinShadowProgram; static int _normalMapTangentLocation; static int _normalSpecularMapTangentLocation; + static int _shadowNormalMapTangentLocation; + static int _shadowNormalSpecularMapTangentLocation; class SkinLocations { public: @@ -366,9 +383,14 @@ private: static SkinLocations _skinNormalMapLocations; static SkinLocations _skinSpecularMapLocations; static SkinLocations _skinNormalSpecularMapLocations; + static SkinLocations _skinShadowMapLocations; + static SkinLocations _skinShadowNormalMapLocations; + static SkinLocations _skinShadowSpecularMapLocations; + static SkinLocations _skinShadowNormalSpecularMapLocations; static SkinLocations _skinShadowLocations; - static void initSkinProgram(ProgramObject& program, SkinLocations& locations, int specularTextureUnit = 1); + static void initSkinProgram(ProgramObject& program, SkinLocations& locations, + int specularTextureUnit = 1, int shadowTextureUnit = 1); }; Q_DECLARE_METATYPE(QPointer) From 67e3454a86ee4bc6f0070b0256d14941d5f81359 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 23 May 2014 16:37:12 -0700 Subject: [PATCH 27/41] Missed a few files. --- .../resources/shaders/model_shadow_map.frag | 41 ++++++++++++++ .../shaders/model_shadow_normal_map.frag | 53 ++++++++++++++++++ .../model_shadow_normal_specular_map.frag | 56 +++++++++++++++++++ .../shaders/model_shadow_specular_map.frag | 44 +++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 interface/resources/shaders/model_shadow_map.frag create mode 100644 interface/resources/shaders/model_shadow_normal_map.frag create mode 100644 interface/resources/shaders/model_shadow_normal_specular_map.frag create mode 100644 interface/resources/shaders/model_shadow_specular_map.frag diff --git a/interface/resources/shaders/model_shadow_map.frag b/interface/resources/shaders/model_shadow_map.frag new file mode 100644 index 0000000000..4a2bb312dc --- /dev/null +++ b/interface/resources/shaders/model_shadow_map.frag @@ -0,0 +1,41 @@ +#version 120 + +// +// model_shadow_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/23/14. +// 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 +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the interpolated position +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the base color based on OpenGL lighting model + vec4 normalizedNormal = normalize(normal); + float diffuse = dot(normalizedNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), + normalizedNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); +} diff --git a/interface/resources/shaders/model_shadow_normal_map.frag b/interface/resources/shaders/model_shadow_normal_map.frag new file mode 100644 index 0000000000..d61b123fba --- /dev/null +++ b/interface/resources/shaders/model_shadow_normal_map.frag @@ -0,0 +1,53 @@ +#version 120 + +// +// model_shadow_normal_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/23/14. +// 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 +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the normal map texture +uniform sampler2D normalMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the interpolated position +varying vec4 interpolatedPosition; + +// the interpolated normal +varying vec4 interpolatedNormal; + +// the interpolated tangent +varying vec4 interpolatedTangent; + +void main(void) { + vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); + vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); + vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); + vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); + + // compute the base color based on OpenGL lighting model + vec4 viewNormal = vec4(normalizedTangent * localNormal.x + + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); + float diffuse = dot(viewNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - + normalize(vec4(vec3(interpolatedPosition), 0.0))), viewNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); +} diff --git a/interface/resources/shaders/model_shadow_normal_specular_map.frag b/interface/resources/shaders/model_shadow_normal_specular_map.frag new file mode 100644 index 0000000000..9865056479 --- /dev/null +++ b/interface/resources/shaders/model_shadow_normal_specular_map.frag @@ -0,0 +1,56 @@ +#version 120 + +// +// model_shadow_normal_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/23/14. +// 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 +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the normal map texture +uniform sampler2D normalMap; + +// the specular map texture +uniform sampler2D specularMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the interpolated position +varying vec4 interpolatedPosition; + +// the interpolated normal +varying vec4 interpolatedNormal; + +// the interpolated tangent +varying vec4 interpolatedTangent; + +void main(void) { + vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); + vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); + vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); + vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); + + // compute the base color based on OpenGL lighting model + vec4 viewNormal = vec4(normalizedTangent * localNormal.x + + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); + float diffuse = dot(viewNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - + normalize(vec4(interpolatedPosition.xyz, 0.0))), viewNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * + gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0); +} diff --git a/interface/resources/shaders/model_shadow_specular_map.frag b/interface/resources/shaders/model_shadow_specular_map.frag new file mode 100644 index 0000000000..4be0f1636d --- /dev/null +++ b/interface/resources/shaders/model_shadow_specular_map.frag @@ -0,0 +1,44 @@ +#version 120 + +// +// model_shadow_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/23/14. +// 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 +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the specular texture +uniform sampler2D specularMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the interpolated position in view space +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the base color based on OpenGL lighting model + vec4 normalizedNormal = normalize(normal); + float diffuse = dot(normalizedNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), + normalizedNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * + gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0); +} From ac2137c3b6c402e7cb728b150a4a8f27cdcb1820 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 23 May 2014 16:56:10 -0700 Subject: [PATCH 28/41] Fixed a couple copy and paste errors. --- interface/src/renderer/Model.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d1a0a3ec7c..11e2a59127 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -350,7 +350,7 @@ void Model::init() { Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag"); _skinShadowNormalSpecularMapProgram.link(); - initSkinProgram(_skinNormalSpecularMapProgram, _skinShadowNormalSpecularMapLocations, 2, 3); + initSkinProgram(_skinShadowNormalSpecularMapProgram, _skinShadowNormalSpecularMapLocations, 2, 3); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, @@ -1646,6 +1646,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { program = &_shadowNormalMapProgram; skinProgram = &_skinShadowNormalMapProgram; skinLocations = &_skinShadowNormalMapLocations; + shadowTextureUnit = GL_TEXTURE2; } else { program = &_normalMapProgram; skinProgram = &_skinNormalMapProgram; @@ -1656,14 +1657,14 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { program = &_shadowSpecularMapProgram; skinProgram = &_skinShadowSpecularMapProgram; skinLocations = &_skinShadowSpecularMapLocations; - specularTextureUnit = GL_TEXTURE1; shadowTextureUnit = GL_TEXTURE2; } else { program = &_specularMapProgram; skinProgram = &_skinSpecularMapProgram; skinLocations = &_skinSpecularMapLocations; - specularTextureUnit = GL_TEXTURE1; } + specularTextureUnit = GL_TEXTURE1; + } else if (receiveShadows) { program = &_shadowMapProgram; skinProgram = &_skinShadowMapProgram; From e48f02f2c56a5698761cd32dec75016821a050f8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 23 May 2014 17:13:27 -0700 Subject: [PATCH 29/41] Remove unused variable. --- interface/src/renderer/Model.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 1c9145139b..5b1f6402d3 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -340,8 +340,6 @@ private: QList _runningAnimations; - bool _receivesShadows; - static ProgramObject _program; static ProgramObject _normalMapProgram; static ProgramObject _specularMapProgram; From 714e29c8870ccea1444b47aea25032cc1b72a37a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 17:37:36 -0700 Subject: [PATCH 30/41] fix credit amount in window title --- domain-server/src/DomainServer.cpp | 2 +- interface/src/Application.cpp | 3 ++- libraries/networking/src/DataServerAccountInfo.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 9cd7080347..8efdeed8a7 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -887,7 +887,7 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { float pendingCreditAmount = 0; while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) { - pendingCreditAmount += i.value()->getAmount() / (float) SATOSHIS_PER_CREDIT; + pendingCreditAmount += i.value()->getAmount() / SATOSHIS_PER_CREDIT; ++i; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 83568998b6..502b1f3ed7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3108,7 +3108,8 @@ void Application::updateWindowTitle(){ AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.getAccountInfo().hasBalance()) { - float creditBalance = accountManager.getAccountInfo().getBalance() / (float) SATOSHIS_PER_CREDIT; + qDebug() << accountManager.getAccountInfo().getBalance(); + float creditBalance = accountManager.getAccountInfo().getBalance() / SATOSHIS_PER_CREDIT; QString creditBalanceString; creditBalanceString.sprintf("%.8f", creditBalance); diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index f37e05ff63..f6c6bf2797 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -16,7 +16,7 @@ #include "OAuthAccessToken.h" -const float SATOSHIS_PER_CREDIT = 10.0e8f; +const float SATOSHIS_PER_CREDIT = 10000000.0f; class DataServerAccountInfo : public QObject { Q_OBJECT From fe05beb88da50f800e63d6967df8451424a1d831 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 23 May 2014 17:41:58 -0700 Subject: [PATCH 31/41] remove an unneeded debug --- interface/src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 502b1f3ed7..8d8c098fe0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3108,7 +3108,6 @@ void Application::updateWindowTitle(){ AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.getAccountInfo().hasBalance()) { - qDebug() << accountManager.getAccountInfo().getBalance(); float creditBalance = accountManager.getAccountInfo().getBalance() / SATOSHIS_PER_CREDIT; QString creditBalanceString; From c832df0783e2926dab76eb5bc9d7c5d583bb9cd7 Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Sat, 24 May 2014 21:22:34 +0200 Subject: [PATCH 32/41] added missing locking against crashing in Overlays::~Overlays() --- interface/src/ui/overlays/Overlays.cpp | 28 +++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index da7b05ead7..6c6c314be4 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -22,16 +22,26 @@ Overlays::Overlays() : _nextOverlayID(1) { } Overlays::~Overlays() { - QMap::iterator it; - for (it = _overlays2D.begin(); it != _overlays2D.end(); ++it) { - delete _overlays2D.take(it.key()); - } - for (it = _overlays3D.begin(); it != _overlays3D.end(); ++it) { - delete _overlays3D.take(it.key()); - } - while (!_overlaysToDelete.isEmpty()) { - delete _overlaysToDelete.takeLast(); + + { + QWriteLocker lock(&_lock); + foreach(Overlay* thisOverlay, _overlays2D) { + delete thisOverlay; + } + _overlays2D.clear(); + foreach(Overlay* thisOverlay, _overlays3D) { + delete thisOverlay; + } + _overlays3D.clear(); + } + + if (!_overlaysToDelete.isEmpty()) { + QWriteLocker lock(&_deleteLock); + do { + delete _overlaysToDelete.takeLast(); + } while (!_overlaysToDelete.isEmpty()); } + } void Overlays::init(QGLWidget* parent) { From 587f60631fb2e1504632bb3bf03b1a0895c12e82 Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Sat, 24 May 2014 21:28:03 +0200 Subject: [PATCH 33/41] missed a tab --- interface/src/ui/overlays/Overlays.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 6c6c314be4..95f4f2b2fe 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -33,7 +33,7 @@ Overlays::~Overlays() { delete thisOverlay; } _overlays3D.clear(); - } + } if (!_overlaysToDelete.isEmpty()) { QWriteLocker lock(&_deleteLock); From 78e311f885e024eb4e799b26c63f24a9eb8775e3 Mon Sep 17 00:00:00 2001 From: Kai Ludwig Date: Sun, 25 May 2014 20:24:15 +0200 Subject: [PATCH 34/41] separate style handling for chat area and its context menu. --- interface/src/ui/ChatWindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 611f955031..445aec62c2 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -306,7 +306,7 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { messageArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); messageArea->setReadOnly(true); - messageArea->setStyleSheet("padding-bottom: 2px;" + messageArea->setStyleSheet("QTextBrowser{ padding-bottom: 2px;" "padding-left: 2px;" "padding-top: 2px;" "padding-right: 20px;" @@ -314,7 +314,8 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { "color: #333333;" "font-size: 14pt;" "background-color: rgba(0, 0, 0, 0%);" - "border: 0;"); + "border: 0; }" + "QMenu{ border: 2px outset gray; }"); QString userLabel = getParticipantName(message.from()); if (fromSelf) { From 97e5c928a4ac97adcab3f937cf8f54f40034ddb3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 25 May 2014 16:41:01 -0700 Subject: [PATCH 35/41] Fix chat scroll bar widget jumping Hovering over the chat window's scroll bar was causing it to jump around. Replaced the 12px style spacing that was causing the problem with a widget-based solution. --- interface/src/ui/ChatWindow.cpp | 4 ++-- interface/ui/chatWindow.ui | 40 ++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 611f955031..1cf45ab81b 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -80,7 +80,7 @@ ChatWindow::ChatWindow(QWidget* parent) : } else { ui->numOnlineLabel->hide(); ui->closeButton->hide(); - ui->usersWidget->hide(); + ui->usersArea->hide(); ui->messagesScrollArea->hide(); ui->messagePlainTextEdit->hide(); connect(&XmppClient::getInstance(), SIGNAL(joinedPublicChatRoom()), this, SLOT(connected())); @@ -208,7 +208,7 @@ void ChatWindow::connected() { ui->connectingToXMPPLabel->hide(); ui->numOnlineLabel->show(); ui->closeButton->show(); - ui->usersWidget->show(); + ui->usersArea->show(); ui->messagesScrollArea->show(); ui->messagePlainTextEdit->show(); ui->messagePlainTextEdit->setFocus(); diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 4d223b2665..46ccafd5f8 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -128,19 +128,43 @@ QPushButton:pressed { - - - #usersWidget { - margin-right: 20px; -} + + + + 0 + 0 + + + + 0 + 0 + + + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 12 + + + + + - - margin-top: 12px; - Qt::ScrollBarAlwaysOff From 7c3d3976eeac578db0c2ddf3522617840ad2324d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 25 May 2014 16:42:36 -0700 Subject: [PATCH 36/41] Fix chat window scrolling to stay at bottom Stay at bottom window when: - There is new chat. - People come and go from online list. - Chat window hides and restores when application focus changes. - Interface is minimized and restored. --- interface/src/ui/ChatWindow.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 1cf45ab81b..2f044739df 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -248,6 +248,7 @@ void ChatWindow::notificationClicked() { return; } } + Application::processEvents(); scrollToBottom(); } @@ -262,6 +263,8 @@ void ChatWindow::error(QXmppClient::Error error) { } void ChatWindow::participantsChanged() { + bool atBottom = isNearBottom(); + QStringList participants = XmppClient::getInstance().getPublicChatRoom()->participants(); ui->numOnlineLabel->setText(tr("%1 online now:").arg(participants.count())); @@ -288,6 +291,11 @@ void ChatWindow::participantsChanged() { userLabel->installEventFilter(this); ui->usersWidget->layout()->addWidget(userLabel); } + Application::processEvents(); + + if (atBottom) { + scrollToBottom(); + } } void ChatWindow::messageReceived(const QXmppMessage& message) { From 51850076e46a8f74cf24b74d040a476741b21db7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 26 May 2014 16:24:47 -0700 Subject: [PATCH 37/41] more correct detection of floor surfaces --- interface/src/avatar/MyAvatar.cpp | 79 ++++++++++++++++++------------- interface/src/avatar/MyAvatar.h | 2 + 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c59df941b0..a598c55aaa 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -65,6 +65,7 @@ MyAvatar::MyAvatar() : _distanceToNearestAvatar(std::numeric_limits::max()), _wasPushing(false), _isPushing(false), + _isBraking(false), _trapDuration(0.0f), _thrust(0.0f), _motorVelocity(0.0f), @@ -790,6 +791,15 @@ bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode rend (glm::length(cameraPosition - head->calculateAverageEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale); } +float MyAvatar::computeDistanceToFloor(const glm::vec3& startPoint) { + glm::vec3 direction = -_worldUpDirection; + OctreeElement* elementHit; // output from findRayIntersection + float distance = FLT_MAX; // output from findRayIntersection + BoxFace face; // output from findRayIntersection + Application::getInstance()->getVoxelTree()->findRayIntersection(startPoint, direction, elementHit, distance, face); + return distance; +} + void MyAvatar::updateOrientation(float deltaTime) { // Gather rotation information from keyboard _bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime; @@ -864,6 +874,8 @@ void MyAvatar::updateOrientation(float deltaTime) { setOrientation(orientation); } +const float NEARBY_FLOOR_THRESHOLD = 5.0f; + void MyAvatar::updatePosition(float deltaTime) { float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT]) + @@ -875,11 +887,11 @@ void MyAvatar::updatePosition(float deltaTime) { const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); glm::vec3 startCap; boundingShape.getStartPoint(startCap); - glm::vec3 bottomOfBoundingCapsule = startCap - boundingShape.getRadius() * _worldUpDirection; + glm::vec3 bottom = startCap - boundingShape.getRadius() * _worldUpDirection; if (gravityLength > EPSILON) { float speedFromGravity = _scale * deltaTime * gravityLength; - float distanceToFall = glm::distance(bottomOfBoundingCapsule, _lastFloorContactPoint); + float distanceToFall = glm::distance(bottom, _lastFloorContactPoint); walkingOnFloor = (distanceToFall < 2.0f * deltaTime * speedFromGravity); if (walkingOnFloor) { @@ -896,14 +908,24 @@ void MyAvatar::updatePosition(float deltaTime) { } // END HACK } else { - _velocity -= speedFromGravity * _worldUpDirection; - } - if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) { - const float MAX_VERTICAL_FLOOR_DETECTION_SPEED = _scale * MAX_WALKING_SPEED; - if (keyboardInput && glm::dot(_motorVelocity, _worldUpDirection) > 0.0f && - glm::dot(_velocity, _worldUpDirection) > MAX_VERTICAL_FLOOR_DETECTION_SPEED) { - // disable gravity because we're pushing with keyboard - setLocalGravity(glm::vec3(0.0f)); + if (!_isBraking) { + // fall with gravity toward floor + _velocity -= speedFromGravity * _worldUpDirection; + } + + if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) { + const float MAX_VERTICAL_FLOOR_DETECTION_SPEED = _scale * MAX_WALKING_SPEED; + if (keyboardInput && glm::dot(_motorVelocity, _worldUpDirection) > 0.0f && + glm::dot(_velocity, _worldUpDirection) > MAX_VERTICAL_FLOOR_DETECTION_SPEED) { + // disable local gravity when flying up + setLocalGravity(glm::vec3(0.0f)); + } else { + const float maxFloorDistance = _scale * NEARBY_FLOOR_THRESHOLD; + if (computeDistanceToFloor(bottom) > maxFloorDistance) { + // disable local gravity when floor is too far + setLocalGravity(glm::vec3(0.0f)); + } + } } } } else { @@ -911,15 +933,10 @@ void MyAvatar::updatePosition(float deltaTime) { _motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) { const float MIN_FLOOR_DETECTION_SPEED = _scale * 1.0f; if (glm::length(_velocity) < MIN_FLOOR_DETECTION_SPEED ) { - // scan for floor - glm::vec3 direction = -_worldUpDirection; - OctreeElement* elementHit; // output from findRayIntersection - float distance; // output from findRayIntersection - BoxFace face; // output from findRayIntersection - Application::getInstance()->getVoxelTree()->findRayIntersection(bottomOfBoundingCapsule, direction, elementHit, distance, face); - const float NEARBY_FLOOR_THRESHOLD = _scale * 2.0f; - if (elementHit && distance < NEARBY_FLOOR_THRESHOLD) { - // turn on local gravity + // scan for floor under avatar + const float maxFloorDistance = _scale * NEARBY_FLOOR_THRESHOLD; + if (computeDistanceToFloor(bottom) < maxFloorDistance) { + // enable local gravity setLocalGravity(-_worldUpDirection); } } @@ -1005,32 +1022,30 @@ float MyAvatar::computeMotorTimescale() { // (1) braking --> short timescale (aggressive motor assertion) // (2) pushing --> medium timescale (mild motor assertion) // (3) inactive --> long timescale (gentle friction for low speeds) - // - // TODO: recover extra braking behavior when flying close to nearest avatar float MIN_MOTOR_TIMESCALE = 0.125f; float MAX_MOTOR_TIMESCALE = 0.5f; float MIN_BRAKE_SPEED = 0.4f; float timescale = MAX_MOTOR_TIMESCALE; - float speed = glm::length(_velocity); - bool areThrusting = (glm::length2(_thrust) > EPSILON); - - if (_wasPushing && !(_isPushing || areThrusting) && speed > MIN_BRAKE_SPEED) { - // we don't change _wasPushing for this case --> - // keeps the brakes on until we go below MIN_BRAKE_SPEED - timescale = MIN_MOTOR_TIMESCALE; + bool isThrust = (glm::length2(_thrust) > EPSILON); + if (_isPushing || isThrust) { + timescale = _motorTimescale; + _isBraking = false; } else { - if (_isPushing) { - timescale = _motorTimescale; - } - _wasPushing = _isPushing || areThrusting; + float speed = glm::length(_velocity); + _isBraking = _wasPushing || (_isBraking && speed > MIN_BRAKE_SPEED); + if (_isBraking) { + timescale = MIN_MOTOR_TIMESCALE; + } } + _wasPushing = _isPushing || isThrust; _isPushing = false; return timescale; } void MyAvatar::applyMotor(float deltaTime) { + // TODO: recover extra braking behavior when flying close to nearest avatar if (!( _motionBehaviors & AVATAR_MOTION_MOTOR_ENABLED)) { // nothing to do --> early exit return; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f8e9fc2e28..c0bc12b6b0 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -154,6 +154,7 @@ private: bool _wasPushing; bool _isPushing; + bool _isBraking; float _trapDuration; // seconds that avatar has been trapped by collisions glm::vec3 _thrust; // final acceleration from outside sources for the current frame @@ -173,6 +174,7 @@ private: QList _animationHandles; // private methods + float computeDistanceToFloor(const glm::vec3& startPoint); void updateOrientation(float deltaTime); void updatePosition(float deltaTime); void updateMotorFromKeyboard(float deltaTime, bool walking); From ab80e3dc84ca5075b2927518c2b8899668ff5ddc Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 27 May 2014 10:32:55 -0700 Subject: [PATCH 38/41] improved playSound.js to work if no spatial controller attached --- examples/playSound.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/playSound.js b/examples/playSound.js index 317581ba36..189c24e86f 100644 --- a/examples/playSound.js +++ b/examples/playSound.js @@ -3,22 +3,22 @@ // examples // // Copyright 2014 High Fidelity, Inc. -// This sample script loads a sound file and plays it at the 'fingertip' of the +// Plays a sample audio file at the avatar's current location // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// First, load the clap sound from a URL -var clap = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/bushtit_1.raw"); +// First, load a sample sound from a URL +var bird = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/bushtit_1.raw"); function maybePlaySound(deltaTime) { if (Math.random() < 0.01) { // Set the location and other info for the sound to play var options = new AudioInjectionOptions(); - var palmPosition = Controller.getSpatialControlPosition(0); - options.position = palmPosition; + var position = MyAvatar.position; + options.position = position; options.volume = 0.5; - Audio.playSound(clap, options); + Audio.playSound(bird, options); } } From 70ab33b65b95f3cc93fd880ac6033dfdf8cecfc1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 10:54:18 -0700 Subject: [PATCH 39/41] Some tricks to avoid shadow artifacts: render back faces to shadow buffer, use polygon offset. --- interface/src/Application.cpp | 5 +++++ interface/src/renderer/Model.cpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b5d9d8939c..cad6c26a00 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2325,10 +2325,15 @@ void Application::updateShadowMap() { // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.1f, 4.0f); + _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); _models.render(OctreeRenderer::SHADOW_RENDER_MODE); + glDisable(GL_POLYGON_OFFSET_FILL); + glPopMatrix(); glMatrixMode(GL_PROJECTION); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 5337e845a1..c4cc312091 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -498,6 +498,9 @@ bool Model::render(float alpha, RenderMode mode) { glDisable(GL_CULL_FACE); } else { glEnable(GL_CULL_FACE); + if (mode == SHADOW_RENDER_MODE) { + glCullFace(GL_FRONT); + } } // render opaque meshes with alpha testing @@ -515,6 +518,10 @@ bool Model::render(float alpha, RenderMode mode) { glDisable(GL_CULL_FACE); + if (mode == SHADOW_RENDER_MODE) { + glCullFace(GL_BACK); + } + // deactivate vertex arrays after drawing glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); From edaa251e5f4b274b31bca21daa437adaa8ad6ec4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 11:43:34 -0700 Subject: [PATCH 40/41] Provide option to disable avatar shadowing. --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/Avatar.cpp | 7 ++++--- interface/src/avatar/Head.cpp | 3 ++- interface/src/avatar/MyAvatar.cpp | 5 +++-- interface/src/renderer/Model.cpp | 10 +++++----- interface/src/renderer/Model.h | 4 ++-- 8 files changed, 19 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cad6c26a00..1addb7bafd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2326,7 +2326,7 @@ void Application::updateShadowMap() { updateUntranslatedViewMatrix(); glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.1f, 4.0f); + glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 856e1efae7..68e3b484d3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -332,6 +332,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AllowOculusCameraModeChange, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AvatarsReceiveShadows, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderSkeletonCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderHeadCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderBoundingCollisionShapes); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 279d2151c9..70f4f62ce4 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -293,6 +293,7 @@ namespace MenuOption { const QString AudioSpatialProcessingDontDistanceAttenuate = "Don't calculate distance attenuation"; const QString AudioSpatialProcessingAlternateDistanceAttenuate = "Alternate distance attenuation"; const QString Avatars = "Avatars"; + const QString AvatarsReceiveShadows = "Avatars Receive Shadows"; const QString Bandwidth = "Bandwidth Display"; const QString BandwidthDetails = "Bandwidth Details"; const QString BuckyBalls = "Bucky Balls"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index aff15f4e0b..306dc0194e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -347,7 +347,6 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { void Avatar::renderBody(RenderMode renderMode, float glowLevel) { Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - { Glower glower(glowLevel); @@ -356,7 +355,8 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { renderBillboard(); return; } - _skeletonModel.render(1.0f, modelRenderMode); + + _skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); renderAttachments(renderMode); getHand()->render(false, modelRenderMode); } @@ -390,8 +390,9 @@ void Avatar::simulateAttachments(float deltaTime) { void Avatar::renderAttachments(RenderMode renderMode) { Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows); foreach (Model* model, _attachmentModels) { - model->render(1.0f, modelRenderMode); + model->render(1.0f, modelRenderMode, receiveShadows); } } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 2d0599b31f..8382843c1e 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -176,7 +176,8 @@ void Head::relaxLean(float deltaTime) { } void Head::render(float alpha, Model::RenderMode mode) { - if (_faceModel.render(alpha, mode) && _renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) { + if (_faceModel.render(alpha, mode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)) && + _renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a598c55aaa..f47880056c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -773,7 +773,7 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { // Render the body's voxels and head Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - _skeletonModel.render(1.0f, modelRenderMode); + _skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); renderAttachments(renderMode); // Render head so long as the camera isn't inside it @@ -1695,10 +1695,11 @@ void MyAvatar::renderAttachments(RenderMode renderMode) { QString headJointName = (geometry.headJointIndex == -1) ? QString() : geometry.joints.at(geometry.headJointIndex).name; Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows); for (int i = 0; i < _attachmentData.size(); i++) { const QString& jointName = _attachmentData.at(i).jointName; if (jointName != headJointName && jointName != "Head") { - _attachmentModels.at(i)->render(1.0f, modelRenderMode); + _attachmentModels.at(i)->render(1.0f, modelRenderMode, receiveShadows); } } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c4cc312091..db2f6e0664 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -470,7 +470,7 @@ bool Model::updateGeometry() { return needFullUpdate; } -bool Model::render(float alpha, RenderMode mode) { +bool Model::render(float alpha, RenderMode mode, bool receiveShadows) { // render the attachments foreach (Model* attachment, _attachments) { attachment->render(alpha, mode); @@ -508,13 +508,14 @@ bool Model::render(float alpha, RenderMode mode) { glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f * alpha); - renderMeshes(alpha, mode, false); + receiveShadows &= Menu::getInstance()->isOptionChecked(MenuOption::Shadows); + renderMeshes(alpha, mode, false, receiveShadows); glDisable(GL_ALPHA_TEST); // render translucent meshes afterwards - renderMeshes(alpha, mode, true); + renderMeshes(alpha, mode, true, receiveShadows); glDisable(GL_CULL_FACE); @@ -1596,11 +1597,10 @@ void Model::deleteGeometry() { } } -void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { +void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool receiveShadows) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); - bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::Shadows); if (receiveShadows) { glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]); glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5b1f6402d3..69ea700b49 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -79,7 +79,7 @@ public: enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; - bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE); + bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, bool receiveShadows = true); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load @@ -315,7 +315,7 @@ private: void applyNextGeometry(); void deleteGeometry(); - void renderMeshes(float alpha, RenderMode mode, bool translucent); + void renderMeshes(float alpha, RenderMode mode, bool translucent, bool receiveShadows); QVector createJointStates(const FBXGeometry& geometry); QSharedPointer _baseGeometry; ///< reference required to prevent collection of base From e22d239d4d4041b32f05f323c5b991e809736d40 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 27 May 2014 12:30:45 -0700 Subject: [PATCH 41/41] What the heck; let's try using some multisampling on the shadow maps. --- interface/resources/shaders/model_shadow_map.frag | 9 ++++++++- interface/resources/shaders/model_shadow_normal_map.frag | 9 ++++++++- .../shaders/model_shadow_normal_specular_map.frag | 9 ++++++++- .../resources/shaders/model_shadow_specular_map.frag | 9 ++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/interface/resources/shaders/model_shadow_map.frag b/interface/resources/shaders/model_shadow_map.frag index 4a2bb312dc..aa1df03b95 100644 --- a/interface/resources/shaders/model_shadow_map.frag +++ b/interface/resources/shaders/model_shadow_map.frag @@ -17,6 +17,9 @@ uniform sampler2D diffuseMap; // the shadow texture uniform sampler2DShadow shadowMap; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the interpolated position varying vec4 position; @@ -27,7 +30,11 @@ void main(void) { // compute the base color based on OpenGL lighting model vec4 normalizedNormal = normalize(normal); float diffuse = dot(normalizedNormal, gl_LightSource[0].position); - float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); diff --git a/interface/resources/shaders/model_shadow_normal_map.frag b/interface/resources/shaders/model_shadow_normal_map.frag index d61b123fba..3461c1b5f3 100644 --- a/interface/resources/shaders/model_shadow_normal_map.frag +++ b/interface/resources/shaders/model_shadow_normal_map.frag @@ -20,6 +20,9 @@ uniform sampler2D normalMap; // the shadow texture uniform sampler2DShadow shadowMap; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the interpolated position varying vec4 interpolatedPosition; @@ -39,7 +42,11 @@ void main(void) { vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); float diffuse = dot(viewNormal, gl_LightSource[0].position); - float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); diff --git a/interface/resources/shaders/model_shadow_normal_specular_map.frag b/interface/resources/shaders/model_shadow_normal_specular_map.frag index 9865056479..273d197fca 100644 --- a/interface/resources/shaders/model_shadow_normal_specular_map.frag +++ b/interface/resources/shaders/model_shadow_normal_specular_map.frag @@ -23,6 +23,9 @@ uniform sampler2D specularMap; // the shadow texture uniform sampler2DShadow shadowMap; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the interpolated position varying vec4 interpolatedPosition; @@ -42,7 +45,11 @@ void main(void) { vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); float diffuse = dot(viewNormal, gl_LightSource[0].position); - float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); diff --git a/interface/resources/shaders/model_shadow_specular_map.frag b/interface/resources/shaders/model_shadow_specular_map.frag index 4be0f1636d..77cff1e04e 100644 --- a/interface/resources/shaders/model_shadow_specular_map.frag +++ b/interface/resources/shaders/model_shadow_specular_map.frag @@ -20,6 +20,9 @@ uniform sampler2D specularMap; // the shadow texture uniform sampler2DShadow shadowMap; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the interpolated position in view space varying vec4 position; @@ -30,7 +33,11 @@ void main(void) { // compute the base color based on OpenGL lighting model vec4 normalizedNormal = normalize(normal); float diffuse = dot(normalizedNormal, gl_LightSource[0].position); - float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r; + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));