diff --git a/CMakeLists.txt b/CMakeLists.txt index d7803259c2..04a5f3ee9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,8 @@ if (NOT ANDROID) add_subdirectory(interface) add_subdirectory(tests) add_subdirectory(tools) -elseif (ANDROID OR DESKTOP_GVR) +endif () + +if (ANDROID OR DESKTOP_GVR) add_subdirectory(gvr-interface) endif () \ No newline at end of file diff --git a/examples/acScripts/ambiance.js b/examples/acScripts/ambiance.js index fcc3ba0d80..f4f023a473 100644 --- a/examples/acScripts/ambiance.js +++ b/examples/acScripts/ambiance.js @@ -32,10 +32,4 @@ Script.update.connect(function() { injector = Audio.playSound(sound, audioOptions); print("Playing: " + injector); } -}); - -Script.scriptEnding.connect(function() { - if (injector !== null) { - injector.stop(); - } }); \ No newline at end of file diff --git a/examples/controllers/hydra/airGuitar.js b/examples/controllers/hydra/airGuitar.js index 29ab2f9c44..750bfb5bc7 100644 --- a/examples/controllers/hydra/airGuitar.js +++ b/examples/controllers/hydra/airGuitar.js @@ -85,10 +85,10 @@ function checkHands(deltaTime) { var chord = Controller.getTriggerValue(chordHand); if (volume > 1.0) volume = 1.0; - if ((chord > 0.1) && Audio.isInjectorPlaying(soundPlaying)) { + if ((chord > 0.1) && soundPlaying.isPlaying) { // If chord finger trigger pulled, stop current chord print("stopped sound"); - Audio.stopInjector(soundPlaying); + soundPlaying.stop(); } var BUTTON_COUNT = 6; @@ -132,16 +132,21 @@ function checkHands(deltaTime) { } function playChord(position, volume) { - if (Audio.isInjectorPlaying(soundPlaying)) { + if (soundPlaying.isPlaying) { print("stopped sound"); - Audio.stopInjector(soundPlaying); + soundPlaying.stop(); } print("Played sound: " + whichChord + " at volume " + options.volume); - soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], { - position: position, - volume: volume - }); + if (!soundPlaying) { + soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], { + position: position, + volume: volume + }); + } else { + soundPlaying.restart(); + } + } function keyPressEvent(event) { diff --git a/examples/editEntities.js b/examples/editEntities.js index f25a873992..398d06cfe8 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -190,6 +190,7 @@ var toolBar = (function () { cameraManager.enable(); entityListTool.setVisible(true); gridTool.setVisible(true); + grid.setEnabled(true); propertiesTool.setVisible(true); Window.setFocus(); } @@ -533,7 +534,9 @@ function highlightEntityUnderCursor(position, accurateRay) { function mouseReleaseEvent(event) { if (placingEntityID) { - selectionManager.setSelections([placingEntityID]); + if (isActive) { + selectionManager.setSelections([placingEntityID]); + } placingEntityID = null; } if (isActive && selectionManager.hasSelection()) { diff --git a/examples/entityScripts/movable.js b/examples/entityScripts/movable.js index 21e6261179..066f258f2e 100644 --- a/examples/entityScripts/movable.js +++ b/examples/entityScripts/movable.js @@ -48,7 +48,8 @@ this.turnSounds = new Array(); this.moveSound = null; this.turnSound = null; - this.injector = null; + this.moveInjector = null; + this.turnInjector = null; var debug = false; var displayRotateTargets = true; // change to false if you don't want the rotate targets @@ -92,9 +93,14 @@ } if (this.moveSound && this.moveSound.downloaded) { if (debug) { - print("playMoveSound() --- calling this.injector = Audio.playSound(this.moveSound...)"); + print("playMoveSound() --- calling this.moveInjector = Audio.playSound(this.moveSound...)"); + } + + if (!this.moveInjector) { + this.moveInjector = Audio.playSound(this.moveSound, { position: this.properties.position, loop: true, volume: 0.1 }); + } else { + this.moveInjector.restart(); } - this.injector = Audio.playSound(this.moveSound, { position: this.properties.position, loop: true, volume: 0.1 }); } } @@ -105,9 +111,13 @@ } if (this.turnSound && this.turnSound.downloaded) { if (debug) { - print("playTurnSound() --- calling this.injector = Audio.playSound(this.turnSound...)"); + print("playTurnSound() --- calling this.turnInjector = Audio.playSound(this.turnSound...)"); + } + if (!this.turnInjector) { + this.turnInjector = Audio.playSound(this.turnSound, { position: this.properties.position, loop: true, volume: 0.1 }); + } else { + this.turnInjector.restart(); } - this.injector = Audio.playSound(this.turnSound, { position: this.properties.position, loop: true, volume: 0.1 }); } } @@ -116,9 +126,11 @@ if (debug) { print("stopSound()"); } - if (this.injector) { - Audio.stopInjector(this.injector); - this.injector = null; + if (this.turnInjector) { + this.turnInjector.stop(); + } + if (this.moveInjector) { + this.moveInjector.stop(); } } @@ -174,7 +186,7 @@ this.move = function(mouseEvent) { this.updatePosition(mouseEvent); - if (this.injector === null) { + if (this.moveInjector === null || !this.moveInjector.isPlaying) { this.playMoveSound(); } }; @@ -233,7 +245,7 @@ } } - if (this.injector === null) { + if (this.turnInjector === null || !this.turnInjector.isPlaying) { this.playTurnSound(); } }; diff --git a/examples/example/audio/birdSongs.js b/examples/example/audio/birdSongs.js index 267fa20b49..876f942dbc 100644 --- a/examples/example/audio/birdSongs.js +++ b/examples/example/audio/birdSongs.js @@ -75,14 +75,14 @@ function maybePlaySound(deltaTime) { //print("number playing = " + numPlaying); } for (var i = 0; i < playing.length; i++) { - if (!Audio.isInjectorPlaying(playing[i].audioId)) { + if (!playing[i].audioId.isPlaying) { Entities.deleteEntity(playing[i].entityId); if (useLights) { Entities.deleteEntity(playing[i].lightId); } playing.splice(i, 1); } else { - var loudness = Audio.getLoudness(playing[i].audioId); + var loudness = playing[i].audioId.loudness; var newColor = { red: playing[i].color.red, green: playing[i].color.green, blue: playing[i].color.blue }; if (loudness > 0.05) { newColor.red *= (1.0 - loudness); diff --git a/examples/example/audio/radio.js b/examples/example/audio/radio.js index 7ac33675a1..5a8b4cbb88 100644 --- a/examples/example/audio/radio.js +++ b/examples/example/audio/radio.js @@ -76,9 +76,6 @@ function scriptEnding() { if (entity != null) { Entities.deleteEntity(entity); } - if (injector != null) { - injector.stop(); - } } Script.update.connect(update); diff --git a/examples/example/entities/butterflies.js b/examples/example/entities/butterflies.js index 336e128d83..9cbe8f966c 100644 --- a/examples/example/entities/butterflies.js +++ b/examples/example/entities/butterflies.js @@ -13,6 +13,9 @@ // +print("BUTTERFLIES START"); + + var numButterflies = 25; @@ -109,7 +112,7 @@ function updateButterflies(deltaTime) { var properties = Entities.getEntityProperties(butterflies[i]); if (Vec3.length(Vec3.subtract(properties.position, flockPosition)) > range) { Entities.editEntity(butterflies[i], { position: flockPosition } ); - } else if (properties.velocity.y < 0.0) { + } else if (properties.velocity.y <= 0.0) { // If falling, Create a new direction and impulse var HORIZ_SCALE = 0.50; var VERT_SCALE = 0.50; @@ -139,3 +142,5 @@ Script.scriptEnding.connect(function() { Entities.deleteEntity(butterflies[i]); } }); + +print("BUTTERFLIES END"); diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html index 7e354c5bec..941a4b5c2a 100644 --- a/examples/html/gridControls.html +++ b/examples/html/gridControls.html @@ -30,8 +30,8 @@ elPosY.value = origin.y.toFixed(2); } - if (data.minorGridSpacing !== undefined) { - elMinorSpacing.value = data.minorGridSpacing; + if (data.minorGridWidth !== undefined) { + elMinorSpacing.value = data.minorGridWidth; } if (data.majorGridEvery !== undefined) { @@ -57,7 +57,7 @@ origin: { y: elPosY.value, }, - minorGridSpacing: elMinorSpacing.value, + minorGridWidth: elMinorSpacing.value, majorGridEvery: elMajorSpacing.value, gridColor: gridColor, colorIndex: gridColorIndex, diff --git a/examples/lobby.js b/examples/lobby.js index 1936a4e531..5d687dc07a 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -55,7 +55,9 @@ var droneSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.st var currentDrone = null; var latinSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.stereo.raw") +var latinInjector = null; var elevatorSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.stereo.raw") +var elevatorInjector = null; var currentMuzakInjector = null; var currentSound = null; @@ -140,7 +142,11 @@ function drawLobby() { if (droneSound.downloaded) { // start the drone sound - currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); + if (!currentDrone) { + currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); + } else { + currentDrone.restart(); + } } // start one of our muzak sounds @@ -173,6 +179,26 @@ function changeLobbyTextures() { var MUZAK_VOLUME = 0.1; +function playCurrentSound(secondOffset) { + if (currentSound == latinSound) { + if (!latinInjector) { + latinInjector = Audio.playSound(latinSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME }); + } else { + latinInjector.restart(); + } + + currentMuzakInjector = latinInjector; + } else if (currentSound == elevatorSound) { + if (!elevatorInjector) { + elevatorInjector = Audio.playSound(elevatorSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME }); + } else { + elevatorInjector.restart(); + } + + currentMuzakInjector = elevatorInjector; + } +} + function playNextMuzak() { if (panelWall) { if (currentSound == latinSound) { @@ -184,8 +210,8 @@ function playNextMuzak() { currentSound = latinSound; } } - - currentMuzakInjector = Audio.playSound(currentSound, { localOnly: true, volume: MUZAK_VOLUME }); + + playCurrentSound(0); } } @@ -200,10 +226,11 @@ function playRandomMuzak() { currentSound = elevatorSound; } - if (currentSound) { + if (currentSound) { // pick a random number of seconds from 0-10 to offset the muzak var secondOffset = Math.random() * 10; - currentMuzakInjector = Audio.playSound(currentSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME }); + + playCurrentSound(secondOffset); } else { currentMuzakInjector = null; } @@ -227,10 +254,9 @@ function cleanupLobby() { panelWall = false; orbShell = false; - Audio.stopInjector(currentDrone); - currentDrone = null; + currentDrone.stop(); + currentMuzakInjector.stop(); - Audio.stopInjector(currentMuzakInjector); currentMuzakInjector = null; places = {}; @@ -354,7 +380,7 @@ function update(deltaTime) { Overlays.editOverlay(descriptionText, { position: textOverlayPosition() }); // if the reticle is up then we may need to play the next muzak - if (currentMuzakInjector && !Audio.isInjectorPlaying(currentMuzakInjector)) { + if (currentMuzakInjector && !currentMuzakInjector.isPlaying) { playNextMuzak(); } } diff --git a/examples/utilities/diagnostics/inWorldTestTone.js b/examples/utilities/diagnostics/inWorldTestTone.js index 77ec7ba3b2..4596bfe2ad 100644 --- a/examples/utilities/diagnostics/inWorldTestTone.js +++ b/examples/utilities/diagnostics/inWorldTestTone.js @@ -21,20 +21,13 @@ var offset = Vec3.normalize(Quat.getFront(MyAvatar.orientation)); var position = Vec3.sum(MyAvatar.position, offset); function update(deltaTime) { - if (!Audio.isInjectorPlaying(soundPlaying)) { - soundPlaying = Audio.playSound(sound, { - position: position, - loop: true - }); - print("Started sound loop"); - } -} - -function scriptEnding() { - if (Audio.isInjectorPlaying(soundPlaying)) { - Audio.stopInjector(soundPlaying); - print("Stopped sound loop"); - } + if (sound.downloaded && !soundPlaying) { + print("Started sound loop"); + soundPlaying = Audio.playSound(sound, { + position: position, + loop: true + }); + } } Script.update.connect(update); diff --git a/examples/utilities/diagnostics/orbitingSound.js b/examples/utilities/diagnostics/orbitingSound.js index 54e319faaa..1af6fab827 100644 --- a/examples/utilities/diagnostics/orbitingSound.js +++ b/examples/utilities/diagnostics/orbitingSound.js @@ -32,14 +32,13 @@ var sound = Audio.playSound(soundClip, { position: orbitCenter, loop: true, volu function update(deltaTime) { time += deltaTime; currentPosition = { x: orbitCenter.x + Math.cos(time * SPEED) * RADIUS, y: orbitCenter.y, z: orbitCenter.z + Math.sin(time * SPEED) * RADIUS }; - trailingLoudness = 0.9 * trailingLoudness + 0.1 * Audio.getLoudness(sound); + trailingLoudness = 0.9 * trailingLoudness + 0.1 * sound.loudness; Entities.editEntity( objectId, { position: currentPosition, color: { red: Math.min(trailingLoudness * 2000, 255), green: 0, blue: 0 } } ); - Audio.setInjectorOptions(sound, { position: currentPosition }); + sound.setOptions({ position: currentPosition }); } Script.scriptEnding.connect(function() { Entities.deleteEntity(objectId); - Audio.stopInjector(sound); }); Script.update.connect(update); \ No newline at end of file diff --git a/examples/utilities/diagnostics/playSoundLoop.js b/examples/utilities/diagnostics/playSoundLoop.js index faf23761b4..83c0ccf6d0 100644 --- a/examples/utilities/diagnostics/playSoundLoop.js +++ b/examples/utilities/diagnostics/playSoundLoop.js @@ -30,7 +30,7 @@ var playing = false; var ball = false; function maybePlaySound(deltaTime) { - if (sound.downloaded) { + if (sound.downloaded && !soundPlaying) { var properties = { type: "Sphere", position: options.position, @@ -45,11 +45,9 @@ function maybePlaySound(deltaTime) { } function scriptEnding() { - if (Audio.isInjectorPlaying(soundPlaying)) { - Audio.stopInjector(soundPlaying); - Entities.deleteEntity(ball); - print("Stopped sound."); - } + if (ball) { + Entities.deleteEntity(ball); + } } // Connect a call back that happens every frame diff --git a/gvr-interface/src/Client.cpp b/gvr-interface/src/Client.cpp index e323ab96b5..65238ad784 100644 --- a/gvr-interface/src/Client.cpp +++ b/gvr-interface/src/Client.cpp @@ -9,8 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include #include #include diff --git a/gvr-interface/src/Client.h b/gvr-interface/src/Client.h index 6eb3913ea9..6fbe40f165 100644 --- a/gvr-interface/src/Client.h +++ b/gvr-interface/src/Client.h @@ -16,13 +16,14 @@ #include -class QThread; - class Client : public QObject { Q_OBJECT public: Client(QObject* parent = 0); + + virtual void cleanupBeforeQuit() = 0; protected: + void setupNetworking(); virtual void processVerifiedPacket(const HifiSockAddr& senderSockAddr, const QByteArray& incomingPacket); private slots: diff --git a/gvr-interface/src/GVRInterface.cpp b/gvr-interface/src/GVRInterface.cpp index 7476bfc764..3d58396322 100644 --- a/gvr-interface/src/GVRInterface.cpp +++ b/gvr-interface/src/GVRInterface.cpp @@ -86,6 +86,13 @@ GVRInterface::GVRInterface(int argc, char* argv[]) : QTimer* idleTimer = new QTimer(this); connect(idleTimer, &QTimer::timeout, this, &GVRInterface::idle); idleTimer->start(0); + + // call our quit handler before we go down + connect(this, &QCoreApplication::aboutToQuit, this, &GVRInterface::handleApplicationQuit); +} + +void GVRInterface::handleApplicationQuit() { + _client->cleanupBeforeQuit(); } void GVRInterface::idle() { diff --git a/gvr-interface/src/GVRInterface.h b/gvr-interface/src/GVRInterface.h index 926c44da15..9ffbd52909 100644 --- a/gvr-interface/src/GVRInterface.h +++ b/gvr-interface/src/GVRInterface.h @@ -53,6 +53,7 @@ private slots: void handleApplicationStateChange(Qt::ApplicationState state); void idle(); private: + void handleApplicationQuit(); void enterVRMode(); void leaveVRMode(); diff --git a/gvr-interface/src/RenderingClient.cpp b/gvr-interface/src/RenderingClient.cpp index 9737263eee..e6d2f6b585 100644 --- a/gvr-interface/src/RenderingClient.cpp +++ b/gvr-interface/src/RenderingClient.cpp @@ -37,7 +37,7 @@ RenderingClient::RenderingClient(QObject *parent, const QString& launchURLString DependencyManager::set(); // get our audio client setup on its own thread - QThread* audioThread = new QThread(this); + QThread* audioThread = new QThread(); auto audioClient = DependencyManager::set(); audioClient->setPositionGetter(getPositionForAudio); @@ -45,6 +45,8 @@ RenderingClient::RenderingClient(QObject *parent, const QString& launchURLString audioClient->moveToThread(audioThread); connect(audioThread, &QThread::started, audioClient.data(), &AudioClient::start); + connect(audioClient.data(), &AudioClient::destroyed, audioThread, &QThread::quit); + connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); audioThread->start(); @@ -68,15 +70,13 @@ void RenderingClient::sendAvatarPacket() { _fakeAvatar.sendIdentityPacket(); } -RenderingClient::~RenderingClient() { - auto audioClient = DependencyManager::get(); - - // stop the audio client - QMetaObject::invokeMethod(audioClient.data(), "stop", Qt::BlockingQueuedConnection); +void RenderingClient::cleanupBeforeQuit() { - // ask the audio thread to quit and wait until it is done - audioClient->thread()->quit(); - audioClient->thread()->wait(); + QMetaObject::invokeMethod(DependencyManager::get().data(), + "stop", Qt::BlockingQueuedConnection); + + // destroy the AudioClient so it and its thread will safely go down + DependencyManager::destroy(); } void RenderingClient::processVerifiedPacket(const HifiSockAddr& senderSockAddr, const QByteArray& incomingPacket) { diff --git a/gvr-interface/src/RenderingClient.h b/gvr-interface/src/RenderingClient.h index 870bde748f..c4724bc086 100644 --- a/gvr-interface/src/RenderingClient.h +++ b/gvr-interface/src/RenderingClient.h @@ -26,7 +26,6 @@ class RenderingClient : public Client { Q_OBJECT public: RenderingClient(QObject* parent = 0, const QString& launchURLString = QString()); - ~RenderingClient(); const glm::vec3& getPosition() const { return _position; } const glm::quat& getOrientation() const { return _orientation; } @@ -35,6 +34,8 @@ public: static glm::vec3 getPositionForAudio() { return _instance->getPosition(); } static glm::quat getOrientationForAudio() { return _instance->getOrientation(); } + virtual void cleanupBeforeQuit(); + private slots: void goToLocation(const glm::vec3& newPosition, bool hasOrientationChange, const glm::quat& newOrientation, diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c720ed7606..2011f9b82e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -328,7 +328,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), &_datagramProcessor, SLOT(processDatagrams())); // put the audio processing on a separate thread - QThread* audioThread = new QThread(this); + QThread* audioThread = new QThread(); audioThread->setObjectName("Audio Thread"); auto audioIO = DependencyManager::get(); @@ -338,7 +338,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : audioIO->moveToThread(audioThread); connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start); - connect(audioIO.data(), SIGNAL(muteToggled()), this, SLOT(audioMuteToggled())); + connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit); + connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); + connect(audioIO.data(), &AudioClient::muteToggled, this, &Application::audioMuteToggled); audioThread->start(); @@ -516,21 +518,33 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : void Application::aboutToQuit() { _aboutToQuit = true; + + cleanupBeforeQuit(); } -Application::~Application() { +void Application::cleanupBeforeQuit() { QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::BlockingQueuedConnection); _settingsThread.quit(); saveSettings(); + // TODO: now that this is in cleanupBeforeQuit do we really need it to stop and force + // an event loop to send the packet? + UserActivityLogger::getInstance().close(); + + // stop the AudioClient + QMetaObject::invokeMethod(DependencyManager::get().data(), + "stop", Qt::BlockingQueuedConnection); + + // destroy the AudioClient so it and its thread have a chance to go down safely + DependencyManager::destroy(); +} + +Application::~Application() { _entities.getTree()->setSimulation(NULL); qInstallMessageHandler(NULL); _window->saveGeometry(); - int DELAY_TIME = 1000; - UserActivityLogger::getInstance().close(DELAY_TIME); - // make sure we don't call the idle timer any more delete idleTimer; @@ -541,18 +555,6 @@ Application::~Application() { _nodeThread->quit(); _nodeThread->wait(); - // kill any audio injectors that are still around - AudioScriptingInterface::getInstance().stopAllInjectors(); - - auto audioIO = DependencyManager::get(); - - // stop the audio process - QMetaObject::invokeMethod(audioIO.data(), "stop", Qt::BlockingQueuedConnection); - - // ask the audio thread to quit and wait until it is done - audioIO->thread()->quit(); - audioIO->thread()->wait(); - _octreeProcessor.terminate(); _entityEditSender.terminate(); @@ -2602,6 +2604,9 @@ const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f }; const GLfloat WORLD_DIFFUSE_COLOR[] = { 0.6f, 0.525f, 0.525f }; const GLfloat WORLD_SPECULAR_COLOR[] = { 0.94f, 0.94f, 0.737f, 1.0f }; +const glm::vec3 GLOBAL_LIGHT_COLOR = { 0.6f, 0.525f, 0.525f }; +const float GLOBAL_LIGHT_INTENSITY = 1.0f; + void Application::setupWorldLight() { // Setup 3D lights (after the camera transform, so that they are positioned in world space) @@ -2616,6 +2621,7 @@ void Application::setupWorldLight() { glLightfv(GL_LIGHT0, GL_SPECULAR, WORLD_SPECULAR_COLOR); glMaterialfv(GL_FRONT, GL_SPECULAR, WORLD_SPECULAR_COLOR); glMateriali(GL_FRONT, GL_SHININESS, 96); + } bool Application::shouldRenderMesh(float largestDimension, float distanceToCamera) { @@ -2822,7 +2828,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs { DependencyManager::get()->setAmbientLightMode(getRenderAmbientLight()); - + DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY); PROFILE_RANGE("DeferredLighting"); PerformanceTimer perfTimer("lighting"); DependencyManager::get()->render(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 1ba1bdf4ca..c41c0970d8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -410,6 +410,8 @@ private: void initDisplay(); void init(); + + void cleanupBeforeQuit(); void update(float deltaTime); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 18b9943e29..f9437221e5 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -788,13 +788,12 @@ void ApplicationOverlay::renderAudioMeter() { // Audio VU Meter and Mute Icon const int MUTE_ICON_SIZE = 24; - const int AUDIO_METER_INSET = 2; const int MUTE_ICON_PADDING = 10; - const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET - MUTE_ICON_PADDING; - const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET; + const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - MUTE_ICON_PADDING; + const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 ; const int AUDIO_METER_HEIGHT = 8; const int AUDIO_METER_GAP = 5; - const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP; + const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_GAP; int audioMeterY; bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !OculusManager::isConnected(); @@ -847,7 +846,7 @@ void ApplicationOverlay::renderAudioMeter() { // Draw audio meter background Quad DependencyManager::get()->renderQuad(AUDIO_METER_X, audioMeterY, AUDIO_METER_WIDTH, AUDIO_METER_HEIGHT, - glm::vec4(0, 0, 0, 1)); + glm::vec4(0.298f, 0.757f, 0.722f, 1)); if (audioLevel > AUDIO_RED_START) { glm::vec4 quadColor; @@ -857,10 +856,10 @@ void ApplicationOverlay::renderAudioMeter() { quadColor = glm::vec4(1, 1, 1, 1); } // Draw Red Quad - DependencyManager::get()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, - audioMeterY + AUDIO_METER_INSET, + DependencyManager::get()->renderQuad(AUDIO_METER_X + AUDIO_RED_START, + audioMeterY, audioLevel - AUDIO_RED_START, - AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor, + AUDIO_METER_HEIGHT, quadColor, _audioRedQuad); audioLevel = AUDIO_RED_START; @@ -874,26 +873,28 @@ void ApplicationOverlay::renderAudioMeter() { quadColor = glm::vec4(1, 1, 1, 1); } // Draw Green Quad - DependencyManager::get()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, - audioMeterY + AUDIO_METER_INSET, + DependencyManager::get()->renderQuad(AUDIO_METER_X + AUDIO_GREEN_START, + audioMeterY, audioLevel - AUDIO_GREEN_START, - AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor, + AUDIO_METER_HEIGHT, quadColor, _audioGreenQuad); audioLevel = AUDIO_GREEN_START; } - // Draw Blue Quad - glm::vec4 quadColor; - if (!isClipping) { - quadColor = AUDIO_METER_BLUE; - } else { - quadColor = glm::vec4(1, 1, 1, 1); + + if (audioLevel >= 0) { + glm::vec4 quadColor; + if (!isClipping) { + quadColor = AUDIO_METER_BLUE; + } else { + quadColor = glm::vec4(1, 1, 1, 1); + } + // Draw Blue (low level) quad + DependencyManager::get()->renderQuad(AUDIO_METER_X, + audioMeterY, + audioLevel, AUDIO_METER_HEIGHT, quadColor, + _audioBlueQuad); } - // Draw Blue (low level) quad - DependencyManager::get()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET, - audioMeterY + AUDIO_METER_INSET, - audioLevel, AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor, - _audioBlueQuad); } void ApplicationOverlay::renderStatsAndLogs() { diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 7f6c509626..a45fae94dc 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -136,6 +136,8 @@ AudioClient::AudioClient() : } AudioClient::~AudioClient() { + stop(); + if (_gverbLocal) { gverb_free(_gverbLocal); } @@ -489,7 +491,6 @@ void AudioClient::start() { } void AudioClient::stop() { - _inputFrameBuffer.finalize(); _inputGain.finalize(); _sourceGain.finalize(); @@ -974,14 +975,16 @@ bool AudioClient::outputLocalInjector(bool isStereo, qreal volume, AudioInjector QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat, - injector); + injector->getLocalBuffer()); + localOutput->setVolume(volume); // move the localOutput to the same thread as the local injector buffer localOutput->moveToThread(injector->getLocalBuffer()->thread()); - // have it be cleaned up when that injector is done - connect(injector, &AudioInjector::finished, localOutput, &QAudioOutput::stop); + // have it be stopped when that local buffer is about to close + connect(injector->getLocalBuffer(), &AudioInjectorLocalBuffer::bufferEmpty, localOutput, &QAudioOutput::stop); + connect(injector->getLocalBuffer(), &QIODevice::aboutToClose, localOutput, &QAudioOutput::stop); qDebug() << "Starting QAudioOutput for local injector" << localOutput; @@ -992,7 +995,6 @@ bool AudioClient::outputLocalInjector(bool isStereo, qreal volume, AudioInjector return false; } - void AudioClient::outputFormatChanged() { int outputFormatChannelCountTimesSampleRate = _outputFormat.channelCount() * _outputFormat.sampleRate(); _outputFrameSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * outputFormatChannelCountTimesSampleRate / _desiredOutputFormat.sampleRate(); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index e55a116e06..4f16500103 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -188,6 +188,10 @@ protected: AudioClient(); ~AudioClient(); + virtual void customDeleter() { + deleteLater(); + } + private: void outputFormatChanged(); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 5568a7e372..9981e0fba7 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include @@ -21,79 +22,77 @@ #include "AudioInjector.h" -QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in) { - return engine->newQObject(in); -} - -void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out) { - out = qobject_cast(object.toQObject()); -} - AudioInjector::AudioInjector(QObject* parent) : - QObject(parent), - _options(), - _shouldStop(false), - _loudness(0.0f), - _isFinished(false), - _currentSendPosition(0), - _localBuffer(NULL) + QObject(parent) { + } AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) : _audioData(sound->getByteArray()), - _options(injectorOptions), - _shouldStop(false), - _loudness(0.0f), - _isFinished(false), - _currentSendPosition(0), - _localBuffer(NULL) + _options(injectorOptions) { } AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) : _audioData(audioData), - _options(injectorOptions), - _shouldStop(false), - _loudness(0.0f), - _isFinished(false), - _currentSendPosition(0), - _localBuffer(NULL) + _options(injectorOptions) { } -AudioInjector::~AudioInjector() { - if (_localBuffer) { - _localBuffer->stop(); +void AudioInjector::setIsFinished(bool isFinished) { + _isFinished = isFinished; + + if (_isFinished) { + emit finished(); + + if (_localBuffer) { + _localBuffer->stop(); + _localBuffer->deleteLater(); + _localBuffer = NULL; + } + + _isStarted = false; + _shouldStop = false; + + if (_shouldDeleteAfterFinish) { + // we've been asked to delete after finishing, trigger a queued deleteLater here + qDebug() << "AudioInjector triggering delete from setIsFinished"; + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); + } } } -void AudioInjector::setOptions(AudioInjectorOptions& options) { - _options = options; -} - -float AudioInjector::getLoudness() { - return _loudness; -} - void AudioInjector::injectAudio() { - - // check if we need to offset the sound by some number of seconds - if (_options.secondOffset > 0.0f) { + if (!_isStarted) { + // check if we need to offset the sound by some number of seconds + if (_options.secondOffset > 0.0f) { + + // convert the offset into a number of bytes + int byteOffset = (int) floorf(AudioConstants::SAMPLE_RATE * _options.secondOffset * (_options.stereo ? 2.0f : 1.0f)); + byteOffset *= sizeof(int16_t); + + _currentSendPosition = byteOffset; + } else { + _currentSendPosition = 0; + } - // convert the offset into a number of bytes - int byteOffset = (int) floorf(AudioConstants::SAMPLE_RATE * _options.secondOffset * (_options.stereo ? 2.0f : 1.0f)); - byteOffset *= sizeof(int16_t); - - _currentSendPosition = byteOffset; - } - - if (_options.localOnly) { - injectLocally(); + if (_options.localOnly) { + injectLocally(); + } else { + injectToMixer(); + } } else { - injectToMixer(); - } + qDebug() << "AudioInjector::injectAudio called but already started."; + } +} + +void AudioInjector::restart() { + qDebug() << "Restarting an AudioInjector by stopping and starting over."; + stop(); + setIsFinished(false); + QMetaObject::invokeMethod(this, "injectAudio", Qt::QueuedConnection); } void AudioInjector::injectLocally() { @@ -102,6 +101,7 @@ void AudioInjector::injectLocally() { if (_audioData.size() > 0) { _localBuffer = new AudioInjectorLocalBuffer(_audioData, this); + _localBuffer->open(QIODevice::ReadOnly); _localBuffer->setShouldLoop(_options.loop); @@ -236,6 +236,14 @@ void AudioInjector::injectToMixer() { // send two packets before the first sleep so the mixer can start playback right away if (_currentSendPosition != bytesToCopy && _currentSendPosition < _audioData.size()) { + + // process events in case we have been told to stop and be deleted + QCoreApplication::processEvents(); + + if (_shouldStop) { + break; + } + // not the first packet and not done // sleep for the appropriate time int usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; @@ -251,8 +259,7 @@ void AudioInjector::injectToMixer() { } } - _isFinished = true; - emit finished(); + setIsFinished(true); } void AudioInjector::stop() { @@ -260,7 +267,11 @@ void AudioInjector::stop() { if (_options.localOnly) { // we're only a local injector, so we can say we are finished right away too - _isFinished = true; - emit finished(); + setIsFinished(true); } } + +void AudioInjector::stopAndDeleteLater() { + stop(); + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); +} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 257b538c11..25d0c1699d 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -13,6 +13,7 @@ #define hifi_AudioInjector_h #include +#include #include #include @@ -24,15 +25,18 @@ class AbstractAudioInterface; +// In order to make scripting cleaner for the AudioInjector, the script now holds on to the AudioInjector object +// until it dies. + class AudioInjector : public QObject { Q_OBJECT public: AudioInjector(QObject* parent); AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions); - ~AudioInjector(); bool isFinished() const { return _isFinished; } + int getCurrentSendPosition() const { return _currentSendPosition; } AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; } @@ -41,30 +45,37 @@ public: void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } public slots: void injectAudio(); + void restart(); + void stop(); - void setOptions(AudioInjectorOptions& options); + void triggerDeleteAfterFinish() { _shouldDeleteAfterFinish = true; } + void stopAndDeleteLater(); + + void setOptions(AudioInjectorOptions& options) { _options = options; } void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; } - float getLoudness(); + float getLoudness() const { return _loudness; } + bool isPlaying() const { return !_isFinished; } signals: void finished(); + private: void injectToMixer(); void injectLocally(); + void setIsFinished(bool isFinished); + QByteArray _audioData; AudioInjectorOptions _options; - bool _shouldStop; - float _loudness; - bool _isFinished; - int _currentSendPosition; - AbstractAudioInterface* _localAudioInterface; - AudioInjectorLocalBuffer* _localBuffer; + bool _shouldStop = false; + float _loudness = 0.0f; + bool _isStarted = false; + bool _isFinished = false; + bool _shouldDeleteAfterFinish = false; + int _currentSendPosition = 0; + AbstractAudioInterface* _localAudioInterface = NULL; + AudioInjectorLocalBuffer* _localBuffer = NULL; }; -Q_DECLARE_METATYPE(AudioInjector*) - -QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in); -void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out); #endif // hifi_AudioInjector_h diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.cpp b/libraries/audio/src/AudioInjectorLocalBuffer.cpp index a58d686498..6cbe56adb7 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.cpp +++ b/libraries/audio/src/AudioInjectorLocalBuffer.cpp @@ -23,9 +23,18 @@ AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArr void AudioInjectorLocalBuffer::stop() { _isStopped = true; + QIODevice::close(); } +bool AudioInjectorLocalBuffer::seek(qint64 pos) { + if (_isStopped) { + return false; + } else { + return QIODevice::seek(pos); + } +} + qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { if (!_isStopped) { diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.h b/libraries/audio/src/AudioInjectorLocalBuffer.h index 399c7515ec..ce41052730 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.h +++ b/libraries/audio/src/AudioInjectorLocalBuffer.h @@ -21,6 +21,8 @@ public: void stop(); + bool seek(qint64 pos); + qint64 readData(char* data, qint64 maxSize); qint64 writeData(const char* data, qint64 maxSize) { return 0; } diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 3502dd219f..72d153289a 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1127,7 +1127,7 @@ FBXTexture getTexture(const QString& textureID, texture.transform.setTranslation(p.translation); texture.transform.setRotation(glm::quat(glm::radians(p.rotation))); texture.transform.setScale(p.scaling); - if ((p.UVSet != "map1") || (p.UVSet != "UVSet0")) { + if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) { texture.texcoordSet = 1; } texture.texcoordSetName = p.UVSet; @@ -1556,6 +1556,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, if (property.name == propertyName) { QString v = property.properties.at(0).toString(); if (property.properties.at(0) == "UVSet") { + std::string uvName = property.properties.at(index).toString().toStdString(); tex.assign(tex.UVSet, property.properties.at(index).toString()); } else if (property.properties.at(0) == "CurrentTextureBlendMode") { tex.assign(tex.currentTextureBlendMode, property.properties.at(index).value()); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 81c861fff8..43d8c991b6 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -85,8 +85,11 @@ bool Texture::Storage::allocateMip(uint16 level) { bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) { // Ok we should be able to do that... allocateMip(level); - _mips[level]->_format = format; - Size allocated = _mips[level]->_sysmem.setData(size, bytes); + auto mip = _mips[level]; + mip->_format = format; + Size allocated = mip->_sysmem.setData(size, bytes); + mip->_isGPULoaded = false; + return allocated == size; } diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index 0beaa20a83..fbd485e6a0 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -23,6 +23,7 @@ typedef gpu::BufferView::Index Index; typedef gpu::BufferView BufferView; typedef AABox Box; typedef std::vector< Box > Boxes; +typedef glm::vec3 Vec3; class Mesh { public: @@ -35,7 +36,7 @@ public: typedef gpu::Stream::Format VertexFormat; typedef std::map< Slot, BufferView > BufferViewMap; - typedef glm::vec3 Vec3; + typedef model::Vec3 Vec3; Mesh(); Mesh(const Mesh& mesh); diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp new file mode 100755 index 0000000000..9616ed2106 --- /dev/null +++ b/libraries/model/src/model/Light.cpp @@ -0,0 +1,97 @@ +// +// Light.cpp +// libraries/model/src/model +// +// Created by Sam Gateau on 1/26/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "Light.h" + +using namespace model; + +Light::Light() : + _flags(0), + _schemaBuffer(), + _transform() { + // only if created from nothing shall we create the Buffer to store the properties + Schema schema; + _schemaBuffer = gpu::BufferView(new gpu::Buffer(sizeof(Schema), (const gpu::Buffer::Byte*) &schema)); +} + +Light::Light(const Light& light) : + _flags(light._flags), + _schemaBuffer(light._schemaBuffer), + _transform(light._transform) { +} + +Light& Light::operator= (const Light& light) { + _flags = (light._flags); + _schemaBuffer = (light._schemaBuffer); + _transform = (light._transform); + + return (*this); +} + +Light::~Light() { +} + +void Light::setPosition(const Vec3& position) { + _transform.setTranslation(position); + editSchema()._position = Vec4(position, 1.f); +} + +void Light::setOrientation(const glm::quat& orientation) { + _transform.setRotation(orientation); +} + +void Light::setDirection(const Vec3& direction) { + editSchema()._direction = glm::normalize(direction); +} + +const Vec3& Light::getDirection() const { + return getSchema()._direction; +} + +void Light::setColor(const Color& color) { + editSchema()._color = color; +} + +void Light::setIntensity(float intensity) { + editSchema()._intensity = intensity; +} + +void Light::setMaximumRadius(float radius) { + if (radius <= 0.f) { + radius = 1.0f; + } + float CutOffIntensityRatio = 0.05f; + float surfaceRadius = radius / (sqrt(1.0f / CutOffIntensityRatio) - 1.f); + editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CutOffIntensityRatio, radius); +} + +void Light::setSpotAngle(float angle) { + if (angle <= 0.f) { + angle = 0.0f; + } + float cosAngle = cos(angle); + editSchema()._spot.x = cos(angle); + editSchema()._spot.y = sin(angle); + editSchema()._spot.z = angle; +} + +void Light::setSpotExponent(float exponent) { + if (exponent <= 0.f) { + exponent = 1.0f; + } + editSchema()._spot.w = exponent; +} + +void Light::setShowContour(float show) { + if (show <= 0.f) { + show = 0.0f; + } + editSchema()._control.w = show; +} diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h new file mode 100755 index 0000000000..2ef2bf3036 --- /dev/null +++ b/libraries/model/src/model/Light.h @@ -0,0 +1,294 @@ +// +// Light.h +// libraries/model/src/model +// +// Created by Sam Gateau on 12/10/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_model_Light_h +#define hifi_model_Light_h + +#include +#include + +#include +#include "Transform.h" +#include "gpu/Resource.h" +#include "gpu/Texture.h" + +namespace model { +typedef gpu::BufferView UniformBufferView; +typedef gpu::TextureView TextureView; +typedef glm::vec3 Vec3; +typedef glm::vec4 Vec4; +typedef glm::quat Quat; + +class SphericalHarmonics { +public: + glm::vec3 L00 ; float spare0; + glm::vec3 L1m1 ; float spare1; + glm::vec3 L10 ; float spare2; + glm::vec3 L11 ; float spare3; + glm::vec3 L2m2 ; float spare4; + glm::vec3 L2m1 ; float spare5; + glm::vec3 L20 ; float spare6; + glm::vec3 L21 ; float spare7; + glm::vec3 L22 ; float spare8; + + static const int NUM_COEFFICIENTS = 9; + + enum Preset { + OLD_TOWN_SQUARE = 0, + GRACE_CATHEDRAL, + EUCALYPTUS_GROVE, + ST_PETERS_BASILICA, + UFFIZI_GALLERY, + GALILEOS_TOMB, + VINE_STREET_KITCHEN, + BREEZEWAY, + CAMPUS_SUNSET, + FUNSTON_BEACH_SUNSET, + + NUM_PRESET, + }; + + void assignPreset(int p) { + switch (p) { + case OLD_TOWN_SQUARE: { + L00 = glm::vec3( 0.871297f, 0.875222f, 0.864470f); + L1m1 = glm::vec3( 0.175058f, 0.245335f, 0.312891f); + L10 = glm::vec3( 0.034675f, 0.036107f, 0.037362f); + L11 = glm::vec3(-0.004629f,-0.029448f,-0.048028f); + L2m2 = glm::vec3(-0.120535f,-0.121160f,-0.117507f); + L2m1 = glm::vec3( 0.003242f, 0.003624f, 0.007511f); + L20 = glm::vec3(-0.028667f,-0.024926f,-0.020998f); + L21 = glm::vec3(-0.077539f,-0.086325f,-0.091591f); + L22 = glm::vec3(-0.161784f,-0.191783f,-0.219152f); + } + break; + case GRACE_CATHEDRAL: { + L00 = glm::vec3( 0.79f, 0.44f, 0.54f); + L1m1 = glm::vec3( 0.39f, 0.35f, 0.60f); + L10 = glm::vec3(-0.34f, -0.18f, -0.27f); + L11 = glm::vec3(-0.29f, -0.06f, 0.01f); + L2m2 = glm::vec3(-0.11f, -0.05f, -0.12f); + L2m1 = glm::vec3(-0.26f, -0.22f, -0.47f); + L20 = glm::vec3(-0.16f, -0.09f, -0.15f); + L21 = glm::vec3( 0.56f, 0.21f, 0.14f); + L22 = glm::vec3( 0.21f, -0.05f, -0.30f); + } + break; + case EUCALYPTUS_GROVE: { + L00 = glm::vec3( 0.38f, 0.43f, 0.45f); + L1m1 = glm::vec3( 0.29f, 0.36f, 0.41f); + L10 = glm::vec3( 0.04f, 0.03f, 0.01f); + L11 = glm::vec3(-0.10f, -0.10f, -0.09f); + L2m2 = glm::vec3(-0.06f, -0.06f, -0.04f); + L2m1 = glm::vec3( 0.01f, -0.01f, -0.05f); + L20 = glm::vec3(-0.09f, -0.13f, -0.15f); + L21 = glm::vec3(-0.06f, -0.05f, -0.04f); + L22 = glm::vec3( 0.02f, 0.00f, -0.05f); + } + break; + case ST_PETERS_BASILICA: { + L00 = glm::vec3( 0.36f, 0.26f, 0.23f); + L1m1 = glm::vec3( 0.18f, 0.14f, 0.13f); + L10 = glm::vec3(-0.02f, -0.01f, 0.00f); + L11 = glm::vec3( 0.03f, 0.02f, -0.00f); + L2m2 = glm::vec3( 0.02f, 0.01f, -0.00f); + L2m1 = glm::vec3(-0.05f, -0.03f, -0.01f); + L20 = glm::vec3(-0.09f, -0.08f, -0.07f); + L21 = glm::vec3( 0.01f, 0.00f, 0.00f); + L22 = glm::vec3(-0.08f, -0.03f, -0.00f); + } + break; + case UFFIZI_GALLERY: { + L00 = glm::vec3( 0.32f, 0.31f, 0.35f); + L1m1 = glm::vec3( 0.37f, 0.37f, 0.43f); + L10 = glm::vec3( 0.00f, 0.00f, 0.00f); + L11 = glm::vec3(-0.01f, -0.01f, -0.01f); + L2m2 = glm::vec3(-0.02f, -0.02f, -0.03f); + L2m1 = glm::vec3(-0.01f, -0.01f, -0.01f); + L20 = glm::vec3(-0.28f, -0.28f, -0.32f); + L21 = glm::vec3( 0.00f, 0.00f, 0.00f); + L22 = glm::vec3(-0.24f, -0.24f, -0.28f); + } + break; + case GALILEOS_TOMB: { + L00 = glm::vec3( 1.04f, 0.76f, 0.71f); + L1m1 = glm::vec3( 0.44f, 0.34f, 0.34f); + L10 = glm::vec3(-0.22f, -0.18f, -0.17f); + L11 = glm::vec3( 0.71f, 0.54f, 0.56f); + L2m2 = glm::vec3( 0.64f, 0.50f, 0.52f); + L2m1 = glm::vec3(-0.12f, -0.09f, -0.08f); + L20 = glm::vec3(-0.37f, -0.28f, -0.32f); + L21 = glm::vec3(-0.17f, -0.13f, -0.13f); + L22 = glm::vec3( 0.55f, 0.42f, 0.42f); + } + break; + case VINE_STREET_KITCHEN: { + L00 = glm::vec3( 0.64f, 0.67f, 0.73f); + L1m1 = glm::vec3( 0.28f, 0.32f, 0.33f); + L10 = glm::vec3( 0.42f, 0.60f, 0.77f); + L11 = glm::vec3(-0.05f, -0.04f, -0.02f); + L2m2 = glm::vec3(-0.10f, -0.08f, -0.05f); + L2m1 = glm::vec3( 0.25f, 0.39f, 0.53f); + L20 = glm::vec3( 0.38f, 0.54f, 0.71f); + L21 = glm::vec3( 0.06f, 0.01f, -0.02f); + L22 = glm::vec3(-0.03f, -0.02f, -0.03f); + } + break; + case BREEZEWAY: { + L00 = glm::vec3( 0.32f, 0.36f, 0.38f); + L1m1 = glm::vec3( 0.37f, 0.41f, 0.45f); + L10 = glm::vec3(-0.01f, -0.01f, -0.01f); + L11 = glm::vec3(-0.10f, -0.12f, -0.12f); + L2m2 = glm::vec3(-0.13f, -0.15f, -0.17f); + L2m1 = glm::vec3(-0.01f, -0.02f, 0.02f); + L20 = glm::vec3(-0.07f, -0.08f, -0.09f); + L21 = glm::vec3( 0.02f, 0.03f, 0.03f); + L22 = glm::vec3(-0.29f, -0.32f, -0.36f); + } + break; + case CAMPUS_SUNSET: { + L00 = glm::vec3( 0.79f, 0.94f, 0.98f); + L1m1 = glm::vec3( 0.44f, 0.56f, 0.70f); + L10 = glm::vec3(-0.10f, -0.18f, -0.27f); + L11 = glm::vec3( 0.45f, 0.38f, 0.20f); + L2m2 = glm::vec3( 0.18f, 0.14f, 0.05f); + L2m1 = glm::vec3(-0.14f, -0.22f, -0.31f); + L20 = glm::vec3(-0.39f, -0.40f, -0.36f); + L21 = glm::vec3( 0.09f, 0.07f, 0.04f); + L22 = glm::vec3( 0.67f, 0.67f, 0.52f); + } + break; + case FUNSTON_BEACH_SUNSET: { + L00 = glm::vec3( 0.68f, 0.69f, 0.70f); + L1m1 = glm::vec3( 0.32f, 0.37f, 0.44f); + L10 = glm::vec3(-0.17f, -0.17f, -0.17f); + L11 = glm::vec3(-0.45f, -0.42f, -0.34f); + L2m2 = glm::vec3(-0.17f, -0.17f, -0.15f); + L2m1 = glm::vec3(-0.08f, -0.09f, -0.10f); + L20 = glm::vec3(-0.03f, -0.02f, -0.01f); + L21 = glm::vec3( 0.16f, 0.14f, 0.10f); + L22 = glm::vec3( 0.37f, 0.31f, 0.20f); + } + break; + } + } +}; + +class Light { +public: + enum Type { + SUN = 0, + POINT, + SPOT, + + NUM_TYPES, + }; + + typedef Vec3 Color; + + enum FlagBit { + COLOR_BIT = 0, + INTENSITY_BIT, + RANGE_BIT, + SPOT_BIT, + TRANSFORM_BIT, + + NUM_FLAGS, + }; + typedef std::bitset Flags; + + Light(); + Light(const Light& light); + Light& operator= (const Light& light); + virtual ~Light(); + + void setType(Type type) { editSchema()._control.x = float(type); } + Type getType() const { return Type((int) getSchema()._control.x); } + + void setPosition(const Vec3& position); + const Vec3& getPosition() const { return _transform.getTranslation(); } + + void setDirection(const Vec3& direction); + const Vec3& getDirection() const; + + void setOrientation(const Quat& orientation); + const glm::quat& getOrientation() const { return _transform.getRotation(); } + + const Color& getColor() const { return getSchema()._color; } + void setColor(const Color& color); + + float getIntensity() const { return getSchema()._intensity; } + void setIntensity(float intensity); + + bool isRanged() const { return (getType() == POINT) || (getType() == SPOT ); } + + void setMaximumRadius(float radius); + float getMaximumRadius() const { return getSchema()._attenuation.w; } + + // Spot properties + bool isSpot() const { return getType() == SPOT; } + void setSpotAngle(float angle); + float getSpotAngle() const { return getSchema()._spot.z; } + void setSpotExponent(float exponent); + float getSpotExponent() const { return getSchema()._spot.w; } + + // For editing purpose, show the light volume contour. + // Set to non 0 to show it, the value is used as the intensity of the contour color + void setShowContour(float show); + float getShowContour() const { return getSchema()._control.w; } + + // Spherical Harmonics storing the Ambien lighting approximation used for the Sun typed light + void setAmbientSphere(const SphericalHarmonics& sphere) { _ambientSphere = sphere; } + const SphericalHarmonics& getAmbientSphere() const { return _ambientSphere; } + void setAmbientSpherePreset(SphericalHarmonics::Preset preset) { _ambientSphere.assignPreset(preset); } + + // Schema to access the attribute values of the light + class Schema { + public: + Vec4 _position; + Vec3 _direction; + float _spare0; + Color _color; + float _intensity; + Vec4 _attenuation; + Vec4 _spot; + Vec4 _shadow; + + Vec4 _control; + + Schema() : + _position(0.0f, 0.0f, 0.0f, 1.0f), + _direction(0.0f, 0.0f, -1.0f), + _spare0(0.f), + _color(1.0f), + _intensity(1.0f), + _attenuation(1.0f, 1.0f, 1.0f, 1.0f), + _spot(0.0f, 0.0f, 0.0f, 3.0f), + _control(0.0f) + {} + }; + + const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } + +protected: + + Flags _flags; + UniformBufferView _schemaBuffer; + Transform _transform; + SphericalHarmonics _ambientSphere; + + const Schema& getSchema() const { return _schemaBuffer.get(); } + Schema& editSchema() { return _schemaBuffer.edit(); } +}; +typedef QSharedPointer< Light > LightPointer; + +}; + +#endif diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index efd2f35968..57e0f68a9c 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -100,7 +100,6 @@ public: void setTextureView(MapChannel channel, const TextureView& texture); const TextureMap& getTextureMap() const { return _textureMap; } - const Schema* getSchema() const { return &_schemaBuffer.get(); } protected: Flags _flags; diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index 4fc6905e3a..f2646369c1 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -86,17 +86,9 @@ void UserActivityLogger::launch(QString applicationVersion) { logAction(ACTION_NAME, actionDetails); } -void UserActivityLogger::close(int delayTime) { +void UserActivityLogger::close() { const QString ACTION_NAME = "close"; - - // In order to get the end of the session, we need to give the account manager enough time to send the packet. - QEventLoop loop; - QTimer timer; - connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); - // Now we can log it logAction(ACTION_NAME, QJsonObject()); - timer.start(delayTime); - loop.exec(); } void UserActivityLogger::changedDisplayName(QString displayName) { diff --git a/libraries/networking/src/UserActivityLogger.h b/libraries/networking/src/UserActivityLogger.h index 9b100461ee..295ad5ee8d 100644 --- a/libraries/networking/src/UserActivityLogger.h +++ b/libraries/networking/src/UserActivityLogger.h @@ -30,7 +30,7 @@ public slots: void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters()); void launch(QString applicationVersion); - void close(int delayTime); + void close(); void changedDisplayName(QString displayName); void changedModel(QString typeOfModel, QString modelURL); void changedDomain(QString domainURL); diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh new file mode 100755 index 0000000000..6868b96c24 --- /dev/null +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -0,0 +1,117 @@ + +<@if not DEFERRED_GLOBAL_LIGHT_SLH@> +<@def DEFERRED_GLOBAL_LIGHT_SLH@> + +<@include DeferredLighting.slh@> + +struct SphericalHarmonics { + vec4 L00; + vec4 L1m1; + vec4 L10; + vec4 L11; + vec4 L2m2; + vec4 L2m1; + vec4 L20; + vec4 L21; + vec4 L22; +}; + +vec4 evalSphericalLight(SphericalHarmonics sh, vec3 direction ) { + + const float C1 = 0.429043; + const float C2 = 0.511664; + const float C3 = 0.743125; + const float C4 = 0.886227; + const float C5 = 0.247708; + + vec4 value = C1 * sh.L22 * (direction.x * direction.x - direction.y * direction.y) + + C3 * sh.L20 * direction.z * direction.z + + C4 * sh.L00 - C5 * sh.L20 + + 2.0 * C1 * ( sh.L2m2 * direction.x * direction.y + + sh.L21 * direction.x * direction.z + + sh.L2m1 * direction.y * direction.z ) + + 2.0 * C2 * ( sh.L11 * direction.x + + sh.L1m1 * direction.y + + sh.L10 * direction.z ) ; + return value; +} + +// Need one SH +uniform SphericalHarmonics ambientSphere; + +// Everything about light +<@include Light.slh@> + +// The view Matrix +uniform mat4 invViewMat; + +vec3 evalAmbienGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { + + // Need the light now + Light light = getLight(); + + vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); + vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); + vec3 fragEyeDir = normalize(fragEyeVector.xyz); + + vec3 color = diffuse.rgb * getLightColor(light) * 0.5; + + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + + color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + + return color; +} +vec3 evalAmbienSphereGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { + // Need the light now + Light light = getLight(); + + vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); + vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); + vec3 fragEyeDir = normalize(fragEyeVector.xyz); + + // TODO: The world space normal doesn;t seem to work properly with the current SH definitions + // FoOr now, we use the normal in view space + vec3 ambientNormal = normal; + + vec3 color = diffuse.rgb * 0.5 * evalSphericalLight(ambientSphere, ambientNormal).xyz; + + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + + color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + + return color; +} + +vec3 evalLightmappedColor(float shadowAttenuation, vec3 normal, vec3 diffuse, vec3 lightmap) { + + Light light = getLight(); + float diffuseDot = dot(normal, getLightDirection(light)); + + // need to catch normals perpendicular to the projection plane hence the magic number for the threshold + // it should be just 0, but we have innacurracy so we need to overshoot + const float PERPENDICULAR_THRESHOLD = -0.005; + float facingLight = step(PERPENDICULAR_THRESHOLD, diffuseDot); + + // evaluate the shadow test but only relevant for light facing fragments + float lightAttenuation = (1 - facingLight) + facingLight * shadowAttenuation; + + // diffuse light is the lightmap dimmed by shadow + vec3 diffuseLight = lightAttenuation * lightmap; + + // ambient is a tiny percentage of the lightmap and only when in the shadow + vec3 ambientLight = (1 - lightAttenuation) * 0.5 * lightmap; + + return diffuse * (ambientLight + diffuseLight); +} + +<@endif@> diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index cd65fd1053..bb37a9e3e8 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -11,86 +11,51 @@ <@if not DEFERRED_LIGHTING_SLH@> <@def DEFERRED_LIGHTING_SLH@> -struct SphericalHarmonics { - vec4 L00; - vec4 L1m1; - vec4 L10; - vec4 L11; - vec4 L2m2; - vec4 L2m1; - vec4 L20; - vec4 L21; - vec4 L22; -}; - -vec4 evalSphericalLight(SphericalHarmonics sh, vec3 direction ) { - - const float C1 = 0.429043; - const float C2 = 0.511664; - const float C3 = 0.743125; - const float C4 = 0.886227; - const float C5 = 0.247708; - - vec4 value = C1 * sh.L22 * (direction.x * direction.x - direction.y * direction.y) + - C3 * sh.L20 * direction.z * direction.z + - C4 * sh.L00 - C5 * sh.L20 + - 2.0 * C1 * ( sh.L2m2 * direction.x * direction.y + - sh.L21 * direction.x * direction.z + - sh.L2m1 * direction.y * direction.z ) + - 2.0 * C2 * ( sh.L11 * direction.x + - sh.L1m1 * direction.y + - sh.L10 * direction.z ) ; - return value; -} - -uniform SphericalHarmonics ambientSphere; - -vec3 evalAmbientColor(vec3 normal, vec3 diffuse, vec3 specular, float gloss) { - return diffuse.rgb * gl_FrontLightProduct[0].ambient.rgb; -} - -vec3 evalAmbientSphereColor(vec3 normal, vec3 diffuse, vec3 specular, float gloss) { - vec3 ambientLight = 0.5 * evalSphericalLight(ambientSphere, normal).xyz; - - return diffuse.rgb * ambientLight; -} - -vec3 evalDirectionalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +// Frag Shading returns the diffuse amount as W and the specular rgb as xyz +vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float gloss) { // Diffuse Lighting - float diffuseDot = dot(normal, gl_LightSource[0].position.xyz); - float facingLight = step(0.0, diffuseDot) * shadowAttenuation; - vec3 diffuseColor = diffuse * (gl_FrontLightProduct[0].diffuse.rgb * (diffuseDot * facingLight)); - - // compute the specular multiplier (sans exponent) - float specularPower = facingLight * max(0.0, - dot(normalize(gl_LightSource[0].position.xyz - normalize(position)), normal)); - vec3 specularColor = pow(specularPower, gloss * 128.0) * specular; + float diffuseDot = dot(fragNormal, fragLightDir); + float facingLight = step(0.0, diffuseDot); + float diffuse = diffuseDot * facingLight; + + // Specular Lighting depends on the half vector and the gloss + vec3 halfDir = normalize(fragEyeDir + fragLightDir); - // add specular contribution - return vec3(diffuseColor + specularColor); + // float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0); + float specularPower = pow(max(0.0, dot(halfDir, fragNormal)), gloss * 128.0); + specularPower *= (gloss * 128.0 * 0.125 + 0.25); + + float shlickPower = (1.0 - dot(fragLightDir,halfDir)); + float shlickPower2 = shlickPower * shlickPower; + float shlickPower5 = shlickPower2 * shlickPower2 * shlickPower; + vec3 schlick = specular * (1.0 - shlickPower5) + vec3(shlickPower5); + vec3 reflect = specularPower * schlick; + + return vec4(reflect, diffuse); } +vec4 evalBlinnShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float gloss) { + // Diffuse Lighting + float diffuseDot = dot(fragNormal, fragLightDir); + float facingLight = step(0.0, diffuseDot); + float diffuse = diffuseDot * facingLight; + + // Specular Lighting depends on the half vector and the gloss + vec3 halfDir = normalize(fragEyeDir + fragLightDir); -vec3 evalLightmappedColor(float shadowAttenuation, vec3 normal, vec3 diffuse, vec3 lightmap) { - - float diffuseDot = dot(normal, gl_LightSource[0].position.xyz); - - // need to catch normals perpendicular to the projection plane hence the magic number for the threshold - // it should be just 0, but we have innacurracy so we need to overshoot - const float PERPENDICULAR_THRESHOLD = -0.005; - float facingLight = step(PERPENDICULAR_THRESHOLD, diffuseDot); - - // evaluate the shadow test but only relevant for light facing fragments - float lightAttenuation = (1 - facingLight) + facingLight * shadowAttenuation; - - // diffuse light is the lightmap dimmed by shadow - vec3 diffuseLight = lightAttenuation * lightmap; + float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0); + vec3 reflect = specularPower * specular; - // ambient is a tiny percentage of the lightmap and only when in the shadow - vec3 ambientLight = (1 - lightAttenuation) * 0.5 * lightmap; - - return diffuse * (ambientLight + diffuseLight); + return vec4(reflect, diffuse); } +vec4 evalFragShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float gloss) { + + /*if (gl_FragCoord.x > 1000) { + return evalBlinnShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss); + } else {*/ + return evalPBRShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss); + //} +} <@endif@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index b84b01b16a..1f5d0ce4c3 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -25,6 +25,9 @@ #include "RenderUtil.h" #include "TextureCache.h" +#include "gpu/Batch.h" +#include "gpu/GLBackend.h" + #include "simple_vert.h" #include "simple_frag.h" @@ -42,146 +45,6 @@ #include "point_light_frag.h" #include "spot_light_frag.h" -class SphericalHarmonics { -public: - glm::vec3 L00 ; float spare0; - glm::vec3 L1m1 ; float spare1; - glm::vec3 L10 ; float spare2; - glm::vec3 L11 ; float spare3; - glm::vec3 L2m2 ; float spare4; - glm::vec3 L2m1 ; float spare5; - glm::vec3 L20 ; float spare6; - glm::vec3 L21 ; float spare7; - glm::vec3 L22 ; float spare8; - - static const int NUM_COEFFICIENTS = 9; - - void assignPreset(int p) { - switch (p) { - case DeferredLightingEffect::OLD_TOWN_SQUARE: { - L00 = glm::vec3( 0.871297f, 0.875222f, 0.864470f); - L1m1 = glm::vec3( 0.175058f, 0.245335f, 0.312891f); - L10 = glm::vec3( 0.034675f, 0.036107f, 0.037362f); - L11 = glm::vec3(-0.004629f,-0.029448f,-0.048028f); - L2m2 = glm::vec3(-0.120535f,-0.121160f,-0.117507f); - L2m1 = glm::vec3( 0.003242f, 0.003624f, 0.007511f); - L20 = glm::vec3(-0.028667f,-0.024926f,-0.020998f); - L21 = glm::vec3(-0.077539f,-0.086325f,-0.091591f); - L22 = glm::vec3(-0.161784f,-0.191783f,-0.219152f); - } - break; - case DeferredLightingEffect::GRACE_CATHEDRAL: { - L00 = glm::vec3( 0.79f, 0.44f, 0.54f); - L1m1 = glm::vec3( 0.39f, 0.35f, 0.60f); - L10 = glm::vec3(-0.34f, -0.18f, -0.27f); - L11 = glm::vec3(-0.29f, -0.06f, 0.01f); - L2m2 = glm::vec3(-0.11f, -0.05f, -0.12f); - L2m1 = glm::vec3(-0.26f, -0.22f, -0.47f); - L20 = glm::vec3(-0.16f, -0.09f, -0.15f); - L21 = glm::vec3( 0.56f, 0.21f, 0.14f); - L22 = glm::vec3( 0.21f, -0.05f, -0.30f); - } - break; - case DeferredLightingEffect::EUCALYPTUS_GROVE: { - L00 = glm::vec3( 0.38f, 0.43f, 0.45f); - L1m1 = glm::vec3( 0.29f, 0.36f, 0.41f); - L10 = glm::vec3( 0.04f, 0.03f, 0.01f); - L11 = glm::vec3(-0.10f, -0.10f, -0.09f); - L2m2 = glm::vec3(-0.06f, -0.06f, -0.04f); - L2m1 = glm::vec3( 0.01f, -0.01f, -0.05f); - L20 = glm::vec3(-0.09f, -0.13f, -0.15f); - L21 = glm::vec3(-0.06f, -0.05f, -0.04f); - L22 = glm::vec3( 0.02f, 0.00f, -0.05f); - } - break; - case DeferredLightingEffect::ST_PETERS_BASILICA: { - L00 = glm::vec3( 0.36f, 0.26f, 0.23f); - L1m1 = glm::vec3( 0.18f, 0.14f, 0.13f); - L10 = glm::vec3(-0.02f, -0.01f, 0.00f); - L11 = glm::vec3( 0.03f, 0.02f, -0.00f); - L2m2 = glm::vec3( 0.02f, 0.01f, -0.00f); - L2m1 = glm::vec3(-0.05f, -0.03f, -0.01f); - L20 = glm::vec3(-0.09f, -0.08f, -0.07f); - L21 = glm::vec3( 0.01f, 0.00f, 0.00f); - L22 = glm::vec3(-0.08f, -0.03f, -0.00f); - } - break; - case DeferredLightingEffect::UFFIZI_GALLERY: { - L00 = glm::vec3( 0.32f, 0.31f, 0.35f); - L1m1 = glm::vec3( 0.37f, 0.37f, 0.43f); - L10 = glm::vec3( 0.00f, 0.00f, 0.00f); - L11 = glm::vec3(-0.01f, -0.01f, -0.01f); - L2m2 = glm::vec3(-0.02f, -0.02f, -0.03f); - L2m1 = glm::vec3(-0.01f, -0.01f, -0.01f); - L20 = glm::vec3(-0.28f, -0.28f, -0.32f); - L21 = glm::vec3( 0.00f, 0.00f, 0.00f); - L22 = glm::vec3(-0.24f, -0.24f, -0.28f); - } - break; - case DeferredLightingEffect::GALILEOS_TOMB: { - L00 = glm::vec3( 1.04f, 0.76f, 0.71f); - L1m1 = glm::vec3( 0.44f, 0.34f, 0.34f); - L10 = glm::vec3(-0.22f, -0.18f, -0.17f); - L11 = glm::vec3( 0.71f, 0.54f, 0.56f); - L2m2 = glm::vec3( 0.64f, 0.50f, 0.52f); - L2m1 = glm::vec3(-0.12f, -0.09f, -0.08f); - L20 = glm::vec3(-0.37f, -0.28f, -0.32f); - L21 = glm::vec3(-0.17f, -0.13f, -0.13f); - L22 = glm::vec3( 0.55f, 0.42f, 0.42f); - } - break; - case DeferredLightingEffect::VINE_STREET_KITCHEN: { - L00 = glm::vec3( 0.64f, 0.67f, 0.73f); - L1m1 = glm::vec3( 0.28f, 0.32f, 0.33f); - L10 = glm::vec3( 0.42f, 0.60f, 0.77f); - L11 = glm::vec3(-0.05f, -0.04f, -0.02f); - L2m2 = glm::vec3(-0.10f, -0.08f, -0.05f); - L2m1 = glm::vec3( 0.25f, 0.39f, 0.53f); - L20 = glm::vec3( 0.38f, 0.54f, 0.71f); - L21 = glm::vec3( 0.06f, 0.01f, -0.02f); - L22 = glm::vec3(-0.03f, -0.02f, -0.03f); - } - break; - case DeferredLightingEffect::BREEZEWAY: { - L00 = glm::vec3( 0.32f, 0.36f, 0.38f); - L1m1 = glm::vec3( 0.37f, 0.41f, 0.45f); - L10 = glm::vec3(-0.01f, -0.01f, -0.01f); - L11 = glm::vec3(-0.10f, -0.12f, -0.12f); - L2m2 = glm::vec3(-0.13f, -0.15f, -0.17f); - L2m1 = glm::vec3(-0.01f, -0.02f, 0.02f); - L20 = glm::vec3(-0.07f, -0.08f, -0.09f); - L21 = glm::vec3( 0.02f, 0.03f, 0.03f); - L22 = glm::vec3(-0.29f, -0.32f, -0.36f); - } - break; - case DeferredLightingEffect::CAMPUS_SUNSET: { - L00 = glm::vec3( 0.79f, 0.94f, 0.98f); - L1m1 = glm::vec3( 0.44f, 0.56f, 0.70f); - L10 = glm::vec3(-0.10f, -0.18f, -0.27f); - L11 = glm::vec3( 0.45f, 0.38f, 0.20f); - L2m2 = glm::vec3( 0.18f, 0.14f, 0.05f); - L2m1 = glm::vec3(-0.14f, -0.22f, -0.31f); - L20 = glm::vec3(-0.39f, -0.40f, -0.36f); - L21 = glm::vec3( 0.09f, 0.07f, 0.04f); - L22 = glm::vec3( 0.67f, 0.67f, 0.52f); - } - break; - case DeferredLightingEffect::FUNSTON_BEACH_SUNSET: { - L00 = glm::vec3( 0.68f, 0.69f, 0.70f); - L1m1 = glm::vec3( 0.32f, 0.37f, 0.44f); - L10 = glm::vec3(-0.17f, -0.17f, -0.17f); - L11 = glm::vec3(-0.45f, -0.42f, -0.34f); - L2m2 = glm::vec3(-0.17f, -0.17f, -0.15f); - L2m1 = glm::vec3(-0.08f, -0.09f, -0.10f); - L20 = glm::vec3(-0.03f, -0.02f, -0.01f); - L21 = glm::vec3( 0.16f, 0.14f, 0.10f); - L22 = glm::vec3( 0.37f, 0.31f, 0.20f); - } - break; - } - } -}; - void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { _viewState = viewState; _simpleProgram.addShaderFromSourceCode(QGLShader::Vertex, simple_vert); @@ -206,6 +69,18 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { loadLightProgram(point_light_frag, true, _pointLight, _pointLightLocations); loadLightProgram(spot_light_frag, true, _spotLight, _spotLightLocations); + + // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light + _globalLights.push_back(0); + _allocatedLights.push_back(model::LightPointer(new model::Light())); + + model::LightPointer lp = _allocatedLights[0]; + + lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f)); + lp->setColor(glm::vec3(1.0f)); + lp->setIntensity(1.0f); + lp->setType(model::Light::SUN); + lp->setAmbientSpherePreset(model::SphericalHarmonics::Preset(_ambientLightMode % model::SphericalHarmonics::NUM_PRESET)); } void DeferredLightingEffect::bindSimpleProgram() { @@ -260,30 +135,29 @@ void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radi void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular, float constantAttenuation, float linearAttenuation, float quadraticAttenuation, const glm::vec3& direction, float exponent, float cutoff) { + + int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size(); + if (lightID >= _allocatedLights.size()) { + _allocatedLights.push_back(model::LightPointer(new model::Light())); + } + model::LightPointer lp = _allocatedLights[lightID]; + + lp->setPosition(position); + lp->setMaximumRadius(radius); + lp->setColor(diffuse); + lp->setIntensity(1.0f); + //lp->setShowContour(quadraticAttenuation); + if (exponent == 0.0f && cutoff == PI) { - PointLight light; - light.position = glm::vec4(position, 1.0f); - light.radius = radius; - light.ambient = glm::vec4(ambient, 1.0f); - light.diffuse = glm::vec4(diffuse, 1.0f); - light.specular = glm::vec4(specular, 1.0f); - light.constantAttenuation = constantAttenuation; - light.linearAttenuation = linearAttenuation; - _pointLights.append(light); + lp->setType(model::Light::POINT); + _pointLights.push_back(lightID); } else { - SpotLight light; - light.position = glm::vec4(position, 1.0f); - light.radius = radius; - light.ambient = glm::vec4(ambient, 1.0f); - light.diffuse = glm::vec4(diffuse, 1.0f); - light.specular = glm::vec4(specular, 1.0f); - light.constantAttenuation = constantAttenuation; - light.linearAttenuation = linearAttenuation; - light.direction = direction; - light.exponent = exponent; - light.cutoff = cutoff; - _spotLights.append(light); + lp->setDirection(direction); + lp->setSpotAngle(cutoff); + lp->setSpotExponent(exponent); + lp->setType(model::Light::SPOT); + _spotLights.push_back(lightID); } } @@ -317,7 +191,7 @@ void DeferredLightingEffect::render() { QOpenGLFramebufferObject* freeFBO = DependencyManager::get()->getFreeFramebufferObject(); freeFBO->bind(); glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_FRAMEBUFFER_SRGB); + // glEnable(GL_FRAMEBUFFER_SRGB); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); @@ -342,6 +216,10 @@ void DeferredLightingEffect::render() { float tMin = viewport[VIEWPORT_Y_INDEX] / (float)primaryFBO->height(); float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)primaryFBO->height(); + // Fetch the ViewMatrix; + glm::mat4 invViewMat; + _viewState->getViewTransform().getMatrix(invViewMat); + ProgramObject* program = &_directionalLight; const LightLocations* locations = &_directionalLightLocations; bool shadowsEnabled = _viewState->getShadowsEnabled(); @@ -379,19 +257,24 @@ void DeferredLightingEffect::render() { program->bind(); } - if (locations->ambientSphere >= 0) { - SphericalHarmonics sh; - if (_ambientLightMode < NUM_PRESET) { - sh.assignPreset(_ambientLightMode); - } else { - sh.assignPreset(0); - } - - for (int i =0; i setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i)); - } - } + { + auto globalLight = _allocatedLights[_globalLights.front()]; + if (locations->ambientSphere >= 0) { + auto sh = globalLight->getAmbientSphere(); + for (int i =0; i setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i)); + } + } + + if (locations->lightBufferUnit >= 0) { + gpu::Batch batch; + batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer()); + gpu::GLBackend::renderBatch(batch); + } + glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); + } + float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; _viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); @@ -434,27 +317,27 @@ void DeferredLightingEffect::render() { auto geometryCache = DependencyManager::get(); - if (!_pointLights.isEmpty()) { + if (!_pointLights.empty()) { _pointLight.bind(); _pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal); _pointLight.setUniformValue(_pointLightLocations.depthScale, depthScale); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); - foreach (const PointLight& light, _pointLights) { - _pointLight.setUniformValue(_pointLightLocations.radius, light.radius); - glLightfv(GL_LIGHT1, GL_AMBIENT, (const GLfloat*)&light.ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular); - glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position); - glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (light.constantAttenuation > 0.0f ? light.constantAttenuation : 0.0f)); - glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, (light.linearAttenuation > 0.0f ? light.linearAttenuation : 0.0f)); - glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (light.quadraticAttenuation > 0.0f ? light.quadraticAttenuation : 0.0f)); - + for (auto lightID : _pointLights) { + auto light = _allocatedLights[lightID]; + + if (_pointLightLocations.lightBufferUnit >= 0) { + gpu::Batch batch; + batch.setUniformBuffer(_pointLightLocations.lightBufferUnit, light->getSchemaBuffer()); + gpu::GLBackend::renderBatch(batch); + } + glUniformMatrix4fv(_pointLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); + glPushMatrix(); - float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION); - if (glm::distance(eyePoint, glm::vec3(light.position)) < expandedRadius + nearRadius) { + float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); + if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); @@ -468,7 +351,7 @@ void DeferredLightingEffect::render() { glMatrixMode(GL_MODELVIEW); } else { - glTranslatef(light.position.x, light.position.y, light.position.z); + glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z); geometryCache->renderSphere(expandedRadius, 32, 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } @@ -479,31 +362,28 @@ void DeferredLightingEffect::render() { _pointLight.release(); } - if (!_spotLights.isEmpty()) { + if (!_spotLights.empty()) { _spotLight.bind(); _spotLight.setUniformValue(_spotLightLocations.nearLocation, nearVal); _spotLight.setUniformValue(_spotLightLocations.depthScale, depthScale); _spotLight.setUniformValue(_spotLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _spotLight.setUniformValue(_spotLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); - foreach (const SpotLight& light, _spotLights) { - _spotLight.setUniformValue(_spotLightLocations.radius, light.radius); - glLightfv(GL_LIGHT1, GL_AMBIENT, (const GLfloat*)&light.ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular); - glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position); - glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (light.constantAttenuation > 0.0f ? light.constantAttenuation : 0.0f)); - glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, (light.linearAttenuation > 0.0f ? light.linearAttenuation : 0.0f)); - glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (light.quadraticAttenuation > 0.0f ? light.quadraticAttenuation : 0.0f)); - glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, (const GLfloat*)&light.direction); - glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, light.exponent); - glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, glm::degrees(light.cutoff)); - + for (auto lightID : _spotLights) { + auto light = _allocatedLights[lightID]; + + if (_spotLightLocations.lightBufferUnit >= 0) { + gpu::Batch batch; + batch.setUniformBuffer(_spotLightLocations.lightBufferUnit, light->getSchemaBuffer()); + gpu::GLBackend::renderBatch(batch); + } + glUniformMatrix4fv(_spotLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); + glPushMatrix(); - float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION); - float edgeRadius = expandedRadius / glm::cos(light.cutoff); - if (glm::distance(eyePoint, glm::vec3(light.position)) < edgeRadius + nearRadius) { + float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); + float edgeRadius = expandedRadius / glm::cos(light->getSpotAngle()); + if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < edgeRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); @@ -517,12 +397,12 @@ void DeferredLightingEffect::render() { glMatrixMode(GL_MODELVIEW); } else { - glTranslatef(light.position.x, light.position.y, light.position.z); - glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light.direction); + glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z); + glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light->getDirection()); glm::vec3 axis = glm::axis(spotRotation); glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z); - glTranslatef(0.0f, 0.0f, -light.radius * (1.0f + SCALE_EXPANSION * 0.5f)); - geometryCache->renderCone(expandedRadius * glm::tan(light.cutoff), + glTranslatef(0.0f, 0.0f, -light->getMaximumRadius() * (1.0f + SCALE_EXPANSION * 0.5f)); + geometryCache->renderCone(expandedRadius * glm::tan(light->getSpotAngle()), expandedRadius, 32, 1); } @@ -545,7 +425,7 @@ void DeferredLightingEffect::render() { glBindTexture(GL_TEXTURE_2D, 0); freeFBO->release(); - glDisable(GL_FRAMEBUFFER_SRGB); + // glDisable(GL_FRAMEBUFFER_SRGB); glDisable(GL_CULL_FACE); @@ -607,11 +487,46 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale"); locations.radius = program.uniformLocation("radius"); locations.ambientSphere = program.uniformLocation("ambientSphere.L00"); + locations.invViewMat = program.uniformLocation("invViewMat"); + + GLint loc = -1; +#if defined(Q_OS_MAC) + loc = program.uniformLocation("lightBuffer"); + if (loc >= 0) { + locations.lightBufferUnit = loc; + } else { + locations.lightBufferUnit = -1; + } +#elif defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "lightBuffer"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, 0); + locations.lightBufferUnit = 0; + } else { + locations.lightBufferUnit = -1; + } +#else + loc = program.uniformLocation("lightBuffer"); + if (loc >= 0) { + locations.lightBufferUnit = loc; + } else { + locations.lightBufferUnit = -1; + } +#endif program.release(); } void DeferredLightingEffect::setAmbientLightMode(int preset) { - if ((preset >= -1) && (preset < NUM_PRESET)) { + if ((preset >= -1) && (preset < model::SphericalHarmonics::NUM_PRESET)) { _ambientLightMode = preset; + auto light = _allocatedLights.front(); + light->setAmbientSpherePreset(model::SphericalHarmonics::Preset(preset % model::SphericalHarmonics::NUM_PRESET)); } } + +void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity) { + auto light = _allocatedLights.front(); + light->setDirection(direction); + light->setColor(diffuse); + light->setIntensity(intensity); +} diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 6c563605ea..eeb92f19c7 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -19,6 +19,8 @@ #include "ProgramObject.h" +#include "model/Light.h" + class AbstractViewStateInterface; class PostLightingRenderable; @@ -71,25 +73,12 @@ public: void prepare(); void render(); - enum AmbientLightPreset { - OLD_TOWN_SQUARE = 0, - GRACE_CATHEDRAL, - EUCALYPTUS_GROVE, - ST_PETERS_BASILICA, - UFFIZI_GALLERY, - GALILEOS_TOMB, - VINE_STREET_KITCHEN, - BREEZEWAY, - CAMPUS_SUNSET, - FUNSTON_BEACH_SUNSET, - - NUM_PRESET, - }; - + // update global lighting void setAmbientLightMode(int preset); + void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity); private: - DeferredLightingEffect() { } + DeferredLightingEffect() {} virtual ~DeferredLightingEffect() { } class LightLocations { @@ -102,6 +91,8 @@ private: int depthTexCoordScale; int radius; int ambientSphere; + int lightBufferUnit; + int invViewMat; }; static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations); @@ -146,9 +137,13 @@ private: float exponent; float cutoff; }; - - QVector _pointLights; - QVector _spotLights; + + typedef std::vector< model::LightPointer > Lights; + + Lights _allocatedLights; + std::vector _globalLights; + std::vector _pointLights; + std::vector _spotLights; QVector _postLightingRenderables; AbstractViewStateInterface* _viewState; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2d9791409f..dffadc730f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1154,7 +1154,7 @@ void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxC gpu::Batch batch; - glEnable(GL_TEXTURE_2D); +// glEnable(GL_TEXTURE_2D); //glBindTexture(GL_TEXTURE_2D, _currentTextureID); // this is quad specific... batch.setInputFormat(details.streamFormat); @@ -1168,8 +1168,8 @@ void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxC glDisableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); + // glBindTexture(GL_TEXTURE_2D, 0); + // glDisable(GL_TEXTURE_2D); } void GeometryCache::renderQuad(const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color, int id) { diff --git a/libraries/render-utils/src/Light.slh b/libraries/render-utils/src/Light.slh new file mode 100755 index 0000000000..abb9fb6c2a --- /dev/null +++ b/libraries/render-utils/src/Light.slh @@ -0,0 +1,107 @@ + +<@if not LIGHT_SLH@> +<@def LIGHT_SLH@> + +struct Light { + vec4 _position; + vec4 _direction; + vec4 _color; + vec4 _attenuation; + vec4 _spot; + + vec4 _shadow; + + vec4 _control; +}; + +vec3 getLightPosition(Light l) { return l._position.xyz; } +vec3 getLightDirection(Light l) { return l._direction.xyz; } // direction is -Z axis + +vec3 getLightColor(Light l) { return l._color.rgb; } +float getLightIntensity(Light l) { return l._color.w; } + +float evalLightAttenuation(Light l, float r) { + float d = max(r - l._attenuation.x, 0.0); + float denom = d * l._attenuation.y + 1.0; + float attenuation = 1.0 / (denom * denom); + return max((attenuation - l._attenuation.z)/(1.0 - l._attenuation.z), 0.0); + // return clamp(1.0/(l._attenuation.x + l._attenuation.y * r + l._attenuation.z * r * r), 0.0, 1.0); +} + +float getLightSpotAngleCos(Light l) { + return l._spot.x; +} + +vec2 getLightSpotOutsideNormal2(Light l) { + return vec2(-l._spot.y, l._spot.x); +} + +float evalLightSpotAttenuation(Light l, float cosA) { + return pow(cosA, l._spot.w); +} + +float getLightSquareRadius(Light l) { + return l._attenuation.w * l._attenuation.w; +} + +float getLightRadius(Light l) { + return l._attenuation.w; +} + +float getLightAttenuationCutoff(Light l) { + return l._attenuation.z; +} + +float getLightShowContour(Light l) { + return l._control.w; +} + +<@if GLPROFILE == PC_GL@> +uniform lightBuffer { + Light light; +}; +Light getLight() { + return light; +} +<@elif GLPROFILE == MAC_GL@> +uniform vec4 lightBuffer[9]; +Light getLight() { + Light light; + light._position = lightBuffer[0]; + light._direction = lightBuffer[1]; + light._color = lightBuffer[2]; + light._attenuation = lightBuffer[3]; + light._spot = lightBuffer[4]; + light._shadow = lightBuffer[5]; + light._control = lightBuffer[6]; + + return light; +} +<@else@> +uniform vec4 lightBuffer[9]; +Light getLight() { + Light light; + light._position = lightBuffer[0]; + light._direction = lightBuffer[1]; + light._color = lightBuffer[2]; + light._attenuation = lightBuffer[3]; + light._spot = lightBuffer[4]; + light._shadow = lightBuffer[5]; + light._control = lightBuffer[6]; + + return light; +} +<@endif@> + + + +<@endif@> diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index 803bd5ac30..308a8a73a7 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -15,22 +15,23 @@ // Everything about deferred buffer <@include DeferredBuffer.slh@> -<@include DeferredLighting.slh@> +<@include DeferredGlobalLight.slh@> void main(void) { DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st); + // Light mapped or not ? if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { - gl_FragColor = vec4( evalLightmappedColor( + vec3 color = evalLightmappedColor( 1.0, frag.normal, frag.diffuse, - frag.specularVal.xyz), - 1.0); + frag.specularVal.xyz); + + gl_FragColor = vec4(color, 1.0); } else { - vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss) - + evalDirectionalColor(1.0, + vec3 color = evalAmbienSphereGlobalColor(1.0, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf b/libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf index 5f88c558d3..db017cf5ac 100755 --- a/libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf +++ b/libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf @@ -15,7 +15,7 @@ // Everything about deferred buffer <@include DeferredBuffer.slh@> -<@include DeferredLighting.slh@> +<@include DeferredGlobalLight.slh@> // Everything about shadow <@include Shadow.slh@> @@ -36,8 +36,7 @@ void main(void) { frag.specularVal.xyz), 1.0); } else { - vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss) - + evalDirectionalColor(shadowAttenuation, + vec3 color = evalAmbienSphereGlobalColor(shadowAttenuation, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_ambient_light_shadow_map.slf b/libraries/render-utils/src/directional_ambient_light_shadow_map.slf index 6c241853e3..43d3e91dbe 100755 --- a/libraries/render-utils/src/directional_ambient_light_shadow_map.slf +++ b/libraries/render-utils/src/directional_ambient_light_shadow_map.slf @@ -15,7 +15,7 @@ // Everything about deferred buffer <@include DeferredBuffer.slh@> -<@include DeferredLighting.slh@> +<@include DeferredGlobalLight.slh@> // Everything about shadow <@include Shadow.slh@> @@ -37,8 +37,7 @@ void main(void) { frag.specularVal.xyz), 1.0); } else { - vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss) - + evalDirectionalColor(shadowAttenuation, + vec3 color = evalAmbienSphereGlobalColor(shadowAttenuation, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index 8ff6cd6c87..3e708f849e 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -15,7 +15,7 @@ // Everything about deferred buffer <@include DeferredBuffer.slh@> -<@include DeferredLighting.slh@> +<@include DeferredGlobalLight.slh@> void main(void) { DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st); @@ -29,8 +29,7 @@ void main(void) { frag.specularVal.xyz), 1.0); } else { - vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss) - + evalDirectionalColor(1.0, + vec3 color = evalAmbienGlobalColor(1.0, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf index ccf8909b64..90b3bf1d2b 100644 --- a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf +++ b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf @@ -15,7 +15,7 @@ // Everything about deferred buffer <@include DeferredBuffer.slh@> -<@include DeferredLighting.slh@> +<@include DeferredGlobalLight.slh@> // Everything about shadow <@include Shadow.slh@> @@ -36,8 +36,7 @@ void main(void) { frag.specularVal.xyz), 1.0); } else { - vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss) - + evalDirectionalColor(shadowAttenuation, + vec3 color = evalAmbienGlobalColor(shadowAttenuation, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_light_shadow_map.slf b/libraries/render-utils/src/directional_light_shadow_map.slf index 13435e9101..5029b57020 100644 --- a/libraries/render-utils/src/directional_light_shadow_map.slf +++ b/libraries/render-utils/src/directional_light_shadow_map.slf @@ -15,7 +15,7 @@ // Everything about deferred buffer <@include DeferredBuffer.slh@> -<@include DeferredLighting.slh@> +<@include DeferredGlobalLight.slh@> // Everything about shadow <@include Shadow.slh@> @@ -37,8 +37,7 @@ void main(void) { frag.specularVal.xyz), 1.0); } else { - vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss) - + evalDirectionalColor(shadowAttenuation, + vec3 color = evalAmbienGlobalColor(shadowAttenuation, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/model_lightmap.slv b/libraries/render-utils/src/model_lightmap.slv index 23d99b399a..1ea5b7b68a 100755 --- a/libraries/render-utils/src/model_lightmap.slv +++ b/libraries/render-utils/src/model_lightmap.slv @@ -33,8 +33,9 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0); + // interpolatedTexcoord1 = vec2(texcoordMatrices[1] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0)).xy; interpolatedTexcoord1 = vec2(texcoordMatrices[1] * vec4(texcoord1.xy, 0.0, 1.0)).xy; - + // use standard pipeline transform gl_Position = ftransform(); } diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index e5142b25ce..abe904ecce 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -15,41 +15,61 @@ // Everything about deferred buffer <@include DeferredBuffer.slh@> -// the radius (hard cutoff) of the light effect -uniform float radius; +//Everything about deferred lighting +<@include DeferredLighting.slh@> + +// Everything about light +<@include Light.slh@> + +// The view Matrix +uniform mat4 invViewMat; void main(void) { - // get the depth and exit early if it doesn't pass the test + // Grab the fragment data from the uv vec2 texCoord = gl_TexCoord[0].st / gl_TexCoord[0].q; - float depth = texture2D(depthMap, texCoord).r; + DeferredFragment frag = unpackDeferredFragment(texCoord); + + // Kill if in front of the light volume + float depth = frag.depthVal; if (depth < gl_FragCoord.z) { discard; } - // compute the view space position using the depth - float z = near / (depth * depthScale - 1.0); - vec4 position = vec4((depthTexCoordOffset + texCoord * depthTexCoordScale) * z, z, 1.0); - - // get the normal from the map - vec4 normal = texture2D(normalMap, texCoord); - vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0)); - - // compute the base color based on OpenGL lighting model - vec4 lightVector = gl_LightSource[1].position - position; - float lightDistance = length(lightVector); - lightVector = lightVector / lightDistance; - float diffuse = dot(normalizedNormal, lightVector); - float facingLight = step(0.0, diffuse); - vec4 baseColor = texture2D(diffuseMap, texCoord) * (gl_FrontLightProduct[1].ambient + - gl_FrontLightProduct[1].diffuse * (diffuse * facingLight)); - - // compute attenuation based on distance, etc. - float attenuation = step(lightDistance, radius) / dot(vec3(gl_LightSource[1].constantAttenuation, - gl_LightSource[1].linearAttenuation, gl_LightSource[1].quadraticAttenuation), - vec3(1.0, lightDistance, lightDistance * lightDistance)); - - // add base to specular, modulate by attenuation - float specular = facingLight * max(0.0, dot(normalize(lightVector - normalize(vec4(position.xyz, 0.0))), - normalizedNormal)); - vec4 specularColor = texture2D(specularMap, texCoord); - gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0); + + // Need the light now + Light light = getLight(); + + // Make the Light vector going from fragment to light center in world space + vec4 fragPos = invViewMat * frag.position; + vec3 fragLightVec = getLightPosition(light) - fragPos.xyz; + + // Kill if too far from the light center + if (dot(fragLightVec, fragLightVec) > getLightSquareRadius(light)) { + discard; + } + + // Allright we re valid in the volume + float fragLightDistance = length(fragLightVec); + vec3 fragLightDir = fragLightVec / fragLightDistance; + + // Eval shading + vec3 fragNormal = vec3(invViewMat * vec4(frag.normal, 0.0)); + vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); + vec3 fragEyeDir = normalize(fragEyeVector.xyz); + vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.specular, frag.gloss); + + // Eval attenuation + float radialAttenuation = evalLightAttenuation(light, fragLightDistance); + + // Final Lighting color + vec3 fragColor = shading.w * (frag.diffuse + shading.xyz); + gl_FragColor = vec4(fragColor * radialAttenuation * getLightColor(light) * getLightIntensity(light), 0.0); + + if (getLightShowContour(light) > 0.0) { + // Show edge + float edge = abs(2.0 * ((getLightRadius(light) - fragLightDistance) / (0.1)) - 1.0); + if (edge < 1) { + float edgeCoord = exp2(-8.0*edge*edge); + gl_FragColor = vec4(edgeCoord * edgeCoord * getLightShowContour(light) * getLightColor(light), 0.0); + } + } } diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index f987760eb8..95fabae3ed 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -15,43 +15,73 @@ // Everything about deferred buffer <@include DeferredBuffer.slh@> -// the radius (hard cutoff) of the light effect -uniform float radius; +//Everything about deferred lighting +<@include DeferredLighting.slh@> + +// Everything about light +<@include Light.slh@> + +// The view Matrix +uniform mat4 invViewMat; void main(void) { - // get the depth and exit early if it doesn't pass the test + // Grab the fragment data from the uv vec2 texCoord = gl_TexCoord[0].st / gl_TexCoord[0].q; - float depth = texture2D(depthMap, texCoord).r; + DeferredFragment frag = unpackDeferredFragment(texCoord); + + // Kill if in front of the light volume + float depth = frag.depthVal; if (depth < gl_FragCoord.z) { discard; } - // compute the view space position using the depth - float z = near / (depth * depthScale - 1.0); - vec4 position = vec4((depthTexCoordOffset + texCoord * depthTexCoordScale) * z, z, 1.0); - - // get the normal from the map - vec4 normal = texture2D(normalMap, texCoord); - vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0)); - - // compute the base color based on OpenGL lighting model - vec4 lightVector = gl_LightSource[1].position - position; - float lightDistance = length(lightVector); - lightVector = lightVector / lightDistance; - float diffuse = dot(normalizedNormal, lightVector); - float facingLight = step(0.0, diffuse); - vec4 baseColor = texture2D(diffuseMap, texCoord) * (gl_FrontLightProduct[1].ambient + - gl_FrontLightProduct[1].diffuse * (diffuse * facingLight)); - - // compute attenuation based on spot angle, distance, etc. - float cosSpotAngle = max(-dot(lightVector.xyz, gl_LightSource[1].spotDirection), 0.0); - float attenuation = step(lightDistance, radius) * step(gl_LightSource[1].spotCosCutoff, cosSpotAngle) * - pow(cosSpotAngle, gl_LightSource[1].spotExponent) / dot(vec3(gl_LightSource[1].constantAttenuation, - gl_LightSource[1].linearAttenuation, gl_LightSource[1].quadraticAttenuation), - vec3(1.0, lightDistance, lightDistance * lightDistance)); - - // add base to specular, modulate by attenuation - float specular = facingLight * max(0.0, dot(normalize(lightVector - normalize(vec4(position.xyz, 0.0))), - normalizedNormal)); - vec4 specularColor = texture2D(specularMap, texCoord); - gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0); + + // Need the light now + Light light = getLight(); + + // Make the Light vector going from fragment to light center in world space + vec4 fragPos = invViewMat * frag.position; + vec3 fragLightVec = getLightPosition(light) - fragPos.xyz; + + // Kill if too far from the light center + if (dot(fragLightVec, fragLightVec) > getLightSquareRadius(light)) { + discard; + } + + // Allright we re valid in the volume + float fragLightDistance = length(fragLightVec); + vec3 fragLightDir = fragLightVec / fragLightDistance; + + // Kill if not in the spot light (ah ah !) + vec3 lightSpotDir = getLightDirection(light); + float cosSpotAngle = max(-dot(fragLightDir, lightSpotDir), 0.0); + if (cosSpotAngle < getLightSpotAngleCos(light)) { + discard; + } + + // Eval shading + vec3 fragNormal = vec3(invViewMat * vec4(frag.normal, 0.0)); + vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); + vec3 fragEyeDir = normalize(fragEyeVector.xyz); + vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.specular, frag.gloss); + + // Eval attenuation + float radialAttenuation = evalLightAttenuation(light, fragLightDistance); + float angularAttenuation = evalLightSpotAttenuation(light, cosSpotAngle); + + // Final Lighting color + vec3 fragColor = shading.w * (frag.diffuse + shading.xyz); + gl_FragColor = vec4(fragColor * angularAttenuation * radialAttenuation * getLightColor(light) * getLightIntensity(light), 0.0); + + if (getLightShowContour(light) > 0.0) { + // Show edges + float edgeDistR = (getLightRadius(light) - fragLightDistance); + float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -getLightSpotOutsideNormal2(light)); + float edgeDist = min(edgeDistR, edgeDistS); + float edge = abs(2.0 * (edgeDist / (0.1)) - 1.0); + if (edge < 1) { + float edgeCoord = exp2(-8.0*edge*edge); + gl_FragColor = vec4(edgeCoord * edgeCoord * getLightColor(light), 0.0); + } + } } + diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp similarity index 52% rename from libraries/audio/src/AudioScriptingInterface.cpp rename to libraries/script-engine/src/AudioScriptingInterface.cpp index 58b72f3fcd..32b9eb23e2 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ScriptAudioInjector.h" + #include "AudioScriptingInterface.h" void registerAudioMetaTypes(QScriptEngine* engine) { @@ -28,80 +30,45 @@ AudioScriptingInterface::AudioScriptingInterface() : } -void AudioScriptingInterface::stopAllInjectors() { - QList >::iterator injector = _activeInjectors.begin(); - while (injector != _activeInjectors.end()) { - if (!injector->isNull()) { - injector->data()->stop(); - - while (injector->data() && !injector->data()->isFinished()) { - // wait for this injector to go down - } - } - - injector = _activeInjectors.erase(injector); +ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { + AudioInjector* injector = NULL; + QMetaObject::invokeMethod(this, "invokedPlaySound", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(AudioInjector*, injector), + Q_ARG(Sound*, sound), Q_ARG(const AudioInjectorOptions&, injectorOptions)); + if (injector) { + return new ScriptAudioInjector(injector); + } else { + return NULL; } } -AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { +AudioInjector* AudioScriptingInterface::invokedPlaySound(Sound* sound, const AudioInjectorOptions& injectorOptions) { if (sound) { // stereo option isn't set from script, this comes from sound metadata or filename AudioInjectorOptions optionsCopy = injectorOptions; optionsCopy.stereo = sound->isStereo(); - AudioInjector* injector = new AudioInjector(sound, optionsCopy); - injector->setLocalAudioInterface(_localAudioInterface); - QThread* injectorThread = new QThread(); injectorThread->setObjectName("Audio Injector Thread"); + AudioInjector* injector = new AudioInjector(sound, optionsCopy); + injector->setLocalAudioInterface(_localAudioInterface); + injector->moveToThread(injectorThread); // start injecting when the injector thread starts connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio); - // connect the right slots and signals so that the AudioInjector is killed once the injection is complete - connect(injector, &AudioInjector::finished, injector, &AudioInjector::deleteLater); - connect(injector, &AudioInjector::finished, injectorThread, &QThread::quit); - connect(injector, &AudioInjector::finished, this, &AudioScriptingInterface::injectorStopped); + // connect the right slots and signals for AudioInjector and thread cleanup + connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit); connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); injectorThread->start(); - _activeInjectors.append(QPointer(injector)); - return injector; + } else { qDebug() << "AudioScriptingInterface::playSound called with null Sound object."; return NULL; } } - -void AudioScriptingInterface::stopInjector(AudioInjector* injector) { - if (injector) { - injector->stop(); - } -} - -bool AudioScriptingInterface::isInjectorPlaying(AudioInjector* injector) { - return (injector != NULL); -} - -void AudioScriptingInterface::setInjectorOptions(AudioInjector* injector, const AudioInjectorOptions& injectorOptions) { - AudioInjectorOptions optionsCopy = injectorOptions; - if (injector) { - injector->setOptions(optionsCopy); - } -} - -float AudioScriptingInterface::getLoudness(AudioInjector* injector) { - if (injector) { - return injector->getLoudness(); - } else { - return 0.0f; - } -} - -void AudioScriptingInterface::injectorStopped() { - _activeInjectors.removeAll(QPointer(reinterpret_cast(sender()))); -} diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h similarity index 58% rename from libraries/audio/src/AudioScriptingInterface.h rename to libraries/script-engine/src/AudioScriptingInterface.h index b437286ecf..ed52d951ad 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -12,40 +12,32 @@ #ifndef hifi_AudioScriptingInterface_h #define hifi_AudioScriptingInterface_h -#include +#include +#include +#include -#include "AbstractAudioInterface.h" -#include "AudioInjector.h" -#include "Sound.h" +class ScriptAudioInjector; class AudioScriptingInterface : public QObject { Q_OBJECT public: static AudioScriptingInterface& getInstance(); - void stopAllInjectors(); - void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } -public slots: - - static float getLoudness(AudioInjector* injector); - - AudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); - void stopInjector(AudioInjector* injector); - bool isInjectorPlaying(AudioInjector* injector); - - void setInjectorOptions(AudioInjector* injector, const AudioInjectorOptions& injectorOptions); - - void injectorStopped(); +protected: + // this method is protected to stop C++ callers from calling, but invokable from script + Q_INVOKABLE ScriptAudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); signals: void mutedByMixer(); void environmentMuted(); +private slots: + AudioInjector* invokedPlaySound(Sound* sound, const AudioInjectorOptions& injectorOptions); + private: AudioScriptingInterface(); - QList< QPointer > _activeInjectors; AbstractAudioInterface* _localAudioInterface; }; diff --git a/libraries/script-engine/src/ScriptAudioInjector.cpp b/libraries/script-engine/src/ScriptAudioInjector.cpp new file mode 100644 index 0000000000..beb056468f --- /dev/null +++ b/libraries/script-engine/src/ScriptAudioInjector.cpp @@ -0,0 +1,40 @@ +// +// ScriptAudioInjector.cpp +// libraries/script-engine/src +// +// Created by Stephen Birarda on 2015-02-11. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptAudioInjector.h" + +QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in) { + // when the script goes down we want to cleanup the injector + QObject::connect(engine, &QScriptEngine::destroyed, in, &ScriptAudioInjector::stopInjectorImmediately); + + return engine->newQObject(in, QScriptEngine::ScriptOwnership); +} + +void injectorFromScriptValue(const QScriptValue& object, ScriptAudioInjector*& out) { + out = qobject_cast(object.toQObject()); +} + +ScriptAudioInjector::ScriptAudioInjector(AudioInjector* injector) : + _injector(injector) +{ + +} + +ScriptAudioInjector::~ScriptAudioInjector() { + if (!_injector.isNull()) { + // we've been asked to delete after finishing, trigger a queued deleteLater here + _injector->triggerDeleteAfterFinish(); + } +} + +void ScriptAudioInjector::stopInjectorImmediately() { + _injector->stopAndDeleteLater(); +} diff --git a/libraries/script-engine/src/ScriptAudioInjector.h b/libraries/script-engine/src/ScriptAudioInjector.h new file mode 100644 index 0000000000..b89a274af1 --- /dev/null +++ b/libraries/script-engine/src/ScriptAudioInjector.h @@ -0,0 +1,52 @@ +// +// ScriptAudioInjector.h +// libraries/script-engine/src +// +// Created by Stephen Birarda on 2015-02-11. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptAudioInjector_h +#define hifi_ScriptAudioInjector_h + +#include + +#include + +class ScriptAudioInjector : public QObject { + Q_OBJECT + + Q_PROPERTY(bool isPlaying READ isPlaying) + Q_PROPERTY(float loudness READ getLoudness) +public: + ScriptAudioInjector(AudioInjector* injector); + ~ScriptAudioInjector(); +public slots: + void restart() { _injector->restart(); } + void stop() { _injector->stop(); } + + void setOptions(AudioInjectorOptions& options) { _injector->setOptions(options); } + + float getLoudness() const { return _injector->getLoudness(); } + bool isPlaying() const { return _injector->isPlaying(); } + +signals: + void finished(); + +protected slots: + void stopInjectorImmediately(); +private: + QPointer _injector; + + friend QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in); +}; + +Q_DECLARE_METATYPE(ScriptAudioInjector*) + +QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in); +void injectorFromScriptValue(const QScriptValue& object, ScriptAudioInjector*& out); + +#endif // hifi_ScriptAudioInjector_h \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 353e215561..062bb0ca06 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -35,6 +34,7 @@ #include "DataViewClass.h" #include "EventTypes.h" #include "MenuItemProperties.h" +#include "ScriptAudioInjector.h" #include "ScriptEngine.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index f78a14bffa..6cc9f64d4c 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -19,13 +19,13 @@ #include #include -#include #include #include #include #include "AbstractControllerScriptingInterface.h" #include "ArrayBufferClass.h" +#include "AudioScriptingInterface.h" #include "Quat.h" #include "ScriptUUID.h" #include "Vec3.h" diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index e08f00c0ac..346a82a3b0 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -100,6 +100,8 @@ public: // Left will be inversed before the multiplication static Transform& inverseMult(Transform& result, const Transform& left, const Transform& right); + Vec4 transform(const Vec4& pos) const; + protected: enum Flag { @@ -414,6 +416,13 @@ inline Transform& Transform::inverseMult( Transform& result, const Transform& le return result; } +inline Transform::Vec4 Transform::transform(const Vec4& pos) const { + Mat4 m; + getMatrix(m); + return m * pos; +} + + inline Transform::Mat4& Transform::getCachedMatrix(Transform::Mat4& result) const { updateCache(); result = (*_matrix);