mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 20:57:09 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into 20224
This commit is contained in:
commit
6bad7a6002
65 changed files with 1695 additions and 581 deletions
|
@ -667,7 +667,7 @@ function chooseFromHighFidelityDomains(clickedButton) {
|
|||
modal_body = "<p>Choose the High Fidelity domain you want this domain-server to represent.<br/>This will set your domain ID on the settings page.</p>"
|
||||
domain_select = $("<select id='domain-name-select' class='form-control'></select>")
|
||||
_.each(data.data.domains, function(domain){
|
||||
domain_select.append("<option value='" + domain.id + "'>" + domain.name + "</option>")
|
||||
domain_select.append("<option value='" + domain.id + "'>(" + domain.id + ")" + (domain.names.length > 0 ? " [" + domain.names + "]" : "") + "</option>");
|
||||
})
|
||||
modal_body += "<label for='domain-name-select'>Domains</label>" + domain_select[0].outerHTML
|
||||
modal_buttons["success"] = {
|
||||
|
|
|
@ -16,6 +16,27 @@
|
|||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
|
||||
var RED = { red: 255, green: 0, blue: 0 };
|
||||
var LASER_WIDTH = 2;
|
||||
|
||||
var pointer = [];
|
||||
pointer.push(Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: LASER_WIDTH
|
||||
}));
|
||||
pointer.push(Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: LASER_WIDTH
|
||||
}));
|
||||
|
||||
function getRandomFloat(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
@ -26,7 +47,7 @@ var yawFromMouse = 0;
|
|||
var pitchFromMouse = 0;
|
||||
var isMouseDown = false;
|
||||
|
||||
var BULLET_VELOCITY = 20.0;
|
||||
var BULLET_VELOCITY = 5.0;
|
||||
var MIN_THROWER_DELAY = 1000;
|
||||
var MAX_THROWER_DELAY = 1000;
|
||||
var LEFT_BUTTON_3 = 3;
|
||||
|
@ -106,8 +127,6 @@ if (showScore) {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function printVector(string, vector) {
|
||||
print(string + " " + vector.x + ", " + vector.y + ", " + vector.z);
|
||||
}
|
||||
|
@ -115,7 +134,7 @@ function printVector(string, vector) {
|
|||
function shootBullet(position, velocity) {
|
||||
var BULLET_SIZE = 0.07;
|
||||
var BULLET_LIFETIME = 10.0;
|
||||
var BULLET_GRAVITY = -0.02;
|
||||
var BULLET_GRAVITY = 0.0;
|
||||
bulletID = Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: position,
|
||||
|
@ -124,6 +143,8 @@ function shootBullet(position, velocity) {
|
|||
velocity: velocity,
|
||||
lifetime: BULLET_LIFETIME,
|
||||
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||
damping: 0.01,
|
||||
density: 5000,
|
||||
ignoreCollisions: false,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
@ -146,11 +167,11 @@ function shootBullet(position, velocity) {
|
|||
|
||||
function shootTarget() {
|
||||
var TARGET_SIZE = 0.50;
|
||||
var TARGET_GRAVITY = -0.25;
|
||||
var TARGET_GRAVITY = 0.0;
|
||||
var TARGET_LIFETIME = 300.0;
|
||||
var TARGET_UP_VELOCITY = 0.5;
|
||||
var TARGET_FWD_VELOCITY = 1.0;
|
||||
var DISTANCE_TO_LAUNCH_FROM = 3.0;
|
||||
var TARGET_UP_VELOCITY = 0.0;
|
||||
var TARGET_FWD_VELOCITY = 0.0;
|
||||
var DISTANCE_TO_LAUNCH_FROM = 5.0;
|
||||
var ANGLE_RANGE_FOR_LAUNCH = 20.0;
|
||||
var camera = Camera.getPosition();
|
||||
//printVector("camera", camera);
|
||||
|
@ -166,13 +187,14 @@ function shootTarget() {
|
|||
targetID = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: newPosition,
|
||||
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
|
||||
color: { red: 0, green: 200, blue: 200 },
|
||||
//angularVelocity: { x: 1, y: 0, z: 0 },
|
||||
dimensions: { x: TARGET_SIZE * (0.5 + Math.random()), y: TARGET_SIZE * (0.5 + Math.random()), z: TARGET_SIZE * (0.5 + Math.random()) / 4.0 },
|
||||
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
|
||||
lifetime: TARGET_LIFETIME,
|
||||
damping: 0.0001,
|
||||
rotation: Camera.getOrientation(),
|
||||
damping: 0.1,
|
||||
density: 100.0,
|
||||
collisionsWillMove: true });
|
||||
|
||||
// Record start time
|
||||
|
@ -183,8 +205,6 @@ function shootTarget() {
|
|||
Audio.playSound(targetLaunchSound, audioOptions);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
|
||||
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
|
||||
|
@ -212,7 +232,7 @@ function keyPressEvent(event) {
|
|||
if (event.text == "t") {
|
||||
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||
Script.setTimeout(shootTarget, time);
|
||||
} else if (event.text == ".") {
|
||||
} else if ((event.text == ".") || (event.text == "SPACE")) {
|
||||
shootFromMouse();
|
||||
} else if (event.text == "r") {
|
||||
playLoadSound();
|
||||
|
@ -254,7 +274,7 @@ function takeFiringPose() {
|
|||
}
|
||||
}
|
||||
|
||||
//MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20);
|
||||
MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20);
|
||||
MyAvatar.attach(gunModel, "LeftHand", {x:-0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(0, 0, 79), 0.20);
|
||||
|
||||
// Give a bit of time to load before playing sound
|
||||
|
@ -262,7 +282,6 @@ Script.setTimeout(playLoadSound, 2000);
|
|||
|
||||
function update(deltaTime) {
|
||||
if (bulletID && !bulletID.isKnownID) {
|
||||
print("Trying to identify bullet");
|
||||
bulletID = Entities.identifyEntity(bulletID);
|
||||
}
|
||||
if (targetID && !targetID.isKnownID) {
|
||||
|
@ -304,15 +323,6 @@ function update(deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check hydra controller for launch button press
|
||||
if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) {
|
||||
isLaunchButtonPressed = true;
|
||||
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||
Script.setTimeout(shootTarget, time);
|
||||
} else if (isLaunchButtonPressed && !Controller.isButtonPressed(LEFT_BUTTON_3)) {
|
||||
isLaunchButtonPressed = false;
|
||||
|
||||
}
|
||||
|
||||
// check for trigger press
|
||||
|
||||
|
@ -335,14 +345,21 @@ function update(deltaTime) {
|
|||
shootABullet = true;
|
||||
}
|
||||
}
|
||||
var palmController = t * controllersPerTrigger;
|
||||
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||
var fingerTipController = palmController + 1;
|
||||
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
|
||||
var laserTip = Vec3.sum(Vec3.multiply(100.0, Vec3.subtract(fingerTipPosition, palmPosition)), palmPosition);
|
||||
|
||||
// Update Lasers
|
||||
Overlays.editOverlay(pointer[t], {
|
||||
start: palmPosition,
|
||||
end: laserTip,
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
if (shootABullet) {
|
||||
var palmController = t * controllersPerTrigger;
|
||||
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||
|
||||
var fingerTipController = palmController + 1;
|
||||
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
|
||||
|
||||
|
||||
var palmToFingerTipVector =
|
||||
{ x: (fingerTipPosition.x - palmPosition.x),
|
||||
y: (fingerTipPosition.y - palmPosition.y),
|
||||
|
@ -361,20 +378,8 @@ function update(deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
isMouseDown = true;
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
|
||||
if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === offButton) {
|
||||
Script.stop();
|
||||
} else {
|
||||
shootFromMouse();
|
||||
}
|
||||
}
|
||||
|
||||
function shootFromMouse() {
|
||||
var DISTANCE_FROM_CAMERA = 2.0;
|
||||
var DISTANCE_FROM_CAMERA = 1.0;
|
||||
var camera = Camera.getPosition();
|
||||
var forwardVector = Quat.getFront(Camera.getOrientation());
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
|
||||
|
@ -402,6 +407,8 @@ function mouseMoveEvent(event) {
|
|||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(reticle);
|
||||
Overlays.deleteOverlay(offButton);
|
||||
Overlays.deleteOverlay(pointer[0]);
|
||||
Overlays.deleteOverlay(pointer[1]);
|
||||
Overlays.deleteOverlay(text);
|
||||
MyAvatar.detachOne(gunModel);
|
||||
clearPose();
|
||||
|
@ -410,7 +417,6 @@ function scriptEnding() {
|
|||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
Script.load("lookWithTouch.js");
|
||||
Script.load("editEntities.js");
|
||||
Script.load("selectAudioDevice.js");
|
||||
Script.load("hydraMove.js");
|
||||
Script.load("controllers/hydra/hydraMove.js");
|
||||
Script.load("headMove.js");
|
||||
Script.load("inspect.js");
|
||||
Script.load("lobby.js");
|
||||
|
|
|
@ -66,20 +66,20 @@ function textOverlayPosition() {
|
|||
Vec3.multiply(Quat.getUp(Camera.orientation), TEXT_DISTANCE_DOWN));
|
||||
}
|
||||
|
||||
var panelLocationOrder = [
|
||||
var panelPlaceOrder = [
|
||||
7, 8, 9, 10, 11, 12, 13,
|
||||
0, 1, 2, 3, 4, 5, 6,
|
||||
14, 15, 16, 17, 18, 19, 20
|
||||
];
|
||||
|
||||
// Location index is 0-based
|
||||
function locationIndexToPanelIndex(locationIndex) {
|
||||
return panelLocationOrder.indexOf(locationIndex) + 1;
|
||||
// place index is 0-based
|
||||
function placeIndexToPanelIndex(placeIndex) {
|
||||
return panelPlaceOrder.indexOf(placeIndex) + 1;
|
||||
}
|
||||
|
||||
// Panel index is 1-based
|
||||
function panelIndexToLocationIndex(panelIndex) {
|
||||
return panelLocationOrder[panelIndex - 1];
|
||||
function panelIndexToPlaceIndex(panelIndex) {
|
||||
return panelPlaceOrder[panelIndex - 1];
|
||||
}
|
||||
|
||||
var MAX_NUM_PANELS = 21;
|
||||
|
@ -148,25 +148,24 @@ function drawLobby() {
|
|||
}
|
||||
}
|
||||
|
||||
var locations = {};
|
||||
var places = {};
|
||||
|
||||
function changeLobbyTextures() {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", "https://data.highfidelity.io/api/v1/locations?limit=21", false);
|
||||
req.open("GET", "https://data.highfidelity.io/api/v1/places?limit=21", false);
|
||||
req.send();
|
||||
|
||||
locations = JSON.parse(req.responseText).data.locations;
|
||||
places = JSON.parse(req.responseText).data.places;
|
||||
|
||||
var NUM_PANELS = locations.length;
|
||||
var NUM_PANELS = places.length;
|
||||
|
||||
var textureProp = {
|
||||
textures: {}
|
||||
};
|
||||
|
||||
for (var j = 0; j < NUM_PANELS; j++) {
|
||||
var panelIndex = locationIndexToPanelIndex(j);
|
||||
textureProp["textures"]["file" + panelIndex] = HIFI_PUBLIC_BUCKET + "images/locations/"
|
||||
+ locations[j].id + "/hifi-location-" + locations[j].id + "_640x360.jpg";
|
||||
var panelIndex = placeIndexToPanelIndex(j);
|
||||
textureProp["textures"]["file" + panelIndex] = places[j].previews.lobby;
|
||||
};
|
||||
|
||||
Overlays.editOverlay(panelWall, textureProp);
|
||||
|
@ -234,7 +233,7 @@ function cleanupLobby() {
|
|||
Audio.stopInjector(currentMuzakInjector);
|
||||
currentMuzakInjector = null;
|
||||
|
||||
locations = {};
|
||||
places = {};
|
||||
toggleEnvironmentRendering(true);
|
||||
|
||||
MyAvatar.detachOne(HELMET_ATTACHMENT_URL);
|
||||
|
@ -252,14 +251,14 @@ function actionStartEvent(event) {
|
|||
var panelStringIndex = panelName.indexOf("Panel");
|
||||
if (panelStringIndex != -1) {
|
||||
var panelIndex = parseInt(panelName.slice(5));
|
||||
var locationIndex = panelIndexToLocationIndex(panelIndex);
|
||||
if (locationIndex < locations.length) {
|
||||
var actionLocation = locations[locationIndex];
|
||||
var placeIndex = panelIndexToPlaceIndex(panelIndex);
|
||||
if (placeIndex < places.length) {
|
||||
var actionPlace = places[placeIndex];
|
||||
|
||||
print("Jumping to " + actionLocation.name + " at " + actionLocation.path
|
||||
+ " in " + actionLocation.domain.name + " after click on panel " + panelIndex + " with location index " + locationIndex);
|
||||
print("Jumping to " + actionPlace.name + " at " + actionPlace.address
|
||||
+ " after click on panel " + panelIndex + " with place index " + placeIndex);
|
||||
|
||||
Window.location = actionLocation;
|
||||
Window.location = actionPlace.address;
|
||||
maybeCleanupLobby();
|
||||
}
|
||||
}
|
||||
|
@ -302,15 +301,15 @@ function handleLookAt(pickRay) {
|
|||
var panelStringIndex = panelName.indexOf("Panel");
|
||||
if (panelStringIndex != -1) {
|
||||
var panelIndex = parseInt(panelName.slice(5));
|
||||
var locationIndex = panelIndexToLocationIndex(panelIndex);
|
||||
if (locationIndex < locations.length) {
|
||||
var actionLocation = locations[locationIndex];
|
||||
var placeIndex = panelIndexToPlaceIndex(panelIndex);
|
||||
if (placeIndex < places.length) {
|
||||
var actionPlace = places[placeIndex];
|
||||
|
||||
if (actionLocation.description == "") {
|
||||
Overlays.editOverlay(descriptionText, { text: actionLocation.name, visible: showText });
|
||||
if (actionPlace.description == "") {
|
||||
Overlays.editOverlay(descriptionText, { text: actionPlace.name, visible: showText });
|
||||
} else {
|
||||
// handle line wrapping
|
||||
var allWords = actionLocation.description.split(" ");
|
||||
var allWords = actionPlace.description.split(" ");
|
||||
var currentGoodLine = "";
|
||||
var currentTestLine = "";
|
||||
var formatedDescription = "";
|
||||
|
|
|
@ -259,14 +259,16 @@ function checkSize(){
|
|||
|
||||
// Triggers notification if a user logs on or off
|
||||
function onOnlineUsersChanged(users) {
|
||||
for (user in users) {
|
||||
if (last_users.indexOf(users[user]) == -1.0) {
|
||||
createNotification(users[user] + " has joined");
|
||||
if (!isStartingUp()) { // Skip user notifications at startup.
|
||||
for (user in users) {
|
||||
if (last_users.indexOf(users[user]) == -1.0) {
|
||||
createNotification(users[user] + " has joined");
|
||||
}
|
||||
}
|
||||
}
|
||||
for (user in last_users) {
|
||||
if (users.indexOf(last_users[user]) == -1.0) {
|
||||
createNotification(last_users[user] + " has left");
|
||||
for (user in last_users) {
|
||||
if (users.indexOf(last_users[user]) == -1.0) {
|
||||
createNotification(last_users[user] + " has left");
|
||||
}
|
||||
}
|
||||
}
|
||||
last_users = users;
|
||||
|
@ -348,17 +350,38 @@ function dismiss(firstNoteOut, firstButOut, firstOut) {
|
|||
myAlpha.splice(firstOut,1);
|
||||
}
|
||||
|
||||
// This is meant to show users online at startup but currently shows 0 users.
|
||||
function onConnected() {
|
||||
// This reports the number of users online at startup
|
||||
function reportUsers() {
|
||||
var numUsers = GlobalServices.onlineUsers.length;
|
||||
var welcome = "Welcome! There are " + numUsers + " users online now.";
|
||||
createNotification(welcome);
|
||||
}
|
||||
|
||||
var STARTUP_TIMEOUT = 500, // ms
|
||||
startingUp = true,
|
||||
startupTimer = null;
|
||||
|
||||
function finishStartup() {
|
||||
startingUp = false;
|
||||
Script.clearTimeout(startupTimer);
|
||||
reportUsers();
|
||||
}
|
||||
|
||||
function isStartingUp() {
|
||||
// Is starting up until get no checks that it is starting up for STARTUP_TIMEOUT
|
||||
if (startingUp) {
|
||||
if (startupTimer) {
|
||||
Script.clearTimeout(startupTimer);
|
||||
}
|
||||
startupTimer = Script.setTimeout(finishStartup, STARTUP_TIMEOUT);
|
||||
}
|
||||
return startingUp;
|
||||
}
|
||||
|
||||
|
||||
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
GlobalServices.connected.connect(onConnected);
|
||||
GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
||||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
|
|
|
@ -339,6 +339,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
// use our MyAvatar position and quat for address manager path
|
||||
addressManager->setPositionGetter(getPositionForPath);
|
||||
addressManager->setOrientationGetter(getOrientationForPath);
|
||||
|
||||
connect(addressManager.data(), &AddressManager::rootPlaceNameChanged, this, &Application::updateWindowTitle);
|
||||
|
||||
_settings = new QSettings(this);
|
||||
_numChangedSettings = 0;
|
||||
|
@ -917,13 +919,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
Menu::getInstance()->triggerOption(MenuOption::Chat);
|
||||
break;
|
||||
|
||||
case Qt::Key_N:
|
||||
if (isMeta) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::NameLocation);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
if (!isShifted) {
|
||||
|
@ -2803,7 +2798,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->prepare();
|
||||
|
||||
if (!selfAvatarOnly) {
|
||||
|
@ -2854,6 +2849,8 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
|
||||
|
||||
{
|
||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||
|
||||
PROFILE_RANGE("DeferredLighting");
|
||||
PerformanceTimer perfTimer("lighting");
|
||||
DependencyManager::get<DeferredLightingEffect>()->render();
|
||||
|
@ -3152,8 +3149,14 @@ void Application::updateWindowTitle(){
|
|||
|
||||
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) ";
|
||||
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
|
||||
QString currentPlaceName = DependencyManager::get<AddressManager>()->getRootPlaceName();
|
||||
|
||||
if (currentPlaceName.isEmpty()) {
|
||||
currentPlaceName = nodeList->getDomainHandler().getHostname();
|
||||
}
|
||||
|
||||
QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())
|
||||
+ DependencyManager::get<AddressManager>()->getCurrentDomain() + connectionStatus + buildVersion;
|
||||
+ currentPlaceName + connectionStatus + buildVersion;
|
||||
|
||||
#ifndef WIN32
|
||||
// crashes with vs2013/win32
|
||||
|
@ -3165,23 +3168,34 @@ void Application::updateWindowTitle(){
|
|||
void Application::updateLocationInServer() {
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
|
||||
if (accountManager.isLoggedIn() && domainHandler.isConnected() && !domainHandler.getUUID().isNull()) {
|
||||
if (accountManager.isLoggedIn() && domainHandler.isConnected()
|
||||
&& (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) {
|
||||
|
||||
// construct a QJsonObject given the user's current address information
|
||||
QJsonObject rootObject;
|
||||
|
||||
QJsonObject locationObject;
|
||||
|
||||
QString pathString = DependencyManager::get<AddressManager>()->currentPath();
|
||||
QString pathString = addressManager->currentPath();
|
||||
|
||||
const QString LOCATION_KEY_IN_ROOT = "location";
|
||||
const QString PATH_KEY_IN_LOCATION = "path";
|
||||
const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id";
|
||||
|
||||
const QString PATH_KEY_IN_LOCATION = "path";
|
||||
locationObject.insert(PATH_KEY_IN_LOCATION, pathString);
|
||||
locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, domainHandler.getUUID().toString());
|
||||
|
||||
if (!addressManager->getRootPlaceID().isNull()) {
|
||||
const QString PLACE_ID_KEY_IN_LOCATION = "place_id";
|
||||
locationObject.insert(PLACE_ID_KEY_IN_LOCATION,
|
||||
uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID()));
|
||||
|
||||
} else {
|
||||
const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id";
|
||||
locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION,
|
||||
uuidStringWithoutCurlyBraces(domainHandler.getUUID()));
|
||||
}
|
||||
|
||||
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
|
||||
|
||||
|
@ -3966,3 +3980,31 @@ float Application::getRenderResolutionScale() const {
|
|||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
int Application::getRenderAmbientLight() const {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLightGlobal)) {
|
||||
return -1;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight0)) {
|
||||
return 0;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight1)) {
|
||||
return 1;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight2)) {
|
||||
return 2;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight3)) {
|
||||
return 3;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight4)) {
|
||||
return 4;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight5)) {
|
||||
return 5;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight6)) {
|
||||
return 6;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight7)) {
|
||||
return 7;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight8)) {
|
||||
return 8;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight9)) {
|
||||
return 9;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <NodeList.h>
|
||||
#include <OctreeQuery.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PhysicsEngine.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <TextureCache.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
@ -287,6 +288,7 @@ public:
|
|||
bool isLookingAtMyAvatar(Avatar* avatar);
|
||||
|
||||
float getRenderResolutionScale() const;
|
||||
int getRenderAmbientLight() const;
|
||||
|
||||
unsigned int getRenderTargetFramerate() const;
|
||||
bool isVSyncOn() const;
|
||||
|
|
|
@ -134,16 +134,6 @@ Menu::Menu() :
|
|||
this, SLOT(deleteBookmark()));
|
||||
_deleteBookmarksMenu->setEnabled(false);
|
||||
loadBookmarks();
|
||||
addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::NameLocation,
|
||||
Qt::CTRL | Qt::Key_N,
|
||||
this,
|
||||
SLOT(nameLocation()));
|
||||
addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::MyLocations,
|
||||
Qt::CTRL | Qt::Key_K,
|
||||
this,
|
||||
SLOT(toggleLocationList()));
|
||||
addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::AddressBar,
|
||||
Qt::Key_Enter,
|
||||
|
@ -353,6 +343,21 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DisableAutoAdjustLOD);
|
||||
|
||||
QMenu* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
|
||||
QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu);
|
||||
ambientLightGroup->setExclusive(true);
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLightGlobal, 0, true));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight0, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight1, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight2, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight3, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight4, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight5, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight6, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight7, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false));
|
||||
|
||||
QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows");
|
||||
QActionGroup* shadowGroup = new QActionGroup(shadowMenu);
|
||||
|
@ -1172,66 +1177,6 @@ void Menu::displayNameLocationResponse(const QString& errorString) {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::toggleLocationList() {
|
||||
if (!_userLocationsDialog) {
|
||||
JavascriptObjectMap locationObjectMap;
|
||||
locationObjectMap.insert("InterfaceLocation", DependencyManager::get<AddressManager>().data());
|
||||
_userLocationsDialog = DataWebDialog::dialogForPath("/user/locations", locationObjectMap);
|
||||
}
|
||||
|
||||
if (!_userLocationsDialog->isVisible()) {
|
||||
_userLocationsDialog->show();
|
||||
}
|
||||
|
||||
_userLocationsDialog->raise();
|
||||
_userLocationsDialog->activateWindow();
|
||||
_userLocationsDialog->showNormal();
|
||||
|
||||
}
|
||||
|
||||
void Menu::nameLocation() {
|
||||
// check if user is logged in or show login dialog if not
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
|
||||
if (!accountManager.isLoggedIn()) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("We need to tie this location to your username.");
|
||||
msgBox.setInformativeText("Please login first, then try naming the location again.");
|
||||
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||
msgBox.button(QMessageBox::Ok)->setText("Login");
|
||||
|
||||
if (msgBox.exec() == QMessageBox::Ok) {
|
||||
loginForCurrentDomain();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
if (domainHandler.getUUID().isNull()) {
|
||||
const QString UNREGISTERED_DOMAIN_MESSAGE = "This domain is not registered with High Fidelity."
|
||||
"\n\nYou cannot create a global location in an unregistered domain.";
|
||||
QMessageBox::critical(this, "Unregistered Domain", UNREGISTERED_DOMAIN_MESSAGE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_newLocationDialog) {
|
||||
JavascriptObjectMap locationObjectMap;
|
||||
locationObjectMap.insert("InterfaceLocation", DependencyManager::get<AddressManager>().data());
|
||||
_newLocationDialog = DataWebDialog::dialogForPath("/user/locations/new", locationObjectMap);
|
||||
}
|
||||
|
||||
if (!_newLocationDialog->isVisible()) {
|
||||
_newLocationDialog->show();
|
||||
}
|
||||
|
||||
_newLocationDialog->raise();
|
||||
_newLocationDialog->activateWindow();
|
||||
_newLocationDialog->showNormal();
|
||||
}
|
||||
|
||||
void Menu::toggleLoginMenuItem() {
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
|
||||
|
|
|
@ -205,8 +205,6 @@ private slots:
|
|||
void bookmarkLocation();
|
||||
void teleportToBookmark();
|
||||
void deleteBookmark();
|
||||
void nameLocation();
|
||||
void toggleLocationList();
|
||||
void hmdToolsClosed();
|
||||
void runTests();
|
||||
void showMetavoxelEditor();
|
||||
|
@ -292,8 +290,6 @@ private:
|
|||
QPointer<AttachmentsDialog> _attachmentsDialog;
|
||||
QPointer<BandwidthDialog> _bandwidthDialog;
|
||||
QPointer<CachesSizeDialog> _cachesSizeDialog;
|
||||
QPointer<DataWebDialog> _newLocationDialog;
|
||||
QPointer<DataWebDialog> _userLocationsDialog;
|
||||
QPointer<HMDToolsDialog> _hmdToolsDialog;
|
||||
QPointer<LodToolsDialog> _lodToolsDialog;
|
||||
QPointer<LoginDialog> _loginDialog;
|
||||
|
@ -413,8 +409,6 @@ namespace MenuOption {
|
|||
const QString Mirror = "Mirror";
|
||||
const QString MuteAudio = "Mute Microphone";
|
||||
const QString MuteEnvironment = "Mute Environment";
|
||||
const QString MyLocations = "My Locations...";
|
||||
const QString NameLocation = "Name this location";
|
||||
const QString NetworkSimulator = "Network Simulator...";
|
||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||
const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
|
||||
|
@ -446,6 +440,18 @@ namespace MenuOption {
|
|||
const QString RenderResolutionHalf = "1/2";
|
||||
const QString RenderResolutionThird = "1/3";
|
||||
const QString RenderResolutionQuarter = "1/4";
|
||||
const QString RenderAmbientLight = "Ambient Light";
|
||||
const QString RenderAmbientLightGlobal = "Global";
|
||||
const QString RenderAmbientLight0 = "OLD_TOWN_SQUARE";
|
||||
const QString RenderAmbientLight1 = "GRACE_CATHEDRAL";
|
||||
const QString RenderAmbientLight2 = "EUCALYPTUS_GROVE";
|
||||
const QString RenderAmbientLight3 = "ST_PETERS_BASILICA";
|
||||
const QString RenderAmbientLight4 = "UFFIZI_GALLERY";
|
||||
const QString RenderAmbientLight5 = "GALILEOS_TOMB";
|
||||
const QString RenderAmbientLight6 = "VINE_STREET_KITCHEN";
|
||||
const QString RenderAmbientLight7 = "BREEZEWAY";
|
||||
const QString RenderAmbientLight8 = "CAMPUS_SUNSET";
|
||||
const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET";
|
||||
const QString ResetAvatarSize = "Reset Avatar Size";
|
||||
const QString ResetSensors = "Reset Sensors";
|
||||
const QString RunningScripts = "Running Scripts";
|
||||
|
|
|
@ -31,20 +31,30 @@ static const QString IS_TRUNCATED_NAME = "IsTruncated";
|
|||
static const QString CONTAINER_NAME = "Contents";
|
||||
static const QString KEY_NAME = "Key";
|
||||
|
||||
ScriptItem::ScriptItem(const QString& filename, const QString& fullPath) :
|
||||
_filename(filename),
|
||||
_fullPath(fullPath) {
|
||||
TreeNodeBase::TreeNodeBase(TreeNodeFolder* parent, const QString& name, TreeNodeType type) :
|
||||
_parent(parent),
|
||||
_name(name),
|
||||
_type(type) {
|
||||
};
|
||||
|
||||
TreeNodeScript::TreeNodeScript(const QString& localPath, const QString& fullPath, ScriptOrigin origin) :
|
||||
TreeNodeBase(NULL, localPath.split("/").last(), TREE_NODE_TYPE_SCRIPT),
|
||||
_localPath(localPath),
|
||||
_fullPath(fullPath),
|
||||
_origin(origin) {
|
||||
};
|
||||
|
||||
TreeNodeFolder::TreeNodeFolder(const QString& foldername, TreeNodeFolder* parent) :
|
||||
TreeNodeBase(parent, foldername, TREE_NODE_TYPE_FOLDER) {
|
||||
};
|
||||
|
||||
ScriptsModel::ScriptsModel(QObject* parent) :
|
||||
QAbstractListModel(parent),
|
||||
QAbstractItemModel(parent),
|
||||
_loadingScripts(false),
|
||||
_localDirectory(),
|
||||
_fsWatcher(),
|
||||
_localFiles(),
|
||||
_remoteFiles()
|
||||
_treeNodes()
|
||||
{
|
||||
|
||||
_localDirectory.setFilter(QDir::Files | QDir::Readable);
|
||||
_localDirectory.setNameFilters(QStringList("*.js"));
|
||||
|
||||
|
@ -57,31 +67,61 @@ ScriptsModel::ScriptsModel(QObject* parent) :
|
|||
reloadRemoteFiles();
|
||||
}
|
||||
|
||||
QVariant ScriptsModel::data(const QModelIndex& index, int role) const {
|
||||
const QList<ScriptItem*>* files = NULL;
|
||||
int row = 0;
|
||||
bool isLocal = index.row() < _localFiles.size();
|
||||
if (isLocal) {
|
||||
files = &_localFiles;
|
||||
row = index.row();
|
||||
} else {
|
||||
files = &_remoteFiles;
|
||||
row = index.row() - _localFiles.size();
|
||||
}
|
||||
ScriptsModel::~ScriptsModel() {
|
||||
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
|
||||
delete _treeNodes.at(i);
|
||||
}
|
||||
_treeNodes.clear();
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
return QVariant((*files)[row]->getFilename() + (isLocal ? " (local)" : ""));
|
||||
} else if (role == ScriptPath) {
|
||||
return QVariant((*files)[row]->getFullPath());
|
||||
TreeNodeBase* ScriptsModel::getTreeNodeFromIndex(const QModelIndex& index) const {
|
||||
if (index.isValid()) {
|
||||
return static_cast<TreeNodeBase*>(index.internalPointer());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QModelIndex ScriptsModel::index(int row, int column, const QModelIndex& parent) const {
|
||||
if (row < 0 || column < 0) {
|
||||
return QModelIndex();
|
||||
}
|
||||
return createIndex(row, column, getFolderNodes(static_cast<TreeNodeFolder*>(getTreeNodeFromIndex(parent))).at(row));
|
||||
}
|
||||
|
||||
QModelIndex ScriptsModel::parent(const QModelIndex& child) const {
|
||||
TreeNodeFolder* parent = (static_cast<TreeNodeBase*>(child.internalPointer()))->getParent();
|
||||
if (!parent) {
|
||||
return QModelIndex();
|
||||
}
|
||||
TreeNodeFolder* grandParent = parent->getParent();
|
||||
int row = getFolderNodes(grandParent).indexOf(parent);
|
||||
return createIndex(row, 0, parent);
|
||||
}
|
||||
|
||||
QVariant ScriptsModel::data(const QModelIndex& index, int role) const {
|
||||
TreeNodeBase* node = getTreeNodeFromIndex(index);
|
||||
if (node->getType() == TREE_NODE_TYPE_SCRIPT) {
|
||||
TreeNodeScript* script = static_cast<TreeNodeScript*>(node);
|
||||
if (role == Qt::DisplayRole) {
|
||||
return QVariant(script->getName() + (script->getOrigin() == SCRIPT_ORIGIN_LOCAL ? " (local)" : ""));
|
||||
} else if (role == ScriptPath) {
|
||||
return QVariant(script->getFullPath());
|
||||
}
|
||||
} else if (node->getType() == TREE_NODE_TYPE_FOLDER) {
|
||||
TreeNodeFolder* folder = static_cast<TreeNodeFolder*>(node);
|
||||
if (role == Qt::DisplayRole) {
|
||||
return QVariant(folder->getName());
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int ScriptsModel::rowCount(const QModelIndex& parent) const {
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return _localFiles.length() + _remoteFiles.length();
|
||||
return getFolderNodes(static_cast<TreeNodeFolder*>(getTreeNodeFromIndex(parent))).count();
|
||||
}
|
||||
|
||||
int ScriptsModel::columnCount(const QModelIndex& parent) const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ScriptsModel::updateScriptsLocation(const QString& newPath) {
|
||||
|
@ -93,7 +133,7 @@ void ScriptsModel::updateScriptsLocation(const QString& newPath) {
|
|||
if (!_localDirectory.absolutePath().isEmpty()) {
|
||||
_fsWatcher.addPath(_localDirectory.absolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reloadLocalFiles();
|
||||
}
|
||||
|
@ -101,8 +141,14 @@ void ScriptsModel::updateScriptsLocation(const QString& newPath) {
|
|||
void ScriptsModel::reloadRemoteFiles() {
|
||||
if (!_loadingScripts) {
|
||||
_loadingScripts = true;
|
||||
while (!_remoteFiles.isEmpty()) {
|
||||
delete _remoteFiles.takeFirst();
|
||||
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
|
||||
TreeNodeBase* node = _treeNodes.at(i);
|
||||
if (node->getType() == TREE_NODE_TYPE_SCRIPT &&
|
||||
static_cast<TreeNodeScript*>(node)->getOrigin() == SCRIPT_ORIGIN_REMOTE)
|
||||
{
|
||||
delete node;
|
||||
_treeNodes.removeAt(i);
|
||||
}
|
||||
}
|
||||
requestRemoteFiles();
|
||||
}
|
||||
|
@ -121,7 +167,6 @@ void ScriptsModel::requestRemoteFiles(QString marker) {
|
|||
QNetworkRequest request(url);
|
||||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
|
||||
|
||||
}
|
||||
|
||||
void ScriptsModel::downloadFinished() {
|
||||
|
@ -170,7 +215,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
|
|||
xml.readNext();
|
||||
lastKey = xml.text().toString();
|
||||
if (jsRegex.exactMatch(xml.text().toString())) {
|
||||
_remoteFiles.append(new ScriptItem(lastKey.mid(MODELS_LOCATION.length()), S3_URL + "/" + lastKey));
|
||||
_treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), S3_URL + "/" + lastKey, SCRIPT_ORIGIN_REMOTE));
|
||||
}
|
||||
}
|
||||
xml.readNext();
|
||||
|
@ -178,7 +223,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
|
|||
}
|
||||
xml.readNext();
|
||||
}
|
||||
|
||||
rebuildTree();
|
||||
endResetModel();
|
||||
|
||||
// Error handling
|
||||
|
@ -198,8 +243,14 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
|
|||
void ScriptsModel::reloadLocalFiles() {
|
||||
beginResetModel();
|
||||
|
||||
while (!_localFiles.isEmpty()) {
|
||||
delete _localFiles.takeFirst();
|
||||
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
|
||||
TreeNodeBase* node = _treeNodes.at(i);
|
||||
if (node->getType() == TREE_NODE_TYPE_SCRIPT &&
|
||||
static_cast<TreeNodeScript*>(node)->getOrigin() == SCRIPT_ORIGIN_LOCAL)
|
||||
{
|
||||
delete node;
|
||||
_treeNodes.removeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
_localDirectory.refresh();
|
||||
|
@ -207,8 +258,53 @@ void ScriptsModel::reloadLocalFiles() {
|
|||
const QFileInfoList localFiles = _localDirectory.entryInfoList();
|
||||
for (int i = 0; i < localFiles.size(); i++) {
|
||||
QFileInfo file = localFiles[i];
|
||||
_localFiles.append(new ScriptItem(file.fileName(), file.absoluteFilePath()));
|
||||
_treeNodes.append(new TreeNodeScript(file.fileName(), file.absoluteFilePath(), SCRIPT_ORIGIN_LOCAL));
|
||||
}
|
||||
|
||||
rebuildTree();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ScriptsModel::rebuildTree() {
|
||||
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
|
||||
if (_treeNodes.at(i)->getType() == TREE_NODE_TYPE_FOLDER) {
|
||||
delete _treeNodes.at(i);
|
||||
_treeNodes.removeAt(i);
|
||||
}
|
||||
}
|
||||
QHash<QString, TreeNodeFolder*> folders;
|
||||
for (int i = 0; i < _treeNodes.size(); i++) {
|
||||
TreeNodeBase* node = _treeNodes.at(i);
|
||||
if (node->getType() == TREE_NODE_TYPE_SCRIPT) {
|
||||
TreeNodeScript* script = static_cast<TreeNodeScript*>(node);
|
||||
TreeNodeFolder* parent = NULL;
|
||||
QString hash;
|
||||
QStringList pathList = script->getLocalPath().split(tr("/"));
|
||||
pathList.removeLast();
|
||||
QStringList::const_iterator pathIterator;
|
||||
for (pathIterator = pathList.constBegin(); pathIterator != pathList.constEnd(); ++pathIterator) {
|
||||
hash.append(*pathIterator + "/");
|
||||
if (!folders.contains(hash)) {
|
||||
folders[hash] = new TreeNodeFolder(*pathIterator, parent);
|
||||
}
|
||||
parent = folders[hash];
|
||||
}
|
||||
script->setParent(parent);
|
||||
}
|
||||
}
|
||||
QHash<QString, TreeNodeFolder*>::const_iterator folderIterator;
|
||||
for (folderIterator = folders.constBegin(); folderIterator != folders.constEnd(); ++folderIterator) {
|
||||
_treeNodes.append(*folderIterator);
|
||||
}
|
||||
folders.clear();
|
||||
}
|
||||
|
||||
QList<TreeNodeBase*> ScriptsModel::getFolderNodes(TreeNodeFolder* parent) const {
|
||||
QList<TreeNodeBase*> result;
|
||||
for (int i = 0; i < _treeNodes.size(); i++) {
|
||||
TreeNodeBase* node = _treeNodes.at(i);
|
||||
if (node->getParent() == parent) {
|
||||
result.append(node);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -12,30 +12,69 @@
|
|||
#ifndef hifi_ScriptsModel_h
|
||||
#define hifi_ScriptsModel_h
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDir>
|
||||
#include <QNetworkReply>
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
class ScriptItem {
|
||||
public:
|
||||
ScriptItem(const QString& filename, const QString& fullPath);
|
||||
class TreeNodeFolder;
|
||||
|
||||
const QString& getFilename() { return _filename; };
|
||||
const QString& getFullPath() { return _fullPath; };
|
||||
|
||||
private:
|
||||
QString _filename;
|
||||
QString _fullPath;
|
||||
enum ScriptOrigin {
|
||||
SCRIPT_ORIGIN_LOCAL,
|
||||
SCRIPT_ORIGIN_REMOTE
|
||||
};
|
||||
|
||||
class ScriptsModel : public QAbstractListModel {
|
||||
enum TreeNodeType {
|
||||
TREE_NODE_TYPE_SCRIPT,
|
||||
TREE_NODE_TYPE_FOLDER
|
||||
};
|
||||
|
||||
class TreeNodeBase {
|
||||
public:
|
||||
TreeNodeFolder* getParent() const { return _parent; }
|
||||
void setParent(TreeNodeFolder* parent) { _parent = parent; }
|
||||
TreeNodeType getType() { return _type; }
|
||||
const QString& getName() { return _name; };
|
||||
|
||||
private:
|
||||
TreeNodeFolder* _parent;
|
||||
TreeNodeType _type;
|
||||
|
||||
protected:
|
||||
QString _name;
|
||||
TreeNodeBase(TreeNodeFolder* parent, const QString& name, TreeNodeType type);
|
||||
};
|
||||
|
||||
class TreeNodeScript : public TreeNodeBase {
|
||||
public:
|
||||
TreeNodeScript(const QString& localPath, const QString& fullPath, ScriptOrigin origin);
|
||||
const QString& getLocalPath() { return _localPath; }
|
||||
const QString& getFullPath() { return _fullPath; };
|
||||
const ScriptOrigin getOrigin() { return _origin; };
|
||||
|
||||
private:
|
||||
QString _localPath;
|
||||
QString _fullPath;
|
||||
ScriptOrigin _origin;
|
||||
};
|
||||
|
||||
class TreeNodeFolder : public TreeNodeBase {
|
||||
public:
|
||||
TreeNodeFolder(const QString& foldername, TreeNodeFolder* parent);
|
||||
};
|
||||
|
||||
class ScriptsModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScriptsModel(QObject* parent = NULL);
|
||||
|
||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||
~ScriptsModel();
|
||||
QModelIndex index(int row, int column, const QModelIndex& parent) const;
|
||||
QModelIndex parent(const QModelIndex& child) const;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||
TreeNodeBase* getTreeNodeFromIndex(const QModelIndex& index) const;
|
||||
QList<TreeNodeBase*> getFolderNodes(TreeNodeFolder* parent) const;
|
||||
|
||||
enum Role {
|
||||
ScriptPath = Qt::UserRole,
|
||||
|
@ -50,13 +89,13 @@ protected slots:
|
|||
protected:
|
||||
void requestRemoteFiles(QString marker = QString());
|
||||
bool parseXML(QByteArray xmlFile);
|
||||
void rebuildTree();
|
||||
|
||||
private:
|
||||
bool _loadingScripts;
|
||||
QDir _localDirectory;
|
||||
QFileSystemWatcher _fsWatcher;
|
||||
QList<ScriptItem*> _localFiles;
|
||||
QList<ScriptItem*> _remoteFiles;
|
||||
QList<TreeNodeBase*> _treeNodes;
|
||||
};
|
||||
|
||||
#endif // hifi_ScriptsModel_h
|
||||
|
|
44
interface/src/ScriptsModelFilter.cpp
Normal file
44
interface/src/ScriptsModelFilter.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// ScriptsModelFilter.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Thijs Wenker on 01/11/15.
|
||||
// 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 "ScriptsModelFilter.h"
|
||||
|
||||
ScriptsModelFilter::ScriptsModelFilter(QObject *parent) :
|
||||
QSortFilterProxyModel(parent) {
|
||||
}
|
||||
|
||||
bool ScriptsModelFilter::lessThan(const QModelIndex& left, const QModelIndex& right) const {
|
||||
ScriptsModel* scriptsModel = static_cast<ScriptsModel*>(sourceModel());
|
||||
TreeNodeBase* leftNode = scriptsModel->getTreeNodeFromIndex(left);
|
||||
TreeNodeBase* rightNode = scriptsModel->getTreeNodeFromIndex(right);
|
||||
if (leftNode->getType() != rightNode->getType()) {
|
||||
return leftNode->getType() == TREE_NODE_TYPE_FOLDER;
|
||||
}
|
||||
return leftNode->getName() < rightNode->getName();
|
||||
}
|
||||
|
||||
bool ScriptsModelFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const {
|
||||
if (!filterRegExp().isEmpty()) {
|
||||
ScriptsModel* scriptsModel = static_cast<ScriptsModel*>(sourceModel());
|
||||
TreeNodeBase* node = scriptsModel->getFolderNodes(
|
||||
static_cast<TreeNodeFolder*>(scriptsModel->getTreeNodeFromIndex(sourceParent))).at(sourceRow);
|
||||
QModelIndex sourceIndex = sourceModel()->index(sourceRow, this->filterKeyColumn(), sourceParent);
|
||||
if (node->getType() == TREE_NODE_TYPE_FOLDER) {
|
||||
int rows = scriptsModel->rowCount(sourceIndex);
|
||||
for (int i = 0; i < rows; i++) {
|
||||
if (filterAcceptsRow(i, sourceIndex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
|
||||
}
|
27
interface/src/ScriptsModelFilter.h
Normal file
27
interface/src/ScriptsModelFilter.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// ScriptsModelFilter.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Thijs Wenker on 01/11/15.
|
||||
// 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_ScriptsModelFilter_h
|
||||
#define hifi_ScriptsModelFilter_h
|
||||
|
||||
#include "ScriptsModel.h"
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class ScriptsModelFilter : public QSortFilterProxyModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScriptsModelFilter(QObject *parent = NULL);
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const;
|
||||
bool lessThan(const QModelIndex& left, const QModelIndex& right) const;
|
||||
};
|
||||
|
||||
#endif // hifi_ScriptsModelFilter_h
|
|
@ -25,16 +25,9 @@ QScriptValue LocationScriptingInterface::locationGetter(QScriptContext* context,
|
|||
QScriptValue LocationScriptingInterface::locationSetter(QScriptContext* context, QScriptEngine* engine) {
|
||||
const QVariant& argumentVariant = context->argument(0).toVariant();
|
||||
|
||||
|
||||
if (argumentVariant.canConvert(QMetaType::QVariantMap)) {
|
||||
// this argument is a variant map, so we'll assume it's an address map
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AddressManager>().data(), "goToAddressFromObject",
|
||||
Q_ARG(const QVariantMap&, argumentVariant.toMap()));
|
||||
} else {
|
||||
// just try and convert the argument to a string, should be a hifi:// address
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AddressManager>().data(), "handleLookupString",
|
||||
Q_ARG(const QString&, argumentVariant.toString()));
|
||||
}
|
||||
// just try and convert the argument to a string, should be a hifi:// address
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AddressManager>().data(), "handleLookupString",
|
||||
Q_ARG(const QString&, argumentVariant.toString()));
|
||||
|
||||
return QScriptValue::UndefinedValue;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
|
|||
Qt::WindowCloseButtonHint),
|
||||
ui(new Ui::RunningScriptsWidget),
|
||||
_signalMapper(this),
|
||||
_proxyModel(this),
|
||||
_scriptsModelFilter(this),
|
||||
_scriptsModel(this) {
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -41,46 +41,49 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
|
|||
|
||||
ui->filterLineEdit->installEventFilter(this);
|
||||
|
||||
connect(&_proxyModel, &QSortFilterProxyModel::modelReset,
|
||||
connect(&_scriptsModelFilter, &QSortFilterProxyModel::modelReset,
|
||||
this, &RunningScriptsWidget::selectFirstInList);
|
||||
|
||||
QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText);
|
||||
ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts.");
|
||||
|
||||
_proxyModel.setSourceModel(&_scriptsModel);
|
||||
_proxyModel.sort(0, Qt::AscendingOrder);
|
||||
_proxyModel.setDynamicSortFilter(true);
|
||||
ui->scriptListView->setModel(&_proxyModel);
|
||||
_scriptsModelFilter.setSourceModel(&_scriptsModel);
|
||||
_scriptsModelFilter.sort(0, Qt::AscendingOrder);
|
||||
_scriptsModelFilter.setDynamicSortFilter(true);
|
||||
ui->scriptTreeView->setModel(&_scriptsModelFilter);
|
||||
|
||||
connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter);
|
||||
connect(ui->scriptListView, &QListView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList);
|
||||
connect(ui->scriptTreeView, &QTreeView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList);
|
||||
|
||||
connect(ui->reloadAllButton, &QPushButton::clicked,
|
||||
Application::getInstance(), &Application::reloadAllScripts);
|
||||
connect(ui->stopAllButton, &QPushButton::clicked,
|
||||
this, &RunningScriptsWidget::allScriptsStopped);
|
||||
connect(ui->loadScriptButton, &QPushButton::clicked,
|
||||
connect(ui->loadScriptFromDiskButton, &QPushButton::clicked,
|
||||
Application::getInstance(), &Application::loadDialog);
|
||||
connect(ui->loadScriptFromURLButton, &QPushButton::clicked,
|
||||
Application::getInstance(), &Application::loadScriptURLDialog);
|
||||
connect(&_signalMapper, SIGNAL(mapped(QString)), Application::getInstance(), SLOT(stopScript(const QString&)));
|
||||
}
|
||||
|
||||
RunningScriptsWidget::~RunningScriptsWidget() {
|
||||
delete ui;
|
||||
_scriptsModel.deleteLater();
|
||||
}
|
||||
|
||||
void RunningScriptsWidget::updateFileFilter(const QString& filter) {
|
||||
QRegExp regex("^.*" + QRegExp::escape(filter) + ".*$", Qt::CaseInsensitive);
|
||||
_proxyModel.setFilterRegExp(regex);
|
||||
_scriptsModelFilter.setFilterRegExp(regex);
|
||||
selectFirstInList();
|
||||
}
|
||||
|
||||
void RunningScriptsWidget::loadScriptFromList(const QModelIndex& index) {
|
||||
QVariant scriptFile = _proxyModel.data(index, ScriptsModel::ScriptPath);
|
||||
QVariant scriptFile = _scriptsModelFilter.data(index, ScriptsModel::ScriptPath);
|
||||
Application::getInstance()->loadScript(scriptFile.toString());
|
||||
}
|
||||
|
||||
void RunningScriptsWidget::loadSelectedScript() {
|
||||
QModelIndex selectedIndex = ui->scriptListView->currentIndex();
|
||||
QModelIndex selectedIndex = ui->scriptTreeView->currentIndex();
|
||||
if (selectedIndex.isValid()) {
|
||||
loadScriptFromList(selectedIndex);
|
||||
}
|
||||
|
@ -165,8 +168,8 @@ void RunningScriptsWidget::showEvent(QShowEvent* event) {
|
|||
}
|
||||
|
||||
void RunningScriptsWidget::selectFirstInList() {
|
||||
if (_proxyModel.rowCount() > 0) {
|
||||
ui->scriptListView->setCurrentIndex(_proxyModel.index(0, 0));
|
||||
if (_scriptsModelFilter.rowCount() > 0) {
|
||||
ui->scriptTreeView->setCurrentIndex(_scriptsModelFilter.index(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +180,7 @@ bool RunningScriptsWidget::eventFilter(QObject* sender, QEvent* event) {
|
|||
}
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
|
||||
QModelIndex selectedIndex = ui->scriptListView->currentIndex();
|
||||
QModelIndex selectedIndex = ui->scriptTreeView->currentIndex();
|
||||
if (selectedIndex.isValid()) {
|
||||
loadScriptFromList(selectedIndex);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "ScriptsModel.h"
|
||||
#include "ScriptsModelFilter.h"
|
||||
#include "ScriptsTableWidget.h"
|
||||
|
||||
namespace Ui {
|
||||
|
@ -54,7 +55,7 @@ private slots:
|
|||
private:
|
||||
Ui::RunningScriptsWidget* ui;
|
||||
QSignalMapper _signalMapper;
|
||||
QSortFilterProxyModel _proxyModel;
|
||||
ScriptsModelFilter _scriptsModelFilter;
|
||||
ScriptsModel _scriptsModel;
|
||||
ScriptsTableWidget* _recentlyLoadedScriptsTable;
|
||||
QStringList _recentlyLoadedScripts;
|
||||
|
|
|
@ -41,7 +41,9 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
|
|||
_rotation(base3DOverlay->_rotation),
|
||||
_isSolid(base3DOverlay->_isSolid),
|
||||
_isDashedLine(base3DOverlay->_isDashedLine),
|
||||
_ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection)
|
||||
_ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection),
|
||||
_drawInFront(base3DOverlay->_drawInFront),
|
||||
_drawOnHUD(base3DOverlay->_drawOnHUD)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -245,8 +245,8 @@ font: bold 16px;
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>328</width>
|
||||
<height>18</height>
|
||||
<width>334</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -373,7 +373,7 @@ font: bold 16px;
|
|||
font: bold 16px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scripts</string>
|
||||
<string>Load Scripts</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -391,9 +391,16 @@ font: bold 16px;</string>
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="loadScriptButton">
|
||||
<widget class="QPushButton" name="loadScriptFromURLButton">
|
||||
<property name="text">
|
||||
<string>Load script</string>
|
||||
<string>from URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="loadScriptFromDiskButton">
|
||||
<property name="text">
|
||||
<string>from Disk</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -429,7 +436,7 @@ font: bold 16px;</string>
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="scriptListView">
|
||||
<widget class="QTreeView" name="scriptTreeView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -442,6 +449,12 @@ font: bold 16px;</string>
|
|||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -691,15 +691,7 @@ void EntityItem::simulate(const quint64& now) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// When Bullet is available we assume that "zero velocity" means "at rest"
|
||||
// because of collision conditions this simulation does not know about
|
||||
// so we don't fall in for the non-zero gravity case here.
|
||||
if (hasVelocity()) {
|
||||
#else // !USE_BULLET_PHYSICS
|
||||
if (hasVelocity() || hasGravity()) {
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
// linear damping
|
||||
glm::vec3 velocity = getVelocity();
|
||||
if (_damping > 0.0f) {
|
||||
|
@ -733,14 +725,6 @@ void EntityItem::simulate(const quint64& now) {
|
|||
// handle bounces off the ground... We bounce at the distance to the bottom of our entity
|
||||
if (position.y <= getDistanceToBottomOfEntity()) {
|
||||
velocity = velocity * glm::vec3(1,-1,1);
|
||||
|
||||
#ifndef USE_BULLET_PHYSICS
|
||||
// if we've slowed considerably, then just stop moving, but only if no BULLET
|
||||
if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) {
|
||||
velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
}
|
||||
#endif // !USE_BULLET_PHYSICS
|
||||
|
||||
position.y = getDistanceToBottomOfEntity();
|
||||
}
|
||||
|
||||
|
@ -756,14 +740,8 @@ void EntityItem::simulate(const quint64& now) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// When Bullet is available we assume that it will tell us when velocities go to zero...
|
||||
#else // !USE_BULLET_PHYSICS
|
||||
// ... otherwise we help things come to rest by clamping small velocities.
|
||||
if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) {
|
||||
velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
// NOTE: we don't zero out very small velocities --> we rely on a remote Bullet simulation
|
||||
// to tell us when the entity has stopped.
|
||||
|
||||
// NOTE: the simulation should NOT set any DirtyFlags on this entity
|
||||
setPosition(position); // this will automatically recalculate our collision shape
|
||||
|
@ -780,14 +758,56 @@ void EntityItem::simulate(const quint64& now) {
|
|||
_lastSimulated = now;
|
||||
}
|
||||
|
||||
void EntityItem::simulateSimpleKinematicMotion(float timeElapsed) {
|
||||
if (hasAngularVelocity()) {
|
||||
// angular damping
|
||||
glm::vec3 angularVelocity = getAngularVelocity();
|
||||
if (_angularDamping > 0.0f) {
|
||||
angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
|
||||
setAngularVelocity(angularVelocity);
|
||||
}
|
||||
|
||||
float angularSpeed = glm::length(_angularVelocity);
|
||||
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; //
|
||||
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
|
||||
setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
|
||||
} else {
|
||||
// NOTE: angularSpeed is currently in degrees/sec!!!
|
||||
// TODO: Andrew to convert to radians/sec
|
||||
float angle = timeElapsed * glm::radians(angularSpeed);
|
||||
glm::vec3 axis = _angularVelocity / angularSpeed;
|
||||
glm::quat dQ = glm::angleAxis(angle, axis);
|
||||
glm::quat rotation = getRotation();
|
||||
rotation = glm::normalize(dQ * rotation);
|
||||
setRotation(rotation);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasVelocity()) {
|
||||
// linear damping
|
||||
glm::vec3 velocity = getVelocity();
|
||||
if (_damping > 0.0f) {
|
||||
velocity *= powf(1.0f - _damping, timeElapsed);
|
||||
}
|
||||
|
||||
// integrate position forward
|
||||
glm::vec3 position = getPosition() + (velocity * timeElapsed);
|
||||
|
||||
// apply gravity
|
||||
if (hasGravity()) {
|
||||
// handle resting on surface case, this is definitely a bit of a hack, and it only works on the
|
||||
// "ground" plane of the domain, but for now it's what we've got
|
||||
velocity += getGravity() * timeElapsed;
|
||||
}
|
||||
|
||||
// NOTE: the simulation should NOT set any DirtyFlags on this entity
|
||||
setPosition(position); // this will automatically recalculate our collision shape
|
||||
setVelocity(velocity);
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityItem::isMoving() const {
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// When Bullet is available we assume that "zero velocity" means "at rest"
|
||||
// because of collision conditions this simulation does not know about.
|
||||
return hasVelocity() || hasAngularVelocity();
|
||||
#else // !USE_BULLET_PHYSICS
|
||||
return hasVelocity() || (hasGravity() && !isRestingOnSurface()) || hasAngularVelocity();
|
||||
#endif //USE_BULLET_PHYSICS
|
||||
}
|
||||
|
||||
bool EntityItem::lifetimeHasExpired() const {
|
||||
|
|
|
@ -128,6 +128,8 @@ public:
|
|||
|
||||
// perform linear extrapolation for SimpleEntitySimulation
|
||||
void simulate(const quint64& now);
|
||||
|
||||
void simulateSimpleKinematicMotion(float timeElapsed);
|
||||
|
||||
virtual bool needsToCallUpdate() const { return false; }
|
||||
|
||||
|
|
|
@ -494,13 +494,16 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) {
|
|||
#if defined(Q_OS_MAC)
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
#else
|
||||
|
||||
// NOT working so we ll stick to the uniform float array until we move to core profile
|
||||
// GLuint bo = getBufferID(*uniformBuffer);
|
||||
//glUniformBufferEXT(_shader._program, slot, bo);
|
||||
#elif defined(Q_OS_WIN)
|
||||
GLuint bo = getBufferID(*uniformBuffer);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize);
|
||||
|
||||
// glUniformBufferEXT(_shader._program, slot, bo);
|
||||
|
||||
//glBindBufferBase(GL_UNIFORM_BUFFER, slot, bo);
|
||||
#else
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
#endif
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#include "AddressManager.h"
|
||||
|
||||
AddressManager::AddressManager() :
|
||||
_currentDomain(),
|
||||
_rootPlaceName(),
|
||||
_rootPlaceID(),
|
||||
_positionGetter(NULL),
|
||||
_orientationGetter(NULL)
|
||||
{
|
||||
|
@ -37,7 +38,7 @@ const QUrl AddressManager::currentAddress() const {
|
|||
QUrl hifiURL;
|
||||
|
||||
hifiURL.setScheme(HIFI_URL_SCHEME);
|
||||
hifiURL.setHost(_currentDomain);
|
||||
hifiURL.setHost(_rootPlaceName);
|
||||
hifiURL.setPath(currentPath());
|
||||
|
||||
return hifiURL;
|
||||
|
@ -88,11 +89,6 @@ const QString AddressManager::currentPath(bool withOrientation) const {
|
|||
}
|
||||
}
|
||||
|
||||
QString AddressManager::getDomainID() const {
|
||||
const QUuid& domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID();
|
||||
return domainID.isNull() ? "" : uuidStringWithoutCurlyBraces(domainID);
|
||||
}
|
||||
|
||||
const JSONCallbackParameters& AddressManager::apiCallbackParameters() {
|
||||
static bool hasSetupParameters = false;
|
||||
static JSONCallbackParameters callbackParams;
|
||||
|
@ -173,67 +169,83 @@ void AddressManager::handleAPIResponse(QNetworkReply& requestReply) {
|
|||
emit lookupResultsFinished();
|
||||
}
|
||||
|
||||
void AddressManager::goToAddressFromObject(const QVariantMap& addressMap) {
|
||||
const QString ADDRESS_API_DOMAIN_KEY = "domain";
|
||||
const QString ADDRESS_API_ONLINE_KEY = "online";
|
||||
void AddressManager::goToAddressFromObject(const QVariantMap& dataObject) {
|
||||
|
||||
if (!addressMap.contains(ADDRESS_API_ONLINE_KEY)
|
||||
|| addressMap[ADDRESS_API_ONLINE_KEY].toBool()) {
|
||||
const QString DATA_OBJECT_PLACE_KEY = "place";
|
||||
const QString DATA_OBJECT_USER_LOCATION_KEY = "location";
|
||||
|
||||
QVariantMap locationMap;
|
||||
if (dataObject.contains(DATA_OBJECT_PLACE_KEY)) {
|
||||
locationMap = dataObject[DATA_OBJECT_PLACE_KEY].toMap();
|
||||
} else {
|
||||
locationMap = dataObject[DATA_OBJECT_USER_LOCATION_KEY].toMap();
|
||||
}
|
||||
|
||||
if (!locationMap.isEmpty()) {
|
||||
const QString LOCATION_API_ROOT_KEY = "root";
|
||||
const QString LOCATION_API_DOMAIN_KEY = "domain";
|
||||
const QString LOCATION_API_ONLINE_KEY = "online";
|
||||
|
||||
if (addressMap.contains(ADDRESS_API_DOMAIN_KEY)) {
|
||||
QVariantMap domainObject = addressMap[ADDRESS_API_DOMAIN_KEY].toMap();
|
||||
if (!locationMap.contains(LOCATION_API_ONLINE_KEY)
|
||||
|| locationMap[LOCATION_API_ONLINE_KEY].toBool()) {
|
||||
|
||||
const QString DOMAIN_NETWORK_ADDRESS_KEY = "network_address";
|
||||
const QString DOMAIN_ICE_SERVER_ADDRESS_KEY = "ice_server_address";
|
||||
|
||||
if (domainObject.contains(DOMAIN_NETWORK_ADDRESS_KEY)) {
|
||||
QString domainHostname = domainObject[DOMAIN_NETWORK_ADDRESS_KEY].toString();
|
||||
|
||||
emit possibleDomainChangeRequired(domainHostname, DEFAULT_DOMAIN_SERVER_PORT);
|
||||
} else {
|
||||
QString iceServerAddress = domainObject[DOMAIN_ICE_SERVER_ADDRESS_KEY].toString();
|
||||
|
||||
const QString DOMAIN_ID_KEY = "id";
|
||||
QString domainIDString = domainObject[DOMAIN_ID_KEY].toString();
|
||||
QUuid domainID(domainIDString);
|
||||
|
||||
emit possibleDomainChangeRequiredViaICEForID(iceServerAddress, domainID);
|
||||
QVariantMap rootMap = locationMap[LOCATION_API_ROOT_KEY].toMap();
|
||||
if (rootMap.isEmpty()) {
|
||||
rootMap = locationMap;
|
||||
}
|
||||
|
||||
// set our current domain to the name that came back
|
||||
const QString DOMAIN_NAME_KEY = "name";
|
||||
QVariantMap domainObject = rootMap[LOCATION_API_DOMAIN_KEY].toMap();
|
||||
|
||||
_currentDomain = domainObject[DOMAIN_NAME_KEY].toString();
|
||||
|
||||
// take the path that came back
|
||||
const QString LOCATION_KEY = "location";
|
||||
const QString LOCATION_PATH_KEY = "path";
|
||||
QString returnedPath;
|
||||
|
||||
if (domainObject.contains(LOCATION_PATH_KEY)) {
|
||||
returnedPath = domainObject[LOCATION_PATH_KEY].toString();
|
||||
} else if (domainObject.contains(LOCATION_KEY)) {
|
||||
returnedPath = domainObject[LOCATION_KEY].toMap()[LOCATION_PATH_KEY].toString();
|
||||
} else if (addressMap.contains(LOCATION_PATH_KEY)) {
|
||||
returnedPath = addressMap[LOCATION_PATH_KEY].toString();
|
||||
}
|
||||
|
||||
bool shouldFaceViewpoint = addressMap.contains(ADDRESS_API_ONLINE_KEY);
|
||||
|
||||
if (!returnedPath.isEmpty()) {
|
||||
// try to parse this returned path as a viewpoint, that's the only thing it could be for now
|
||||
if (!handleRelativeViewpoint(returnedPath, shouldFaceViewpoint)) {
|
||||
qDebug() << "Received a location path that was could not be handled as a viewpoint -" << returnedPath;
|
||||
if (!domainObject.isEmpty()) {
|
||||
const QString DOMAIN_NETWORK_ADDRESS_KEY = "network_address";
|
||||
const QString DOMAIN_ICE_SERVER_ADDRESS_KEY = "ice_server_address";
|
||||
|
||||
if (domainObject.contains(DOMAIN_NETWORK_ADDRESS_KEY)) {
|
||||
QString domainHostname = domainObject[DOMAIN_NETWORK_ADDRESS_KEY].toString();
|
||||
|
||||
emit possibleDomainChangeRequired(domainHostname, DEFAULT_DOMAIN_SERVER_PORT);
|
||||
} else {
|
||||
QString iceServerAddress = domainObject[DOMAIN_ICE_SERVER_ADDRESS_KEY].toString();
|
||||
|
||||
const QString DOMAIN_ID_KEY = "id";
|
||||
QString domainIDString = domainObject[DOMAIN_ID_KEY].toString();
|
||||
QUuid domainID(domainIDString);
|
||||
|
||||
emit possibleDomainChangeRequiredViaICEForID(iceServerAddress, domainID);
|
||||
}
|
||||
|
||||
// set our current root place id to the ID that came back
|
||||
const QString PLACE_ID_KEY = "id";
|
||||
_rootPlaceID = rootMap[PLACE_ID_KEY].toUuid();
|
||||
|
||||
// set our current root place name to the name that came back
|
||||
const QString PLACE_NAME_KEY = "name";
|
||||
QString newRootPlaceName = rootMap[PLACE_NAME_KEY].toString();
|
||||
setRootPlaceName(newRootPlaceName);
|
||||
|
||||
// take the path that came back
|
||||
const QString PLACE_PATH_KEY = "path";
|
||||
QString returnedPath = locationMap[PLACE_PATH_KEY].toString();
|
||||
|
||||
bool shouldFaceViewpoint = locationMap.contains(LOCATION_API_ONLINE_KEY);
|
||||
|
||||
if (!returnedPath.isEmpty()) {
|
||||
// try to parse this returned path as a viewpoint, that's the only thing it could be for now
|
||||
if (!handleRelativeViewpoint(returnedPath, shouldFaceViewpoint)) {
|
||||
qDebug() << "Received a location path that was could not be handled as a viewpoint -" << returnedPath;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Received an address manager API response with no domain key. Cannot parse.";
|
||||
qDebug() << locationMap;
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << "Received an address manager API response with no domain key. Cannot parse.";
|
||||
qDebug() << addressMap;
|
||||
// we've been told that this result exists but is offline, emit our signal so the application can handle
|
||||
emit lookupResultIsOffline();
|
||||
}
|
||||
} else {
|
||||
// we've been told that this result exists but is offline, emit our signal so the application can handle
|
||||
emit lookupResultIsOffline();
|
||||
qDebug() << "Received an address manager API response with no location key or place key. Cannot parse.";
|
||||
qDebug() << locationMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,9 +377,18 @@ bool AddressManager::handleUsername(const QString& lookupString) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void AddressManager::setRootPlaceName(const QString& rootPlaceName) {
|
||||
if (rootPlaceName != _rootPlaceName) {
|
||||
_rootPlaceName = rootPlaceName;
|
||||
emit rootPlaceNameChanged(_rootPlaceName);
|
||||
}
|
||||
}
|
||||
|
||||
void AddressManager::setDomainInfo(const QString& hostname, quint16 port, const QString& domainName) {
|
||||
_currentDomain = domainName.isEmpty() ? hostname : domainName;
|
||||
|
||||
void AddressManager::setDomainInfo(const QString& hostname, quint16 port) {
|
||||
_rootPlaceName = hostname;
|
||||
_rootPlaceID = QUuid();
|
||||
|
||||
emit possibleDomainChangeRequired(hostname, port);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,9 +33,8 @@ class AddressManager : public QObject, public Dependency {
|
|||
Q_PROPERTY(bool isConnected READ isConnected)
|
||||
Q_PROPERTY(QUrl href READ currentAddress)
|
||||
Q_PROPERTY(QString protocol READ getProtocol)
|
||||
Q_PROPERTY(QString hostname READ getCurrentDomain)
|
||||
Q_PROPERTY(QString hostname READ getRootPlaceName)
|
||||
Q_PROPERTY(QString pathname READ currentPath)
|
||||
Q_PROPERTY(QString domainID READ getDomainID)
|
||||
public:
|
||||
bool isConnected();
|
||||
const QString& getProtocol() { return HIFI_URL_SCHEME; };
|
||||
|
@ -43,8 +42,10 @@ public:
|
|||
const QUrl currentAddress() const;
|
||||
const QString currentPath(bool withOrientation = true) const;
|
||||
|
||||
const QString& getCurrentDomain() const { return _currentDomain; }
|
||||
QString getDomainID() const;
|
||||
const QUuid& getRootPlaceID() const { return _rootPlaceID; }
|
||||
|
||||
const QString& getRootPlaceName() const { return _rootPlaceName; }
|
||||
void setRootPlaceName(const QString& rootPlaceName);
|
||||
|
||||
void attemptPlaceNameLookup(const QString& lookupString);
|
||||
|
||||
|
@ -69,13 +70,14 @@ signals:
|
|||
void locationChangeRequired(const glm::vec3& newPosition,
|
||||
bool hasOrientationChange, const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation);
|
||||
void rootPlaceNameChanged(const QString& newRootPlaceName);
|
||||
protected:
|
||||
AddressManager();
|
||||
private slots:
|
||||
void handleAPIResponse(QNetworkReply& requestReply);
|
||||
void handleAPIError(QNetworkReply& errorReply);
|
||||
private:
|
||||
void setDomainInfo(const QString& hostname, quint16 port, const QString& domainName = QString());
|
||||
void setDomainInfo(const QString& hostname, quint16 port);
|
||||
|
||||
const JSONCallbackParameters& apiCallbackParameters();
|
||||
|
||||
|
@ -85,7 +87,8 @@ private:
|
|||
bool handleRelativeViewpoint(const QString& pathSubsection, bool shouldFace = false);
|
||||
bool handleUsername(const QString& lookupString);
|
||||
|
||||
QString _currentDomain;
|
||||
QString _rootPlaceName;
|
||||
QUuid _rootPlaceID;
|
||||
PositionGetter _positionGetter;
|
||||
OrientationGetter _orientationGetter;
|
||||
};
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include "BulletUtil.h"
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
#include "EntityMotionState.h"
|
||||
#include "SimpleEntityKinematicController.h"
|
||||
|
||||
|
||||
QSet<EntityItem*>* _outgoingEntityList;
|
||||
|
||||
|
@ -40,13 +42,24 @@ EntityMotionState::~EntityMotionState() {
|
|||
assert(_entity);
|
||||
_entity->setPhysicsInfo(NULL);
|
||||
_entity = NULL;
|
||||
delete _kinematicController;
|
||||
_kinematicController = NULL;
|
||||
}
|
||||
|
||||
MotionType EntityMotionState::computeMotionType() const {
|
||||
// HACK: According to EntityTree the meaning of "static" is "not moving" whereas
|
||||
// to Bullet it means "can't move". For demo purposes we temporarily interpret
|
||||
// Entity::weightless to mean Bullet::static.
|
||||
return _entity->getCollisionsWillMove() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC;
|
||||
if (_entity->getCollisionsWillMove()) {
|
||||
return MOTION_TYPE_DYNAMIC;
|
||||
}
|
||||
return _entity->isMoving() ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
|
||||
}
|
||||
|
||||
void EntityMotionState::addKinematicController() {
|
||||
if (!_kinematicController) {
|
||||
_kinematicController = new SimpleEntityKinematicController(_entity);
|
||||
_kinematicController->start();
|
||||
} else {
|
||||
_kinematicController->start();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
@ -56,6 +69,9 @@ MotionType EntityMotionState::computeMotionType() const {
|
|||
// (2) at the beginning of each simulation frame for KINEMATIC RigidBody's --
|
||||
// it is an opportunity for outside code to update the object's simulation position
|
||||
void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
|
||||
if (_kinematicController && _kinematicController->isRunning()) {
|
||||
_kinematicController->stepForward();
|
||||
}
|
||||
worldTrans.setOrigin(glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset()));
|
||||
worldTrans.setRotation(glmToBullet(_entity->getRotation()));
|
||||
}
|
||||
|
@ -147,6 +163,9 @@ float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const {
|
|||
|
||||
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) {
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
if (!_entity->isKnownID()) {
|
||||
return; // never update entities that are unknown
|
||||
}
|
||||
if (_outgoingPacketFlags) {
|
||||
EntityItemProperties properties = _entity->getProperties();
|
||||
|
||||
|
@ -215,3 +234,17 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
}
|
||||
|
||||
uint32_t EntityMotionState::getIncomingDirtyFlags() const {
|
||||
uint32_t dirtyFlags = _entity->getDirtyFlags();
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings
|
||||
int bodyFlags = _body->getCollisionFlags();
|
||||
bool isMoving = _entity->isMoving();
|
||||
if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) ||
|
||||
(bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) {
|
||||
dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
return dirtyFlags;
|
||||
}
|
||||
|
|
|
@ -15,11 +15,14 @@
|
|||
#include <AACube.h>
|
||||
|
||||
#include "ObjectMotionState.h"
|
||||
|
||||
#ifndef USE_BULLET_PHYSICS
|
||||
// ObjectMotionState stubbery
|
||||
#include "KinematicController.h"
|
||||
class ObjectMotionState {
|
||||
public:
|
||||
// so that this stub implementation is not completely empty we give the class a data member
|
||||
KinematicController* _kinematicController;
|
||||
bool _stubData;
|
||||
};
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
@ -39,12 +42,16 @@ public:
|
|||
static void setOutgoingEntityList(QSet<EntityItem*>* list);
|
||||
static void enqueueOutgoingEntity(EntityItem* entity);
|
||||
|
||||
EntityMotionState() = delete; // prevent compiler from making default ctor
|
||||
EntityMotionState(EntityItem* item);
|
||||
virtual ~EntityMotionState();
|
||||
|
||||
/// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem
|
||||
MotionType computeMotionType() const;
|
||||
|
||||
// virtual override for ObjectMotionState
|
||||
void addKinematicController();
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// this relays incoming position/rotation to the RigidBody
|
||||
void getWorldTransform(btTransform& worldTrans) const;
|
||||
|
@ -62,7 +69,7 @@ public:
|
|||
|
||||
void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame);
|
||||
|
||||
uint32_t getIncomingDirtyFlags() const { return _entity->getDirtyFlags(); }
|
||||
uint32_t getIncomingDirtyFlags() const;
|
||||
void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); }
|
||||
|
||||
protected:
|
||||
|
|
22
libraries/physics/src/KinematicController.cpp
Normal file
22
libraries/physics/src/KinematicController.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// KinematicController.cpp
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2015.01.13
|
||||
// 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 "KinematicController.h"
|
||||
#include "PhysicsEngine.h"
|
||||
|
||||
KinematicController::KinematicController() {
|
||||
_lastFrame = PhysicsEngine::getFrameCount();
|
||||
}
|
||||
|
||||
void KinematicController::start() {
|
||||
_enabled = true;
|
||||
_lastFrame = PhysicsEngine::getFrameCount();
|
||||
}
|
36
libraries/physics/src/KinematicController.h
Normal file
36
libraries/physics/src/KinematicController.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// KinematicController.h
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2015.01.13
|
||||
// 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_KinematicController_h
|
||||
#define hifi_KinematicController_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/// KinematicController defines an API for derived classes.
|
||||
|
||||
class KinematicController {
|
||||
public:
|
||||
KinematicController();
|
||||
|
||||
virtual ~KinematicController() {}
|
||||
|
||||
virtual void stepForward() = 0;
|
||||
|
||||
void start();
|
||||
void stop() { _enabled = false; }
|
||||
bool isRunning() const { return _enabled; }
|
||||
|
||||
protected:
|
||||
bool _enabled = false;
|
||||
uint32_t _lastFrame;
|
||||
};
|
||||
|
||||
#endif // hifi_KinematicController_h
|
|
@ -14,7 +14,9 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "BulletUtil.h"
|
||||
#include "KinematicController.h"
|
||||
#include "ObjectMotionState.h"
|
||||
#include "PhysicsEngine.h"
|
||||
|
||||
const float MIN_DENSITY = 200.0f;
|
||||
const float DEFAULT_DENSITY = 1000.0f;
|
||||
|
@ -64,6 +66,10 @@ ObjectMotionState::ObjectMotionState() :
|
|||
ObjectMotionState::~ObjectMotionState() {
|
||||
// NOTE: you MUST remove this MotionState from the world before you call the dtor.
|
||||
assert(_body == NULL);
|
||||
if (_kinematicController) {
|
||||
delete _kinematicController;
|
||||
_kinematicController = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectMotionState::setFriction(float friction) {
|
||||
|
@ -110,30 +116,23 @@ bool ObjectMotionState::doesNotNeedToSendUpdate() const {
|
|||
return !_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES;
|
||||
}
|
||||
|
||||
const float FIXED_SUBSTEP = 1.0f / 60.0f;
|
||||
|
||||
bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
||||
assert(_body);
|
||||
float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP;
|
||||
float dt = (float)(simulationFrame - _sentFrame) * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||
_sentFrame = simulationFrame;
|
||||
bool isActive = _body->isActive();
|
||||
|
||||
if (isActive) {
|
||||
const float MAX_UPDATE_PERIOD_FOR_ACTIVE_THINGS = 10.0f;
|
||||
if (dt > MAX_UPDATE_PERIOD_FOR_ACTIVE_THINGS) {
|
||||
return true;
|
||||
}
|
||||
} else if (_sentMoving) {
|
||||
if (!isActive) {
|
||||
if (!isActive) {
|
||||
if (_sentMoving) {
|
||||
// this object just went inactive so send an update immediately
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
const float NON_MOVING_UPDATE_PERIOD = 1.0f;
|
||||
if (dt > NON_MOVING_UPDATE_PERIOD && _numNonMovingUpdates < MAX_NUM_NON_MOVING_UPDATES) {
|
||||
// RELIABLE_SEND_HACK: since we're not yet using a reliable method for non-moving update packets we repeat these
|
||||
// at a faster rate than the MAX period above, and only send a limited number of them.
|
||||
return true;
|
||||
} else {
|
||||
const float NON_MOVING_UPDATE_PERIOD = 1.0f;
|
||||
if (dt > NON_MOVING_UPDATE_PERIOD && _numNonMovingUpdates < MAX_NUM_NON_MOVING_UPDATES) {
|
||||
// RELIABLE_SEND_HACK: since we're not yet using a reliable method for non-moving update packets we repeat these
|
||||
// at a faster rate than the MAX period above, and only send a limited number of them.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,4 +174,11 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
|||
return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT);
|
||||
}
|
||||
|
||||
void ObjectMotionState::removeKinematicController() {
|
||||
if (_kinematicController) {
|
||||
delete _kinematicController;
|
||||
_kinematicController = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
|
|
@ -22,7 +22,6 @@ enum MotionType {
|
|||
|
||||
// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
|
||||
// and re-added to the physics engine and "easy" which just updates the body properties.
|
||||
typedef unsigned int uint32_t;
|
||||
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE);
|
||||
const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY |
|
||||
EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP);
|
||||
|
@ -42,6 +41,7 @@ const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_POSITION | Entit
|
|||
#include "ShapeInfo.h"
|
||||
|
||||
class OctreeEditPacketSender;
|
||||
class KinematicController;
|
||||
|
||||
class ObjectMotionState : public btMotionState {
|
||||
public:
|
||||
|
@ -87,6 +87,9 @@ public:
|
|||
|
||||
virtual MotionType computeMotionType() const = 0;
|
||||
|
||||
virtual void addKinematicController() = 0;
|
||||
virtual void removeKinematicController();
|
||||
|
||||
friend class PhysicsEngine;
|
||||
protected:
|
||||
// TODO: move these materials properties to EntityItem
|
||||
|
@ -110,6 +113,8 @@ protected:
|
|||
glm::vec3 _sentVelocity;
|
||||
glm::vec3 _sentAngularVelocity; // radians per second
|
||||
glm::vec3 _sentAcceleration;
|
||||
|
||||
KinematicController* _kinematicController = NULL;
|
||||
};
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
|
|
@ -10,13 +10,20 @@
|
|||
//
|
||||
|
||||
#include "PhysicsEngine.h"
|
||||
|
||||
|
||||
static uint32_t _frameCount;
|
||||
|
||||
// static
|
||||
uint32_t PhysicsEngine::getFrameCount() {
|
||||
return _frameCount;
|
||||
}
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
||||
#include "ShapeInfoUtil.h"
|
||||
#include "ThreadSafeDynamicsWorld.h"
|
||||
|
||||
class EntityTree;
|
||||
|
||||
PhysicsEngine::PhysicsEngine(const glm::vec3& offset)
|
||||
: _collisionConfig(NULL),
|
||||
_collisionDispatcher(NULL),
|
||||
|
@ -24,8 +31,7 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset)
|
|||
_constraintSolver(NULL),
|
||||
_dynamicsWorld(NULL),
|
||||
_originOffset(offset),
|
||||
_entityPacketSender(NULL),
|
||||
_frameCount(0) {
|
||||
_entityPacketSender(NULL) {
|
||||
}
|
||||
|
||||
PhysicsEngine::~PhysicsEngine() {
|
||||
|
@ -196,8 +202,6 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) {
|
|||
EntityMotionState::setOutgoingEntityList(&_entitiesToBeSorted);
|
||||
}
|
||||
|
||||
const float FIXED_SUBSTEP = 1.0f / 60.0f;
|
||||
|
||||
void PhysicsEngine::stepSimulation() {
|
||||
lock();
|
||||
// NOTE: the grand order of operations is:
|
||||
|
@ -210,13 +214,13 @@ void PhysicsEngine::stepSimulation() {
|
|||
relayIncomingChangesToSimulation();
|
||||
|
||||
const int MAX_NUM_SUBSTEPS = 4;
|
||||
const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * FIXED_SUBSTEP;
|
||||
const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||
float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds());
|
||||
_clock.reset();
|
||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||
|
||||
// This is step (2).
|
||||
int numSubSteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, FIXED_SUBSTEP);
|
||||
int numSubSteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
_frameCount += (uint32_t)numSubSteps;
|
||||
unlock();
|
||||
|
||||
|
@ -257,9 +261,12 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) {
|
|||
case MOTION_TYPE_KINEMATIC: {
|
||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
body->setActivationState(DISABLE_DEACTIVATION);
|
||||
body->updateInertiaTensor();
|
||||
motionState->_body = body;
|
||||
motionState->addKinematicController();
|
||||
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
|
||||
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
|
||||
body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD);
|
||||
break;
|
||||
}
|
||||
case MOTION_TYPE_DYNAMIC: {
|
||||
|
@ -271,9 +278,9 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) {
|
|||
motionState->updateObjectVelocities();
|
||||
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
||||
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
||||
const float LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
||||
const float ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
|
||||
body->setSleepingThresholds(LINEAR_VELOCITY_THRESHOLD, ANGULAR_VELOCITY_THRESHOLD);
|
||||
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
||||
const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
|
||||
body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD);
|
||||
break;
|
||||
}
|
||||
case MOTION_TYPE_STATIC:
|
||||
|
@ -307,6 +314,7 @@ bool PhysicsEngine::removeObject(ObjectMotionState* motionState) {
|
|||
_shapeManager.releaseShape(shapeInfo);
|
||||
delete body;
|
||||
motionState->_body = NULL;
|
||||
motionState->removeKinematicController();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -361,6 +369,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
|||
|
||||
body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f));
|
||||
body->updateInertiaTensor();
|
||||
motionState->addKinematicController();
|
||||
break;
|
||||
}
|
||||
case MOTION_TYPE_DYNAMIC: {
|
||||
|
@ -377,6 +386,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
|||
body->updateInertiaTensor();
|
||||
}
|
||||
body->forceActivationState(ACTIVE_TAG);
|
||||
motionState->removeKinematicController();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -391,6 +401,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
|||
|
||||
body->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
motionState->removeKinematicController();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#ifndef hifi_PhysicsEngine_h
|
||||
#define hifi_PhysicsEngine_h
|
||||
|
||||
typedef unsigned int uint32_t;
|
||||
#include <stdint.h>
|
||||
|
||||
const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f;
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
||||
|
@ -29,8 +31,11 @@ typedef unsigned int uint32_t;
|
|||
|
||||
const float HALF_SIMULATION_EXTENT = 512.0f; // meters
|
||||
|
||||
class ObjectMotionState;
|
||||
|
||||
class PhysicsEngine : public EntitySimulation {
|
||||
public:
|
||||
static uint32_t getFrameCount();
|
||||
|
||||
PhysicsEngine(const glm::vec3& offset);
|
||||
|
||||
|
@ -68,9 +73,6 @@ public:
|
|||
/// \return duration of fixed simulation substep
|
||||
float getFixedSubStep() const;
|
||||
|
||||
/// \return number of simulation frames the physics engine has taken
|
||||
uint32_t getFrameCount() const { return _frameCount; }
|
||||
|
||||
protected:
|
||||
void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||
void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||
|
@ -92,13 +94,13 @@ private:
|
|||
QSet<ObjectMotionState*> _outgoingPackets; // MotionStates with pending changes that need to be sent over wire
|
||||
|
||||
EntityEditPacketSender* _entityPacketSender;
|
||||
|
||||
uint32_t _frameCount;
|
||||
};
|
||||
|
||||
#else // USE_BULLET_PHYSICS
|
||||
// PhysicsEngine stubbery until Bullet is required
|
||||
class PhysicsEngine {
|
||||
public:
|
||||
static uint32_t getFrameCount();
|
||||
};
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
#endif // hifi_PhysicsEngine_h
|
||||
|
|
|
@ -21,10 +21,6 @@
|
|||
#include <CollisionInfo.h>
|
||||
#include <RayIntersectionInfo.h>
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
#include "PhysicsEngine.h"
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
class Shape;
|
||||
class PhysicsSimulation;
|
||||
|
||||
|
|
21
libraries/physics/src/SimpleEntityKinematicController.cpp
Normal file
21
libraries/physics/src/SimpleEntityKinematicController.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// SimpleEntityKinematicController.cpp
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2015.01.13
|
||||
// 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 "PhysicsEngine.h"
|
||||
#include "SimpleEntityKinematicController.h"
|
||||
|
||||
void SimpleEntityKinematicController:: stepForward() {
|
||||
uint32_t frame = PhysicsEngine::getFrameCount();
|
||||
float dt = (frame - _lastFrame) * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||
_entity->simulateSimpleKinematicMotion(dt);
|
||||
_lastFrame = frame;
|
||||
}
|
||||
|
38
libraries/physics/src/SimpleEntityKinematicController.h
Normal file
38
libraries/physics/src/SimpleEntityKinematicController.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// SimpleEntityKinematicController.h
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2015.01.13
|
||||
// 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_SimpleEntityKinematicController_h
|
||||
#define hifi_SimpleEntityKinematicController_h
|
||||
|
||||
/// SimpleKinematicConstroller performs simple exrapolation of velocities.
|
||||
|
||||
#include <assert.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <EntityItem.h>
|
||||
|
||||
#include "KinematicController.h"
|
||||
|
||||
class SimpleEntityKinematicController : public KinematicController {
|
||||
public:
|
||||
SimpleEntityKinematicController() = delete; // prevent compiler from making a default ctor
|
||||
|
||||
SimpleEntityKinematicController(EntityItem* entity) : KinematicController(), _entity(entity) { assert(entity); }
|
||||
|
||||
~SimpleEntityKinematicController() { _entity = NULL; }
|
||||
|
||||
void stepForward();
|
||||
|
||||
private:
|
||||
EntityItem* _entity;
|
||||
};
|
||||
|
||||
#endif // hifi_SimpleEntityKinematicController_h
|
|
@ -11,7 +11,6 @@
|
|||
<@if not DEFERRED_BUFFER_SLH@>
|
||||
<@def DEFERRED_BUFFER_SLH@>
|
||||
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
|
@ -43,6 +42,10 @@ struct DeferredFragment {
|
|||
vec4 specularVal;
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
vec3 diffuse;
|
||||
float opacity;
|
||||
vec3 specular;
|
||||
float gloss;
|
||||
};
|
||||
|
||||
DeferredFragment unpackDeferredFragment(vec2 texcoord) {
|
||||
|
@ -59,6 +62,11 @@ DeferredFragment unpackDeferredFragment(vec2 texcoord) {
|
|||
// Unpack the normal from the map
|
||||
frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0));
|
||||
|
||||
frag.diffuse = frag.diffuseVal.xyz;
|
||||
frag.opacity = frag.diffuseVal.w;
|
||||
frag.specular = frag.specularVal.xyz;
|
||||
frag.gloss = frag.specularVal.w;
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
|
|
43
libraries/render-utils/src/DeferredBufferWrite.slh
Executable file
43
libraries/render-utils/src/DeferredBufferWrite.slh
Executable file
|
@ -0,0 +1,43 @@
|
|||
<!
|
||||
// DeferredBufferWrite.slh
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Sam Gateau on 1/12/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_BUFFER_WRITE_SLH@>
|
||||
<@def DEFERRED_BUFFER_WRITE_SLH@>
|
||||
|
||||
// the glow intensity
|
||||
uniform float glowIntensity;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
float evalOpaqueFinalAlpha(float alpha, float mapAlpha) {
|
||||
return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold));
|
||||
}
|
||||
|
||||
void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) {
|
||||
gl_FragData[0] = vec4(diffuse.rgb, alpha);
|
||||
gl_FragData[1] = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(specular, shininess / 128.0);
|
||||
}
|
||||
|
||||
void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess, vec3 emissive) {
|
||||
gl_FragData[0] = vec4(diffuse.rgb, alpha);
|
||||
//gl_FragData[1] = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[1] = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);
|
||||
gl_FragData[2] = vec4(emissive, shininess / 128.0);
|
||||
}
|
||||
|
||||
void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) {
|
||||
gl_FragData[0] = vec4(diffuse.rgb, alpha);
|
||||
// gl_FragData[1] = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
// gl_FragData[2] = vec4(specular, shininess / 128.0);
|
||||
}
|
||||
|
||||
<@endif@>
|
96
libraries/render-utils/src/DeferredLighting.slh
Executable file
96
libraries/render-utils/src/DeferredLighting.slh
Executable file
|
@ -0,0 +1,96 @@
|
|||
<!
|
||||
// DeferredLighting.slh
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Sam Gateau on 1/15/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_LIGHTING_SLH@>
|
||||
<@def DEFERRED_LIGHTING_SLH@>
|
||||
|
||||
struct SphericalHarmonics {
|
||||
vec4 L00;
|
||||
vec4 L1m1;
|
||||
vec4 L10;
|
||||
vec4 L11;
|
||||
vec4 L2m2;
|
||||
vec4 L2m1;
|
||||
vec4 L20;
|
||||
vec4 L21;
|
||||
vec4 L22;
|
||||
};
|
||||
|
||||
vec4 evalSphericalLight(SphericalHarmonics sh, vec3 direction ) {
|
||||
|
||||
const float C1 = 0.429043;
|
||||
const float C2 = 0.511664;
|
||||
const float C3 = 0.743125;
|
||||
const float C4 = 0.886227;
|
||||
const float C5 = 0.247708;
|
||||
|
||||
vec4 value = C1 * sh.L22 * (direction.x * direction.x - direction.y * direction.y) +
|
||||
C3 * sh.L20 * direction.z * direction.z +
|
||||
C4 * sh.L00 - C5 * sh.L20 +
|
||||
2.0 * C1 * ( sh.L2m2 * direction.x * direction.y +
|
||||
sh.L21 * direction.x * direction.z +
|
||||
sh.L2m1 * direction.y * direction.z ) +
|
||||
2.0 * C2 * ( sh.L11 * direction.x +
|
||||
sh.L1m1 * direction.y +
|
||||
sh.L10 * direction.z ) ;
|
||||
return value;
|
||||
}
|
||||
|
||||
uniform SphericalHarmonics ambientSphere;
|
||||
|
||||
vec3 evalAmbientColor(vec3 normal, vec3 diffuse, vec3 specular, float gloss) {
|
||||
return diffuse.rgb * gl_FrontLightProduct[0].ambient.rgb;
|
||||
}
|
||||
|
||||
vec3 evalAmbientSphereColor(vec3 normal, vec3 diffuse, vec3 specular, float gloss) {
|
||||
vec3 ambientLight = 0.5 * evalSphericalLight(ambientSphere, normal).xyz;
|
||||
|
||||
return diffuse.rgb * ambientLight;
|
||||
}
|
||||
|
||||
vec3 evalDirectionalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) {
|
||||
// Diffuse Lighting
|
||||
float diffuseDot = dot(normal, gl_LightSource[0].position.xyz);
|
||||
float facingLight = step(0.0, diffuseDot) * shadowAttenuation;
|
||||
vec3 diffuseColor = diffuse * (gl_FrontLightModelProduct.sceneColor.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuseDot * facingLight));
|
||||
|
||||
// compute the specular multiplier (sans exponent)
|
||||
float specularPower = facingLight * max(0.0,
|
||||
dot(normalize(gl_LightSource[0].position.xyz - normalize(position)), normal));
|
||||
vec3 specularColor = pow(specularPower, gloss * 128.0) * specular;
|
||||
|
||||
// add specular contribution
|
||||
return vec3(diffuseColor + specularColor);
|
||||
}
|
||||
|
||||
|
||||
vec3 evalLightmappedColor(float shadowAttenuation, vec3 normal, vec3 diffuse, vec3 lightmap) {
|
||||
|
||||
float diffuseDot = dot(normal, gl_LightSource[0].position.xyz);
|
||||
|
||||
// need to catch normals perpendicular to the projection plane hence the magic number for the threshold
|
||||
// it should be just 0, but we have innacurracy so we need to overshoot
|
||||
const float PERPENDICULAR_THRESHOLD = -0.005;
|
||||
float facingLight = step(PERPENDICULAR_THRESHOLD, diffuseDot);
|
||||
|
||||
// evaluate the shadow test but only relevant for light facing fragments
|
||||
float lightAttenuation = (1 - facingLight) + facingLight * shadowAttenuation;
|
||||
|
||||
// diffuse light is the lightmap dimmed by shadow
|
||||
vec3 diffuseLight = lightAttenuation * lightmap;
|
||||
|
||||
// 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@>
|
|
@ -35,9 +35,152 @@
|
|||
#include "directional_light_shadow_map_frag.h"
|
||||
#include "directional_light_cascaded_shadow_map_frag.h"
|
||||
|
||||
#include "directional_ambient_light_frag.h"
|
||||
#include "directional_ambient_light_shadow_map_frag.h"
|
||||
#include "directional_ambient_light_cascaded_shadow_map_frag.h"
|
||||
|
||||
#include "point_light_frag.h"
|
||||
#include "spot_light_frag.h"
|
||||
|
||||
class SphericalHarmonics {
|
||||
public:
|
||||
glm::vec3 L00 ; float spare0;
|
||||
glm::vec3 L1m1 ; float spare1;
|
||||
glm::vec3 L10 ; float spare2;
|
||||
glm::vec3 L11 ; float spare3;
|
||||
glm::vec3 L2m2 ; float spare4;
|
||||
glm::vec3 L2m1 ; float spare5;
|
||||
glm::vec3 L20 ; float spare6;
|
||||
glm::vec3 L21 ; float spare7;
|
||||
glm::vec3 L22 ; float spare8;
|
||||
|
||||
static const int NUM_COEFFICIENTS = 9;
|
||||
|
||||
void assignPreset(int p) {
|
||||
switch (p) {
|
||||
case DeferredLightingEffect::OLD_TOWN_SQUARE: {
|
||||
L00 = glm::vec3( 0.871297f, 0.875222f, 0.864470f);
|
||||
L1m1 = glm::vec3( 0.175058f, 0.245335f, 0.312891f);
|
||||
L10 = glm::vec3( 0.034675f, 0.036107f, 0.037362f);
|
||||
L11 = glm::vec3(-0.004629f,-0.029448f,-0.048028f);
|
||||
L2m2 = glm::vec3(-0.120535f,-0.121160f,-0.117507f);
|
||||
L2m1 = glm::vec3( 0.003242f, 0.003624f, 0.007511f);
|
||||
L20 = glm::vec3(-0.028667f,-0.024926f,-0.020998f);
|
||||
L21 = glm::vec3(-0.077539f,-0.086325f,-0.091591f);
|
||||
L22 = glm::vec3(-0.161784f,-0.191783f,-0.219152f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::GRACE_CATHEDRAL: {
|
||||
L00 = glm::vec3( 0.79f, 0.44f, 0.54f);
|
||||
L1m1 = glm::vec3( 0.39f, 0.35f, 0.60f);
|
||||
L10 = glm::vec3(-0.34f, -0.18f, -0.27f);
|
||||
L11 = glm::vec3(-0.29f, -0.06f, 0.01f);
|
||||
L2m2 = glm::vec3(-0.11f, -0.05f, -0.12f);
|
||||
L2m1 = glm::vec3(-0.26f, -0.22f, -0.47f);
|
||||
L20 = glm::vec3(-0.16f, -0.09f, -0.15f);
|
||||
L21 = glm::vec3( 0.56f, 0.21f, 0.14f);
|
||||
L22 = glm::vec3( 0.21f, -0.05f, -0.30f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::EUCALYPTUS_GROVE: {
|
||||
L00 = glm::vec3( 0.38f, 0.43f, 0.45f);
|
||||
L1m1 = glm::vec3( 0.29f, 0.36f, 0.41f);
|
||||
L10 = glm::vec3( 0.04f, 0.03f, 0.01f);
|
||||
L11 = glm::vec3(-0.10f, -0.10f, -0.09f);
|
||||
L2m2 = glm::vec3(-0.06f, -0.06f, -0.04f);
|
||||
L2m1 = glm::vec3( 0.01f, -0.01f, -0.05f);
|
||||
L20 = glm::vec3(-0.09f, -0.13f, -0.15f);
|
||||
L21 = glm::vec3(-0.06f, -0.05f, -0.04f);
|
||||
L22 = glm::vec3( 0.02f, 0.00f, -0.05f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::ST_PETERS_BASILICA: {
|
||||
L00 = glm::vec3( 0.36f, 0.26f, 0.23f);
|
||||
L1m1 = glm::vec3( 0.18f, 0.14f, 0.13f);
|
||||
L10 = glm::vec3(-0.02f, -0.01f, 0.00f);
|
||||
L11 = glm::vec3( 0.03f, 0.02f, -0.00f);
|
||||
L2m2 = glm::vec3( 0.02f, 0.01f, -0.00f);
|
||||
L2m1 = glm::vec3(-0.05f, -0.03f, -0.01f);
|
||||
L20 = glm::vec3(-0.09f, -0.08f, -0.07f);
|
||||
L21 = glm::vec3( 0.01f, 0.00f, 0.00f);
|
||||
L22 = glm::vec3(-0.08f, -0.03f, -0.00f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::UFFIZI_GALLERY: {
|
||||
L00 = glm::vec3( 0.32f, 0.31f, 0.35f);
|
||||
L1m1 = glm::vec3( 0.37f, 0.37f, 0.43f);
|
||||
L10 = glm::vec3( 0.00f, 0.00f, 0.00f);
|
||||
L11 = glm::vec3(-0.01f, -0.01f, -0.01f);
|
||||
L2m2 = glm::vec3(-0.02f, -0.02f, -0.03f);
|
||||
L2m1 = glm::vec3(-0.01f, -0.01f, -0.01f);
|
||||
L20 = glm::vec3(-0.28f, -0.28f, -0.32f);
|
||||
L21 = glm::vec3( 0.00f, 0.00f, 0.00f);
|
||||
L22 = glm::vec3(-0.24f, -0.24f, -0.28f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::GALILEOS_TOMB: {
|
||||
L00 = glm::vec3( 1.04f, 0.76f, 0.71f);
|
||||
L1m1 = glm::vec3( 0.44f, 0.34f, 0.34f);
|
||||
L10 = glm::vec3(-0.22f, -0.18f, -0.17f);
|
||||
L11 = glm::vec3( 0.71f, 0.54f, 0.56f);
|
||||
L2m2 = glm::vec3( 0.64f, 0.50f, 0.52f);
|
||||
L2m1 = glm::vec3(-0.12f, -0.09f, -0.08f);
|
||||
L20 = glm::vec3(-0.37f, -0.28f, -0.32f);
|
||||
L21 = glm::vec3(-0.17f, -0.13f, -0.13f);
|
||||
L22 = glm::vec3( 0.55f, 0.42f, 0.42f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::VINE_STREET_KITCHEN: {
|
||||
L00 = glm::vec3( 0.64f, 0.67f, 0.73f);
|
||||
L1m1 = glm::vec3( 0.28f, 0.32f, 0.33f);
|
||||
L10 = glm::vec3( 0.42f, 0.60f, 0.77f);
|
||||
L11 = glm::vec3(-0.05f, -0.04f, -0.02f);
|
||||
L2m2 = glm::vec3(-0.10f, -0.08f, -0.05f);
|
||||
L2m1 = glm::vec3( 0.25f, 0.39f, 0.53f);
|
||||
L20 = glm::vec3( 0.38f, 0.54f, 0.71f);
|
||||
L21 = glm::vec3( 0.06f, 0.01f, -0.02f);
|
||||
L22 = glm::vec3(-0.03f, -0.02f, -0.03f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::BREEZEWAY: {
|
||||
L00 = glm::vec3( 0.32f, 0.36f, 0.38f);
|
||||
L1m1 = glm::vec3( 0.37f, 0.41f, 0.45f);
|
||||
L10 = glm::vec3(-0.01f, -0.01f, -0.01f);
|
||||
L11 = glm::vec3(-0.10f, -0.12f, -0.12f);
|
||||
L2m2 = glm::vec3(-0.13f, -0.15f, -0.17f);
|
||||
L2m1 = glm::vec3(-0.01f, -0.02f, 0.02f);
|
||||
L20 = glm::vec3(-0.07f, -0.08f, -0.09f);
|
||||
L21 = glm::vec3( 0.02f, 0.03f, 0.03f);
|
||||
L22 = glm::vec3(-0.29f, -0.32f, -0.36f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::CAMPUS_SUNSET: {
|
||||
L00 = glm::vec3( 0.79f, 0.94f, 0.98f);
|
||||
L1m1 = glm::vec3( 0.44f, 0.56f, 0.70f);
|
||||
L10 = glm::vec3(-0.10f, -0.18f, -0.27f);
|
||||
L11 = glm::vec3( 0.45f, 0.38f, 0.20f);
|
||||
L2m2 = glm::vec3( 0.18f, 0.14f, 0.05f);
|
||||
L2m1 = glm::vec3(-0.14f, -0.22f, -0.31f);
|
||||
L20 = glm::vec3(-0.39f, -0.40f, -0.36f);
|
||||
L21 = glm::vec3( 0.09f, 0.07f, 0.04f);
|
||||
L22 = glm::vec3( 0.67f, 0.67f, 0.52f);
|
||||
}
|
||||
break;
|
||||
case DeferredLightingEffect::FUNSTON_BEACH_SUNSET: {
|
||||
L00 = glm::vec3( 0.68f, 0.69f, 0.70f);
|
||||
L1m1 = glm::vec3( 0.32f, 0.37f, 0.44f);
|
||||
L10 = glm::vec3(-0.17f, -0.17f, -0.17f);
|
||||
L11 = glm::vec3(-0.45f, -0.42f, -0.34f);
|
||||
L2m2 = glm::vec3(-0.17f, -0.17f, -0.15f);
|
||||
L2m1 = glm::vec3(-0.08f, -0.09f, -0.10f);
|
||||
L20 = glm::vec3(-0.03f, -0.02f, -0.01f);
|
||||
L21 = glm::vec3( 0.16f, 0.14f, 0.10f);
|
||||
L22 = glm::vec3( 0.37f, 0.31f, 0.20f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||
_viewState = viewState;
|
||||
|
@ -54,6 +197,13 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
|||
_directionalLightShadowMapLocations);
|
||||
loadLightProgram(directional_light_cascaded_shadow_map_frag, false, _directionalLightCascadedShadowMap,
|
||||
_directionalLightCascadedShadowMapLocations);
|
||||
|
||||
loadLightProgram(directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);
|
||||
loadLightProgram(directional_ambient_light_shadow_map_frag, false, _directionalAmbientSphereLightShadowMap,
|
||||
_directionalAmbientSphereLightShadowMapLocations);
|
||||
loadLightProgram(directional_ambient_light_cascaded_shadow_map_frag, false, _directionalAmbientSphereLightCascadedShadowMap,
|
||||
_directionalAmbientSphereLightCascadedShadowMapLocations);
|
||||
|
||||
loadLightProgram(point_light_frag, true, _pointLight, _pointLightLocations);
|
||||
loadLightProgram(spot_light_frag, true, _spotLight, _spotLightLocations);
|
||||
}
|
||||
|
@ -169,7 +319,8 @@ void DeferredLightingEffect::render() {
|
|||
QOpenGLFramebufferObject* freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebufferObject();
|
||||
freeFBO->bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
|
@ -205,18 +356,43 @@ void DeferredLightingEffect::render() {
|
|||
if (_viewState->getCascadeShadowsEnabled()) {
|
||||
program = &_directionalLightCascadedShadowMap;
|
||||
locations = &_directionalLightCascadedShadowMapLocations;
|
||||
_directionalLightCascadedShadowMap.bind();
|
||||
_directionalLightCascadedShadowMap.setUniform(locations->shadowDistances, _viewState->getShadowDistances());
|
||||
if (_ambientLightMode > -1) {
|
||||
program = &_directionalAmbientSphereLightCascadedShadowMap;
|
||||
locations = &_directionalAmbientSphereLightCascadedShadowMapLocations;
|
||||
}
|
||||
program->bind();
|
||||
program->setUniform(locations->shadowDistances, _viewState->getShadowDistances());
|
||||
|
||||
} else {
|
||||
if (_ambientLightMode > -1) {
|
||||
program = &_directionalAmbientSphereLightShadowMap;
|
||||
locations = &_directionalAmbientSphereLightShadowMapLocations;
|
||||
}
|
||||
program->bind();
|
||||
}
|
||||
program->setUniformValue(locations->shadowScale,
|
||||
1.0f / textureCache->getShadowFramebufferObject()->width());
|
||||
|
||||
} else {
|
||||
if (_ambientLightMode > -1) {
|
||||
program = &_directionalAmbientSphereLight;
|
||||
locations = &_directionalAmbientSphereLightLocations;
|
||||
}
|
||||
program->bind();
|
||||
}
|
||||
|
||||
if (locations->ambientSphere >= 0) {
|
||||
SphericalHarmonics sh;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
float left, right, bottom, top, nearVal, farVal;
|
||||
glm::vec4 nearClipPlane, farClipPlane;
|
||||
|
@ -371,6 +547,7 @@ void DeferredLightingEffect::render() {
|
|||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
freeFBO->release();
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
|
@ -431,5 +608,12 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit
|
|||
locations.depthTexCoordOffset = program.uniformLocation("depthTexCoordOffset");
|
||||
locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale");
|
||||
locations.radius = program.uniformLocation("radius");
|
||||
locations.ambientSphere = program.uniformLocation("ambientSphere.L00");
|
||||
program.release();
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::setAmbientLightMode(int preset) {
|
||||
if ((preset >= -1) && (preset < NUM_PRESET)) {
|
||||
_ambientLightMode = preset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,23 @@ public:
|
|||
void prepare();
|
||||
void render();
|
||||
|
||||
enum AmbientLightPreset {
|
||||
OLD_TOWN_SQUARE = 0,
|
||||
GRACE_CATHEDRAL,
|
||||
EUCALYPTUS_GROVE,
|
||||
ST_PETERS_BASILICA,
|
||||
UFFIZI_GALLERY,
|
||||
GALILEOS_TOMB,
|
||||
VINE_STREET_KITCHEN,
|
||||
BREEZEWAY,
|
||||
CAMPUS_SUNSET,
|
||||
FUNSTON_BEACH_SUNSET,
|
||||
|
||||
NUM_PRESET,
|
||||
};
|
||||
|
||||
void setAmbientLightMode(int preset);
|
||||
|
||||
private:
|
||||
DeferredLightingEffect() { }
|
||||
virtual ~DeferredLightingEffect() { }
|
||||
|
@ -84,6 +101,7 @@ private:
|
|||
int depthTexCoordOffset;
|
||||
int depthTexCoordScale;
|
||||
int radius;
|
||||
int ambientSphere;
|
||||
};
|
||||
|
||||
static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
|
||||
|
@ -91,12 +109,20 @@ private:
|
|||
ProgramObject _simpleProgram;
|
||||
int _glowIntensityLocation;
|
||||
|
||||
ProgramObject _directionalAmbientSphereLight;
|
||||
LightLocations _directionalAmbientSphereLightLocations;
|
||||
ProgramObject _directionalAmbientSphereLightShadowMap;
|
||||
LightLocations _directionalAmbientSphereLightShadowMapLocations;
|
||||
ProgramObject _directionalAmbientSphereLightCascadedShadowMap;
|
||||
LightLocations _directionalAmbientSphereLightCascadedShadowMapLocations;
|
||||
|
||||
ProgramObject _directionalLight;
|
||||
LightLocations _directionalLightLocations;
|
||||
ProgramObject _directionalLightShadowMap;
|
||||
LightLocations _directionalLightShadowMapLocations;
|
||||
ProgramObject _directionalLightCascadedShadowMap;
|
||||
LightLocations _directionalLightCascadedShadowMapLocations;
|
||||
|
||||
ProgramObject _pointLight;
|
||||
LightLocations _pointLightLocations;
|
||||
ProgramObject _spotLight;
|
||||
|
@ -126,6 +152,8 @@ private:
|
|||
QVector<PostLightingRenderable*> _postLightingRenderables;
|
||||
|
||||
AbstractViewStateInterface* _viewState;
|
||||
|
||||
int _ambientLightMode = 0;
|
||||
};
|
||||
|
||||
/// Simple interface for objects that require something to be rendered after deferred lighting.
|
||||
|
|
63
libraries/render-utils/src/Material.slh
Executable file
63
libraries/render-utils/src/Material.slh
Executable file
|
@ -0,0 +1,63 @@
|
|||
<!
|
||||
// Material.slh
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 12/16/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 MATERIAL_SLH@>
|
||||
<@def MATERIAL_SLH@>
|
||||
|
||||
struct Material {
|
||||
vec4 _diffuse;
|
||||
vec4 _specular;
|
||||
|
||||
};
|
||||
|
||||
float getMaterialOpacity(Material m) { return m._diffuse.a; }
|
||||
vec3 getMaterialDiffuse(Material m) { return m._diffuse.rgb; }
|
||||
vec3 getMaterialSpecular(Material m) { return m._specular.rgb; }
|
||||
float getMaterialShininess(Material m) { return m._specular.a; }
|
||||
|
||||
|
||||
|
||||
<@if GLPROFILE == PC_GL@>
|
||||
uniform materialBuffer {
|
||||
Material mat;
|
||||
};
|
||||
Material getMaterial() {
|
||||
return mat;
|
||||
}
|
||||
<@elif GLPROFILE == MAC_GL@>
|
||||
uniform vec4 materialBuffer[2];
|
||||
Material getMaterial() {
|
||||
Material mat;
|
||||
mat._diffuse = materialBuffer[0];
|
||||
mat._specular = materialBuffer[1];
|
||||
return mat;
|
||||
}
|
||||
<!/* tryed and failed...
|
||||
bindable uniform struct {
|
||||
Material mat;
|
||||
} materialBuffer;
|
||||
|
||||
Material getMaterial() {
|
||||
return materialBuffer.mat;
|
||||
}
|
||||
*/!>
|
||||
<@else@>
|
||||
uniform vec4 materialBuffer[2];
|
||||
Material getMaterial() {
|
||||
Material mat;
|
||||
mat._diffuse = materialBuffer[0];
|
||||
mat._specular = materialBuffer[1];
|
||||
return mat;
|
||||
}
|
||||
<@endif@>
|
||||
|
||||
|
||||
|
||||
<@endif@>
|
|
@ -178,7 +178,7 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo
|
|||
locations.alphaThreshold = program.uniformLocation("alphaThreshold");
|
||||
locations.texcoordMatrices = program.uniformLocation("texcoordMatrices");
|
||||
locations.emissiveParams = program.uniformLocation("emissiveParams");
|
||||
|
||||
locations.glowIntensity = program.uniformLocation("glowIntensity");
|
||||
program.setUniformValue("diffuseMap", 0);
|
||||
program.setUniformValue("normalMap", 1);
|
||||
|
||||
|
@ -198,6 +198,35 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo
|
|||
locations.emissiveTextureUnit = -1;
|
||||
}
|
||||
|
||||
// bindable uniform version
|
||||
#if defined(Q_OS_MAC)
|
||||
loc = program.uniformLocation("materialBuffer");
|
||||
if (loc >= 0) {
|
||||
locations.materialBufferUnit = loc;
|
||||
} else {
|
||||
locations.materialBufferUnit = -1;
|
||||
}
|
||||
#elif defined(Q_OS_WIN)
|
||||
loc = glGetUniformBlockIndex(program.programId(), "materialBuffer");
|
||||
if (loc >= 0) {
|
||||
glUniformBlockBinding(program.programId(), loc, 1);
|
||||
locations.materialBufferUnit = 1;
|
||||
} else {
|
||||
locations.materialBufferUnit = -1;
|
||||
}
|
||||
#else
|
||||
loc = program.uniformLocation("materialBuffer");
|
||||
if (loc >= 0) {
|
||||
locations.materialBufferUnit = loc;
|
||||
} else {
|
||||
locations.materialBufferUnit = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!program.isLinked()) {
|
||||
program.release();
|
||||
}
|
||||
|
||||
program.release();
|
||||
}
|
||||
|
||||
|
@ -2348,6 +2377,7 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
|
|||
for (int j = 0; j < networkMesh.parts.size(); j++) {
|
||||
const NetworkMeshPart& networkPart = networkMesh.parts.at(j);
|
||||
const FBXMeshPart& part = mesh.parts.at(j);
|
||||
model::MaterialPointer material = part._material;
|
||||
if ((networkPart.isTranslucent() || part.opacity != 1.0f) != translucent) {
|
||||
offset += (part.quadIndices.size() + part.triangleIndices.size()) * sizeof(int);
|
||||
continue;
|
||||
|
@ -2365,16 +2395,17 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
|
|||
qDebug() << "part INDEX:" << j;
|
||||
qDebug() << "NEW part.materialID:" << part.materialID;
|
||||
}
|
||||
|
||||
glm::vec4 diffuse = glm::vec4(part.diffuseColor, part.opacity);
|
||||
if (!(translucent && alphaThreshold == 0.0f)) {
|
||||
GLBATCH(glAlphaFunc)(GL_EQUAL, diffuse.a = glowEffect->getIntensity());
|
||||
|
||||
if (locations->glowIntensity >= 0) {
|
||||
GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity());
|
||||
}
|
||||
if (!(translucent && alphaThreshold == 0.0f)) {
|
||||
GLBATCH(glAlphaFunc)(GL_EQUAL, glowEffect->getIntensity());
|
||||
}
|
||||
|
||||
if (locations->materialBufferUnit >= 0) {
|
||||
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
|
||||
}
|
||||
glm::vec4 specular = glm::vec4(part.specularColor, 1.0f);
|
||||
GLBATCH(glMaterialfv)(GL_FRONT, GL_AMBIENT, (const float*)&diffuse);
|
||||
GLBATCH(glMaterialfv)(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse);
|
||||
GLBATCH(glMaterialfv)(GL_FRONT, GL_SPECULAR, (const float*)&specular);
|
||||
GLBATCH(glMaterialf)(GL_FRONT, GL_SHININESS, (part.shininess > 128.0f ? 128.0f: part.shininess));
|
||||
|
||||
Texture* diffuseMap = networkPart.diffuseTexture.data();
|
||||
if (mesh.isEye && diffuseMap) {
|
||||
|
|
|
@ -338,6 +338,8 @@ private:
|
|||
int specularTextureUnit;
|
||||
int emissiveTextureUnit;
|
||||
int emissiveParams;
|
||||
int glowIntensity;
|
||||
int materialBufferUnit;
|
||||
};
|
||||
|
||||
static Locations _locations;
|
||||
|
|
42
libraries/render-utils/src/directional_ambient_light.slf
Executable file
42
libraries/render-utils/src/directional_ambient_light.slf
Executable file
|
@ -0,0 +1,42 @@
|
|||
<@include Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// directional_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/3/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
<@include DeferredLighting.slh@>
|
||||
|
||||
void main(void) {
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||
gl_FragColor = vec4( evalLightmappedColor(
|
||||
1.0,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specularVal.xyz),
|
||||
1.0);
|
||||
} else {
|
||||
vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
||||
+ evalDirectionalColor(1.0,
|
||||
frag.position.xyz,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specular,
|
||||
frag.gloss);
|
||||
|
||||
gl_FragColor = vec4(color, frag.normalVal.a);
|
||||
}
|
||||
}
|
49
libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf
Executable file
49
libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf
Executable file
|
@ -0,0 +1,49 @@
|
|||
<@include Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// directional_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/3/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
<@include DeferredLighting.slh@>
|
||||
|
||||
// Everything about shadow
|
||||
<@include Shadow.slh@>
|
||||
|
||||
void main(void) {
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
|
||||
// Eval shadow Texcoord and then Attenuation
|
||||
vec4 shadowTexcoord = evalCascadedShadowTexcoord(frag.position);
|
||||
float shadowAttenuation = evalShadowAttenuation(shadowTexcoord);
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||
gl_FragColor = vec4(evalLightmappedColor(
|
||||
shadowAttenuation,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specularVal.xyz),
|
||||
1.0);
|
||||
} else {
|
||||
vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
||||
+ evalDirectionalColor(shadowAttenuation,
|
||||
frag.position.xyz,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specular,
|
||||
frag.gloss);
|
||||
|
||||
gl_FragColor = vec4(color, frag.normalVal.a);
|
||||
}
|
||||
}
|
50
libraries/render-utils/src/directional_ambient_light_shadow_map.slf
Executable file
50
libraries/render-utils/src/directional_ambient_light_shadow_map.slf
Executable file
|
@ -0,0 +1,50 @@
|
|||
<@include Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// directional_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/3/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
<@include DeferredLighting.slh@>
|
||||
|
||||
// Everything about shadow
|
||||
<@include Shadow.slh@>
|
||||
|
||||
|
||||
void main(void) {
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
|
||||
// Eval shadow Texcoord and then Attenuation
|
||||
vec4 shadowTexcoord = evalShadowTexcoord(frag.position);
|
||||
float shadowAttenuation = evalShadowAttenuation(shadowTexcoord);
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||
gl_FragColor = vec4(evalLightmappedColor(
|
||||
shadowAttenuation,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specularVal.xyz),
|
||||
1.0);
|
||||
} else {
|
||||
vec3 color = evalAmbientSphereColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
||||
+ evalDirectionalColor(shadowAttenuation,
|
||||
frag.position.xyz,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specular,
|
||||
frag.gloss);
|
||||
|
||||
gl_FragColor = vec4(color, frag.normalVal.a);
|
||||
}
|
||||
}
|
|
@ -15,29 +15,28 @@
|
|||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
<@include DeferredLighting.slh@>
|
||||
|
||||
void main(void) {
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
|
||||
vec4 normalVal = frag.normalVal;
|
||||
vec4 diffuseVal = frag.diffuseVal;
|
||||
vec4 specularVal = frag.specularVal;
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) {
|
||||
gl_FragColor = vec4(diffuseVal.rgb * specularVal.rgb, 1.0);
|
||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||
gl_FragColor = vec4( evalLightmappedColor(
|
||||
1.0,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specularVal.xyz),
|
||||
1.0);
|
||||
} else {
|
||||
// compute the base color based on OpenGL lighting model
|
||||
float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz);
|
||||
float facingLight = step(0.0, diffuse);
|
||||
vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb +
|
||||
gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight));
|
||||
|
||||
// compute the specular multiplier (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)),
|
||||
frag.normal));
|
||||
|
||||
// add specular contribution
|
||||
vec4 specularColor = specularVal;
|
||||
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normalVal.a);
|
||||
vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
||||
+ evalDirectionalColor(1.0,
|
||||
frag.position.xyz,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specular,
|
||||
frag.gloss);
|
||||
|
||||
gl_FragColor = vec4(color, frag.normalVal.a);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,55 +15,35 @@
|
|||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
<@include DeferredLighting.slh@>
|
||||
|
||||
// Everything about shadow
|
||||
<@include Shadow.slh@>
|
||||
|
||||
void main(void) {
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
vec4 normalVal = frag.normalVal;
|
||||
vec4 diffuseVal = frag.diffuseVal;
|
||||
vec4 specularVal = frag.specularVal;
|
||||
|
||||
// Eval shadow Texcoord and then Attenuation
|
||||
vec4 shadowTexcoord = evalCascadedShadowTexcoord(frag.position);
|
||||
float shadowAttenuation = evalShadowAttenuation(shadowTexcoord);
|
||||
|
||||
// how much this fragment faces the light direction
|
||||
float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz);
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) {
|
||||
normalVal.a = 1.0;
|
||||
|
||||
// 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, diffuse);
|
||||
|
||||
// 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 * specularVal.rgb;
|
||||
// ambient is a tiny percentage of the lightmap and only when in the shadow
|
||||
vec3 ambientLight = (1 - lightAttenuation) * 0.5 * specularVal.rgb;
|
||||
|
||||
gl_FragColor = vec4(diffuseVal.rgb * (ambientLight + diffuseLight), 1.0);
|
||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||
gl_FragColor = vec4(evalLightmappedColor(
|
||||
shadowAttenuation,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specularVal.xyz),
|
||||
1.0);
|
||||
} else {
|
||||
vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
||||
+ evalDirectionalColor(shadowAttenuation,
|
||||
frag.position.xyz,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specular,
|
||||
frag.gloss);
|
||||
|
||||
// average values from the shadow map
|
||||
float facingLight = step(0.0, diffuse) * shadowAttenuation;
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb +
|
||||
gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight));
|
||||
|
||||
// compute the specular multiplier (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)),
|
||||
frag.normal));
|
||||
|
||||
// add specular contribution
|
||||
vec4 specularColor = specularVal;
|
||||
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normalVal.a);
|
||||
gl_FragColor = vec4(color, frag.normalVal.a);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,54 +15,36 @@
|
|||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
<@include DeferredLighting.slh@>
|
||||
|
||||
// Everything about shadow
|
||||
<@include Shadow.slh@>
|
||||
<@include Shadow.slh@>
|
||||
|
||||
|
||||
void main(void) {
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
vec4 normalVal = frag.normalVal;
|
||||
vec4 diffuseVal = frag.diffuseVal;
|
||||
vec4 specularVal = frag.specularVal;
|
||||
|
||||
// Eval shadow Texcoord and then Attenuation
|
||||
vec4 shadowTexcoord = evalShadowTexcoord(frag.position);
|
||||
float shadowAttenuation = evalShadowAttenuation(shadowTexcoord);
|
||||
|
||||
// how much this fragment faces the light direction
|
||||
float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz);
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) {
|
||||
normalVal.a = 0.0;
|
||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||
gl_FragColor = vec4(evalLightmappedColor(
|
||||
shadowAttenuation,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specularVal.xyz),
|
||||
1.0);
|
||||
} else {
|
||||
vec3 color = evalAmbientColor(frag.normal, frag.diffuse, frag.specular, frag.gloss)
|
||||
+ evalDirectionalColor(shadowAttenuation,
|
||||
frag.position.xyz,
|
||||
frag.normal,
|
||||
frag.diffuse,
|
||||
frag.specular,
|
||||
frag.gloss);
|
||||
|
||||
// need to catch normals perpendicular to the projection plane hence the magic number for the threshold
|
||||
// it should be just 0, be we have innacurracy so we need to overshoot
|
||||
const float PERPENDICULAR_THRESHOLD = -0.005;
|
||||
float facingLight = step(PERPENDICULAR_THRESHOLD, diffuse);
|
||||
|
||||
// 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 * specularVal.rgb;
|
||||
// ambient is a tiny percentage of the lightmap and only when in the shadow
|
||||
vec3 ambientLight = (1 - lightAttenuation) * 0.5 * specularVal.rgb;
|
||||
|
||||
gl_FragColor = vec4(diffuseVal.rgb * (ambientLight + diffuseLight), 1.0);
|
||||
} else {
|
||||
// average values from the shadow map
|
||||
float facingLight = step(0.0, diffuse) * shadowAttenuation;
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb +
|
||||
gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight));
|
||||
|
||||
// compute the specular multiplier (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)),
|
||||
frag.normal));
|
||||
|
||||
// add specular contribution
|
||||
vec4 specularColor = specularVal;
|
||||
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normalVal.a);
|
||||
gl_FragColor = vec4(color, frag.normalVal.a);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,19 +11,26 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// set the diffuse, normal, specular data
|
||||
// Fetch diffuse map
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(normal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a),
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
getMaterialSpecular(mat),
|
||||
getMaterialShininess(mat));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ void main(void) {
|
|||
normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
|
||||
|
||||
// pass along the diffuse color
|
||||
gl_FrontColor = gl_Color * gl_FrontMaterial.diffuse;
|
||||
gl_FrontColor = gl_Color;
|
||||
|
||||
// and the texture coordinates
|
||||
gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0);
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
|
@ -19,9 +23,6 @@ uniform sampler2D diffuseMap;
|
|||
uniform sampler2D emissiveMap;
|
||||
uniform vec2 emissiveParams;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
|
@ -32,7 +33,14 @@ void main(void) {
|
|||
// set the diffuse, normal, specular data
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
vec4 emissive = texture2D(emissiveMap, interpolatedTexcoord1.st);
|
||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);
|
||||
gl_FragData[2] = vec4((vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb), gl_FrontMaterial.shininess / 128.0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragmentLightmap(
|
||||
normalize(normal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a),
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
getMaterialSpecular(mat),
|
||||
getMaterialShininess(mat),
|
||||
(vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb));
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ void main(void) {
|
|||
normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
|
||||
|
||||
// pass along the diffuse color
|
||||
gl_FrontColor = gl_Color * gl_FrontMaterial.diffuse;
|
||||
gl_FrontColor = gl_Color;
|
||||
|
||||
// and the texture coordinates
|
||||
gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0);
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
|
@ -22,9 +26,6 @@ uniform sampler2D normalMap;
|
|||
uniform sampler2D emissiveMap;
|
||||
uniform vec2 emissiveParams;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 interpolatedNormal;
|
||||
|
||||
|
@ -45,7 +46,14 @@ void main(void) {
|
|||
// set the diffuse, normal, specular data
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
vec4 emissive = texture2D(emissiveMap, interpolatedTexcoord1.st);
|
||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb * (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb), mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||
gl_FragData[1] = viewNormal + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragmentLightmap(
|
||||
normalize(viewNormal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a),
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
getMaterialSpecular(mat),
|
||||
getMaterialShininess(mat),
|
||||
(vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb));
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ void main(void) {
|
|||
interpolatedTangent = gl_ModelViewMatrix * vec4(tangent, 0.0);
|
||||
|
||||
// pass along the diffuse color
|
||||
gl_FrontColor = gl_Color * gl_FrontMaterial.diffuse;
|
||||
gl_FrontColor = gl_Color;
|
||||
|
||||
// and the texture coordinates
|
||||
gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0);
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
|
@ -25,9 +29,6 @@ uniform sampler2D normalMap;
|
|||
// the specular map texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 interpolatedNormal;
|
||||
|
||||
|
@ -47,9 +48,16 @@ void main(void) {
|
|||
|
||||
// set the diffuse, normal, specular data
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
vec3 specular = texture2D(specularMap, gl_TexCoord[0].st).rgb;
|
||||
vec4 emissive = texture2D(emissiveMap, interpolatedTexcoord1.st);
|
||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb * (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb), mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||
gl_FragData[1] = viewNormal + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb,
|
||||
gl_FrontMaterial.shininess / 128.0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragmentLightmap(
|
||||
normalize(viewNormal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a),
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
specular, // no use of getMaterialSpecular(mat)
|
||||
getMaterialShininess(mat),
|
||||
(vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
|
@ -22,9 +26,6 @@ uniform vec2 emissiveParams;
|
|||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
|
@ -33,9 +34,16 @@ varying vec2 interpolatedTexcoord1;
|
|||
void main(void) {
|
||||
// set the diffuse, normal, specular data
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
vec3 specular = texture2D(specularMap, gl_TexCoord[0].st).rgb;
|
||||
vec4 emissive = texture2D(emissiveMap, interpolatedTexcoord1.st);
|
||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb * (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb), mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb,
|
||||
gl_FrontMaterial.shininess / 128.0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragmentLightmap(
|
||||
normalize(normal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a),
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
specular, // no use of getMaterialSpecular(mat)
|
||||
getMaterialShininess(mat),
|
||||
(vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb));
|
||||
}
|
||||
|
|
|
@ -12,15 +12,16 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal map texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 interpolatedNormal;
|
||||
|
||||
|
@ -35,10 +36,15 @@ void main(void) {
|
|||
vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) - vec3(0.5, 0.5, 0.5);
|
||||
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
|
||||
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
|
||||
|
||||
// set the diffuse, normal, specular data
|
||||
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||
gl_FragData[1] = viewNormal + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(viewNormal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a),
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
getMaterialSpecular(mat),
|
||||
getMaterialShininess(mat));
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ void main(void) {
|
|||
interpolatedTangent = gl_ModelViewMatrix * vec4(tangent, 0.0);
|
||||
|
||||
// pass along the diffuse color
|
||||
gl_FrontColor = gl_Color * gl_FrontMaterial.diffuse;
|
||||
gl_FrontColor = gl_Color;
|
||||
|
||||
// and the texture coordinates
|
||||
gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0);
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
|
@ -21,9 +25,6 @@ uniform sampler2D normalMap;
|
|||
// the specular map texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 interpolatedNormal;
|
||||
|
||||
|
@ -41,8 +42,14 @@ void main(void) {
|
|||
|
||||
// set the diffuse, normal, specular data
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||
gl_FragData[1] = viewNormal + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb,
|
||||
gl_FrontMaterial.shininess / 128.0);
|
||||
vec3 specular = texture2D(specularMap, gl_TexCoord[0].st).rgb;
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(viewNormal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a),
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
specular, //getMaterialSpecular(mat),
|
||||
getMaterialShininess(mat));
|
||||
}
|
||||
|
|
|
@ -12,23 +12,30 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// set the diffuse, normal, specular data
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb,
|
||||
gl_FrontMaterial.shininess / 128.0);
|
||||
vec3 specular = texture2D(specularMap, gl_TexCoord[0].st).rgb;
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(normal.xyz),
|
||||
evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a),
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
specular, //getMaterialSpecular(mat),
|
||||
getMaterialShininess(mat));
|
||||
}
|
||||
|
|
|
@ -12,10 +12,29 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include Material.slh@>
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
|
||||
// Fetch diffuse map
|
||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(normal.xyz),
|
||||
getMaterialOpacity(mat) * diffuse.a,
|
||||
getMaterialDiffuse(mat) * diffuse.rgb,
|
||||
getMaterialSpecular(mat),
|
||||
getMaterialShininess(mat));
|
||||
|
||||
// set the diffuse data
|
||||
gl_FragData[0] = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
// gl_FragData[0] = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
}
|
||||
|
|
|
@ -12,15 +12,25 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
// the glow intensity
|
||||
uniform float glowIntensity;
|
||||
//uniform float glowIntensity;
|
||||
|
||||
void main(void) {
|
||||
// set the diffuse, normal, specular data
|
||||
/* // set the diffuse, normal, specular data
|
||||
gl_FragData[0] = vec4(gl_Color.rgb, glowIntensity);
|
||||
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
|
||||
*/
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(normal.xyz),
|
||||
glowIntensity,
|
||||
gl_Color.rgb,
|
||||
gl_FrontMaterial.specular.rgb,
|
||||
gl_FrontMaterial.shininess);
|
||||
}
|
||||
|
|
|
@ -38,8 +38,8 @@ void main(void) {
|
|||
normal = normalize(gl_ModelViewMatrix * normal);
|
||||
|
||||
// pass along the diffuse color
|
||||
gl_FrontColor = gl_FrontMaterial.diffuse;
|
||||
|
||||
gl_FrontColor = gl_Color;
|
||||
|
||||
// and the texture coordinates
|
||||
gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0);
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@ void main(void) {
|
|||
interpolatedTangent = gl_ModelViewMatrix * interpolatedTangent;
|
||||
|
||||
// pass along the diffuse color
|
||||
gl_FrontColor = gl_FrontMaterial.diffuse;
|
||||
|
||||
gl_FrontColor = gl_Color;
|
||||
|
||||
// and the texture coordinates
|
||||
gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0);
|
||||
|
||||
|
|
|
@ -83,11 +83,13 @@ template <typename T, typename ...Args>
|
|||
QSharedPointer<T> DependencyManager::set(Args&&... args) {
|
||||
static size_t hashCode = _manager.getHashCode<T>();
|
||||
|
||||
QSharedPointer<T> instance(new T(args...), &T::customDeleter);
|
||||
QSharedPointer<Dependency> storedInstance = qSharedPointerCast<Dependency>(instance);
|
||||
_manager.safeGet(hashCode).swap(storedInstance);
|
||||
QSharedPointer<Dependency>& instance = _manager.safeGet(hashCode);
|
||||
instance.clear(); // Clear instance before creation of new one to avoid edge cases
|
||||
QSharedPointer<T> newInstance(new T(args...), &T::customDeleter);
|
||||
QSharedPointer<Dependency> storedInstance = qSharedPointerCast<Dependency>(newInstance);
|
||||
instance.swap(storedInstance);
|
||||
|
||||
return instance;
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
Loading…
Reference in a new issue