mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
Merge remote-tracking branch 'upstream/master' into 20315
This commit is contained in:
commit
81d4af86a7
58 changed files with 1357 additions and 674 deletions
|
@ -125,6 +125,8 @@ if (NOT ANDROID)
|
||||||
add_subdirectory(interface)
|
add_subdirectory(interface)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
add_subdirectory(tools)
|
add_subdirectory(tools)
|
||||||
elseif (ANDROID OR DESKTOP_GVR)
|
endif ()
|
||||||
|
|
||||||
|
if (ANDROID OR DESKTOP_GVR)
|
||||||
add_subdirectory(gvr-interface)
|
add_subdirectory(gvr-interface)
|
||||||
endif ()
|
endif ()
|
|
@ -32,10 +32,4 @@ Script.update.connect(function() {
|
||||||
injector = Audio.playSound(sound, audioOptions);
|
injector = Audio.playSound(sound, audioOptions);
|
||||||
print("Playing: " + injector);
|
print("Playing: " + injector);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
Script.scriptEnding.connect(function() {
|
|
||||||
if (injector !== null) {
|
|
||||||
injector.stop();
|
|
||||||
}
|
|
||||||
});
|
});
|
|
@ -85,10 +85,10 @@ function checkHands(deltaTime) {
|
||||||
var chord = Controller.getTriggerValue(chordHand);
|
var chord = Controller.getTriggerValue(chordHand);
|
||||||
|
|
||||||
if (volume > 1.0) volume = 1.0;
|
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
|
// If chord finger trigger pulled, stop current chord
|
||||||
print("stopped sound");
|
print("stopped sound");
|
||||||
Audio.stopInjector(soundPlaying);
|
soundPlaying.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
var BUTTON_COUNT = 6;
|
var BUTTON_COUNT = 6;
|
||||||
|
@ -132,16 +132,21 @@ function checkHands(deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function playChord(position, volume) {
|
function playChord(position, volume) {
|
||||||
if (Audio.isInjectorPlaying(soundPlaying)) {
|
if (soundPlaying.isPlaying) {
|
||||||
print("stopped sound");
|
print("stopped sound");
|
||||||
Audio.stopInjector(soundPlaying);
|
soundPlaying.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Played sound: " + whichChord + " at volume " + options.volume);
|
print("Played sound: " + whichChord + " at volume " + options.volume);
|
||||||
soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], {
|
if (!soundPlaying) {
|
||||||
position: position,
|
soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], {
|
||||||
volume: volume
|
position: position,
|
||||||
});
|
volume: volume
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
soundPlaying.restart();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function keyPressEvent(event) {
|
function keyPressEvent(event) {
|
||||||
|
|
|
@ -190,6 +190,7 @@ var toolBar = (function () {
|
||||||
cameraManager.enable();
|
cameraManager.enable();
|
||||||
entityListTool.setVisible(true);
|
entityListTool.setVisible(true);
|
||||||
gridTool.setVisible(true);
|
gridTool.setVisible(true);
|
||||||
|
grid.setEnabled(true);
|
||||||
propertiesTool.setVisible(true);
|
propertiesTool.setVisible(true);
|
||||||
Window.setFocus();
|
Window.setFocus();
|
||||||
}
|
}
|
||||||
|
@ -533,7 +534,9 @@ function highlightEntityUnderCursor(position, accurateRay) {
|
||||||
|
|
||||||
function mouseReleaseEvent(event) {
|
function mouseReleaseEvent(event) {
|
||||||
if (placingEntityID) {
|
if (placingEntityID) {
|
||||||
selectionManager.setSelections([placingEntityID]);
|
if (isActive) {
|
||||||
|
selectionManager.setSelections([placingEntityID]);
|
||||||
|
}
|
||||||
placingEntityID = null;
|
placingEntityID = null;
|
||||||
}
|
}
|
||||||
if (isActive && selectionManager.hasSelection()) {
|
if (isActive && selectionManager.hasSelection()) {
|
||||||
|
|
|
@ -48,7 +48,8 @@
|
||||||
this.turnSounds = new Array();
|
this.turnSounds = new Array();
|
||||||
this.moveSound = null;
|
this.moveSound = null;
|
||||||
this.turnSound = null;
|
this.turnSound = null;
|
||||||
this.injector = null;
|
this.moveInjector = null;
|
||||||
|
this.turnInjector = null;
|
||||||
|
|
||||||
var debug = false;
|
var debug = false;
|
||||||
var displayRotateTargets = true; // change to false if you don't want the rotate targets
|
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 (this.moveSound && this.moveSound.downloaded) {
|
||||||
if (debug) {
|
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 (this.turnSound && this.turnSound.downloaded) {
|
||||||
if (debug) {
|
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) {
|
if (debug) {
|
||||||
print("stopSound()");
|
print("stopSound()");
|
||||||
}
|
}
|
||||||
if (this.injector) {
|
if (this.turnInjector) {
|
||||||
Audio.stopInjector(this.injector);
|
this.turnInjector.stop();
|
||||||
this.injector = null;
|
}
|
||||||
|
if (this.moveInjector) {
|
||||||
|
this.moveInjector.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +186,7 @@
|
||||||
|
|
||||||
this.move = function(mouseEvent) {
|
this.move = function(mouseEvent) {
|
||||||
this.updatePosition(mouseEvent);
|
this.updatePosition(mouseEvent);
|
||||||
if (this.injector === null) {
|
if (this.moveInjector === null || !this.moveInjector.isPlaying) {
|
||||||
this.playMoveSound();
|
this.playMoveSound();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -233,7 +245,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.injector === null) {
|
if (this.turnInjector === null || !this.turnInjector.isPlaying) {
|
||||||
this.playTurnSound();
|
this.playTurnSound();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,14 +75,14 @@ function maybePlaySound(deltaTime) {
|
||||||
//print("number playing = " + numPlaying);
|
//print("number playing = " + numPlaying);
|
||||||
}
|
}
|
||||||
for (var i = 0; i < playing.length; i++) {
|
for (var i = 0; i < playing.length; i++) {
|
||||||
if (!Audio.isInjectorPlaying(playing[i].audioId)) {
|
if (!playing[i].audioId.isPlaying) {
|
||||||
Entities.deleteEntity(playing[i].entityId);
|
Entities.deleteEntity(playing[i].entityId);
|
||||||
if (useLights) {
|
if (useLights) {
|
||||||
Entities.deleteEntity(playing[i].lightId);
|
Entities.deleteEntity(playing[i].lightId);
|
||||||
}
|
}
|
||||||
playing.splice(i, 1);
|
playing.splice(i, 1);
|
||||||
} else {
|
} 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 };
|
var newColor = { red: playing[i].color.red, green: playing[i].color.green, blue: playing[i].color.blue };
|
||||||
if (loudness > 0.05) {
|
if (loudness > 0.05) {
|
||||||
newColor.red *= (1.0 - loudness);
|
newColor.red *= (1.0 - loudness);
|
||||||
|
|
|
@ -76,9 +76,6 @@ function scriptEnding() {
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
Entities.deleteEntity(entity);
|
Entities.deleteEntity(entity);
|
||||||
}
|
}
|
||||||
if (injector != null) {
|
|
||||||
injector.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
print("BUTTERFLIES START");
|
||||||
|
|
||||||
|
|
||||||
var numButterflies = 25;
|
var numButterflies = 25;
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,7 +112,7 @@ function updateButterflies(deltaTime) {
|
||||||
var properties = Entities.getEntityProperties(butterflies[i]);
|
var properties = Entities.getEntityProperties(butterflies[i]);
|
||||||
if (Vec3.length(Vec3.subtract(properties.position, flockPosition)) > range) {
|
if (Vec3.length(Vec3.subtract(properties.position, flockPosition)) > range) {
|
||||||
Entities.editEntity(butterflies[i], { position: flockPosition } );
|
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
|
// If falling, Create a new direction and impulse
|
||||||
var HORIZ_SCALE = 0.50;
|
var HORIZ_SCALE = 0.50;
|
||||||
var VERT_SCALE = 0.50;
|
var VERT_SCALE = 0.50;
|
||||||
|
@ -139,3 +142,5 @@ Script.scriptEnding.connect(function() {
|
||||||
Entities.deleteEntity(butterflies[i]);
|
Entities.deleteEntity(butterflies[i]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
print("BUTTERFLIES END");
|
||||||
|
|
|
@ -30,8 +30,8 @@
|
||||||
elPosY.value = origin.y.toFixed(2);
|
elPosY.value = origin.y.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.minorGridSpacing !== undefined) {
|
if (data.minorGridWidth !== undefined) {
|
||||||
elMinorSpacing.value = data.minorGridSpacing;
|
elMinorSpacing.value = data.minorGridWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.majorGridEvery !== undefined) {
|
if (data.majorGridEvery !== undefined) {
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
origin: {
|
origin: {
|
||||||
y: elPosY.value,
|
y: elPosY.value,
|
||||||
},
|
},
|
||||||
minorGridSpacing: elMinorSpacing.value,
|
minorGridWidth: elMinorSpacing.value,
|
||||||
majorGridEvery: elMajorSpacing.value,
|
majorGridEvery: elMajorSpacing.value,
|
||||||
gridColor: gridColor,
|
gridColor: gridColor,
|
||||||
colorIndex: gridColorIndex,
|
colorIndex: gridColorIndex,
|
||||||
|
|
|
@ -55,7 +55,9 @@ var droneSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.st
|
||||||
var currentDrone = null;
|
var currentDrone = null;
|
||||||
|
|
||||||
var latinSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.stereo.raw")
|
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 elevatorSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.stereo.raw")
|
||||||
|
var elevatorInjector = null;
|
||||||
var currentMuzakInjector = null;
|
var currentMuzakInjector = null;
|
||||||
var currentSound = null;
|
var currentSound = null;
|
||||||
|
|
||||||
|
@ -140,7 +142,11 @@ function drawLobby() {
|
||||||
|
|
||||||
if (droneSound.downloaded) {
|
if (droneSound.downloaded) {
|
||||||
// start the drone sound
|
// 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
|
// start one of our muzak sounds
|
||||||
|
@ -173,6 +179,26 @@ function changeLobbyTextures() {
|
||||||
|
|
||||||
var MUZAK_VOLUME = 0.1;
|
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() {
|
function playNextMuzak() {
|
||||||
if (panelWall) {
|
if (panelWall) {
|
||||||
if (currentSound == latinSound) {
|
if (currentSound == latinSound) {
|
||||||
|
@ -184,8 +210,8 @@ function playNextMuzak() {
|
||||||
currentSound = latinSound;
|
currentSound = latinSound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentMuzakInjector = Audio.playSound(currentSound, { localOnly: true, volume: MUZAK_VOLUME });
|
playCurrentSound(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,10 +226,11 @@ function playRandomMuzak() {
|
||||||
currentSound = elevatorSound;
|
currentSound = elevatorSound;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentSound) {
|
if (currentSound) {
|
||||||
// pick a random number of seconds from 0-10 to offset the muzak
|
// pick a random number of seconds from 0-10 to offset the muzak
|
||||||
var secondOffset = Math.random() * 10;
|
var secondOffset = Math.random() * 10;
|
||||||
currentMuzakInjector = Audio.playSound(currentSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME });
|
|
||||||
|
playCurrentSound(secondOffset);
|
||||||
} else {
|
} else {
|
||||||
currentMuzakInjector = null;
|
currentMuzakInjector = null;
|
||||||
}
|
}
|
||||||
|
@ -227,10 +254,9 @@ function cleanupLobby() {
|
||||||
panelWall = false;
|
panelWall = false;
|
||||||
orbShell = false;
|
orbShell = false;
|
||||||
|
|
||||||
Audio.stopInjector(currentDrone);
|
currentDrone.stop();
|
||||||
currentDrone = null;
|
currentMuzakInjector.stop();
|
||||||
|
|
||||||
Audio.stopInjector(currentMuzakInjector);
|
|
||||||
currentMuzakInjector = null;
|
currentMuzakInjector = null;
|
||||||
|
|
||||||
places = {};
|
places = {};
|
||||||
|
@ -354,7 +380,7 @@ function update(deltaTime) {
|
||||||
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
|
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
|
||||||
|
|
||||||
// if the reticle is up then we may need to play the next muzak
|
// if the reticle is up then we may need to play the next muzak
|
||||||
if (currentMuzakInjector && !Audio.isInjectorPlaying(currentMuzakInjector)) {
|
if (currentMuzakInjector && !currentMuzakInjector.isPlaying) {
|
||||||
playNextMuzak();
|
playNextMuzak();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,20 +21,13 @@ var offset = Vec3.normalize(Quat.getFront(MyAvatar.orientation));
|
||||||
var position = Vec3.sum(MyAvatar.position, offset);
|
var position = Vec3.sum(MyAvatar.position, offset);
|
||||||
|
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
if (!Audio.isInjectorPlaying(soundPlaying)) {
|
if (sound.downloaded && !soundPlaying) {
|
||||||
soundPlaying = Audio.playSound(sound, {
|
print("Started sound loop");
|
||||||
position: position,
|
soundPlaying = Audio.playSound(sound, {
|
||||||
loop: true
|
position: position,
|
||||||
});
|
loop: true
|
||||||
print("Started sound loop");
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function scriptEnding() {
|
|
||||||
if (Audio.isInjectorPlaying(soundPlaying)) {
|
|
||||||
Audio.stopInjector(soundPlaying);
|
|
||||||
print("Stopped sound loop");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
|
|
|
@ -32,14 +32,13 @@ var sound = Audio.playSound(soundClip, { position: orbitCenter, loop: true, volu
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
time += deltaTime;
|
time += deltaTime;
|
||||||
currentPosition = { x: orbitCenter.x + Math.cos(time * SPEED) * RADIUS, y: orbitCenter.y, z: orbitCenter.z + Math.sin(time * SPEED) * RADIUS };
|
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 } } );
|
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() {
|
Script.scriptEnding.connect(function() {
|
||||||
Entities.deleteEntity(objectId);
|
Entities.deleteEntity(objectId);
|
||||||
Audio.stopInjector(sound);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
|
@ -30,7 +30,7 @@ var playing = false;
|
||||||
var ball = false;
|
var ball = false;
|
||||||
|
|
||||||
function maybePlaySound(deltaTime) {
|
function maybePlaySound(deltaTime) {
|
||||||
if (sound.downloaded) {
|
if (sound.downloaded && !soundPlaying) {
|
||||||
var properties = {
|
var properties = {
|
||||||
type: "Sphere",
|
type: "Sphere",
|
||||||
position: options.position,
|
position: options.position,
|
||||||
|
@ -45,11 +45,9 @@ function maybePlaySound(deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function scriptEnding() {
|
function scriptEnding() {
|
||||||
if (Audio.isInjectorPlaying(soundPlaying)) {
|
if (ball) {
|
||||||
Audio.stopInjector(soundPlaying);
|
Entities.deleteEntity(ball);
|
||||||
Entities.deleteEntity(ball);
|
}
|
||||||
print("Stopped sound.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect a call back that happens every frame
|
// Connect a call back that happens every frame
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <QtCore/QThread>
|
|
||||||
|
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <AddressManager.h>
|
#include <AddressManager.h>
|
||||||
#include <HifiSockAddr.h>
|
#include <HifiSockAddr.h>
|
||||||
|
|
|
@ -16,13 +16,14 @@
|
||||||
|
|
||||||
#include <HifiSockAddr.h>
|
#include <HifiSockAddr.h>
|
||||||
|
|
||||||
class QThread;
|
|
||||||
|
|
||||||
class Client : public QObject {
|
class Client : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Client(QObject* parent = 0);
|
Client(QObject* parent = 0);
|
||||||
|
|
||||||
|
virtual void cleanupBeforeQuit() = 0;
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void setupNetworking();
|
void setupNetworking();
|
||||||
virtual void processVerifiedPacket(const HifiSockAddr& senderSockAddr, const QByteArray& incomingPacket);
|
virtual void processVerifiedPacket(const HifiSockAddr& senderSockAddr, const QByteArray& incomingPacket);
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
@ -86,6 +86,13 @@ GVRInterface::GVRInterface(int argc, char* argv[]) :
|
||||||
QTimer* idleTimer = new QTimer(this);
|
QTimer* idleTimer = new QTimer(this);
|
||||||
connect(idleTimer, &QTimer::timeout, this, &GVRInterface::idle);
|
connect(idleTimer, &QTimer::timeout, this, &GVRInterface::idle);
|
||||||
idleTimer->start(0);
|
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() {
|
void GVRInterface::idle() {
|
||||||
|
|
|
@ -53,6 +53,7 @@ private slots:
|
||||||
void handleApplicationStateChange(Qt::ApplicationState state);
|
void handleApplicationStateChange(Qt::ApplicationState state);
|
||||||
void idle();
|
void idle();
|
||||||
private:
|
private:
|
||||||
|
void handleApplicationQuit();
|
||||||
|
|
||||||
void enterVRMode();
|
void enterVRMode();
|
||||||
void leaveVRMode();
|
void leaveVRMode();
|
||||||
|
|
|
@ -37,7 +37,7 @@ RenderingClient::RenderingClient(QObject *parent, const QString& launchURLString
|
||||||
DependencyManager::set<AvatarHashMap>();
|
DependencyManager::set<AvatarHashMap>();
|
||||||
|
|
||||||
// get our audio client setup on its own thread
|
// get our audio client setup on its own thread
|
||||||
QThread* audioThread = new QThread(this);
|
QThread* audioThread = new QThread();
|
||||||
auto audioClient = DependencyManager::set<AudioClient>();
|
auto audioClient = DependencyManager::set<AudioClient>();
|
||||||
|
|
||||||
audioClient->setPositionGetter(getPositionForAudio);
|
audioClient->setPositionGetter(getPositionForAudio);
|
||||||
|
@ -45,6 +45,8 @@ RenderingClient::RenderingClient(QObject *parent, const QString& launchURLString
|
||||||
|
|
||||||
audioClient->moveToThread(audioThread);
|
audioClient->moveToThread(audioThread);
|
||||||
connect(audioThread, &QThread::started, audioClient.data(), &AudioClient::start);
|
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();
|
audioThread->start();
|
||||||
|
|
||||||
|
@ -68,15 +70,13 @@ void RenderingClient::sendAvatarPacket() {
|
||||||
_fakeAvatar.sendIdentityPacket();
|
_fakeAvatar.sendIdentityPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderingClient::~RenderingClient() {
|
void RenderingClient::cleanupBeforeQuit() {
|
||||||
auto audioClient = DependencyManager::get<AudioClient>();
|
|
||||||
|
|
||||||
// stop the audio client
|
|
||||||
QMetaObject::invokeMethod(audioClient.data(), "stop", Qt::BlockingQueuedConnection);
|
|
||||||
|
|
||||||
// ask the audio thread to quit and wait until it is done
|
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
|
||||||
audioClient->thread()->quit();
|
"stop", Qt::BlockingQueuedConnection);
|
||||||
audioClient->thread()->wait();
|
|
||||||
|
// destroy the AudioClient so it and its thread will safely go down
|
||||||
|
DependencyManager::destroy<AudioClient>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingClient::processVerifiedPacket(const HifiSockAddr& senderSockAddr, const QByteArray& incomingPacket) {
|
void RenderingClient::processVerifiedPacket(const HifiSockAddr& senderSockAddr, const QByteArray& incomingPacket) {
|
||||||
|
|
|
@ -26,7 +26,6 @@ class RenderingClient : public Client {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
RenderingClient(QObject* parent = 0, const QString& launchURLString = QString());
|
RenderingClient(QObject* parent = 0, const QString& launchURLString = QString());
|
||||||
~RenderingClient();
|
|
||||||
|
|
||||||
const glm::vec3& getPosition() const { return _position; }
|
const glm::vec3& getPosition() const { return _position; }
|
||||||
const glm::quat& getOrientation() const { return _orientation; }
|
const glm::quat& getOrientation() const { return _orientation; }
|
||||||
|
@ -35,6 +34,8 @@ public:
|
||||||
static glm::vec3 getPositionForAudio() { return _instance->getPosition(); }
|
static glm::vec3 getPositionForAudio() { return _instance->getPosition(); }
|
||||||
static glm::quat getOrientationForAudio() { return _instance->getOrientation(); }
|
static glm::quat getOrientationForAudio() { return _instance->getOrientation(); }
|
||||||
|
|
||||||
|
virtual void cleanupBeforeQuit();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void goToLocation(const glm::vec3& newPosition,
|
void goToLocation(const glm::vec3& newPosition,
|
||||||
bool hasOrientationChange, const glm::quat& newOrientation,
|
bool hasOrientationChange, const glm::quat& newOrientation,
|
||||||
|
|
|
@ -328,7 +328,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), &_datagramProcessor, SLOT(processDatagrams()));
|
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), &_datagramProcessor, SLOT(processDatagrams()));
|
||||||
|
|
||||||
// put the audio processing on a separate thread
|
// put the audio processing on a separate thread
|
||||||
QThread* audioThread = new QThread(this);
|
QThread* audioThread = new QThread();
|
||||||
audioThread->setObjectName("Audio Thread");
|
audioThread->setObjectName("Audio Thread");
|
||||||
|
|
||||||
auto audioIO = DependencyManager::get<AudioClient>();
|
auto audioIO = DependencyManager::get<AudioClient>();
|
||||||
|
@ -338,7 +338,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
|
|
||||||
audioIO->moveToThread(audioThread);
|
audioIO->moveToThread(audioThread);
|
||||||
connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start);
|
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();
|
audioThread->start();
|
||||||
|
|
||||||
|
@ -516,21 +518,33 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
|
|
||||||
void Application::aboutToQuit() {
|
void Application::aboutToQuit() {
|
||||||
_aboutToQuit = true;
|
_aboutToQuit = true;
|
||||||
|
|
||||||
|
cleanupBeforeQuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application() {
|
void Application::cleanupBeforeQuit() {
|
||||||
QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::BlockingQueuedConnection);
|
QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::BlockingQueuedConnection);
|
||||||
_settingsThread.quit();
|
_settingsThread.quit();
|
||||||
saveSettings();
|
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<AudioClient>().data(),
|
||||||
|
"stop", Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
|
// destroy the AudioClient so it and its thread have a chance to go down safely
|
||||||
|
DependencyManager::destroy<AudioClient>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::~Application() {
|
||||||
_entities.getTree()->setSimulation(NULL);
|
_entities.getTree()->setSimulation(NULL);
|
||||||
qInstallMessageHandler(NULL);
|
qInstallMessageHandler(NULL);
|
||||||
|
|
||||||
_window->saveGeometry();
|
_window->saveGeometry();
|
||||||
|
|
||||||
int DELAY_TIME = 1000;
|
|
||||||
UserActivityLogger::getInstance().close(DELAY_TIME);
|
|
||||||
|
|
||||||
// make sure we don't call the idle timer any more
|
// make sure we don't call the idle timer any more
|
||||||
delete idleTimer;
|
delete idleTimer;
|
||||||
|
|
||||||
|
@ -541,18 +555,6 @@ Application::~Application() {
|
||||||
_nodeThread->quit();
|
_nodeThread->quit();
|
||||||
_nodeThread->wait();
|
_nodeThread->wait();
|
||||||
|
|
||||||
// kill any audio injectors that are still around
|
|
||||||
AudioScriptingInterface::getInstance().stopAllInjectors();
|
|
||||||
|
|
||||||
auto audioIO = DependencyManager::get<AudioClient>();
|
|
||||||
|
|
||||||
// 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();
|
_octreeProcessor.terminate();
|
||||||
_entityEditSender.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_DIFFUSE_COLOR[] = { 0.6f, 0.525f, 0.525f };
|
||||||
const GLfloat WORLD_SPECULAR_COLOR[] = { 0.94f, 0.94f, 0.737f, 1.0f };
|
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() {
|
void Application::setupWorldLight() {
|
||||||
|
|
||||||
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
|
// 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);
|
glLightfv(GL_LIGHT0, GL_SPECULAR, WORLD_SPECULAR_COLOR);
|
||||||
glMaterialfv(GL_FRONT, GL_SPECULAR, WORLD_SPECULAR_COLOR);
|
glMaterialfv(GL_FRONT, GL_SPECULAR, WORLD_SPECULAR_COLOR);
|
||||||
glMateriali(GL_FRONT, GL_SHININESS, 96);
|
glMateriali(GL_FRONT, GL_SHININESS, 96);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::shouldRenderMesh(float largestDimension, float distanceToCamera) {
|
bool Application::shouldRenderMesh(float largestDimension, float distanceToCamera) {
|
||||||
|
@ -2822,7 +2828,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
||||||
|
|
||||||
{
|
{
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||||
|
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY);
|
||||||
PROFILE_RANGE("DeferredLighting");
|
PROFILE_RANGE("DeferredLighting");
|
||||||
PerformanceTimer perfTimer("lighting");
|
PerformanceTimer perfTimer("lighting");
|
||||||
DependencyManager::get<DeferredLightingEffect>()->render();
|
DependencyManager::get<DeferredLightingEffect>()->render();
|
||||||
|
|
|
@ -410,6 +410,8 @@ private:
|
||||||
|
|
||||||
void initDisplay();
|
void initDisplay();
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
void cleanupBeforeQuit();
|
||||||
|
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
|
|
||||||
|
|
|
@ -788,13 +788,12 @@ void ApplicationOverlay::renderAudioMeter() {
|
||||||
|
|
||||||
// Audio VU Meter and Mute Icon
|
// Audio VU Meter and Mute Icon
|
||||||
const int MUTE_ICON_SIZE = 24;
|
const int MUTE_ICON_SIZE = 24;
|
||||||
const int AUDIO_METER_INSET = 2;
|
|
||||||
const int MUTE_ICON_PADDING = 10;
|
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_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - MUTE_ICON_PADDING;
|
||||||
const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
|
const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 ;
|
||||||
const int AUDIO_METER_HEIGHT = 8;
|
const int AUDIO_METER_HEIGHT = 8;
|
||||||
const int AUDIO_METER_GAP = 5;
|
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;
|
int audioMeterY;
|
||||||
bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !OculusManager::isConnected();
|
bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !OculusManager::isConnected();
|
||||||
|
@ -847,7 +846,7 @@ void ApplicationOverlay::renderAudioMeter() {
|
||||||
|
|
||||||
// Draw audio meter background Quad
|
// Draw audio meter background Quad
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X, audioMeterY, AUDIO_METER_WIDTH, AUDIO_METER_HEIGHT,
|
DependencyManager::get<GeometryCache>()->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) {
|
if (audioLevel > AUDIO_RED_START) {
|
||||||
glm::vec4 quadColor;
|
glm::vec4 quadColor;
|
||||||
|
@ -857,10 +856,10 @@ void ApplicationOverlay::renderAudioMeter() {
|
||||||
quadColor = glm::vec4(1, 1, 1, 1);
|
quadColor = glm::vec4(1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
// Draw Red Quad
|
// Draw Red Quad
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START,
|
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X + AUDIO_RED_START,
|
||||||
audioMeterY + AUDIO_METER_INSET,
|
audioMeterY,
|
||||||
audioLevel - AUDIO_RED_START,
|
audioLevel - AUDIO_RED_START,
|
||||||
AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor,
|
AUDIO_METER_HEIGHT, quadColor,
|
||||||
_audioRedQuad);
|
_audioRedQuad);
|
||||||
|
|
||||||
audioLevel = AUDIO_RED_START;
|
audioLevel = AUDIO_RED_START;
|
||||||
|
@ -874,26 +873,28 @@ void ApplicationOverlay::renderAudioMeter() {
|
||||||
quadColor = glm::vec4(1, 1, 1, 1);
|
quadColor = glm::vec4(1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
// Draw Green Quad
|
// Draw Green Quad
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START,
|
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X + AUDIO_GREEN_START,
|
||||||
audioMeterY + AUDIO_METER_INSET,
|
audioMeterY,
|
||||||
audioLevel - AUDIO_GREEN_START,
|
audioLevel - AUDIO_GREEN_START,
|
||||||
AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor,
|
AUDIO_METER_HEIGHT, quadColor,
|
||||||
_audioGreenQuad);
|
_audioGreenQuad);
|
||||||
|
|
||||||
audioLevel = AUDIO_GREEN_START;
|
audioLevel = AUDIO_GREEN_START;
|
||||||
}
|
}
|
||||||
// Draw Blue Quad
|
|
||||||
glm::vec4 quadColor;
|
if (audioLevel >= 0) {
|
||||||
if (!isClipping) {
|
glm::vec4 quadColor;
|
||||||
quadColor = AUDIO_METER_BLUE;
|
if (!isClipping) {
|
||||||
} else {
|
quadColor = AUDIO_METER_BLUE;
|
||||||
quadColor = glm::vec4(1, 1, 1, 1);
|
} else {
|
||||||
|
quadColor = glm::vec4(1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
// Draw Blue (low level) quad
|
||||||
|
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X,
|
||||||
|
audioMeterY,
|
||||||
|
audioLevel, AUDIO_METER_HEIGHT, quadColor,
|
||||||
|
_audioBlueQuad);
|
||||||
}
|
}
|
||||||
// Draw Blue (low level) quad
|
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET,
|
|
||||||
audioMeterY + AUDIO_METER_INSET,
|
|
||||||
audioLevel, AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor,
|
|
||||||
_audioBlueQuad);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplicationOverlay::renderStatsAndLogs() {
|
void ApplicationOverlay::renderStatsAndLogs() {
|
||||||
|
|
|
@ -136,6 +136,8 @@ AudioClient::AudioClient() :
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioClient::~AudioClient() {
|
AudioClient::~AudioClient() {
|
||||||
|
stop();
|
||||||
|
|
||||||
if (_gverbLocal) {
|
if (_gverbLocal) {
|
||||||
gverb_free(_gverbLocal);
|
gverb_free(_gverbLocal);
|
||||||
}
|
}
|
||||||
|
@ -489,7 +491,6 @@ void AudioClient::start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::stop() {
|
void AudioClient::stop() {
|
||||||
|
|
||||||
_inputFrameBuffer.finalize();
|
_inputFrameBuffer.finalize();
|
||||||
_inputGain.finalize();
|
_inputGain.finalize();
|
||||||
_sourceGain.finalize();
|
_sourceGain.finalize();
|
||||||
|
@ -974,14 +975,16 @@ bool AudioClient::outputLocalInjector(bool isStereo, qreal volume, AudioInjector
|
||||||
|
|
||||||
QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName),
|
QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName),
|
||||||
localFormat,
|
localFormat,
|
||||||
injector);
|
injector->getLocalBuffer());
|
||||||
|
|
||||||
localOutput->setVolume(volume);
|
localOutput->setVolume(volume);
|
||||||
|
|
||||||
// move the localOutput to the same thread as the local injector buffer
|
// move the localOutput to the same thread as the local injector buffer
|
||||||
localOutput->moveToThread(injector->getLocalBuffer()->thread());
|
localOutput->moveToThread(injector->getLocalBuffer()->thread());
|
||||||
|
|
||||||
// have it be cleaned up when that injector is done
|
// have it be stopped when that local buffer is about to close
|
||||||
connect(injector, &AudioInjector::finished, localOutput, &QAudioOutput::stop);
|
connect(injector->getLocalBuffer(), &AudioInjectorLocalBuffer::bufferEmpty, localOutput, &QAudioOutput::stop);
|
||||||
|
connect(injector->getLocalBuffer(), &QIODevice::aboutToClose, localOutput, &QAudioOutput::stop);
|
||||||
|
|
||||||
qDebug() << "Starting QAudioOutput for local injector" << localOutput;
|
qDebug() << "Starting QAudioOutput for local injector" << localOutput;
|
||||||
|
|
||||||
|
@ -992,7 +995,6 @@ bool AudioClient::outputLocalInjector(bool isStereo, qreal volume, AudioInjector
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioClient::outputFormatChanged() {
|
void AudioClient::outputFormatChanged() {
|
||||||
int outputFormatChannelCountTimesSampleRate = _outputFormat.channelCount() * _outputFormat.sampleRate();
|
int outputFormatChannelCountTimesSampleRate = _outputFormat.channelCount() * _outputFormat.sampleRate();
|
||||||
_outputFrameSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * outputFormatChannelCountTimesSampleRate / _desiredOutputFormat.sampleRate();
|
_outputFrameSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * outputFormatChannelCountTimesSampleRate / _desiredOutputFormat.sampleRate();
|
||||||
|
|
|
@ -188,6 +188,10 @@ protected:
|
||||||
AudioClient();
|
AudioClient();
|
||||||
~AudioClient();
|
~AudioClient();
|
||||||
|
|
||||||
|
virtual void customDeleter() {
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void outputFormatChanged();
|
void outputFormatChanged();
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QDataStream>
|
#include <QtCore/QDataStream>
|
||||||
|
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
|
@ -21,79 +22,77 @@
|
||||||
|
|
||||||
#include "AudioInjector.h"
|
#include "AudioInjector.h"
|
||||||
|
|
||||||
QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in) {
|
|
||||||
return engine->newQObject(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out) {
|
|
||||||
out = qobject_cast<AudioInjector*>(object.toQObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioInjector::AudioInjector(QObject* parent) :
|
AudioInjector::AudioInjector(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent)
|
||||||
_options(),
|
|
||||||
_shouldStop(false),
|
|
||||||
_loudness(0.0f),
|
|
||||||
_isFinished(false),
|
|
||||||
_currentSendPosition(0),
|
|
||||||
_localBuffer(NULL)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) :
|
AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) :
|
||||||
_audioData(sound->getByteArray()),
|
_audioData(sound->getByteArray()),
|
||||||
_options(injectorOptions),
|
_options(injectorOptions)
|
||||||
_shouldStop(false),
|
|
||||||
_loudness(0.0f),
|
|
||||||
_isFinished(false),
|
|
||||||
_currentSendPosition(0),
|
|
||||||
_localBuffer(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) :
|
AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) :
|
||||||
_audioData(audioData),
|
_audioData(audioData),
|
||||||
_options(injectorOptions),
|
_options(injectorOptions)
|
||||||
_shouldStop(false),
|
|
||||||
_loudness(0.0f),
|
|
||||||
_isFinished(false),
|
|
||||||
_currentSendPosition(0),
|
|
||||||
_localBuffer(NULL)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInjector::~AudioInjector() {
|
void AudioInjector::setIsFinished(bool isFinished) {
|
||||||
if (_localBuffer) {
|
_isFinished = isFinished;
|
||||||
_localBuffer->stop();
|
|
||||||
|
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() {
|
void AudioInjector::injectAudio() {
|
||||||
|
if (!_isStarted) {
|
||||||
// check if we need to offset the sound by some number of seconds
|
// check if we need to offset the sound by some number of seconds
|
||||||
if (_options.secondOffset > 0.0f) {
|
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
|
if (_options.localOnly) {
|
||||||
int byteOffset = (int) floorf(AudioConstants::SAMPLE_RATE * _options.secondOffset * (_options.stereo ? 2.0f : 1.0f));
|
injectLocally();
|
||||||
byteOffset *= sizeof(int16_t);
|
} else {
|
||||||
|
injectToMixer();
|
||||||
_currentSendPosition = byteOffset;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_options.localOnly) {
|
|
||||||
injectLocally();
|
|
||||||
} else {
|
} 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() {
|
void AudioInjector::injectLocally() {
|
||||||
|
@ -102,6 +101,7 @@ void AudioInjector::injectLocally() {
|
||||||
if (_audioData.size() > 0) {
|
if (_audioData.size() > 0) {
|
||||||
|
|
||||||
_localBuffer = new AudioInjectorLocalBuffer(_audioData, this);
|
_localBuffer = new AudioInjectorLocalBuffer(_audioData, this);
|
||||||
|
|
||||||
_localBuffer->open(QIODevice::ReadOnly);
|
_localBuffer->open(QIODevice::ReadOnly);
|
||||||
_localBuffer->setShouldLoop(_options.loop);
|
_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
|
// send two packets before the first sleep so the mixer can start playback right away
|
||||||
|
|
||||||
if (_currentSendPosition != bytesToCopy && _currentSendPosition < _audioData.size()) {
|
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
|
// not the first packet and not done
|
||||||
// sleep for the appropriate time
|
// sleep for the appropriate time
|
||||||
int usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000;
|
int usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000;
|
||||||
|
@ -251,8 +259,7 @@ void AudioInjector::injectToMixer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_isFinished = true;
|
setIsFinished(true);
|
||||||
emit finished();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInjector::stop() {
|
void AudioInjector::stop() {
|
||||||
|
@ -260,7 +267,11 @@ void AudioInjector::stop() {
|
||||||
|
|
||||||
if (_options.localOnly) {
|
if (_options.localOnly) {
|
||||||
// we're only a local injector, so we can say we are finished right away too
|
// we're only a local injector, so we can say we are finished right away too
|
||||||
_isFinished = true;
|
setIsFinished(true);
|
||||||
emit finished();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioInjector::stopAndDeleteLater() {
|
||||||
|
stop();
|
||||||
|
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_AudioInjector_h
|
#define hifi_AudioInjector_h
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
@ -24,15 +25,18 @@
|
||||||
|
|
||||||
class AbstractAudioInterface;
|
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 {
|
class AudioInjector : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AudioInjector(QObject* parent);
|
AudioInjector(QObject* parent);
|
||||||
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
||||||
AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions);
|
AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions);
|
||||||
~AudioInjector();
|
|
||||||
|
|
||||||
bool isFinished() const { return _isFinished; }
|
bool isFinished() const { return _isFinished; }
|
||||||
|
|
||||||
int getCurrentSendPosition() const { return _currentSendPosition; }
|
int getCurrentSendPosition() const { return _currentSendPosition; }
|
||||||
|
|
||||||
AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; }
|
AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; }
|
||||||
|
@ -41,30 +45,37 @@ public:
|
||||||
void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; }
|
void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; }
|
||||||
public slots:
|
public slots:
|
||||||
void injectAudio();
|
void injectAudio();
|
||||||
|
void restart();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
void setOptions(AudioInjectorOptions& options);
|
void triggerDeleteAfterFinish() { _shouldDeleteAfterFinish = true; }
|
||||||
|
void stopAndDeleteLater();
|
||||||
|
|
||||||
|
void setOptions(AudioInjectorOptions& options) { _options = options; }
|
||||||
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
|
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
|
||||||
float getLoudness();
|
float getLoudness() const { return _loudness; }
|
||||||
|
bool isPlaying() const { return !_isFinished; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void injectToMixer();
|
void injectToMixer();
|
||||||
void injectLocally();
|
void injectLocally();
|
||||||
|
|
||||||
|
void setIsFinished(bool isFinished);
|
||||||
|
|
||||||
QByteArray _audioData;
|
QByteArray _audioData;
|
||||||
AudioInjectorOptions _options;
|
AudioInjectorOptions _options;
|
||||||
bool _shouldStop;
|
bool _shouldStop = false;
|
||||||
float _loudness;
|
float _loudness = 0.0f;
|
||||||
bool _isFinished;
|
bool _isStarted = false;
|
||||||
int _currentSendPosition;
|
bool _isFinished = false;
|
||||||
AbstractAudioInterface* _localAudioInterface;
|
bool _shouldDeleteAfterFinish = false;
|
||||||
AudioInjectorLocalBuffer* _localBuffer;
|
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
|
#endif // hifi_AudioInjector_h
|
||||||
|
|
|
@ -23,9 +23,18 @@ AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArr
|
||||||
|
|
||||||
void AudioInjectorLocalBuffer::stop() {
|
void AudioInjectorLocalBuffer::stop() {
|
||||||
_isStopped = true;
|
_isStopped = true;
|
||||||
|
|
||||||
QIODevice::close();
|
QIODevice::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioInjectorLocalBuffer::seek(qint64 pos) {
|
||||||
|
if (_isStopped) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return QIODevice::seek(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) {
|
qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) {
|
||||||
if (!_isStopped) {
|
if (!_isStopped) {
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ public:
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
bool seek(qint64 pos);
|
||||||
|
|
||||||
qint64 readData(char* data, qint64 maxSize);
|
qint64 readData(char* data, qint64 maxSize);
|
||||||
qint64 writeData(const char* data, qint64 maxSize) { return 0; }
|
qint64 writeData(const char* data, qint64 maxSize) { return 0; }
|
||||||
|
|
||||||
|
|
|
@ -1127,7 +1127,7 @@ FBXTexture getTexture(const QString& textureID,
|
||||||
texture.transform.setTranslation(p.translation);
|
texture.transform.setTranslation(p.translation);
|
||||||
texture.transform.setRotation(glm::quat(glm::radians(p.rotation)));
|
texture.transform.setRotation(glm::quat(glm::radians(p.rotation)));
|
||||||
texture.transform.setScale(p.scaling);
|
texture.transform.setScale(p.scaling);
|
||||||
if ((p.UVSet != "map1") || (p.UVSet != "UVSet0")) {
|
if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) {
|
||||||
texture.texcoordSet = 1;
|
texture.texcoordSet = 1;
|
||||||
}
|
}
|
||||||
texture.texcoordSetName = p.UVSet;
|
texture.texcoordSetName = p.UVSet;
|
||||||
|
@ -1556,6 +1556,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
||||||
if (property.name == propertyName) {
|
if (property.name == propertyName) {
|
||||||
QString v = property.properties.at(0).toString();
|
QString v = property.properties.at(0).toString();
|
||||||
if (property.properties.at(0) == "UVSet") {
|
if (property.properties.at(0) == "UVSet") {
|
||||||
|
std::string uvName = property.properties.at(index).toString().toStdString();
|
||||||
tex.assign(tex.UVSet, property.properties.at(index).toString());
|
tex.assign(tex.UVSet, property.properties.at(index).toString());
|
||||||
} else if (property.properties.at(0) == "CurrentTextureBlendMode") {
|
} else if (property.properties.at(0) == "CurrentTextureBlendMode") {
|
||||||
tex.assign<uint8_t>(tex.currentTextureBlendMode, property.properties.at(index).value<int>());
|
tex.assign<uint8_t>(tex.currentTextureBlendMode, property.properties.at(index).value<int>());
|
||||||
|
|
|
@ -85,8 +85,11 @@ bool Texture::Storage::allocateMip(uint16 level) {
|
||||||
bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) {
|
bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) {
|
||||||
// Ok we should be able to do that...
|
// Ok we should be able to do that...
|
||||||
allocateMip(level);
|
allocateMip(level);
|
||||||
_mips[level]->_format = format;
|
auto mip = _mips[level];
|
||||||
Size allocated = _mips[level]->_sysmem.setData(size, bytes);
|
mip->_format = format;
|
||||||
|
Size allocated = mip->_sysmem.setData(size, bytes);
|
||||||
|
mip->_isGPULoaded = false;
|
||||||
|
|
||||||
return allocated == size;
|
return allocated == size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ typedef gpu::BufferView::Index Index;
|
||||||
typedef gpu::BufferView BufferView;
|
typedef gpu::BufferView BufferView;
|
||||||
typedef AABox Box;
|
typedef AABox Box;
|
||||||
typedef std::vector< Box > Boxes;
|
typedef std::vector< Box > Boxes;
|
||||||
|
typedef glm::vec3 Vec3;
|
||||||
|
|
||||||
class Mesh {
|
class Mesh {
|
||||||
public:
|
public:
|
||||||
|
@ -35,7 +36,7 @@ public:
|
||||||
typedef gpu::Stream::Format VertexFormat;
|
typedef gpu::Stream::Format VertexFormat;
|
||||||
typedef std::map< Slot, BufferView > BufferViewMap;
|
typedef std::map< Slot, BufferView > BufferViewMap;
|
||||||
|
|
||||||
typedef glm::vec3 Vec3;
|
typedef model::Vec3 Vec3;
|
||||||
|
|
||||||
Mesh();
|
Mesh();
|
||||||
Mesh(const Mesh& mesh);
|
Mesh(const Mesh& mesh);
|
||||||
|
|
97
libraries/model/src/model/Light.cpp
Executable file
97
libraries/model/src/model/Light.cpp
Executable file
|
@ -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;
|
||||||
|
}
|
294
libraries/model/src/model/Light.h
Executable file
294
libraries/model/src/model/Light.h
Executable file
|
@ -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 <bitset>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#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<NUM_FLAGS> 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>(); }
|
||||||
|
Schema& editSchema() { return _schemaBuffer.edit<Schema>(); }
|
||||||
|
};
|
||||||
|
typedef QSharedPointer< Light > LightPointer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -100,7 +100,6 @@ public:
|
||||||
void setTextureView(MapChannel channel, const TextureView& texture);
|
void setTextureView(MapChannel channel, const TextureView& texture);
|
||||||
const TextureMap& getTextureMap() const { return _textureMap; }
|
const TextureMap& getTextureMap() const { return _textureMap; }
|
||||||
|
|
||||||
const Schema* getSchema() const { return &_schemaBuffer.get<Schema>(); }
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Flags _flags;
|
Flags _flags;
|
||||||
|
|
|
@ -86,17 +86,9 @@ void UserActivityLogger::launch(QString applicationVersion) {
|
||||||
logAction(ACTION_NAME, actionDetails);
|
logAction(ACTION_NAME, actionDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserActivityLogger::close(int delayTime) {
|
void UserActivityLogger::close() {
|
||||||
const QString ACTION_NAME = "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());
|
logAction(ACTION_NAME, QJsonObject());
|
||||||
timer.start(delayTime);
|
|
||||||
loop.exec();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserActivityLogger::changedDisplayName(QString displayName) {
|
void UserActivityLogger::changedDisplayName(QString displayName) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ public slots:
|
||||||
void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters());
|
void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters());
|
||||||
|
|
||||||
void launch(QString applicationVersion);
|
void launch(QString applicationVersion);
|
||||||
void close(int delayTime);
|
void close();
|
||||||
void changedDisplayName(QString displayName);
|
void changedDisplayName(QString displayName);
|
||||||
void changedModel(QString typeOfModel, QString modelURL);
|
void changedModel(QString typeOfModel, QString modelURL);
|
||||||
void changedDomain(QString domainURL);
|
void changedDomain(QString domainURL);
|
||||||
|
|
117
libraries/render-utils/src/DeferredGlobalLight.slh
Executable file
117
libraries/render-utils/src/DeferredGlobalLight.slh
Executable file
|
@ -0,0 +1,117 @@
|
||||||
|
<!
|
||||||
|
// DeferredGlobalLight.slh
|
||||||
|
// libraries/render-utils/src
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/5/15.
|
||||||
|
// Copyright 2013 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
|
||||||
|
!>
|
||||||
|
<@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@>
|
|
@ -11,86 +11,51 @@
|
||||||
<@if not DEFERRED_LIGHTING_SLH@>
|
<@if not DEFERRED_LIGHTING_SLH@>
|
||||||
<@def DEFERRED_LIGHTING_SLH@>
|
<@def DEFERRED_LIGHTING_SLH@>
|
||||||
|
|
||||||
struct SphericalHarmonics {
|
// Frag Shading returns the diffuse amount as W and the specular rgb as xyz
|
||||||
vec4 L00;
|
vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float gloss) {
|
||||||
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) {
|
|
||||||
// Diffuse Lighting
|
// Diffuse Lighting
|
||||||
float diffuseDot = dot(normal, gl_LightSource[0].position.xyz);
|
float diffuseDot = dot(fragNormal, fragLightDir);
|
||||||
float facingLight = step(0.0, diffuseDot) * shadowAttenuation;
|
float facingLight = step(0.0, diffuseDot);
|
||||||
vec3 diffuseColor = diffuse * (gl_FrontLightProduct[0].diffuse.rgb * (diffuseDot * facingLight));
|
float diffuse = diffuseDot * facingLight;
|
||||||
|
|
||||||
// compute the specular multiplier (sans exponent)
|
// Specular Lighting depends on the half vector and the gloss
|
||||||
float specularPower = facingLight * max(0.0,
|
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
|
||||||
dot(normalize(gl_LightSource[0].position.xyz - normalize(position)), normal));
|
|
||||||
vec3 specularColor = pow(specularPower, gloss * 128.0) * specular;
|
|
||||||
|
|
||||||
// add specular contribution
|
// float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0);
|
||||||
return vec3(diffuseColor + specularColor);
|
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 specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0);
|
||||||
|
vec3 reflect = specularPower * specular;
|
||||||
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;
|
|
||||||
|
|
||||||
// ambient is a tiny percentage of the lightmap and only when in the shadow
|
return vec4(reflect, diffuse);
|
||||||
vec3 ambientLight = (1 - lightAttenuation) * 0.5 * lightmap;
|
|
||||||
|
|
||||||
return diffuse * (ambientLight + diffuseLight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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@>
|
<@endif@>
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#include "RenderUtil.h"
|
#include "RenderUtil.h"
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
|
|
||||||
|
#include "gpu/Batch.h"
|
||||||
|
#include "gpu/GLBackend.h"
|
||||||
|
|
||||||
#include "simple_vert.h"
|
#include "simple_vert.h"
|
||||||
#include "simple_frag.h"
|
#include "simple_frag.h"
|
||||||
|
|
||||||
|
@ -42,146 +45,6 @@
|
||||||
#include "point_light_frag.h"
|
#include "point_light_frag.h"
|
||||||
#include "spot_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) {
|
void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||||
_viewState = viewState;
|
_viewState = viewState;
|
||||||
_simpleProgram.addShaderFromSourceCode(QGLShader::Vertex, simple_vert);
|
_simpleProgram.addShaderFromSourceCode(QGLShader::Vertex, simple_vert);
|
||||||
|
@ -206,6 +69,18 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||||
|
|
||||||
loadLightProgram(point_light_frag, true, _pointLight, _pointLightLocations);
|
loadLightProgram(point_light_frag, true, _pointLight, _pointLightLocations);
|
||||||
loadLightProgram(spot_light_frag, true, _spotLight, _spotLightLocations);
|
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() {
|
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,
|
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,
|
const glm::vec3& diffuse, const glm::vec3& specular, float constantAttenuation, float linearAttenuation,
|
||||||
float quadraticAttenuation, const glm::vec3& direction, float exponent, float cutoff) {
|
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) {
|
if (exponent == 0.0f && cutoff == PI) {
|
||||||
PointLight light;
|
lp->setType(model::Light::POINT);
|
||||||
light.position = glm::vec4(position, 1.0f);
|
_pointLights.push_back(lightID);
|
||||||
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);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
SpotLight light;
|
lp->setDirection(direction);
|
||||||
light.position = glm::vec4(position, 1.0f);
|
lp->setSpotAngle(cutoff);
|
||||||
light.radius = radius;
|
lp->setSpotExponent(exponent);
|
||||||
light.ambient = glm::vec4(ambient, 1.0f);
|
lp->setType(model::Light::SPOT);
|
||||||
light.diffuse = glm::vec4(diffuse, 1.0f);
|
_spotLights.push_back(lightID);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +191,7 @@ void DeferredLightingEffect::render() {
|
||||||
QOpenGLFramebufferObject* freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebufferObject();
|
QOpenGLFramebufferObject* freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebufferObject();
|
||||||
freeFBO->bind();
|
freeFBO->bind();
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
// glEnable(GL_FRAMEBUFFER_SRGB);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
|
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
|
||||||
|
|
||||||
|
@ -342,6 +216,10 @@ void DeferredLightingEffect::render() {
|
||||||
float tMin = viewport[VIEWPORT_Y_INDEX] / (float)primaryFBO->height();
|
float tMin = viewport[VIEWPORT_Y_INDEX] / (float)primaryFBO->height();
|
||||||
float tHeight = viewport[VIEWPORT_HEIGHT_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;
|
ProgramObject* program = &_directionalLight;
|
||||||
const LightLocations* locations = &_directionalLightLocations;
|
const LightLocations* locations = &_directionalLightLocations;
|
||||||
bool shadowsEnabled = _viewState->getShadowsEnabled();
|
bool shadowsEnabled = _viewState->getShadowsEnabled();
|
||||||
|
@ -379,19 +257,24 @@ void DeferredLightingEffect::render() {
|
||||||
program->bind();
|
program->bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locations->ambientSphere >= 0) {
|
{
|
||||||
SphericalHarmonics sh;
|
auto globalLight = _allocatedLights[_globalLights.front()];
|
||||||
if (_ambientLightMode < NUM_PRESET) {
|
|
||||||
sh.assignPreset(_ambientLightMode);
|
|
||||||
} else {
|
|
||||||
sh.assignPreset(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i =0; i <SphericalHarmonics::NUM_COEFFICIENTS; i++) {
|
|
||||||
program->setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (locations->ambientSphere >= 0) {
|
||||||
|
auto sh = globalLight->getAmbientSphere();
|
||||||
|
for (int i =0; i <model::SphericalHarmonics::NUM_COEFFICIENTS; i++) {
|
||||||
|
program->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;
|
float left, right, bottom, top, nearVal, farVal;
|
||||||
glm::vec4 nearClipPlane, farClipPlane;
|
glm::vec4 nearClipPlane, farClipPlane;
|
||||||
_viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
_viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||||
|
@ -434,27 +317,27 @@ void DeferredLightingEffect::render() {
|
||||||
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
|
|
||||||
if (!_pointLights.isEmpty()) {
|
if (!_pointLights.empty()) {
|
||||||
_pointLight.bind();
|
_pointLight.bind();
|
||||||
_pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal);
|
_pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal);
|
||||||
_pointLight.setUniformValue(_pointLightLocations.depthScale, depthScale);
|
_pointLight.setUniformValue(_pointLightLocations.depthScale, depthScale);
|
||||||
_pointLight.setUniformValue(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT);
|
_pointLight.setUniformValue(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT);
|
||||||
_pointLight.setUniformValue(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT);
|
_pointLight.setUniformValue(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT);
|
||||||
|
|
||||||
foreach (const PointLight& light, _pointLights) {
|
for (auto lightID : _pointLights) {
|
||||||
_pointLight.setUniformValue(_pointLightLocations.radius, light.radius);
|
auto light = _allocatedLights[lightID];
|
||||||
glLightfv(GL_LIGHT1, GL_AMBIENT, (const GLfloat*)&light.ambient);
|
|
||||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse);
|
if (_pointLightLocations.lightBufferUnit >= 0) {
|
||||||
glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular);
|
gpu::Batch batch;
|
||||||
glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position);
|
batch.setUniformBuffer(_pointLightLocations.lightBufferUnit, light->getSchemaBuffer());
|
||||||
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (light.constantAttenuation > 0.0f ? light.constantAttenuation : 0.0f));
|
gpu::GLBackend::renderBatch(batch);
|
||||||
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));
|
glUniformMatrix4fv(_pointLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat));
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
||||||
float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION);
|
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
|
||||||
if (glm::distance(eyePoint, glm::vec3(light.position)) < expandedRadius + nearRadius) {
|
if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) {
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glTranslatef(0.0f, 0.0f, -1.0f);
|
glTranslatef(0.0f, 0.0f, -1.0f);
|
||||||
|
|
||||||
|
@ -468,7 +351,7 @@ void DeferredLightingEffect::render() {
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
|
||||||
} else {
|
} 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));
|
geometryCache->renderSphere(expandedRadius, 32, 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,31 +362,28 @@ void DeferredLightingEffect::render() {
|
||||||
_pointLight.release();
|
_pointLight.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_spotLights.isEmpty()) {
|
if (!_spotLights.empty()) {
|
||||||
_spotLight.bind();
|
_spotLight.bind();
|
||||||
_spotLight.setUniformValue(_spotLightLocations.nearLocation, nearVal);
|
_spotLight.setUniformValue(_spotLightLocations.nearLocation, nearVal);
|
||||||
_spotLight.setUniformValue(_spotLightLocations.depthScale, depthScale);
|
_spotLight.setUniformValue(_spotLightLocations.depthScale, depthScale);
|
||||||
_spotLight.setUniformValue(_spotLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT);
|
_spotLight.setUniformValue(_spotLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT);
|
||||||
_spotLight.setUniformValue(_spotLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT);
|
_spotLight.setUniformValue(_spotLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT);
|
||||||
|
|
||||||
foreach (const SpotLight& light, _spotLights) {
|
for (auto lightID : _spotLights) {
|
||||||
_spotLight.setUniformValue(_spotLightLocations.radius, light.radius);
|
auto light = _allocatedLights[lightID];
|
||||||
glLightfv(GL_LIGHT1, GL_AMBIENT, (const GLfloat*)&light.ambient);
|
|
||||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse);
|
if (_spotLightLocations.lightBufferUnit >= 0) {
|
||||||
glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular);
|
gpu::Batch batch;
|
||||||
glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position);
|
batch.setUniformBuffer(_spotLightLocations.lightBufferUnit, light->getSchemaBuffer());
|
||||||
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (light.constantAttenuation > 0.0f ? light.constantAttenuation : 0.0f));
|
gpu::GLBackend::renderBatch(batch);
|
||||||
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));
|
glUniformMatrix4fv(_spotLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat));
|
||||||
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));
|
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
||||||
float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION);
|
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
|
||||||
float edgeRadius = expandedRadius / glm::cos(light.cutoff);
|
float edgeRadius = expandedRadius / glm::cos(light->getSpotAngle());
|
||||||
if (glm::distance(eyePoint, glm::vec3(light.position)) < edgeRadius + nearRadius) {
|
if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < edgeRadius + nearRadius) {
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glTranslatef(0.0f, 0.0f, -1.0f);
|
glTranslatef(0.0f, 0.0f, -1.0f);
|
||||||
|
|
||||||
|
@ -517,12 +397,12 @@ void DeferredLightingEffect::render() {
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
glTranslatef(light.position.x, light.position.y, light.position.z);
|
glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z);
|
||||||
glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light.direction);
|
glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light->getDirection());
|
||||||
glm::vec3 axis = glm::axis(spotRotation);
|
glm::vec3 axis = glm::axis(spotRotation);
|
||||||
glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z);
|
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));
|
glTranslatef(0.0f, 0.0f, -light->getMaximumRadius() * (1.0f + SCALE_EXPANSION * 0.5f));
|
||||||
geometryCache->renderCone(expandedRadius * glm::tan(light.cutoff),
|
geometryCache->renderCone(expandedRadius * glm::tan(light->getSpotAngle()),
|
||||||
expandedRadius, 32, 1);
|
expandedRadius, 32, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,7 +425,7 @@ void DeferredLightingEffect::render() {
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
freeFBO->release();
|
freeFBO->release();
|
||||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
// glDisable(GL_FRAMEBUFFER_SRGB);
|
||||||
|
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
@ -607,11 +487,46 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit
|
||||||
locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale");
|
locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale");
|
||||||
locations.radius = program.uniformLocation("radius");
|
locations.radius = program.uniformLocation("radius");
|
||||||
locations.ambientSphere = program.uniformLocation("ambientSphere.L00");
|
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();
|
program.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::setAmbientLightMode(int preset) {
|
void DeferredLightingEffect::setAmbientLightMode(int preset) {
|
||||||
if ((preset >= -1) && (preset < NUM_PRESET)) {
|
if ((preset >= -1) && (preset < model::SphericalHarmonics::NUM_PRESET)) {
|
||||||
_ambientLightMode = 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);
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
#include "ProgramObject.h"
|
#include "ProgramObject.h"
|
||||||
|
|
||||||
|
#include "model/Light.h"
|
||||||
|
|
||||||
class AbstractViewStateInterface;
|
class AbstractViewStateInterface;
|
||||||
class PostLightingRenderable;
|
class PostLightingRenderable;
|
||||||
|
|
||||||
|
@ -71,25 +73,12 @@ public:
|
||||||
void prepare();
|
void prepare();
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
enum AmbientLightPreset {
|
// update global lighting
|
||||||
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 setAmbientLightMode(int preset);
|
void setAmbientLightMode(int preset);
|
||||||
|
void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeferredLightingEffect() { }
|
DeferredLightingEffect() {}
|
||||||
virtual ~DeferredLightingEffect() { }
|
virtual ~DeferredLightingEffect() { }
|
||||||
|
|
||||||
class LightLocations {
|
class LightLocations {
|
||||||
|
@ -102,6 +91,8 @@ private:
|
||||||
int depthTexCoordScale;
|
int depthTexCoordScale;
|
||||||
int radius;
|
int radius;
|
||||||
int ambientSphere;
|
int ambientSphere;
|
||||||
|
int lightBufferUnit;
|
||||||
|
int invViewMat;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
|
static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
|
||||||
|
@ -146,9 +137,13 @@ private:
|
||||||
float exponent;
|
float exponent;
|
||||||
float cutoff;
|
float cutoff;
|
||||||
};
|
};
|
||||||
|
|
||||||
QVector<PointLight> _pointLights;
|
typedef std::vector< model::LightPointer > Lights;
|
||||||
QVector<SpotLight> _spotLights;
|
|
||||||
|
Lights _allocatedLights;
|
||||||
|
std::vector<int> _globalLights;
|
||||||
|
std::vector<int> _pointLights;
|
||||||
|
std::vector<int> _spotLights;
|
||||||
QVector<PostLightingRenderable*> _postLightingRenderables;
|
QVector<PostLightingRenderable*> _postLightingRenderables;
|
||||||
|
|
||||||
AbstractViewStateInterface* _viewState;
|
AbstractViewStateInterface* _viewState;
|
||||||
|
|
|
@ -1154,7 +1154,7 @@ void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxC
|
||||||
|
|
||||||
gpu::Batch batch;
|
gpu::Batch batch;
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
// glEnable(GL_TEXTURE_2D);
|
||||||
//glBindTexture(GL_TEXTURE_2D, _currentTextureID); // this is quad specific...
|
//glBindTexture(GL_TEXTURE_2D, _currentTextureID); // this is quad specific...
|
||||||
|
|
||||||
batch.setInputFormat(details.streamFormat);
|
batch.setInputFormat(details.streamFormat);
|
||||||
|
@ -1168,8 +1168,8 @@ void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxC
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
// glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glDisable(GL_TEXTURE_2D);
|
// glDisable(GL_TEXTURE_2D);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryCache::renderQuad(const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color, int id) {
|
void GeometryCache::renderQuad(const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color, int id) {
|
||||||
|
|
107
libraries/render-utils/src/Light.slh
Executable file
107
libraries/render-utils/src/Light.slh
Executable file
|
@ -0,0 +1,107 @@
|
||||||
|
<!
|
||||||
|
// Light.slh
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 1/25/14.
|
||||||
|
// Copyright 2013 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
|
||||||
|
!>
|
||||||
|
<@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@>
|
|
@ -15,22 +15,23 @@
|
||||||
// Everything about deferred buffer
|
// Everything about deferred buffer
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredLighting.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||||
|
|
||||||
|
|
||||||
// Light mapped or not ?
|
// Light mapped or not ?
|
||||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||||
gl_FragColor = vec4( evalLightmappedColor(
|
vec3 color = evalLightmappedColor(
|
||||||
1.0,
|
1.0,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
frag.specularVal.xyz),
|
frag.specularVal.xyz);
|
||||||
1.0);
|
|
||||||
|
gl_FragColor = vec4(color, 1.0);
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
vec3 color = evalAmbienSphereGlobalColor(1.0,
|
||||||
+ evalDirectionalColor(1.0,
|
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// Everything about deferred buffer
|
// Everything about deferred buffer
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredLighting.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
// Everything about shadow
|
// Everything about shadow
|
||||||
<@include Shadow.slh@>
|
<@include Shadow.slh@>
|
||||||
|
@ -36,8 +36,7 @@ void main(void) {
|
||||||
frag.specularVal.xyz),
|
frag.specularVal.xyz),
|
||||||
1.0);
|
1.0);
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
vec3 color = evalAmbienSphereGlobalColor(shadowAttenuation,
|
||||||
+ evalDirectionalColor(shadowAttenuation,
|
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// Everything about deferred buffer
|
// Everything about deferred buffer
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredLighting.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
// Everything about shadow
|
// Everything about shadow
|
||||||
<@include Shadow.slh@>
|
<@include Shadow.slh@>
|
||||||
|
@ -37,8 +37,7 @@ void main(void) {
|
||||||
frag.specularVal.xyz),
|
frag.specularVal.xyz),
|
||||||
1.0);
|
1.0);
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
vec3 color = evalAmbienSphereGlobalColor(shadowAttenuation,
|
||||||
+ evalDirectionalColor(shadowAttenuation,
|
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// Everything about deferred buffer
|
// Everything about deferred buffer
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredLighting.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||||
|
@ -29,8 +29,7 @@ void main(void) {
|
||||||
frag.specularVal.xyz),
|
frag.specularVal.xyz),
|
||||||
1.0);
|
1.0);
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
vec3 color = evalAmbienGlobalColor(1.0,
|
||||||
+ evalDirectionalColor(1.0,
|
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// Everything about deferred buffer
|
// Everything about deferred buffer
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredLighting.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
// Everything about shadow
|
// Everything about shadow
|
||||||
<@include Shadow.slh@>
|
<@include Shadow.slh@>
|
||||||
|
@ -36,8 +36,7 @@ void main(void) {
|
||||||
frag.specularVal.xyz),
|
frag.specularVal.xyz),
|
||||||
1.0);
|
1.0);
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
vec3 color = evalAmbienGlobalColor(shadowAttenuation,
|
||||||
+ evalDirectionalColor(shadowAttenuation,
|
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// Everything about deferred buffer
|
// Everything about deferred buffer
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredLighting.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
// Everything about shadow
|
// Everything about shadow
|
||||||
<@include Shadow.slh@>
|
<@include Shadow.slh@>
|
||||||
|
@ -37,8 +37,7 @@ void main(void) {
|
||||||
frag.specularVal.xyz),
|
frag.specularVal.xyz),
|
||||||
1.0);
|
1.0);
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
vec3 color = evalAmbienGlobalColor(shadowAttenuation,
|
||||||
+ evalDirectionalColor(shadowAttenuation,
|
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
|
@ -33,8 +33,9 @@ void main(void) {
|
||||||
|
|
||||||
// and the texture coordinates
|
// and the texture coordinates
|
||||||
gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0);
|
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;
|
interpolatedTexcoord1 = vec2(texcoordMatrices[1] * vec4(texcoord1.xy, 0.0, 1.0)).xy;
|
||||||
|
|
||||||
// use standard pipeline transform
|
// use standard pipeline transform
|
||||||
gl_Position = ftransform();
|
gl_Position = ftransform();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,41 +15,61 @@
|
||||||
// Everything about deferred buffer
|
// Everything about deferred buffer
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
// the radius (hard cutoff) of the light effect
|
//Everything about deferred lighting
|
||||||
uniform float radius;
|
<@include DeferredLighting.slh@>
|
||||||
|
|
||||||
|
// Everything about light
|
||||||
|
<@include Light.slh@>
|
||||||
|
|
||||||
|
// The view Matrix
|
||||||
|
uniform mat4 invViewMat;
|
||||||
|
|
||||||
void main(void) {
|
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;
|
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) {
|
if (depth < gl_FragCoord.z) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
// compute the view space position using the depth
|
|
||||||
float z = near / (depth * depthScale - 1.0);
|
// Need the light now
|
||||||
vec4 position = vec4((depthTexCoordOffset + texCoord * depthTexCoordScale) * z, z, 1.0);
|
Light light = getLight();
|
||||||
|
|
||||||
// get the normal from the map
|
// Make the Light vector going from fragment to light center in world space
|
||||||
vec4 normal = texture2D(normalMap, texCoord);
|
vec4 fragPos = invViewMat * frag.position;
|
||||||
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
|
vec3 fragLightVec = getLightPosition(light) - fragPos.xyz;
|
||||||
|
|
||||||
// compute the base color based on OpenGL lighting model
|
// Kill if too far from the light center
|
||||||
vec4 lightVector = gl_LightSource[1].position - position;
|
if (dot(fragLightVec, fragLightVec) > getLightSquareRadius(light)) {
|
||||||
float lightDistance = length(lightVector);
|
discard;
|
||||||
lightVector = lightVector / lightDistance;
|
}
|
||||||
float diffuse = dot(normalizedNormal, lightVector);
|
|
||||||
float facingLight = step(0.0, diffuse);
|
// Allright we re valid in the volume
|
||||||
vec4 baseColor = texture2D(diffuseMap, texCoord) * (gl_FrontLightProduct[1].ambient +
|
float fragLightDistance = length(fragLightVec);
|
||||||
gl_FrontLightProduct[1].diffuse * (diffuse * facingLight));
|
vec3 fragLightDir = fragLightVec / fragLightDistance;
|
||||||
|
|
||||||
// compute attenuation based on distance, etc.
|
// Eval shading
|
||||||
float attenuation = step(lightDistance, radius) / dot(vec3(gl_LightSource[1].constantAttenuation,
|
vec3 fragNormal = vec3(invViewMat * vec4(frag.normal, 0.0));
|
||||||
gl_LightSource[1].linearAttenuation, gl_LightSource[1].quadraticAttenuation),
|
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
|
||||||
vec3(1.0, lightDistance, lightDistance * lightDistance));
|
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
||||||
|
vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.specular, frag.gloss);
|
||||||
// add base to specular, modulate by attenuation
|
|
||||||
float specular = facingLight * max(0.0, dot(normalize(lightVector - normalize(vec4(position.xyz, 0.0))),
|
// Eval attenuation
|
||||||
normalizedNormal));
|
float radialAttenuation = evalLightAttenuation(light, fragLightDistance);
|
||||||
vec4 specularColor = texture2D(specularMap, texCoord);
|
|
||||||
gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0);
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,43 +15,73 @@
|
||||||
// Everything about deferred buffer
|
// Everything about deferred buffer
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
// the radius (hard cutoff) of the light effect
|
//Everything about deferred lighting
|
||||||
uniform float radius;
|
<@include DeferredLighting.slh@>
|
||||||
|
|
||||||
|
// Everything about light
|
||||||
|
<@include Light.slh@>
|
||||||
|
|
||||||
|
// The view Matrix
|
||||||
|
uniform mat4 invViewMat;
|
||||||
|
|
||||||
void main(void) {
|
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;
|
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) {
|
if (depth < gl_FragCoord.z) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
// compute the view space position using the depth
|
|
||||||
float z = near / (depth * depthScale - 1.0);
|
// Need the light now
|
||||||
vec4 position = vec4((depthTexCoordOffset + texCoord * depthTexCoordScale) * z, z, 1.0);
|
Light light = getLight();
|
||||||
|
|
||||||
// get the normal from the map
|
// Make the Light vector going from fragment to light center in world space
|
||||||
vec4 normal = texture2D(normalMap, texCoord);
|
vec4 fragPos = invViewMat * frag.position;
|
||||||
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
|
vec3 fragLightVec = getLightPosition(light) - fragPos.xyz;
|
||||||
|
|
||||||
// compute the base color based on OpenGL lighting model
|
// Kill if too far from the light center
|
||||||
vec4 lightVector = gl_LightSource[1].position - position;
|
if (dot(fragLightVec, fragLightVec) > getLightSquareRadius(light)) {
|
||||||
float lightDistance = length(lightVector);
|
discard;
|
||||||
lightVector = lightVector / lightDistance;
|
}
|
||||||
float diffuse = dot(normalizedNormal, lightVector);
|
|
||||||
float facingLight = step(0.0, diffuse);
|
// Allright we re valid in the volume
|
||||||
vec4 baseColor = texture2D(diffuseMap, texCoord) * (gl_FrontLightProduct[1].ambient +
|
float fragLightDistance = length(fragLightVec);
|
||||||
gl_FrontLightProduct[1].diffuse * (diffuse * facingLight));
|
vec3 fragLightDir = fragLightVec / fragLightDistance;
|
||||||
|
|
||||||
// compute attenuation based on spot angle, distance, etc.
|
// Kill if not in the spot light (ah ah !)
|
||||||
float cosSpotAngle = max(-dot(lightVector.xyz, gl_LightSource[1].spotDirection), 0.0);
|
vec3 lightSpotDir = getLightDirection(light);
|
||||||
float attenuation = step(lightDistance, radius) * step(gl_LightSource[1].spotCosCutoff, cosSpotAngle) *
|
float cosSpotAngle = max(-dot(fragLightDir, lightSpotDir), 0.0);
|
||||||
pow(cosSpotAngle, gl_LightSource[1].spotExponent) / dot(vec3(gl_LightSource[1].constantAttenuation,
|
if (cosSpotAngle < getLightSpotAngleCos(light)) {
|
||||||
gl_LightSource[1].linearAttenuation, gl_LightSource[1].quadraticAttenuation),
|
discard;
|
||||||
vec3(1.0, lightDistance, lightDistance * lightDistance));
|
}
|
||||||
|
|
||||||
// add base to specular, modulate by attenuation
|
// Eval shading
|
||||||
float specular = facingLight * max(0.0, dot(normalize(lightVector - normalize(vec4(position.xyz, 0.0))),
|
vec3 fragNormal = vec3(invViewMat * vec4(frag.normal, 0.0));
|
||||||
normalizedNormal));
|
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
|
||||||
vec4 specularColor = texture2D(specularMap, texCoord);
|
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
||||||
gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "ScriptAudioInjector.h"
|
||||||
|
|
||||||
#include "AudioScriptingInterface.h"
|
#include "AudioScriptingInterface.h"
|
||||||
|
|
||||||
void registerAudioMetaTypes(QScriptEngine* engine) {
|
void registerAudioMetaTypes(QScriptEngine* engine) {
|
||||||
|
@ -28,80 +30,45 @@ AudioScriptingInterface::AudioScriptingInterface() :
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioScriptingInterface::stopAllInjectors() {
|
ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) {
|
||||||
QList<QPointer<AudioInjector> >::iterator injector = _activeInjectors.begin();
|
AudioInjector* injector = NULL;
|
||||||
while (injector != _activeInjectors.end()) {
|
QMetaObject::invokeMethod(this, "invokedPlaySound", Qt::BlockingQueuedConnection,
|
||||||
if (!injector->isNull()) {
|
Q_RETURN_ARG(AudioInjector*, injector),
|
||||||
injector->data()->stop();
|
Q_ARG(Sound*, sound), Q_ARG(const AudioInjectorOptions&, injectorOptions));
|
||||||
|
if (injector) {
|
||||||
while (injector->data() && !injector->data()->isFinished()) {
|
return new ScriptAudioInjector(injector);
|
||||||
// wait for this injector to go down
|
} else {
|
||||||
}
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
injector = _activeInjectors.erase(injector);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) {
|
AudioInjector* AudioScriptingInterface::invokedPlaySound(Sound* sound, const AudioInjectorOptions& injectorOptions) {
|
||||||
if (sound) {
|
if (sound) {
|
||||||
// stereo option isn't set from script, this comes from sound metadata or filename
|
// stereo option isn't set from script, this comes from sound metadata or filename
|
||||||
AudioInjectorOptions optionsCopy = injectorOptions;
|
AudioInjectorOptions optionsCopy = injectorOptions;
|
||||||
optionsCopy.stereo = sound->isStereo();
|
optionsCopy.stereo = sound->isStereo();
|
||||||
|
|
||||||
AudioInjector* injector = new AudioInjector(sound, optionsCopy);
|
|
||||||
injector->setLocalAudioInterface(_localAudioInterface);
|
|
||||||
|
|
||||||
QThread* injectorThread = new QThread();
|
QThread* injectorThread = new QThread();
|
||||||
injectorThread->setObjectName("Audio Injector Thread");
|
injectorThread->setObjectName("Audio Injector Thread");
|
||||||
|
|
||||||
|
AudioInjector* injector = new AudioInjector(sound, optionsCopy);
|
||||||
|
injector->setLocalAudioInterface(_localAudioInterface);
|
||||||
|
|
||||||
injector->moveToThread(injectorThread);
|
injector->moveToThread(injectorThread);
|
||||||
|
|
||||||
// start injecting when the injector thread starts
|
// start injecting when the injector thread starts
|
||||||
connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
|
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 the right slots and signals for AudioInjector and thread cleanup
|
||||||
connect(injector, &AudioInjector::finished, injector, &AudioInjector::deleteLater);
|
connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
|
||||||
connect(injector, &AudioInjector::finished, injectorThread, &QThread::quit);
|
|
||||||
connect(injector, &AudioInjector::finished, this, &AudioScriptingInterface::injectorStopped);
|
|
||||||
connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
|
connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
|
||||||
|
|
||||||
injectorThread->start();
|
injectorThread->start();
|
||||||
|
|
||||||
_activeInjectors.append(QPointer<AudioInjector>(injector));
|
|
||||||
|
|
||||||
return injector;
|
return injector;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "AudioScriptingInterface::playSound called with null Sound object.";
|
qDebug() << "AudioScriptingInterface::playSound called with null Sound object.";
|
||||||
return NULL;
|
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<AudioInjector>(reinterpret_cast<AudioInjector*>(sender())));
|
|
||||||
}
|
|
|
@ -12,40 +12,32 @@
|
||||||
#ifndef hifi_AudioScriptingInterface_h
|
#ifndef hifi_AudioScriptingInterface_h
|
||||||
#define hifi_AudioScriptingInterface_h
|
#define hifi_AudioScriptingInterface_h
|
||||||
|
|
||||||
#include <qpointer.h>
|
#include <AbstractAudioInterface.h>
|
||||||
|
#include <AudioInjector.h>
|
||||||
|
#include <Sound.h>
|
||||||
|
|
||||||
#include "AbstractAudioInterface.h"
|
class ScriptAudioInjector;
|
||||||
#include "AudioInjector.h"
|
|
||||||
#include "Sound.h"
|
|
||||||
|
|
||||||
class AudioScriptingInterface : public QObject {
|
class AudioScriptingInterface : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static AudioScriptingInterface& getInstance();
|
static AudioScriptingInterface& getInstance();
|
||||||
|
|
||||||
void stopAllInjectors();
|
|
||||||
|
|
||||||
void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; }
|
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);
|
protected:
|
||||||
bool isInjectorPlaying(AudioInjector* injector);
|
// this method is protected to stop C++ callers from calling, but invokable from script
|
||||||
|
Q_INVOKABLE ScriptAudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
|
||||||
void setInjectorOptions(AudioInjector* injector, const AudioInjectorOptions& injectorOptions);
|
|
||||||
|
|
||||||
void injectorStopped();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mutedByMixer();
|
void mutedByMixer();
|
||||||
void environmentMuted();
|
void environmentMuted();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
AudioInjector* invokedPlaySound(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioScriptingInterface();
|
AudioScriptingInterface();
|
||||||
QList< QPointer<AudioInjector> > _activeInjectors;
|
|
||||||
AbstractAudioInterface* _localAudioInterface;
|
AbstractAudioInterface* _localAudioInterface;
|
||||||
};
|
};
|
||||||
|
|
40
libraries/script-engine/src/ScriptAudioInjector.cpp
Normal file
40
libraries/script-engine/src/ScriptAudioInjector.cpp
Normal file
|
@ -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<ScriptAudioInjector*>(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();
|
||||||
|
}
|
52
libraries/script-engine/src/ScriptAudioInjector.h
Normal file
52
libraries/script-engine/src/ScriptAudioInjector.h
Normal file
|
@ -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 <QtCore/QObject>
|
||||||
|
|
||||||
|
#include <AudioInjector.h>
|
||||||
|
|
||||||
|
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<AudioInjector> _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
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
#include <AudioConstants.h>
|
#include <AudioConstants.h>
|
||||||
#include <AudioEffectOptions.h>
|
#include <AudioEffectOptions.h>
|
||||||
#include <AudioInjector.h>
|
|
||||||
#include <AvatarData.h>
|
#include <AvatarData.h>
|
||||||
#include <Bitstream.h>
|
#include <Bitstream.h>
|
||||||
#include <CollisionInfo.h>
|
#include <CollisionInfo.h>
|
||||||
|
@ -35,6 +34,7 @@
|
||||||
#include "DataViewClass.h"
|
#include "DataViewClass.h"
|
||||||
#include "EventTypes.h"
|
#include "EventTypes.h"
|
||||||
#include "MenuItemProperties.h"
|
#include "MenuItemProperties.h"
|
||||||
|
#include "ScriptAudioInjector.h"
|
||||||
#include "ScriptEngine.h"
|
#include "ScriptEngine.h"
|
||||||
#include "TypedArrays.h"
|
#include "TypedArrays.h"
|
||||||
#include "XMLHttpRequestClass.h"
|
#include "XMLHttpRequestClass.h"
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
#include <QtScript/QScriptEngine>
|
#include <QtScript/QScriptEngine>
|
||||||
|
|
||||||
#include <AnimationCache.h>
|
#include <AnimationCache.h>
|
||||||
#include <AudioScriptingInterface.h>
|
|
||||||
#include <AvatarData.h>
|
#include <AvatarData.h>
|
||||||
#include <AvatarHashMap.h>
|
#include <AvatarHashMap.h>
|
||||||
#include <LimitedNodeList.h>
|
#include <LimitedNodeList.h>
|
||||||
|
|
||||||
#include "AbstractControllerScriptingInterface.h"
|
#include "AbstractControllerScriptingInterface.h"
|
||||||
#include "ArrayBufferClass.h"
|
#include "ArrayBufferClass.h"
|
||||||
|
#include "AudioScriptingInterface.h"
|
||||||
#include "Quat.h"
|
#include "Quat.h"
|
||||||
#include "ScriptUUID.h"
|
#include "ScriptUUID.h"
|
||||||
#include "Vec3.h"
|
#include "Vec3.h"
|
||||||
|
|
|
@ -100,6 +100,8 @@ public:
|
||||||
// Left will be inversed before the multiplication
|
// Left will be inversed before the multiplication
|
||||||
static Transform& inverseMult(Transform& result, const Transform& left, const Transform& right);
|
static Transform& inverseMult(Transform& result, const Transform& left, const Transform& right);
|
||||||
|
|
||||||
|
Vec4 transform(const Vec4& pos) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
enum Flag {
|
enum Flag {
|
||||||
|
@ -414,6 +416,13 @@ inline Transform& Transform::inverseMult( Transform& result, const Transform& le
|
||||||
return result;
|
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 {
|
inline Transform::Mat4& Transform::getCachedMatrix(Transform::Mat4& result) const {
|
||||||
updateCache();
|
updateCache();
|
||||||
result = (*_matrix);
|
result = (*_matrix);
|
||||||
|
|
Loading…
Reference in a new issue