mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge branch 'master' of https://github.com/highfidelity/hifi into seth-branch
This commit is contained in:
commit
23b99f04cd
60 changed files with 836 additions and 466 deletions
|
@ -17,11 +17,12 @@ ListModel {
|
||||||
id: root;
|
id: root;
|
||||||
property string sortColumnName: "";
|
property string sortColumnName: "";
|
||||||
property bool isSortingDescending: true;
|
property bool isSortingDescending: true;
|
||||||
|
property bool valuesAreNumerical: false;
|
||||||
|
|
||||||
function swap(a, b) {
|
function swap(a, b) {
|
||||||
if (a < b) {
|
if (a < b) {
|
||||||
move(a, b, 1);
|
move(a, b, 1);
|
||||||
move (b - 1, a, 1);
|
move(b - 1, a, 1);
|
||||||
} else if (a > b) {
|
} else if (a > b) {
|
||||||
move(b, a, 1);
|
move(b, a, 1);
|
||||||
move(a - 1, b, 1);
|
move(a - 1, b, 1);
|
||||||
|
@ -29,26 +30,53 @@ ListModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
function partition(begin, end, pivot) {
|
function partition(begin, end, pivot) {
|
||||||
var piv = get(pivot)[sortColumnName];
|
if (valuesAreNumerical) {
|
||||||
swap(pivot, end - 1);
|
var piv = get(pivot)[sortColumnName];
|
||||||
var store = begin;
|
swap(pivot, end - 1);
|
||||||
|
var store = begin;
|
||||||
|
var i;
|
||||||
|
|
||||||
for (var i = begin; i < end - 1; ++i) {
|
for (i = begin; i < end - 1; ++i) {
|
||||||
if (isSortingDescending) {
|
var currentElement = get(i)[sortColumnName];
|
||||||
if (get(i)[sortColumnName] < piv) {
|
if (isSortingDescending) {
|
||||||
swap(store, i);
|
if (currentElement > piv) {
|
||||||
++store;
|
swap(store, i);
|
||||||
}
|
++store;
|
||||||
} else {
|
}
|
||||||
if (get(i)[sortColumnName] > piv) {
|
} else {
|
||||||
swap(store, i);
|
if (currentElement < piv) {
|
||||||
++store;
|
swap(store, i);
|
||||||
|
++store;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
swap(end - 1, store);
|
||||||
swap(end - 1, store);
|
|
||||||
|
|
||||||
return store;
|
return store;
|
||||||
|
} else {
|
||||||
|
var piv = get(pivot)[sortColumnName].toLowerCase();
|
||||||
|
swap(pivot, end - 1);
|
||||||
|
var store = begin;
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = begin; i < end - 1; ++i) {
|
||||||
|
var currentElement = get(i)[sortColumnName].toLowerCase();
|
||||||
|
if (isSortingDescending) {
|
||||||
|
if (currentElement > piv) {
|
||||||
|
swap(store, i);
|
||||||
|
++store;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (currentElement < piv) {
|
||||||
|
swap(store, i);
|
||||||
|
++store;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
swap(end - 1, store);
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function qsort(begin, end) {
|
function qsort(begin, end) {
|
||||||
|
|
|
@ -317,6 +317,7 @@ Rectangle {
|
||||||
|
|
||||||
HifiControlsUit.TextField {
|
HifiControlsUit.TextField {
|
||||||
id: filterBar;
|
id: filterBar;
|
||||||
|
property string previousText: "";
|
||||||
colorScheme: hifi.colorSchemes.faintGray;
|
colorScheme: hifi.colorSchemes.faintGray;
|
||||||
hasClearButton: true;
|
hasClearButton: true;
|
||||||
hasRoundedBorder: true;
|
hasRoundedBorder: true;
|
||||||
|
@ -329,6 +330,8 @@ Rectangle {
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
buildFilteredPurchasesModel();
|
buildFilteredPurchasesModel();
|
||||||
|
purchasesContentsList.positionViewAtIndex(0, ListView.Beginning)
|
||||||
|
filterBar.previousText = filterBar.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
|
@ -647,7 +650,8 @@ Rectangle {
|
||||||
|
|
||||||
function sortByDate() {
|
function sortByDate() {
|
||||||
filteredPurchasesModel.sortColumnName = "purchase_date";
|
filteredPurchasesModel.sortColumnName = "purchase_date";
|
||||||
filteredPurchasesModel.isSortingDescending = false;
|
filteredPurchasesModel.isSortingDescending = true;
|
||||||
|
filteredPurchasesModel.valuesAreNumerical = true;
|
||||||
filteredPurchasesModel.quickSort();
|
filteredPurchasesModel.quickSort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,7 +681,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sameItemCount !== tempPurchasesModel.count) {
|
if (sameItemCount !== tempPurchasesModel.count || filterBar.text !== filterBar.previousText) {
|
||||||
filteredPurchasesModel.clear();
|
filteredPurchasesModel.clear();
|
||||||
for (var i = 0; i < tempPurchasesModel.count; i++) {
|
for (var i = 0; i < tempPurchasesModel.count; i++) {
|
||||||
filteredPurchasesModel.append(tempPurchasesModel.get(i));
|
filteredPurchasesModel.append(tempPurchasesModel.get(i));
|
||||||
|
|
|
@ -193,7 +193,7 @@ Item {
|
||||||
color: hifi.colors.white;
|
color: hifi.colors.white;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Change Passphrase" button
|
// "Change Security Pic" button
|
||||||
HifiControlsUit.Button {
|
HifiControlsUit.Button {
|
||||||
id: changeSecurityImageButton;
|
id: changeSecurityImageButton;
|
||||||
color: hifi.buttons.blue;
|
color: hifi.buttons.blue;
|
||||||
|
|
|
@ -34,13 +34,11 @@ Item {
|
||||||
securityImageChangePageSecurityImage.source = "image://security/securityImage";
|
securityImageChangePageSecurityImage.source = "image://security/securityImage";
|
||||||
if (exists) { // Success submitting new security image
|
if (exists) { // Success submitting new security image
|
||||||
if (root.justSubmitted) {
|
if (root.justSubmitted) {
|
||||||
root.resetSubmitButton();
|
|
||||||
sendSignalToWallet({method: "walletSecurity_changeSecurityImageSuccess"});
|
sendSignalToWallet({method: "walletSecurity_changeSecurityImageSuccess"});
|
||||||
root.justSubmitted = false;
|
root.justSubmitted = false;
|
||||||
}
|
}
|
||||||
} else if (root.justSubmitted) {
|
} else if (root.justSubmitted) {
|
||||||
// Error submitting new security image.
|
// Error submitting new security image.
|
||||||
root.resetSubmitButton();
|
|
||||||
root.justSubmitted = false;
|
root.justSubmitted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +178,8 @@ Item {
|
||||||
// "Submit" button
|
// "Submit" button
|
||||||
HifiControlsUit.Button {
|
HifiControlsUit.Button {
|
||||||
id: securityImageSubmitButton;
|
id: securityImageSubmitButton;
|
||||||
enabled: securityImageSelection.currentIndex !== -1;
|
text: root.justSubmitted ? "Submitting..." : "Submit";
|
||||||
|
enabled: securityImageSelection.currentIndex !== -1 && !root.justSubmitted;
|
||||||
color: hifi.buttons.blue;
|
color: hifi.buttons.blue;
|
||||||
colorScheme: hifi.colorSchemes.dark;
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
anchors.top: parent.top;
|
anchors.top: parent.top;
|
||||||
|
@ -188,11 +187,8 @@ Item {
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
anchors.rightMargin: 20;
|
anchors.rightMargin: 20;
|
||||||
width: 150;
|
width: 150;
|
||||||
text: "Submit";
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.justSubmitted = true;
|
root.justSubmitted = true;
|
||||||
securityImageSubmitButton.text = "Submitting...";
|
|
||||||
securityImageSubmitButton.enabled = false;
|
|
||||||
var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex())
|
var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex())
|
||||||
Commerce.chooseSecurityImage(securityImagePath);
|
Commerce.chooseSecurityImage(securityImagePath);
|
||||||
}
|
}
|
||||||
|
@ -205,11 +201,6 @@ Item {
|
||||||
|
|
||||||
signal sendSignalToWallet(var msg);
|
signal sendSignalToWallet(var msg);
|
||||||
|
|
||||||
function resetSubmitButton() {
|
|
||||||
securityImageSubmitButton.enabled = true;
|
|
||||||
securityImageSubmitButton.text = "Submit";
|
|
||||||
}
|
|
||||||
|
|
||||||
function initModel() {
|
function initModel() {
|
||||||
securityImageSelection.initModel();
|
securityImageSelection.initModel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ Item {
|
||||||
HifiConstants { id: hifi; }
|
HifiConstants { id: hifi; }
|
||||||
|
|
||||||
id: root;
|
id: root;
|
||||||
property int currentIndex: securityImageGrid.currentIndex;
|
property alias currentIndex: securityImageGrid.currentIndex;
|
||||||
|
|
||||||
// This will cause a bug -- if you bring up security image selection in HUD mode while
|
// This will cause a bug -- if you bring up security image selection in HUD mode while
|
||||||
// in HMD while having HMD preview enabled, then move, then finish passphrase selection,
|
// in HMD while having HMD preview enabled, then move, then finish passphrase selection,
|
||||||
|
@ -98,6 +98,11 @@ Item {
|
||||||
|
|
||||||
function initModel() {
|
function initModel() {
|
||||||
gridModel.initModel();
|
gridModel.initModel();
|
||||||
|
securityImageGrid.currentIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetSelection() {
|
||||||
|
securityImageGrid.currentIndex = -1;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// FUNCTION DEFINITIONS END
|
// FUNCTION DEFINITIONS END
|
||||||
|
|
|
@ -348,6 +348,7 @@ Item {
|
||||||
width: 200;
|
width: 200;
|
||||||
text: "Back"
|
text: "Back"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
securityImageSelection.resetSelection();
|
||||||
root.activeView = "step_1";
|
root.activeView = "step_1";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,6 +517,7 @@ Item {
|
||||||
width: 200;
|
width: 200;
|
||||||
text: "Back"
|
text: "Back"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
securityImageSelection.resetSelection();
|
||||||
root.lastPage = "step_3";
|
root.lastPage = "step_3";
|
||||||
root.activeView = "step_2";
|
root.activeView = "step_2";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// AdvancedPreferencesDialog.qml
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 20 Jan 2018
|
||||||
|
// Copyright 2018 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
|
||||||
|
//
|
||||||
|
|
||||||
|
import QtQuick 2.5
|
||||||
|
import Qt.labs.settings 1.0
|
||||||
|
|
||||||
|
import "../../dialogs"
|
||||||
|
|
||||||
|
PreferencesDialog {
|
||||||
|
id: root
|
||||||
|
objectName: "AdvancedPreferencesDialog"
|
||||||
|
title: "Advanced Settings"
|
||||||
|
showCategories: ["Advanced UI" ]
|
||||||
|
property var settings: Settings {
|
||||||
|
category: root.objectName
|
||||||
|
property alias x: root.x
|
||||||
|
property alias y: root.y
|
||||||
|
property alias width: root.width
|
||||||
|
property alias height: root.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ PreferencesDialog {
|
||||||
id: root
|
id: root
|
||||||
objectName: "GeneralPreferencesDialog"
|
objectName: "GeneralPreferencesDialog"
|
||||||
title: "General Settings"
|
title: "General Settings"
|
||||||
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
|
showCategories: ["UI", "Snapshots", "Privacy", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
|
||||||
property var settings: Settings {
|
property var settings: Settings {
|
||||||
category: root.objectName
|
category: root.objectName
|
||||||
property alias x: root.x
|
property alias x: root.x
|
||||||
|
|
|
@ -41,14 +41,14 @@ QSpinBox, QDoubleSpinBox {
|
||||||
|
|
||||||
QDoubleSpinBox::up-arrow,
|
QDoubleSpinBox::up-arrow,
|
||||||
QSpinBox::up-arrow {
|
QSpinBox::up-arrow {
|
||||||
background-image: url(styles/up.svg);
|
background-image: url(:/styles/up.svg);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDoubleSpinBox::down-arrow,
|
QDoubleSpinBox::down-arrow,
|
||||||
QSpinBox::down-arrow {
|
QSpinBox::down-arrow {
|
||||||
background-image: url(styles/down.svg);
|
background-image: url(:/styles/down.svg);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ QSlider {
|
||||||
|
|
||||||
QSlider::groove:horizontal {
|
QSlider::groove:horizontal {
|
||||||
border: none;
|
border: none;
|
||||||
background-image: url(styles/slider-bg.svg);
|
background-image: url(:/styles/slider-bg.svg);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ QSlider::groove:horizontal {
|
||||||
QSlider::handle:horizontal {
|
QSlider::handle:horizontal {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
background-image: url(styles/slider-handle.svg);
|
background-image: url(:/styles/slider-handle.svg);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ QPushButton#closeButton {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
background-image: url(styles/close.svg);
|
background-image: url(:/styles/close.svg);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,17 +63,17 @@ QPushButton#cancelButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
#backButton {
|
#backButton {
|
||||||
background-image: url(icons/backButton.svg);
|
background-image: url(:/icons/backButton.svg);
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#forwardButton {
|
#forwardButton {
|
||||||
background-image: url(icons/forwardButton.svg);
|
background-image: url(:/icons/forwardButton.svg);
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toParentButton {
|
#toParentButton {
|
||||||
background-image: url(icons/toParentButton.svg);
|
background-image: url(:/icons/toParentButton.svg);
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ QLineEdit {
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton#searchButton {
|
QPushButton#searchButton {
|
||||||
background: url(styles/search.svg);
|
background: url(:/styles/search.svg);
|
||||||
background-repeat: none;
|
background-repeat: none;
|
||||||
background-position: left center;
|
background-position: left center;
|
||||||
background-origin: content;
|
background-origin: content;
|
||||||
|
@ -55,7 +55,7 @@ QPushButton#searchPrevButton {
|
||||||
|
|
||||||
QPushButton#revealLogButton {
|
QPushButton#revealLogButton {
|
||||||
font-family: Helvetica, Arial, sans-serif;
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
background: url(styles/txt-file.svg);
|
background: url(:/styles/txt-file.svg);
|
||||||
background-repeat: none;
|
background-repeat: none;
|
||||||
background-position: left center;
|
background-position: left center;
|
||||||
background-origin: content;
|
background-origin: content;
|
||||||
|
@ -86,11 +86,11 @@ QCheckBox {
|
||||||
}
|
}
|
||||||
|
|
||||||
QCheckBox::indicator:unchecked {
|
QCheckBox::indicator:unchecked {
|
||||||
image: url(styles/unchecked.svg);
|
image: url(:/styles/unchecked.svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
QCheckBox::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
image: url(styles/checked.svg);
|
image: url(:/styles/checked.svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
QComboBox {
|
QComboBox {
|
||||||
|
@ -110,6 +110,6 @@ QComboBox::drop-down {
|
||||||
}
|
}
|
||||||
|
|
||||||
QComboBox::down-arrow {
|
QComboBox::down-arrow {
|
||||||
image: url(styles/filter.png);
|
image: url(:/styles/filter.png);
|
||||||
border-width: 0px;
|
border-width: 0px;
|
||||||
}
|
}
|
|
@ -351,7 +351,7 @@ static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;
|
||||||
static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND;
|
static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND;
|
||||||
|
|
||||||
static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
|
static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
|
||||||
static const QString INFO_HELP_PATH = "../../../html/tabletHelp.html";
|
static const QString INFO_HELP_PATH = "html/tabletHelp.html";
|
||||||
|
|
||||||
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
|
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
|
||||||
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
|
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
|
||||||
|
@ -1436,8 +1436,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
userInputMapper->registerDevice(_touchscreenDevice->getInputDevice());
|
userInputMapper->registerDevice(_touchscreenDevice->getInputDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
// force the model the look at the correct directory (weird order of operations issue)
|
// this will force the model the look at the correct directory (weird order of operations issue)
|
||||||
scriptEngines->setScriptsLocation(scriptEngines->getScriptsLocation());
|
scriptEngines->reloadLocalFiles();
|
||||||
|
|
||||||
// do this as late as possible so that all required subsystems are initialized
|
// do this as late as possible so that all required subsystems are initialized
|
||||||
// If we've overridden the default scripts location, just load default scripts
|
// If we've overridden the default scripts location, just load default scripts
|
||||||
// otherwise, load 'em all
|
// otherwise, load 'em all
|
||||||
|
@ -2723,7 +2724,8 @@ void Application::showHelp() {
|
||||||
queryString.addQueryItem("defaultTab", defaultTab);
|
queryString.addQueryItem("defaultTab", defaultTab);
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet(SYSTEM_TABLET));
|
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet(SYSTEM_TABLET));
|
||||||
tablet->gotoWebScreen(INFO_HELP_PATH + "?" + queryString.toString());
|
tablet->gotoWebScreen(PathUtils::resourcesUrl() + INFO_HELP_PATH + "?" + queryString.toString());
|
||||||
|
DependencyManager::get<HMDScriptingInterface>()->openTablet();
|
||||||
//InfoView::show(INFO_HELP_PATH, false, queryString.toString());
|
//InfoView::show(INFO_HELP_PATH, false, queryString.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -756,6 +756,13 @@ Menu::Menu() {
|
||||||
// Developer > Stats
|
// Developer > Stats
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats);
|
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats);
|
||||||
|
|
||||||
|
// Developer > Advanced Settings...
|
||||||
|
action = addActionToQMenuAndActionHash(developerMenu, "Advanced Preferences...");
|
||||||
|
connect(action, &QAction::triggered, [] {
|
||||||
|
qApp->showDialog(QString("hifi/dialogs/AdvancedPreferencesDialog.qml"),
|
||||||
|
QString("hifi/tablet/AdvancedPreferencesDialog.qml"), "AdvancedPreferencesDialog");
|
||||||
|
});
|
||||||
|
|
||||||
// Developer > API Debugger
|
// Developer > API Debugger
|
||||||
action = addActionToQMenuAndActionHash(developerMenu, "API Debugger");
|
action = addActionToQMenuAndActionHash(developerMenu, "API Debugger");
|
||||||
connect(action, &QAction::triggered, [] {
|
connect(action, &QAction::triggered, [] {
|
||||||
|
|
|
@ -591,8 +591,8 @@ void Wallet::chooseSecurityImage(const QString& filename) {
|
||||||
if (_securityImage) {
|
if (_securityImage) {
|
||||||
delete _securityImage;
|
delete _securityImage;
|
||||||
}
|
}
|
||||||
QString path = qApp->applicationDirPath();
|
QString path = PathUtils::resourcesPath();
|
||||||
path.append("/resources/qml/hifi/commerce/wallet/");
|
path.append("/qml/hifi/commerce/wallet/");
|
||||||
path.append(filename);
|
path.append(filename);
|
||||||
|
|
||||||
// now create a new security image pixmap
|
// now create a new security image pixmap
|
||||||
|
|
|
@ -39,7 +39,6 @@ BaseLogDialog::BaseLogDialog(QWidget* parent) : QDialog(parent, Qt::Window) {
|
||||||
|
|
||||||
QFile styleSheet(PathUtils::resourcesPath() + "styles/log_dialog.qss");
|
QFile styleSheet(PathUtils::resourcesPath() + "styles/log_dialog.qss");
|
||||||
if (styleSheet.open(QIODevice::ReadOnly)) {
|
if (styleSheet.open(QIODevice::ReadOnly)) {
|
||||||
QDir::setCurrent(PathUtils::resourcesPath());
|
|
||||||
setStyleSheet(styleSheet.readAll());
|
setStyleSheet(styleSheet.readAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,19 +82,42 @@ void setupPreferences() {
|
||||||
preference->setMax(500);
|
preference->setMax(500);
|
||||||
preferences->addPreference(preference);
|
preferences->addPreference(preference);
|
||||||
}
|
}
|
||||||
{
|
|
||||||
auto getter = []()->float { return qApp->getDesktopTabletScale(); };
|
|
||||||
auto setter = [](float value) { qApp->setDesktopTabletScale(value); };
|
|
||||||
auto preference = new SpinnerPreference(UI_CATEGORY, "Desktop Tablet Scale %", getter, setter);
|
|
||||||
preference->setMin(20);
|
|
||||||
preference->setMax(500);
|
|
||||||
preferences->addPreference(preference);
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
auto getter = []()->bool { return qApp->getPreferStylusOverLaser(); };
|
auto getter = []()->bool { return qApp->getPreferStylusOverLaser(); };
|
||||||
auto setter = [](bool value) { qApp->setPreferStylusOverLaser(value); };
|
auto setter = [](bool value) { qApp->setPreferStylusOverLaser(value); };
|
||||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Stylus Over Laser", getter, setter));
|
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Stylus Over Laser", getter, setter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const QString ADVANCED_UI_CATEGORY { "Advanced UI" };
|
||||||
|
{
|
||||||
|
auto getter = []()->float { return qApp->getDesktopTabletScale(); };
|
||||||
|
auto setter = [](float value) { qApp->setDesktopTabletScale(value); };
|
||||||
|
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Desktop Tablet Scale %", getter, setter);
|
||||||
|
preference->setMin(20);
|
||||||
|
preference->setMax(500);
|
||||||
|
preferences->addPreference(preference);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
|
||||||
|
auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); };
|
||||||
|
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Real world vertical field of view (angular size of monitor)", getter, setter);
|
||||||
|
preference->setMin(1);
|
||||||
|
preference->setMax(180);
|
||||||
|
preferences->addPreference(preference);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto getter = []()->float { return qApp->getFieldOfView(); };
|
||||||
|
auto setter = [](float value) { qApp->setFieldOfView(value); };
|
||||||
|
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Vertical field of view", getter, setter);
|
||||||
|
preference->setMin(1);
|
||||||
|
preference->setMax(180);
|
||||||
|
preference->setStep(1);
|
||||||
|
preferences->addPreference(preference);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME: Remove setting completely or make available through JavaScript API?
|
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
|
@ -128,21 +151,13 @@ void setupPreferences() {
|
||||||
preferences->addPreference(preference);
|
preferences->addPreference(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scripts
|
|
||||||
{
|
|
||||||
auto getter = []()->QString { return DependencyManager::get<ScriptEngines>()->getScriptsLocation(); };
|
|
||||||
auto setter = [](const QString& value) { DependencyManager::get<ScriptEngines>()->setScriptsLocation(value); };
|
|
||||||
preferences->addPreference(new BrowsePreference("Scripts", "Load scripts from this directory", getter, setter));
|
|
||||||
}
|
|
||||||
|
|
||||||
preferences->addPreference(new ButtonPreference("Scripts", "Load Default Scripts", [] {
|
|
||||||
DependencyManager::get<ScriptEngines>()->loadDefaultScripts();
|
|
||||||
}));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto getter = []()->bool { return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); };
|
auto getter = []()->bool { return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); };
|
||||||
auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); };
|
auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); };
|
||||||
preferences->addPreference(new CheckPreference("Privacy", "Send data", getter, setter));
|
preferences->addPreference(new CheckPreference("Privacy", "Send data - High Fidelity uses information provided by your "
|
||||||
|
"client to improve the product through the logging of errors, tracking of usage patterns, "
|
||||||
|
"installation and system details, and crash events. By allowing High Fidelity to collect "
|
||||||
|
"this information you are helping to improve the product. ", getter, setter));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString LOD_TUNING("Level of Detail Tuning");
|
static const QString LOD_TUNING("Level of Detail Tuning");
|
||||||
|
@ -167,23 +182,6 @@ void setupPreferences() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString AVATAR_TUNING { "Avatar Tuning" };
|
static const QString AVATAR_TUNING { "Avatar Tuning" };
|
||||||
{
|
|
||||||
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
|
|
||||||
auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); };
|
|
||||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Real world vertical field of view (angular size of monitor)", getter, setter);
|
|
||||||
preference->setMin(1);
|
|
||||||
preference->setMax(180);
|
|
||||||
preferences->addPreference(preference);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto getter = []()->float { return qApp->getFieldOfView(); };
|
|
||||||
auto setter = [](float value) { qApp->setFieldOfView(value); };
|
|
||||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Vertical field of view", getter, setter);
|
|
||||||
preference->setMin(1);
|
|
||||||
preference->setMax(180);
|
|
||||||
preference->setStep(1);
|
|
||||||
preferences->addPreference(preference);
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
auto getter = [=]()->QString { return myAvatar->getDominantHand(); };
|
auto getter = [=]()->QString { return myAvatar->getDominantHand(); };
|
||||||
auto setter = [=](const QString& value) { myAvatar->setDominantHand(value); };
|
auto setter = [=](const QString& value) { myAvatar->setDominantHand(value); };
|
||||||
|
@ -297,26 +295,6 @@ void setupPreferences() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
|
||||||
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };
|
|
||||||
auto setter = [](float value) { qApp->setMaxOctreePacketsPerSecond(value); };
|
|
||||||
auto preference = new SpinnerPreference("Octree", "Max packets sent each second", getter, setter);
|
|
||||||
preference->setMin(60);
|
|
||||||
preference->setMax(6000);
|
|
||||||
preference->setStep(10);
|
|
||||||
preferences->addPreference(preference);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
auto getter = []()->float { return qApp->getApplicationCompositor().getHmdUIAngularSize(); };
|
|
||||||
auto setter = [](float value) { qApp->getApplicationCompositor().setHmdUIAngularSize(value); };
|
|
||||||
auto preference = new SpinnerPreference("HMD", "UI horizontal angular size (degrees)", getter, setter);
|
|
||||||
preference->setMin(30);
|
|
||||||
preference->setMax(160);
|
|
||||||
preference->setStep(1);
|
|
||||||
preferences->addPreference(preference);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
static const QString RENDER("Graphics");
|
static const QString RENDER("Graphics");
|
||||||
|
@ -342,7 +320,7 @@ void setupPreferences() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
static const QString RENDER("Networking");
|
static const QString NETWORKING("Networking");
|
||||||
|
|
||||||
auto nodelist = DependencyManager::get<NodeList>();
|
auto nodelist = DependencyManager::get<NodeList>();
|
||||||
{
|
{
|
||||||
|
@ -350,10 +328,21 @@ void setupPreferences() {
|
||||||
static const int MAX_PORT_NUMBER { 65535 };
|
static const int MAX_PORT_NUMBER { 65535 };
|
||||||
auto getter = [nodelist] { return static_cast<int>(nodelist->getSocketLocalPort()); };
|
auto getter = [nodelist] { return static_cast<int>(nodelist->getSocketLocalPort()); };
|
||||||
auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast<quint16>(preset)); };
|
auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast<quint16>(preset)); };
|
||||||
auto preference = new IntSpinnerPreference(RENDER, "Listening Port", getter, setter);
|
auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter);
|
||||||
preference->setMin(MIN_PORT_NUMBER);
|
preference->setMin(MIN_PORT_NUMBER);
|
||||||
preference->setMax(MAX_PORT_NUMBER);
|
preference->setMax(MAX_PORT_NUMBER);
|
||||||
preferences->addPreference(preference);
|
preferences->addPreference(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };
|
||||||
|
auto setter = [](float value) { qApp->setMaxOctreePacketsPerSecond(value); };
|
||||||
|
auto preference = new SpinnerPreference(NETWORKING, "Max entities packets sent each second", getter, setter);
|
||||||
|
preference->setMin(60);
|
||||||
|
preference->setMax(6000);
|
||||||
|
preference->setStep(10);
|
||||||
|
preferences->addPreference(preference);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
|
||||||
_contextOverlay->setColorPulse(CONTEXT_OVERLAY_UNHOVERED_COLORPULSE);
|
_contextOverlay->setColorPulse(CONTEXT_OVERLAY_UNHOVERED_COLORPULSE);
|
||||||
_contextOverlay->setIgnoreRayIntersection(false);
|
_contextOverlay->setIgnoreRayIntersection(false);
|
||||||
_contextOverlay->setDrawInFront(true);
|
_contextOverlay->setDrawInFront(true);
|
||||||
_contextOverlay->setURL(PathUtils::resourcesPath() + "images/inspect-icon.png");
|
_contextOverlay->setURL(PathUtils::resourcesUrl() + "images/inspect-icon.png");
|
||||||
_contextOverlay->setIsFacingAvatar(true);
|
_contextOverlay->setIsFacingAvatar(true);
|
||||||
_contextOverlayID = qApp->getOverlays().addOverlay(_contextOverlay);
|
_contextOverlayID = qApp->getOverlays().addOverlay(_contextOverlay);
|
||||||
}
|
}
|
||||||
|
|
|
@ -427,28 +427,11 @@ AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const fl
|
||||||
options.stereo = sound->isStereo();
|
options.stereo = sound->isStereo();
|
||||||
options.position = position;
|
options.position = position;
|
||||||
options.volume = volume;
|
options.volume = volume;
|
||||||
|
options.pitch = 1.0f / stretchFactor;
|
||||||
|
|
||||||
QByteArray samples = sound->getByteArray();
|
QByteArray samples = sound->getByteArray();
|
||||||
if (stretchFactor == 1.0f) {
|
|
||||||
return playSoundAndDelete(samples, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int standardRate = AudioConstants::SAMPLE_RATE;
|
return playSoundAndDelete(samples, options);
|
||||||
const int resampledRate = standardRate * stretchFactor;
|
|
||||||
const int channelCount = sound->isStereo() ? 2 : 1;
|
|
||||||
|
|
||||||
AudioSRC resampler(standardRate, resampledRate, channelCount);
|
|
||||||
|
|
||||||
const int nInputFrames = samples.size() / (channelCount * sizeof(int16_t));
|
|
||||||
const int maxOutputFrames = resampler.getMaxOutput(nInputFrames);
|
|
||||||
QByteArray resampled(maxOutputFrames * channelCount * sizeof(int16_t), '\0');
|
|
||||||
|
|
||||||
int nOutputFrames = resampler.render(reinterpret_cast<const int16_t*>(samples.data()),
|
|
||||||
reinterpret_cast<int16_t*>(resampled.data()),
|
|
||||||
nInputFrames);
|
|
||||||
|
|
||||||
Q_UNUSED(nOutputFrames);
|
|
||||||
return playSoundAndDelete(resampled, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options) {
|
AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options) {
|
||||||
|
@ -461,12 +444,40 @@ AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer,
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioInjectorPointer AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options) {
|
AudioInjectorPointer AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options) {
|
||||||
AudioInjectorPointer injector = AudioInjectorPointer::create(buffer, options);
|
|
||||||
|
|
||||||
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
|
if (options.pitch == 1.0f) {
|
||||||
qWarning() << "AudioInjector::playSound failed to thread injector";
|
|
||||||
|
AudioInjectorPointer injector = AudioInjectorPointer::create(buffer, options);
|
||||||
|
|
||||||
|
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
|
||||||
|
qWarning() << "AudioInjector::playSound failed to thread injector";
|
||||||
|
}
|
||||||
|
return injector;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const int standardRate = AudioConstants::SAMPLE_RATE;
|
||||||
|
const int resampledRate = AudioConstants::SAMPLE_RATE / glm::clamp(options.pitch, 1/16.0f, 16.0f); // limit to 4 octaves
|
||||||
|
const int numChannels = options.ambisonic ? AudioConstants::AMBISONIC :
|
||||||
|
(options.stereo ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||||
|
|
||||||
|
AudioSRC resampler(standardRate, resampledRate, numChannels);
|
||||||
|
|
||||||
|
// create a resampled buffer that is guaranteed to be large enough
|
||||||
|
const int nInputFrames = buffer.size() / (numChannels * sizeof(int16_t));
|
||||||
|
const int maxOutputFrames = resampler.getMaxOutput(nInputFrames);
|
||||||
|
QByteArray resampledBuffer(maxOutputFrames * numChannels * sizeof(int16_t), '\0');
|
||||||
|
|
||||||
|
resampler.render(reinterpret_cast<const int16_t*>(buffer.data()),
|
||||||
|
reinterpret_cast<int16_t*>(resampledBuffer.data()),
|
||||||
|
nInputFrames);
|
||||||
|
|
||||||
|
AudioInjectorPointer injector = AudioInjectorPointer::create(resampledBuffer, options);
|
||||||
|
|
||||||
|
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
|
||||||
|
qWarning() << "AudioInjector::playSound failed to thread pitch-shifted injector";
|
||||||
|
}
|
||||||
|
return injector;
|
||||||
}
|
}
|
||||||
return injector;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,8 @@ AudioInjectorOptions::AudioInjectorOptions() :
|
||||||
ambisonic(false),
|
ambisonic(false),
|
||||||
ignorePenumbra(false),
|
ignorePenumbra(false),
|
||||||
localOnly(false),
|
localOnly(false),
|
||||||
secondOffset(0.0f)
|
secondOffset(0.0f),
|
||||||
|
pitch(1.0f)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,6 +41,7 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje
|
||||||
obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra);
|
obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra);
|
||||||
obj.setProperty("localOnly", injectorOptions.localOnly);
|
obj.setProperty("localOnly", injectorOptions.localOnly);
|
||||||
obj.setProperty("secondOffset", injectorOptions.secondOffset);
|
obj.setProperty("secondOffset", injectorOptions.secondOffset);
|
||||||
|
obj.setProperty("pitch", injectorOptions.pitch);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +89,12 @@ void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOpt
|
||||||
} else {
|
} else {
|
||||||
qCWarning(audio) << "Audio injector options: secondOffset is not a number";
|
qCWarning(audio) << "Audio injector options: secondOffset is not a number";
|
||||||
}
|
}
|
||||||
|
} else if (it.name() == "pitch") {
|
||||||
|
if (it.value().isNumber()) {
|
||||||
|
injectorOptions.pitch = it.value().toNumber();
|
||||||
|
} else {
|
||||||
|
qCWarning(audio) << "Audio injector options: pitch is not a number";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(audio) << "Unknown audio injector option:" << it.name();
|
qCWarning(audio) << "Unknown audio injector option:" << it.name();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ public:
|
||||||
bool ignorePenumbra;
|
bool ignorePenumbra;
|
||||||
bool localOnly;
|
bool localOnly;
|
||||||
float secondOffset;
|
float secondOffset;
|
||||||
|
float pitch; // multiplier, where 2.0f shifts up one octave
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AudioInjectorOptions);
|
Q_DECLARE_METATYPE(AudioInjectorOptions);
|
||||||
|
|
|
@ -53,8 +53,6 @@ public:
|
||||||
|
|
||||||
bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
|
bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
|
||||||
|
|
||||||
float getHmdUIAngularSize() const { return _hmdUIAngularSize; }
|
|
||||||
void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; }
|
|
||||||
bool isHMD() const;
|
bool isHMD() const;
|
||||||
bool fakeEventActive() const { return _fakeMouseEvent; }
|
bool fakeEventActive() const { return _fakeMouseEvent; }
|
||||||
|
|
||||||
|
@ -139,7 +137,6 @@ private:
|
||||||
//quint64 _hoverItemEnterUsecs { 0 };
|
//quint64 _hoverItemEnterUsecs { 0 };
|
||||||
|
|
||||||
bool _isOverDesktop { true };
|
bool _isOverDesktop { true };
|
||||||
float _hmdUIAngularSize { glm::degrees(VIRTUAL_UI_TARGET_FOV.y) };
|
|
||||||
float _textureFov { VIRTUAL_UI_TARGET_FOV.y };
|
float _textureFov { VIRTUAL_UI_TARGET_FOV.y };
|
||||||
float _textureAspectRatio { VIRTUAL_UI_ASPECT_RATIO };
|
float _textureAspectRatio { VIRTUAL_UI_ASPECT_RATIO };
|
||||||
|
|
||||||
|
|
|
@ -1733,8 +1733,18 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
qCDebug(modelformat) << "Joint not in model list: " << jointID;
|
qCDebug(modelformat) << "Joint not in model list: " << jointID;
|
||||||
fbxCluster.jointIndex = 0;
|
fbxCluster.jointIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fbxCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform;
|
fbxCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform;
|
||||||
|
|
||||||
|
// slam bottom row to (0, 0, 0, 1), we KNOW this is not a perspective matrix and
|
||||||
|
// sometimes floating point fuzz can be introduced after the inverse.
|
||||||
|
fbxCluster.inverseBindMatrix[0][3] = 0.0f;
|
||||||
|
fbxCluster.inverseBindMatrix[1][3] = 0.0f;
|
||||||
|
fbxCluster.inverseBindMatrix[2][3] = 0.0f;
|
||||||
|
fbxCluster.inverseBindMatrix[3][3] = 1.0f;
|
||||||
|
|
||||||
fbxCluster.inverseBindTransform = Transform(fbxCluster.inverseBindMatrix);
|
fbxCluster.inverseBindTransform = Transform(fbxCluster.inverseBindMatrix);
|
||||||
|
|
||||||
extracted.mesh.clusters.append(fbxCluster);
|
extracted.mesh.clusters.append(fbxCluster);
|
||||||
|
|
||||||
// override the bind rotation with the transform link
|
// override the bind rotation with the transform link
|
||||||
|
@ -1836,13 +1846,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
}
|
}
|
||||||
|
|
||||||
// now that we've accumulated the most relevant weights for each vertex
|
// now that we've accumulated the most relevant weights for each vertex
|
||||||
// normalize and compress to 8-bits
|
// normalize and compress to 16-bits
|
||||||
extracted.mesh.clusterWeights.fill(0, numClusterIndices);
|
extracted.mesh.clusterWeights.fill(0, numClusterIndices);
|
||||||
int numVertices = extracted.mesh.vertices.size();
|
int numVertices = extracted.mesh.vertices.size();
|
||||||
for (int i = 0; i < numVertices; ++i) {
|
for (int i = 0; i < numVertices; ++i) {
|
||||||
int j = i * WEIGHTS_PER_VERTEX;
|
int j = i * WEIGHTS_PER_VERTEX;
|
||||||
|
|
||||||
// normalize weights into uint8_t
|
// normalize weights into uint16_t
|
||||||
float totalWeight = weightAccumulators[j];
|
float totalWeight = weightAccumulators[j];
|
||||||
for (int k = j + 1; k < j + WEIGHTS_PER_VERTEX; ++k) {
|
for (int k = j + 1; k < j + WEIGHTS_PER_VERTEX; ++k) {
|
||||||
totalWeight += weightAccumulators[k];
|
totalWeight += weightAccumulators[k];
|
||||||
|
|
|
@ -56,10 +56,10 @@ Light getLight(int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
<@else@>
|
<@else@>
|
||||||
uniform lightBuffer {
|
uniform keyLightBuffer {
|
||||||
Light light;
|
Light light;
|
||||||
};
|
};
|
||||||
Light getLight() {
|
Light getKeyLight() {
|
||||||
return light;
|
return light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,21 +21,25 @@
|
||||||
<@include LightDirectional.slh@>
|
<@include LightDirectional.slh@>
|
||||||
|
|
||||||
|
|
||||||
<@func prepareGlobalLight(isScattering)@>
|
<@func fetchGlobalLight()@>
|
||||||
// prepareGlobalLight
|
|
||||||
// Transform directions to worldspace
|
|
||||||
vec3 fragNormal = vec3((normal));
|
|
||||||
vec3 fragEyeVector = vec3(invViewMat * vec4(-1.0*position, 0.0));
|
|
||||||
vec3 fragEyeDir = normalize(fragEyeVector);
|
|
||||||
|
|
||||||
// Get light
|
// Get light
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
LightAmbient lightAmbient = getLightAmbient();
|
LightAmbient lightAmbient = getLightAmbient();
|
||||||
|
|
||||||
vec3 lightDirection = getLightDirection(light);
|
vec3 lightDirection = getLightDirection(light);
|
||||||
vec3 lightIrradiance = getLightIrradiance(light);
|
vec3 lightIrradiance = getLightIrradiance(light);
|
||||||
|
|
||||||
vec3 color = vec3(0.0);
|
vec3 color = vec3(0.0);
|
||||||
|
<@endfunc@>
|
||||||
|
|
||||||
|
<@func prepareGlobalLight(isScattering)@>
|
||||||
|
// prepareGlobalLight
|
||||||
|
// Transform directions to worldspace
|
||||||
|
vec3 fragNormal = vec3((normal));
|
||||||
|
vec3 fragEyeVector = vec3(invViewMat * vec4(-position, 0.0));
|
||||||
|
vec3 fragEyeDir = normalize(fragEyeVector);
|
||||||
|
|
||||||
|
<$fetchGlobalLight()$>
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
|
@ -147,7 +151,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
|
||||||
|
|
||||||
<@func declareEvalLightmappedColor()@>
|
<@func declareEvalLightmappedColor()@>
|
||||||
vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 albedo, vec3 lightmap) {
|
vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 albedo, vec3 lightmap) {
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
LightAmbient ambient = getLightAmbient();
|
LightAmbient ambient = getLightAmbient();
|
||||||
|
|
||||||
// Catch normals perpendicular to the projection plane, hence the magic number for the threshold
|
// Catch normals perpendicular to the projection plane, hence the magic number for the threshold
|
||||||
|
@ -175,11 +179,12 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur
|
||||||
<$declareLightingAmbient(1, 1, 1)$>
|
<$declareLightingAmbient(1, 1, 1)$>
|
||||||
<$declareLightingDirectional()$>
|
<$declareLightingDirectional()$>
|
||||||
|
|
||||||
vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, float roughness, float opacity) {
|
vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, float roughness, float opacity, vec3 prevLighting) {
|
||||||
<$prepareGlobalLight()$>
|
<$prepareGlobalLight()$>
|
||||||
|
|
||||||
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
|
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
|
||||||
|
|
||||||
|
color = prevLighting;
|
||||||
color += emissive * isEmissiveEnabled();
|
color += emissive * isEmissiveEnabled();
|
||||||
|
|
||||||
// Ambient
|
// Ambient
|
||||||
|
@ -238,6 +243,44 @@ vec3 evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
|
mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position,
|
||||||
|
vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, SurfaceData surface, float opacity, vec3 prevLighting)
|
||||||
|
{
|
||||||
|
<$fetchGlobalLight()$>
|
||||||
|
|
||||||
|
color = prevLighting;
|
||||||
|
color += emissive * isEmissiveEnabled();
|
||||||
|
|
||||||
|
// Ambient
|
||||||
|
vec3 ambientDiffuse;
|
||||||
|
vec3 ambientSpecular;
|
||||||
|
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surface, metallic, fresnel, albedo, obscurance);
|
||||||
|
|
||||||
|
// Directional
|
||||||
|
vec3 directionalDiffuse;
|
||||||
|
vec3 directionalSpecular;
|
||||||
|
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation);
|
||||||
|
|
||||||
|
color += ambientDiffuse + directionalDiffuse;
|
||||||
|
color += (ambientSpecular + directionalSpecular) / opacity;
|
||||||
|
|
||||||
|
// Haze
|
||||||
|
if ((hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE) {
|
||||||
|
vec4 colorV4 = computeHazeColor(
|
||||||
|
vec4(color, 1.0), // fragment original color
|
||||||
|
position, // fragment position in eye coordinates
|
||||||
|
surface.eyeDir, // fragment eye vector in world coordinates
|
||||||
|
invViewMat[3].y, // eye height in world coordinates
|
||||||
|
lightDirection // keylight direction vector
|
||||||
|
);
|
||||||
|
|
||||||
|
color = colorV4.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ using namespace render;
|
||||||
|
|
||||||
struct LightLocations {
|
struct LightLocations {
|
||||||
int radius{ -1 };
|
int radius{ -1 };
|
||||||
|
int keyLightBufferUnit{ -1 };
|
||||||
int lightBufferUnit{ -1 };
|
int lightBufferUnit{ -1 };
|
||||||
int ambientBufferUnit { -1 };
|
int ambientBufferUnit { -1 };
|
||||||
int lightIndexBufferUnit { -1 };
|
int lightIndexBufferUnit { -1 };
|
||||||
|
@ -147,6 +148,29 @@ void DeferredLightingEffect::unsetKeyLightBatch(gpu::Batch& batch, int lightBuff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeferredLightingEffect::setupLocalLightsBatch(gpu::Batch& batch,
|
||||||
|
int clusterGridBufferUnit, int clusterContentBufferUnit, int frustumGridBufferUnit,
|
||||||
|
const LightClustersPointer& lightClusters) {
|
||||||
|
// Bind the global list of lights and the visible lights this frame
|
||||||
|
batch.setUniformBuffer(_localLightLocations->lightBufferUnit, lightClusters->_lightStage->getLightArrayBuffer());
|
||||||
|
|
||||||
|
batch.setUniformBuffer(frustumGridBufferUnit, lightClusters->_frustumGridBuffer);
|
||||||
|
batch.setUniformBuffer(clusterGridBufferUnit, lightClusters->_clusterGridBuffer);
|
||||||
|
batch.setUniformBuffer(clusterContentBufferUnit, lightClusters->_clusterContentBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeferredLightingEffect::unsetLocalLightsBatch(gpu::Batch& batch, int clusterGridBufferUnit, int clusterContentBufferUnit, int frustumGridBufferUnit) {
|
||||||
|
if (clusterGridBufferUnit >= 0) {
|
||||||
|
batch.setUniformBuffer(clusterGridBufferUnit, nullptr);
|
||||||
|
}
|
||||||
|
if (clusterContentBufferUnit >= 0) {
|
||||||
|
batch.setUniformBuffer(clusterContentBufferUnit, nullptr);
|
||||||
|
}
|
||||||
|
if (frustumGridBufferUnit >= 0) {
|
||||||
|
batch.setUniformBuffer(frustumGridBufferUnit, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* fragSource, LightLocationsPtr& locations) {
|
static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* fragSource, LightLocationsPtr& locations) {
|
||||||
auto VS = gpu::Shader::createVertex(std::string(vertSource));
|
auto VS = gpu::Shader::createVertex(std::string(vertSource));
|
||||||
auto PS = gpu::Shader::createPixel(std::string(fragSource));
|
auto PS = gpu::Shader::createPixel(std::string(fragSource));
|
||||||
|
@ -189,6 +213,7 @@ static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* f
|
||||||
|
|
||||||
locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform");
|
locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform");
|
||||||
|
|
||||||
|
locations->keyLightBufferUnit = program->getUniformBuffers().findLocation("keyLightBuffer");
|
||||||
locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer");
|
locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer");
|
||||||
locations->ambientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer");
|
locations->ambientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer");
|
||||||
locations->lightIndexBufferUnit = program->getUniformBuffers().findLocation("lightIndexBuffer");
|
locations->lightIndexBufferUnit = program->getUniformBuffers().findLocation("lightIndexBuffer");
|
||||||
|
@ -561,7 +586,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
|
||||||
batch._glUniform4fv(locations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform));
|
batch._glUniform4fv(locations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform));
|
||||||
|
|
||||||
// Setup the global lighting
|
// Setup the global lighting
|
||||||
deferredLightingEffect->setupKeyLightBatch(args, batch, locations->lightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT);
|
deferredLightingEffect->setupKeyLightBatch(args, batch, locations->keyLightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT);
|
||||||
|
|
||||||
// Haze
|
// Haze
|
||||||
if (haze) {
|
if (haze) {
|
||||||
|
@ -570,7 +595,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
|
||||||
|
|
||||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||||
|
|
||||||
deferredLightingEffect->unsetKeyLightBatch(batch, locations->lightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT);
|
deferredLightingEffect->unsetKeyLightBatch(batch, locations->keyLightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT);
|
||||||
|
|
||||||
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
|
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
|
||||||
batch.setResourceTexture(SHADOW_MAP_UNIT+i, nullptr);
|
batch.setResourceTexture(SHADOW_MAP_UNIT+i, nullptr);
|
||||||
|
@ -625,12 +650,8 @@ void RenderDeferredLocals::run(const render::RenderContextPointer& renderContext
|
||||||
|
|
||||||
auto& lightIndices = lightClusters->_visibleLightIndices;
|
auto& lightIndices = lightClusters->_visibleLightIndices;
|
||||||
if (!lightIndices.empty() && lightIndices[0] > 0) {
|
if (!lightIndices.empty() && lightIndices[0] > 0) {
|
||||||
// Bind the global list of lights and the visible lights this frame
|
deferredLightingEffect->setupLocalLightsBatch(batch, LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT,
|
||||||
batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, lightClusters->_lightStage->getLightArrayBuffer());
|
lightClusters);
|
||||||
|
|
||||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer);
|
|
||||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer);
|
|
||||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer);
|
|
||||||
|
|
||||||
// Local light pipeline
|
// Local light pipeline
|
||||||
batch.setPipeline(deferredLightingEffect->_localLight);
|
batch.setPipeline(deferredLightingEffect->_localLight);
|
||||||
|
|
|
@ -51,6 +51,9 @@ public:
|
||||||
void setupKeyLightBatch(const RenderArgs* args, gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
|
void setupKeyLightBatch(const RenderArgs* args, gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
|
||||||
void unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
|
void unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
|
||||||
|
|
||||||
|
void setupLocalLightsBatch(gpu::Batch& batch, int clusterGridBufferUnit, int clusterContentBufferUnit, int frustumGridBufferUnit, const LightClustersPointer& lightClusters);
|
||||||
|
void unsetLocalLightsBatch(gpu::Batch& batch, int clusterGridBufferUnit, int clusterContentBufferUnit, int frustumGridBufferUnit);
|
||||||
|
|
||||||
void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; };
|
void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; };
|
||||||
void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; }
|
void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; }
|
||||||
bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; }
|
bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; }
|
||||||
|
|
|
@ -147,7 +147,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), HazeEffect_TransformBufferSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), HazeEffect_TransformBufferSlot));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), HazeEffect_ColorMapSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), HazeEffect_ColorMapSlot));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("linearDepthMap"), HazeEffect_LinearDepthMapSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("linearDepthMap"), HazeEffect_LinearDepthMapSlot));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), HazeEffect_LightingMapSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), HazeEffect_LightingMapSlot));
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
_hazePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
|
_hazePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
vec3 fragEyeDir = normalize(fragEyeVector);
|
vec3 fragEyeDir = normalize(fragEyeVector);
|
||||||
|
|
||||||
// Get light
|
// Get light
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
LightAmbient lightAmbient = getLightAmbient();
|
LightAmbient lightAmbient = getLightAmbient();
|
||||||
|
|
||||||
vec3 lightDirection = getLightDirection(light);
|
vec3 lightDirection = getLightDirection(light);
|
||||||
|
@ -143,7 +143,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
|
||||||
|
|
||||||
<@func declareEvalLightmappedColor()@>
|
<@func declareEvalLightmappedColor()@>
|
||||||
vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 albedo, vec3 lightmap) {
|
vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 albedo, vec3 lightmap) {
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
LightAmbient ambient = getLightAmbient();
|
LightAmbient ambient = getLightAmbient();
|
||||||
|
|
||||||
// Catch normals perpendicular to the projection plane, hence the magic number for the threshold
|
// Catch normals perpendicular to the projection plane, hence the magic number for the threshold
|
||||||
|
|
|
@ -53,7 +53,7 @@ void main(void) {
|
||||||
vec4 worldFragPos = viewInverse * eyeFragPos;
|
vec4 worldFragPos = viewInverse * eyeFragPos;
|
||||||
vec4 worldEyePos = viewInverse[3];
|
vec4 worldEyePos = viewInverse[3];
|
||||||
|
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
vec3 lightDirection = getLightDirection(light);
|
vec3 lightDirection = getLightDirection(light);
|
||||||
|
|
||||||
outFragColor = computeHazeColor(fragColor, eyeFragPos.xyz, worldFragPos.xyz, worldEyePos.y, lightDirection);
|
outFragColor = computeHazeColor(fragColor, eyeFragPos.xyz, worldFragPos.xyz, worldEyePos.y, lightDirection);
|
||||||
|
|
|
@ -86,4 +86,24 @@ int clusterGrid_getClusterLightId(int index, int offset) {
|
||||||
return (((elementIndex & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF;
|
return (((elementIndex & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<@func fetchClusterInfo(fragWorldPos)@>
|
||||||
|
|
||||||
|
// From frag world pos find the cluster
|
||||||
|
vec4 clusterEyePos = frustumGrid_worldToEye(<$fragWorldPos$>);
|
||||||
|
ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz);
|
||||||
|
|
||||||
|
ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos));
|
||||||
|
int numLights = cluster.x + cluster.y;
|
||||||
|
ivec3 dims = frustumGrid.dims.xyz;
|
||||||
|
|
||||||
|
<@endfunc@>
|
||||||
|
|
||||||
|
bool hasLocalLights(int numLights, ivec3 clusterPos, ivec3 dims) {
|
||||||
|
return numLights>0
|
||||||
|
&& all(greaterThanEqual(clusterPos, ivec3(0)))
|
||||||
|
&& all(lessThan(clusterPos.xy, dims.xy))
|
||||||
|
&& clusterPos.z <= dims.z;
|
||||||
|
}
|
||||||
|
|
||||||
<@endif@>
|
<@endif@>
|
||||||
|
|
148
libraries/render-utils/src/LightLocal.slh
Normal file
148
libraries/render-utils/src/LightLocal.slh
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 15/01/18.
|
||||||
|
// Copyright 2018 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 light
|
||||||
|
<@include graphics/Light.slh@>
|
||||||
|
<$declareLightBuffer(256)$>
|
||||||
|
<@include LightingModel.slh@>
|
||||||
|
|
||||||
|
|
||||||
|
<@include LightPoint.slh@>
|
||||||
|
<$declareLightingPoint(supportScattering)$>
|
||||||
|
<@include LightSpot.slh@>
|
||||||
|
<$declareLightingSpot(supportScattering)$>
|
||||||
|
|
||||||
|
<@include LightClusterGrid.slh@>
|
||||||
|
|
||||||
|
vec4 evalLocalLighting(ivec3 cluster, int numLights, vec3 fragWorldPos, SurfaceData surface,
|
||||||
|
float fragMetallic, vec3 fragFresnel, vec3 fragAlbedo, float fragScattering,
|
||||||
|
vec4 midNormalCurvature, vec4 lowNormalCurvature, float opacity) {
|
||||||
|
vec4 fragColor = vec4(0.0);
|
||||||
|
vec3 fragSpecular = vec3(0.0);
|
||||||
|
vec3 fragDiffuse = vec3(0.0);
|
||||||
|
int lightClusterOffset = cluster.z;
|
||||||
|
|
||||||
|
// Compute the rougness into gloss2 once:
|
||||||
|
bool withScattering = (fragScattering * isScatteringEnabled() > 0.0);
|
||||||
|
|
||||||
|
int numLightTouching = 0;
|
||||||
|
for (int i = 0; i < cluster.x; i++) {
|
||||||
|
// Need the light now
|
||||||
|
int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset);
|
||||||
|
Light light = getLight(theLightIndex);
|
||||||
|
|
||||||
|
// Clip againgst the light volume and Make the Light vector going from fragment to light center in world space
|
||||||
|
vec4 fragLightVecLen2;
|
||||||
|
vec4 fragLightDirLen;
|
||||||
|
|
||||||
|
if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragWorldPos.xyz, fragLightVecLen2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allright we re in the light sphere volume
|
||||||
|
fragLightDirLen.w = length(fragLightVecLen2.xyz);
|
||||||
|
fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w;
|
||||||
|
if (dot(surface.normal, fragLightDirLen.xyz) < 0.0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numLightTouching++;
|
||||||
|
|
||||||
|
vec3 diffuse = vec3(1.0);
|
||||||
|
vec3 specular = vec3(0.1);
|
||||||
|
|
||||||
|
// Allright we re valid in the volume
|
||||||
|
float fragLightDistance = fragLightDirLen.w;
|
||||||
|
vec3 fragLightDir = fragLightDirLen.xyz;
|
||||||
|
|
||||||
|
updateSurfaceDataWithLight(surface, fragLightDir);
|
||||||
|
|
||||||
|
// Eval attenuation
|
||||||
|
float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance);
|
||||||
|
vec3 lightEnergy = radialAttenuation * getLightIrradiance(light);
|
||||||
|
|
||||||
|
// Eval shading
|
||||||
|
if (withScattering) {
|
||||||
|
evalFragShadingScattering(diffuse, specular, fragMetallic, fragFresnel, surface, fragAlbedo,
|
||||||
|
fragScattering, midNormalCurvature, lowNormalCurvature );
|
||||||
|
} else {
|
||||||
|
evalFragShadingGloss(diffuse, specular, fragMetallic, fragFresnel, surface, fragAlbedo);
|
||||||
|
}
|
||||||
|
|
||||||
|
diffuse *= lightEnergy;
|
||||||
|
specular *= lightEnergy;
|
||||||
|
|
||||||
|
fragDiffuse.rgb += diffuse;
|
||||||
|
fragSpecular.rgb += specular;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = cluster.x; i < numLights; i++) {
|
||||||
|
// Need the light now
|
||||||
|
int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset);
|
||||||
|
Light light = getLight(theLightIndex);
|
||||||
|
|
||||||
|
// Clip againgst the light volume and Make the Light vector going from fragment to light center in world space
|
||||||
|
vec4 fragLightVecLen2;
|
||||||
|
vec4 fragLightDirLen;
|
||||||
|
float cosSpotAngle;
|
||||||
|
|
||||||
|
if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragWorldPos.xyz, fragLightVecLen2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allright we re in the light sphere volume
|
||||||
|
fragLightDirLen.w = length(fragLightVecLen2.xyz);
|
||||||
|
fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w;
|
||||||
|
if (dot(surface.normal, fragLightDirLen.xyz) < 0.0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check spot
|
||||||
|
if (!lightVolume_clipFragToLightVolumeSpotSide(light.volume, fragLightDirLen, cosSpotAngle)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numLightTouching++;
|
||||||
|
|
||||||
|
vec3 diffuse = vec3(1.0);
|
||||||
|
vec3 specular = vec3(0.1);
|
||||||
|
|
||||||
|
// Allright we re valid in the volume
|
||||||
|
float fragLightDistance = fragLightDirLen.w;
|
||||||
|
vec3 fragLightDir = fragLightDirLen.xyz;
|
||||||
|
|
||||||
|
updateSurfaceDataWithLight(surface, fragLightDir);
|
||||||
|
|
||||||
|
// Eval attenuation
|
||||||
|
float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance);
|
||||||
|
float angularAttenuation = lightIrradiance_evalLightSpotAttenuation(light.irradiance, cosSpotAngle);
|
||||||
|
vec3 lightEnergy = radialAttenuation * angularAttenuation * getLightIrradiance(light);
|
||||||
|
|
||||||
|
// Eval shading
|
||||||
|
if (withScattering) {
|
||||||
|
evalFragShadingScattering(diffuse, specular, fragMetallic, fragFresnel, surface, fragAlbedo,
|
||||||
|
fragScattering, midNormalCurvature, lowNormalCurvature );
|
||||||
|
} else {
|
||||||
|
evalFragShadingGloss(diffuse, specular, fragMetallic, fragFresnel, surface, fragAlbedo);
|
||||||
|
}
|
||||||
|
|
||||||
|
diffuse *= lightEnergy;
|
||||||
|
specular *= lightEnergy;
|
||||||
|
|
||||||
|
fragDiffuse.rgb += diffuse;
|
||||||
|
fragSpecular.rgb += specular;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragDiffuse *= isDiffuseEnabled();
|
||||||
|
fragSpecular *= isSpecularEnabled();
|
||||||
|
|
||||||
|
fragColor.rgb += fragDiffuse;
|
||||||
|
fragColor.rgb += fragSpecular / opacity;
|
||||||
|
return fragColor;
|
||||||
|
}
|
|
@ -289,9 +289,8 @@ void evalFragShading(out vec3 diffuse, out vec3 specular,
|
||||||
|
|
||||||
|
|
||||||
void evalFragShadingScattering(out vec3 diffuse, out vec3 specular,
|
void evalFragShadingScattering(out vec3 diffuse, out vec3 specular,
|
||||||
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo
|
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo,
|
||||||
,float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature
|
float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature) {
|
||||||
) {
|
|
||||||
vec3 brdf = evalSkinBRDF(surface.lightDir, surface.normal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w);
|
vec3 brdf = evalSkinBRDF(surface.lightDir, surface.normal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w);
|
||||||
float NdotL = surface.ndotl;
|
float NdotL = surface.ndotl;
|
||||||
diffuse = mix(vec3(NdotL), brdf, scattering);
|
diffuse = mix(vec3(NdotL), brdf, scattering);
|
||||||
|
@ -305,8 +304,7 @@ void evalFragShadingScattering(out vec3 diffuse, out vec3 specular,
|
||||||
}
|
}
|
||||||
|
|
||||||
void evalFragShadingGloss(out vec3 diffuse, out vec3 specular,
|
void evalFragShadingGloss(out vec3 diffuse, out vec3 specular,
|
||||||
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo
|
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo) {
|
||||||
) {
|
|
||||||
vec4 shading = evalPBRShading(metallic, fresnel, surface);
|
vec4 shading = evalPBRShading(metallic, fresnel, surface);
|
||||||
diffuse = vec3(shading.w);
|
diffuse = vec3(shading.w);
|
||||||
diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled());
|
diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled());
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include "RenderDeferredTask.h"
|
#include "RenderDeferredTask.h"
|
||||||
|
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
|
@ -168,7 +170,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
task.addJob<DrawHaze>("DrawHazeDeferred", drawHazeInputs);
|
task.addJob<DrawHaze>("DrawHazeDeferred", drawHazeInputs);
|
||||||
|
|
||||||
// Render transparent objects forward in LightingBuffer
|
// Render transparent objects forward in LightingBuffer
|
||||||
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying();
|
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel, lightClusters).asVarying();
|
||||||
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
||||||
|
|
||||||
// Light Cluster Grid Debuging job
|
// Light Cluster Grid Debuging job
|
||||||
|
@ -298,6 +300,8 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs&
|
||||||
|
|
||||||
const auto& inItems = inputs.get0();
|
const auto& inItems = inputs.get0();
|
||||||
const auto& lightingModel = inputs.get1();
|
const auto& lightingModel = inputs.get1();
|
||||||
|
const auto& lightClusters = inputs.get2();
|
||||||
|
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
|
||||||
|
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
|
@ -319,7 +323,13 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs&
|
||||||
// Setup lighting model for all items;
|
// Setup lighting model for all items;
|
||||||
batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer());
|
batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer());
|
||||||
|
|
||||||
// Setup haze iff current zone has haze
|
deferredLightingEffect->setupLocalLightsBatch(batch,
|
||||||
|
render::ShapePipeline::Slot::LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT,
|
||||||
|
render::ShapePipeline::Slot::LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT,
|
||||||
|
render::ShapePipeline::Slot::LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT,
|
||||||
|
lightClusters);
|
||||||
|
|
||||||
|
// Setup haze if current zone has haze
|
||||||
auto hazeStage = args->_scene->getStage<HazeStage>();
|
auto hazeStage = args->_scene->getStage<HazeStage>();
|
||||||
if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) {
|
if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) {
|
||||||
graphics::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front());
|
graphics::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front());
|
||||||
|
@ -341,6 +351,11 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs&
|
||||||
|
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
args->_globalShapeKey = 0;
|
args->_globalShapeKey = 0;
|
||||||
|
|
||||||
|
deferredLightingEffect->unsetLocalLightsBatch(batch,
|
||||||
|
render::ShapePipeline::Slot::LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT,
|
||||||
|
render::ShapePipeline::Slot::LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT,
|
||||||
|
render::ShapePipeline::Slot::LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT);
|
||||||
});
|
});
|
||||||
|
|
||||||
config->setNumDrawn((int)inItems.size());
|
config->setNumDrawn((int)inItems.size());
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <gpu/Pipeline.h>
|
#include <gpu/Pipeline.h>
|
||||||
#include <render/RenderFetchCullSortTask.h>
|
#include <render/RenderFetchCullSortTask.h>
|
||||||
#include "LightingModel.h"
|
#include "LightingModel.h"
|
||||||
|
#include "LightClusters.h"
|
||||||
|
|
||||||
class DrawDeferredConfig : public render::Job::Config {
|
class DrawDeferredConfig : public render::Job::Config {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -40,7 +41,7 @@ protected:
|
||||||
|
|
||||||
class DrawDeferred {
|
class DrawDeferred {
|
||||||
public:
|
public:
|
||||||
using Inputs = render::VaryingSet2<render::ItemBounds, LightingModelPointer>;
|
using Inputs = render::VaryingSet3 <render::ItemBounds, LightingModelPointer, LightClustersPointer>;
|
||||||
using Config = DrawDeferredConfig;
|
using Config = DrawDeferredConfig;
|
||||||
using JobModel = render::Job::ModelI<DrawDeferred, Inputs, Config>;
|
using JobModel = render::Job::ModelI<DrawDeferred, Inputs, Config>;
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
#include "model_lightmap_fade_vert.h"
|
#include "model_lightmap_fade_vert.h"
|
||||||
#include "model_lightmap_normal_map_fade_vert.h"
|
#include "model_lightmap_normal_map_fade_vert.h"
|
||||||
|
#include "model_translucent_vert.h"
|
||||||
|
#include "model_translucent_fade_vert.h"
|
||||||
#include "skin_model_fade_vert.h"
|
#include "skin_model_fade_vert.h"
|
||||||
#include "skin_model_normal_map_fade_vert.h"
|
#include "skin_model_normal_map_fade_vert.h"
|
||||||
|
|
||||||
|
@ -188,6 +190,8 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
||||||
auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert));
|
auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert));
|
||||||
auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert));
|
auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert));
|
||||||
auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert));
|
auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert));
|
||||||
|
auto modelTranslucentVertex = gpu::Shader::createVertex(std::string(model_translucent_vert));
|
||||||
|
auto modelTranslucentFadeVertex = gpu::Shader::createVertex(std::string(model_translucent_fade_vert));
|
||||||
auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
|
auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
|
||||||
auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert));
|
auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert));
|
||||||
auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert));
|
auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert));
|
||||||
|
@ -196,6 +200,8 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
||||||
auto modelLightmapNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_fade_vert));
|
auto modelLightmapNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_fade_vert));
|
||||||
auto skinModelFadeVertex = gpu::Shader::createVertex(std::string(skin_model_fade_vert));
|
auto skinModelFadeVertex = gpu::Shader::createVertex(std::string(skin_model_fade_vert));
|
||||||
auto skinModelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_fade_vert));
|
auto skinModelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_fade_vert));
|
||||||
|
auto skinModelTranslucentVertex = skinModelFadeVertex; // We use the same because it ouputs world position per vertex
|
||||||
|
auto skinModelNormalMapTranslucentVertex = skinModelNormalMapFadeVertex; // We use the same because it ouputs world position per vertex
|
||||||
|
|
||||||
auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_fade_vert));
|
auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_fade_vert));
|
||||||
auto modelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_normal_map_fade_vert));
|
auto modelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_normal_map_fade_vert));
|
||||||
|
@ -289,7 +295,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
||||||
// Translucents
|
// Translucents
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withTranslucent(),
|
Key::Builder().withMaterial().withTranslucent(),
|
||||||
modelVertex, modelTranslucentPixel, nullptr, nullptr);
|
modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withTranslucent(),
|
Key::Builder().withTranslucent(),
|
||||||
simpleVertex, simpleTranslucentPixel, nullptr, nullptr);
|
simpleVertex, simpleTranslucentPixel, nullptr, nullptr);
|
||||||
|
@ -301,21 +307,21 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
||||||
simpleVertex, simpleTranslucentUnlitPixel, nullptr, nullptr);
|
simpleVertex, simpleTranslucentUnlitPixel, nullptr, nullptr);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withTranslucent().withTangents(),
|
Key::Builder().withMaterial().withTranslucent().withTangents(),
|
||||||
modelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr);
|
modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withTranslucent().withSpecular(),
|
Key::Builder().withMaterial().withTranslucent().withSpecular(),
|
||||||
modelVertex, modelTranslucentPixel, nullptr, nullptr);
|
modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(),
|
Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(),
|
||||||
modelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr);
|
modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
// FIXME: Ignore lightmap for translucents meshpart
|
// FIXME: Ignore lightmap for translucents meshpart
|
||||||
Key::Builder().withMaterial().withTranslucent().withLightmap(),
|
Key::Builder().withMaterial().withTranslucent().withLightmap(),
|
||||||
modelVertex, modelTranslucentPixel, nullptr, nullptr);
|
modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
// Same thing but with Fade on
|
// Same thing but with Fade on
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withTranslucent().withFade(),
|
Key::Builder().withMaterial().withTranslucent().withFade(),
|
||||||
modelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
modelTranslucentFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withTranslucent().withFade(),
|
Key::Builder().withTranslucent().withFade(),
|
||||||
simpleFadeVertex, simpleTranslucentFadePixel, batchSetter, itemSetter);
|
simpleFadeVertex, simpleTranslucentFadePixel, batchSetter, itemSetter);
|
||||||
|
@ -396,16 +402,16 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
||||||
// Skinned and Translucent
|
// Skinned and Translucent
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withSkinned().withTranslucent(),
|
Key::Builder().withMaterial().withSkinned().withTranslucent(),
|
||||||
skinModelVertex, modelTranslucentPixel, nullptr, nullptr);
|
skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(),
|
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(),
|
||||||
skinModelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr);
|
skinModelNormalMapTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(),
|
Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(),
|
||||||
skinModelVertex, modelTranslucentPixel, nullptr, nullptr);
|
skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(),
|
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(),
|
||||||
skinModelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr);
|
skinModelNormalMapTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||||
// Same thing but with Fade on
|
// Same thing but with Fade on
|
||||||
addPipeline(
|
addPipeline(
|
||||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withFade(),
|
Key::Builder().withMaterial().withSkinned().withTranslucent().withFade(),
|
||||||
|
@ -571,9 +577,9 @@ void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderAr
|
||||||
batchSetter(pipeline, batch, args);
|
batchSetter(pipeline, batch, args);
|
||||||
|
|
||||||
// Set the light
|
// Set the light
|
||||||
if (pipeline.locations->lightBufferUnit >= 0) {
|
if (pipeline.locations->keyLightBufferUnit >= 0) {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setupKeyLightBatch(args, batch,
|
DependencyManager::get<DeferredLightingEffect>()->setupKeyLightBatch(args, batch,
|
||||||
pipeline.locations->lightBufferUnit,
|
pipeline.locations->keyLightBufferUnit,
|
||||||
pipeline.locations->lightAmbientBufferUnit,
|
pipeline.locations->lightAmbientBufferUnit,
|
||||||
pipeline.locations->lightAmbientMapUnit);
|
pipeline.locations->lightAmbientMapUnit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -463,7 +463,7 @@ gpu::PipelinePointer DebugSubsurfaceScattering::getScatteringPipeline() {
|
||||||
gpu::Shader::BindingSet slotBindings;
|
gpu::Shader::BindingSet slotBindings;
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ScatteringTask_FrameTransformSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ScatteringTask_FrameTransformSlot));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringParamsBuffer"), ScatteringTask_ParamSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringParamsBuffer"), ScatteringTask_ParamSlot));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ScatteringTask_LightSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), ScatteringTask_LightSlot));
|
||||||
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringLUT"), ScatteringTask_ScatteringTableSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringLUT"), ScatteringTask_ScatteringTableSlot));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("curvatureMap"), ScatteringTask_CurvatureMapSlot));
|
slotBindings.insert(gpu::Shader::Binding(std::string("curvatureMap"), ScatteringTask_CurvatureMapSlot));
|
||||||
|
|
|
@ -83,7 +83,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
gpu::Shader::BindingSet slotBindings;
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ZONE_DEFERRED_TRANSFORM_BUFFER));
|
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ZONE_DEFERRED_TRANSFORM_BUFFER));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ZONE_KEYLIGHT_BUFFER));
|
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), ZONE_KEYLIGHT_BUFFER));
|
||||||
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
|
|
|
@ -54,26 +54,8 @@ void main(void) {
|
||||||
mat4 invViewMat = getViewInverse();
|
mat4 invViewMat = getViewInverse();
|
||||||
vec4 fragPos = invViewMat * fragPosition;
|
vec4 fragPos = invViewMat * fragPosition;
|
||||||
|
|
||||||
// From frag world pos find the cluster
|
<$fetchClusterInfo(fragPos)$>;
|
||||||
vec4 clusterEyePos = frustumGrid_worldToEye(fragPos);
|
if (!hasLocalLights(numLights, clusterPos, dims)) {
|
||||||
ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz);
|
|
||||||
|
|
||||||
ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos));
|
|
||||||
int numLights = cluster.x + cluster.y;
|
|
||||||
if (numLights <= 0) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
int lightClusterOffset = cluster.z;
|
|
||||||
|
|
||||||
ivec3 dims = frustumGrid.dims.xyz;
|
|
||||||
if (clusterPos.x < 0 || clusterPos.x >= dims.x) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clusterPos.y < 0 || clusterPos.y >= dims.y) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
if (clusterPos.z < 0 || clusterPos.z > dims.z) {
|
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +64,7 @@ void main(void) {
|
||||||
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
||||||
|
|
||||||
int numLightTouching = 0;
|
int numLightTouching = 0;
|
||||||
|
int lightClusterOffset = cluster.z;
|
||||||
for (int i = 0; i < cluster.x; i++) {
|
for (int i = 0; i < cluster.x; i++) {
|
||||||
// Need the light now
|
// Need the light now
|
||||||
int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset);
|
int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset);
|
||||||
|
|
|
@ -17,18 +17,7 @@
|
||||||
|
|
||||||
<$declareDeferredCurvature()$>
|
<$declareDeferredCurvature()$>
|
||||||
|
|
||||||
// Everything about light
|
<@include LightLocal.slh@>
|
||||||
<@include graphics/Light.slh@>
|
|
||||||
<$declareLightBuffer(256)$>
|
|
||||||
<@include LightingModel.slh@>
|
|
||||||
|
|
||||||
|
|
||||||
<@include LightPoint.slh@>
|
|
||||||
<$declareLightingPoint(supportScattering)$>
|
|
||||||
<@include LightSpot.slh@>
|
|
||||||
<$declareLightingSpot(supportScattering)$>
|
|
||||||
|
|
||||||
<@include LightClusterGrid.slh@>
|
|
||||||
|
|
||||||
in vec2 _texCoord0;
|
in vec2 _texCoord0;
|
||||||
out vec4 _fragColor;
|
out vec4 _fragColor;
|
||||||
|
@ -49,28 +38,10 @@ void main(void) {
|
||||||
|
|
||||||
// Frag pos in world
|
// Frag pos in world
|
||||||
mat4 invViewMat = getViewInverse();
|
mat4 invViewMat = getViewInverse();
|
||||||
vec4 fragPos = invViewMat * fragPosition;
|
vec4 fragWorldPos = invViewMat * fragPosition;
|
||||||
|
|
||||||
// From frag world pos find the cluster
|
<$fetchClusterInfo(fragWorldPos)$>;
|
||||||
vec4 clusterEyePos = frustumGrid_worldToEye(fragPos);
|
if (!hasLocalLights(numLights, clusterPos, dims)) {
|
||||||
ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz);
|
|
||||||
|
|
||||||
ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos));
|
|
||||||
int numLights = cluster.x + cluster.y;
|
|
||||||
if (numLights <= 0) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
int lightClusterOffset = cluster.z;
|
|
||||||
|
|
||||||
ivec3 dims = frustumGrid.dims.xyz;
|
|
||||||
if (clusterPos.x < 0 || clusterPos.x >= dims.x) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clusterPos.y < 0 || clusterPos.y >= dims.y) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
if (clusterPos.z < 0 || clusterPos.z > dims.z) {
|
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,117 +55,11 @@ void main(void) {
|
||||||
// Frag to eye vec
|
// Frag to eye vec
|
||||||
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
|
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
|
||||||
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
||||||
|
|
||||||
SurfaceData surface = initSurfaceData(frag.roughness, frag.normal, fragEyeDir);
|
SurfaceData surface = initSurfaceData(frag.roughness, frag.normal, fragEyeDir);
|
||||||
bool withScattering = (frag.scattering * isScatteringEnabled() > 0.0);
|
|
||||||
|
|
||||||
int numLightTouching = 0;
|
_fragColor = evalLocalLighting(cluster, numLights, fragWorldPos.xyz, surface,
|
||||||
for (int i = 0; i < cluster.x; i++) {
|
frag.metallic, frag.fresnel, frag.albedo, frag.scattering,
|
||||||
// Need the light now
|
midNormalCurvature, lowNormalCurvature, 1.0);
|
||||||
int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset);
|
|
||||||
Light light = getLight(theLightIndex);
|
|
||||||
|
|
||||||
// Clip againgst the light volume and Make the Light vector going from fragment to light center in world space
|
|
||||||
vec4 fragLightVecLen2;
|
|
||||||
vec4 fragLightDirLen;
|
|
||||||
|
|
||||||
if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allright we re in the light sphere volume
|
|
||||||
fragLightDirLen.w = length(fragLightVecLen2.xyz);
|
|
||||||
fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w;
|
|
||||||
if (dot(frag.normal, fragLightDirLen.xyz) < 0.0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
numLightTouching++;
|
|
||||||
|
|
||||||
vec3 diffuse = vec3(1.0);
|
|
||||||
vec3 specular = vec3(0.1);
|
|
||||||
|
|
||||||
// Allright we re valid in the volume
|
|
||||||
float fragLightDistance = fragLightDirLen.w;
|
|
||||||
vec3 fragLightDir = fragLightDirLen.xyz;
|
|
||||||
|
|
||||||
updateSurfaceDataWithLight(surface, fragLightDir);
|
|
||||||
|
|
||||||
// Eval attenuation
|
|
||||||
float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance);
|
|
||||||
vec3 lightEnergy = radialAttenuation * getLightIrradiance(light);
|
|
||||||
|
|
||||||
// Eval shading
|
|
||||||
if (withScattering) {
|
|
||||||
evalFragShadingScattering(diffuse, specular, frag.metallic, frag.fresnel, surface, frag.albedo
|
|
||||||
,frag.scattering, midNormalCurvature, lowNormalCurvature );
|
|
||||||
} else {
|
|
||||||
evalFragShadingGloss(diffuse, specular, frag.metallic, frag.fresnel, surface, frag.albedo);
|
|
||||||
}
|
|
||||||
|
|
||||||
diffuse *= lightEnergy * isDiffuseEnabled();
|
|
||||||
specular *= lightEnergy * isSpecularEnabled();
|
|
||||||
|
|
||||||
_fragColor.rgb += diffuse;
|
|
||||||
_fragColor.rgb += specular;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = cluster.x; i < numLights; i++) {
|
|
||||||
// Need the light now
|
|
||||||
int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset);
|
|
||||||
Light light = getLight(theLightIndex);
|
|
||||||
|
|
||||||
// Clip againgst the light volume and Make the Light vector going from fragment to light center in world space
|
|
||||||
vec4 fragLightVecLen2;
|
|
||||||
vec4 fragLightDirLen;
|
|
||||||
float cosSpotAngle;
|
|
||||||
|
|
||||||
if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allright we re in the light sphere volume
|
|
||||||
fragLightDirLen.w = length(fragLightVecLen2.xyz);
|
|
||||||
fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w;
|
|
||||||
if (dot(frag.normal, fragLightDirLen.xyz) < 0.0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check spot
|
|
||||||
if (!lightVolume_clipFragToLightVolumeSpotSide(light.volume, fragLightDirLen, cosSpotAngle)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
numLightTouching++;
|
|
||||||
|
|
||||||
vec3 diffuse = vec3(1.0);
|
|
||||||
vec3 specular = vec3(0.1);
|
|
||||||
|
|
||||||
// Allright we re valid in the volume
|
|
||||||
float fragLightDistance = fragLightDirLen.w;
|
|
||||||
vec3 fragLightDir = fragLightDirLen.xyz;
|
|
||||||
|
|
||||||
updateSurfaceDataWithLight(surface, fragLightDir);
|
|
||||||
|
|
||||||
// Eval attenuation
|
|
||||||
float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance);
|
|
||||||
float angularAttenuation = lightIrradiance_evalLightSpotAttenuation(light.irradiance, cosSpotAngle);
|
|
||||||
vec3 lightEnergy = radialAttenuation * angularAttenuation * getLightIrradiance(light);
|
|
||||||
|
|
||||||
// Eval shading
|
|
||||||
if (withScattering) {
|
|
||||||
evalFragShadingScattering(diffuse, specular, frag.metallic, frag.fresnel, surface, frag.albedo
|
|
||||||
,frag.scattering, midNormalCurvature, lowNormalCurvature );
|
|
||||||
} else {
|
|
||||||
evalFragShadingGloss(diffuse, specular, frag.metallic, frag.fresnel, surface, frag.albedo);
|
|
||||||
}
|
|
||||||
|
|
||||||
diffuse *= lightEnergy * isDiffuseEnabled();
|
|
||||||
specular *= lightEnergy * isSpecularEnabled();
|
|
||||||
|
|
||||||
_fragColor.rgb += diffuse;
|
|
||||||
_fragColor.rgb += specular;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||||
|
|
||||||
|
<@include LightLocal.slh@>
|
||||||
|
|
||||||
<@include gpu/Transform.slh@>
|
<@include gpu/Transform.slh@>
|
||||||
<$declareStandardCameraTransform()$>
|
<$declareStandardCameraTransform()$>
|
||||||
|
|
||||||
|
@ -27,6 +29,7 @@
|
||||||
in vec2 _texCoord0;
|
in vec2 _texCoord0;
|
||||||
in vec2 _texCoord1;
|
in vec2 _texCoord1;
|
||||||
in vec4 _position;
|
in vec4 _position;
|
||||||
|
in vec4 _worldPosition;
|
||||||
in vec3 _normal;
|
in vec3 _normal;
|
||||||
in vec3 _color;
|
in vec3 _color;
|
||||||
in float _alpha;
|
in float _alpha;
|
||||||
|
@ -56,20 +59,32 @@ void main(void) {
|
||||||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||||
|
|
||||||
vec3 fragPosition = _position.xyz;
|
vec3 fragPosition = _position.xyz;
|
||||||
|
// Lighting is done in world space
|
||||||
vec3 fragNormal = normalize(_normal);
|
vec3 fragNormal = normalize(_normal);
|
||||||
|
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
|
||||||
|
vec3 fragEyeDir = normalize(fragEyeVector);
|
||||||
|
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
|
||||||
|
|
||||||
|
vec4 localLighting = vec4(0.0);
|
||||||
|
|
||||||
|
<$fetchClusterInfo(_worldPosition)$>;
|
||||||
|
if (hasLocalLights(numLights, clusterPos, dims)) {
|
||||||
|
localLighting = evalLocalLighting(cluster, numLights, _worldPosition.xyz, surface,
|
||||||
|
metallic, fresnel, albedo, 0.0,
|
||||||
|
vec4(0), vec4(0), opacity);
|
||||||
|
}
|
||||||
|
|
||||||
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
cam._viewInverse,
|
cam._viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
occlusionTex,
|
occlusionTex,
|
||||||
fragPosition,
|
fragPosition,
|
||||||
fragNormal,
|
|
||||||
albedo,
|
albedo,
|
||||||
fresnel,
|
fresnel,
|
||||||
metallic,
|
metallic,
|
||||||
emissive,
|
emissive,
|
||||||
roughness, opacity),
|
surface, opacity, localLighting.rgb),
|
||||||
opacity);
|
opacity);
|
||||||
}
|
}
|
||||||
|
|
44
libraries/render-utils/src/model_translucent.slv
Normal file
44
libraries/render-utils/src/model_translucent.slv
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
// model_translucent.slv
|
||||||
|
// vertex shader
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 15/01/18.
|
||||||
|
// Copyright 2018 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 gpu/Inputs.slh@>
|
||||||
|
<@include gpu/Color.slh@>
|
||||||
|
<@include gpu/Transform.slh@>
|
||||||
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
|
<@include MaterialTextures.slh@>
|
||||||
|
<$declareMaterialTexMapArrayBuffer()$>
|
||||||
|
|
||||||
|
out float _alpha;
|
||||||
|
out vec2 _texCoord0;
|
||||||
|
out vec2 _texCoord1;
|
||||||
|
out vec4 _position;
|
||||||
|
out vec4 _worldPosition;
|
||||||
|
out vec3 _normal;
|
||||||
|
out vec3 _color;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
_color = colorToLinearRGB(inColor.xyz);
|
||||||
|
_alpha = inColor.w;
|
||||||
|
|
||||||
|
TexMapArray texMapArray = getTexMapArray();
|
||||||
|
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
|
||||||
|
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
|
||||||
|
|
||||||
|
// standard transform
|
||||||
|
TransformCamera cam = getTransformCamera();
|
||||||
|
TransformObject obj = getTransformObject();
|
||||||
|
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
|
||||||
|
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
|
||||||
|
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
|
||||||
|
}
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||||
|
|
||||||
|
<@include LightLocal.slh@>
|
||||||
|
|
||||||
<@include gpu/Transform.slh@>
|
<@include gpu/Transform.slh@>
|
||||||
<$declareStandardCameraTransform()$>
|
<$declareStandardCameraTransform()$>
|
||||||
|
|
||||||
|
@ -66,20 +68,32 @@ void main(void) {
|
||||||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||||
|
|
||||||
vec3 fragPosition = _position.xyz;
|
vec3 fragPosition = _position.xyz;
|
||||||
|
// Lighting is done in world space
|
||||||
vec3 fragNormal = normalize(_normal);
|
vec3 fragNormal = normalize(_normal);
|
||||||
|
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
|
||||||
|
vec3 fragEyeDir = normalize(fragEyeVector);
|
||||||
|
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
|
||||||
|
|
||||||
|
vec4 localLighting = vec4(0.0);
|
||||||
|
|
||||||
|
<$fetchClusterInfo(_worldPosition)$>;
|
||||||
|
if (hasLocalLights(numLights, clusterPos, dims)) {
|
||||||
|
localLighting = evalLocalLighting(cluster, numLights, _worldPosition.xyz, surface,
|
||||||
|
metallic, fresnel, albedo, 0.0,
|
||||||
|
vec4(0), vec4(0), opacity);
|
||||||
|
}
|
||||||
|
|
||||||
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||||
cam._viewInverse,
|
cam._viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
occlusionTex,
|
occlusionTex,
|
||||||
fragPosition,
|
fragPosition,
|
||||||
fragNormal,
|
|
||||||
albedo,
|
albedo,
|
||||||
fresnel,
|
fresnel,
|
||||||
metallic,
|
metallic,
|
||||||
emissive+fadeEmissive,
|
emissive+fadeEmissive,
|
||||||
roughness, opacity),
|
surface, opacity, localLighting.rgb),
|
||||||
opacity);
|
opacity);
|
||||||
}
|
}
|
||||||
|
|
44
libraries/render-utils/src/model_translucent_fade.slv
Normal file
44
libraries/render-utils/src/model_translucent_fade.slv
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
// model_translucent_fade.slv
|
||||||
|
// vertex shader
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 15/01/18.
|
||||||
|
// Copyright 2018 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 gpu/Inputs.slh@>
|
||||||
|
<@include gpu/Color.slh@>
|
||||||
|
<@include gpu/Transform.slh@>
|
||||||
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
|
<@include MaterialTextures.slh@>
|
||||||
|
<$declareMaterialTexMapArrayBuffer()$>
|
||||||
|
|
||||||
|
out float _alpha;
|
||||||
|
out vec2 _texCoord0;
|
||||||
|
out vec2 _texCoord1;
|
||||||
|
out vec4 _position;
|
||||||
|
out vec4 _worldPosition;
|
||||||
|
out vec3 _normal;
|
||||||
|
out vec3 _color;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
_color = colorToLinearRGB(inColor.xyz);
|
||||||
|
_alpha = inColor.w;
|
||||||
|
|
||||||
|
TexMapArray texMapArray = getTexMapArray();
|
||||||
|
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
|
||||||
|
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
|
||||||
|
|
||||||
|
// standard transform
|
||||||
|
TransformCamera cam = getTransformCamera();
|
||||||
|
TransformObject obj = getTransformObject();
|
||||||
|
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
|
||||||
|
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
|
||||||
|
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
|
||||||
|
}
|
|
@ -27,7 +27,7 @@
|
||||||
vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness, float opacity) {
|
vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness, float opacity) {
|
||||||
|
|
||||||
// Need the light now
|
// Need the light now
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
vec3 lightDirection = getLightDirection(light);
|
vec3 lightDirection = getLightDirection(light);
|
||||||
vec3 lightIrradiance = getLightIrradiance(light);
|
vec3 lightIrradiance = getLightIrradiance(light);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness, float opacity) {
|
vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness, float opacity) {
|
||||||
|
|
||||||
// Need the light now
|
// Need the light now
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
vec3 lightDirection = getLightDirection(light);
|
vec3 lightDirection = getLightDirection(light);
|
||||||
vec3 lightIrradiance = getLightIrradiance(light);
|
vec3 lightIrradiance = getLightIrradiance(light);
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ vec3 evalScatteringBRDF(vec2 texcoord) {
|
||||||
vec3 fragNormal = vec3((normal));
|
vec3 fragNormal = vec3((normal));
|
||||||
|
|
||||||
// Get light
|
// Get light
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
vec3 fresnel = vec3(0.028); // Default Di-electric fresnel value for skin
|
vec3 fresnel = vec3(0.028); // Default Di-electric fresnel value for skin
|
||||||
float metallic = 0.0;
|
float metallic = 0.0;
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ vec3 drawScatteringTableUV(vec2 cursor, vec2 texcoord) {
|
||||||
float curvature = unpackCurvature(diffusedCurvature.w);
|
float curvature = unpackCurvature(diffusedCurvature.w);
|
||||||
|
|
||||||
// Get light
|
// Get light
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
vec3 fresnel = vec3(0.028); // Default Di-electric fresnel value for skin
|
vec3 fresnel = vec3(0.028); // Default Di-electric fresnel value for skin
|
||||||
|
|
||||||
vec3 fragLightDir = -normalize(getLightDirection(light));
|
vec3 fragLightDir = -normalize(getLightDirection(light));
|
||||||
|
|
|
@ -25,7 +25,7 @@ void main(void) {
|
||||||
|
|
||||||
<$evalGlobeWidget()$>
|
<$evalGlobeWidget()$>
|
||||||
|
|
||||||
Light light = getLight();
|
Light light = getKeyLight();
|
||||||
vec3 lightDirection = normalize(getLightDirection(light));
|
vec3 lightDirection = normalize(getLightDirection(light));
|
||||||
vec3 lightIrradiance = getLightIrradiance(light);
|
vec3 lightIrradiance = getLightIrradiance(light);
|
||||||
vec3 color = vec3(0.0);
|
vec3 color = vec3(0.0);
|
||||||
|
|
|
@ -45,8 +45,8 @@ void Engine::load() {
|
||||||
auto config = getConfiguration();
|
auto config = getConfiguration();
|
||||||
const QString configFile= "config/render.json";
|
const QString configFile= "config/render.json";
|
||||||
|
|
||||||
QUrl path(PathUtils::resourcesPath() + configFile);
|
QString path(PathUtils::resourcesPath() + configFile);
|
||||||
QFile file(path.toString());
|
QFile file(path);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
qWarning() << "Engine configuration file" << path << "does not exist";
|
qWarning() << "Engine configuration file" << path << "does not exist";
|
||||||
} else if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
} else if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
|
|
@ -70,6 +70,8 @@ void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program
|
||||||
|
|
||||||
void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||||
BatchSetter batchSetter, ItemSetter itemSetter) {
|
BatchSetter batchSetter, ItemSetter itemSetter) {
|
||||||
|
ShapeKey key{ filter._flags };
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
gpu::Shader::BindingSet slotBindings;
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
|
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
|
||||||
|
@ -82,6 +84,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::MAP::EMISSIVE_LIGHTMAP));
|
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::MAP::EMISSIVE_LIGHTMAP));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::MAP::OCCLUSION));
|
slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::MAP::OCCLUSION));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringMap"), Slot::MAP::SCATTERING));
|
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringMap"), Slot::MAP::SCATTERING));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), Slot::BUFFER::KEY_LIGHT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER));
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
|
||||||
|
@ -89,6 +92,12 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
|
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL));
|
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL));
|
||||||
|
|
||||||
|
if (key.isTranslucent()) {
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
|
||||||
|
}
|
||||||
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
auto locations = std::make_shared<Locations>();
|
auto locations = std::make_shared<Locations>();
|
||||||
|
@ -103,14 +112,23 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
||||||
locations->skinClusterBufferUnit = program->getUniformBuffers().findLocation("skinClusterBuffer");
|
locations->skinClusterBufferUnit = program->getUniformBuffers().findLocation("skinClusterBuffer");
|
||||||
locations->materialBufferUnit = program->getUniformBuffers().findLocation("materialBuffer");
|
locations->materialBufferUnit = program->getUniformBuffers().findLocation("materialBuffer");
|
||||||
locations->texMapArrayBufferUnit = program->getUniformBuffers().findLocation("texMapArrayBuffer");
|
locations->texMapArrayBufferUnit = program->getUniformBuffers().findLocation("texMapArrayBuffer");
|
||||||
|
locations->keyLightBufferUnit = program->getUniformBuffers().findLocation("keyLightBuffer");
|
||||||
locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer");
|
locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer");
|
||||||
locations->lightAmbientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer");
|
locations->lightAmbientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer");
|
||||||
locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap");
|
locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap");
|
||||||
locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap");
|
locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap");
|
||||||
locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer");
|
locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer");
|
||||||
locations->hazeParameterBufferUnit = program->getUniformBuffers().findLocation("hazeParametersBuffer");
|
locations->hazeParameterBufferUnit = program->getUniformBuffers().findLocation("hazeParametersBuffer");
|
||||||
|
if (key.isTranslucent()) {
|
||||||
|
locations->lightClusterGridBufferUnit = program->getUniformBuffers().findLocation("clusterGridBuffer");
|
||||||
|
locations->lightClusterContentBufferUnit = program->getUniformBuffers().findLocation("clusterContentBuffer");
|
||||||
|
locations->lightClusterFrustumBufferUnit = program->getUniformBuffers().findLocation("frustumGridBuffer");
|
||||||
|
} else {
|
||||||
|
locations->lightClusterGridBufferUnit = -1;
|
||||||
|
locations->lightClusterContentBufferUnit = -1;
|
||||||
|
locations->lightClusterFrustumBufferUnit = -1;
|
||||||
|
}
|
||||||
|
|
||||||
ShapeKey key{filter._flags};
|
|
||||||
auto gpuPipeline = gpu::Pipeline::create(program, state);
|
auto gpuPipeline = gpu::Pipeline::create(program, state);
|
||||||
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter, itemSetter);
|
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter, itemSetter);
|
||||||
addPipelineHelper(filter, key, 0, shapePipeline);
|
addPipelineHelper(filter, key, 0, shapePipeline);
|
||||||
|
|
|
@ -235,10 +235,15 @@ public:
|
||||||
MATERIAL,
|
MATERIAL,
|
||||||
TEXMAPARRAY,
|
TEXMAPARRAY,
|
||||||
LIGHTING_MODEL,
|
LIGHTING_MODEL,
|
||||||
|
KEY_LIGHT,
|
||||||
LIGHT,
|
LIGHT,
|
||||||
LIGHT_AMBIENT_BUFFER,
|
LIGHT_AMBIENT_BUFFER,
|
||||||
HAZE_MODEL,
|
HAZE_MODEL,
|
||||||
FADE_PARAMETERS,
|
FADE_PARAMETERS,
|
||||||
|
LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT,
|
||||||
|
LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT,
|
||||||
|
LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MAP {
|
enum MAP {
|
||||||
|
@ -266,12 +271,16 @@ public:
|
||||||
int skinClusterBufferUnit;
|
int skinClusterBufferUnit;
|
||||||
int materialBufferUnit;
|
int materialBufferUnit;
|
||||||
int texMapArrayBufferUnit;
|
int texMapArrayBufferUnit;
|
||||||
|
int keyLightBufferUnit;
|
||||||
int lightBufferUnit;
|
int lightBufferUnit;
|
||||||
int lightAmbientBufferUnit;
|
int lightAmbientBufferUnit;
|
||||||
int lightAmbientMapUnit;
|
int lightAmbientMapUnit;
|
||||||
int fadeMaskTextureUnit;
|
int fadeMaskTextureUnit;
|
||||||
int fadeParameterBufferUnit;
|
int fadeParameterBufferUnit;
|
||||||
int hazeParameterBufferUnit;
|
int hazeParameterBufferUnit;
|
||||||
|
int lightClusterGridBufferUnit;
|
||||||
|
int lightClusterContentBufferUnit;
|
||||||
|
int lightClusterFrustumBufferUnit;
|
||||||
};
|
};
|
||||||
using LocationsPointer = std::shared_ptr<Locations>;
|
using LocationsPointer = std::shared_ptr<Locations>;
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,7 @@ void ScriptEngines::onErrorLoadingScript(const QString& url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptEngines::ScriptEngines(ScriptEngine::Context context)
|
ScriptEngines::ScriptEngines(ScriptEngine::Context context)
|
||||||
: _context(context),
|
: _context(context)
|
||||||
_scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION)
|
|
||||||
{
|
{
|
||||||
_scriptsModelFilter.setSourceModel(&_scriptsModel);
|
_scriptsModelFilter.setSourceModel(&_scriptsModel);
|
||||||
_scriptsModelFilter.sort(0, Qt::AscendingOrder);
|
_scriptsModelFilter.sort(0, Qt::AscendingOrder);
|
||||||
|
@ -429,13 +428,8 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) {
|
||||||
return stoppedScript;
|
return stoppedScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ScriptEngines::getScriptsLocation() const {
|
void ScriptEngines::reloadLocalFiles() {
|
||||||
return _scriptsLocationHandle.get();
|
_scriptsModel.reloadLocalFiles();
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptEngines::setScriptsLocation(const QString& scriptsLocation) {
|
|
||||||
_scriptsLocationHandle.set(scriptsLocation);
|
|
||||||
_scriptsModel.updateScriptsLocation(scriptsLocation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngines::reloadAllScripts() {
|
void ScriptEngines::reloadAllScripts() {
|
||||||
|
|
|
@ -45,9 +45,9 @@ public:
|
||||||
QString getDebugScriptUrl() { return _debugScriptUrl; };
|
QString getDebugScriptUrl() { return _debugScriptUrl; };
|
||||||
void setDebugScriptUrl(const QString& url) { _debugScriptUrl = url; };
|
void setDebugScriptUrl(const QString& url) { _debugScriptUrl = url; };
|
||||||
|
|
||||||
QString getScriptsLocation() const;
|
|
||||||
void loadDefaultScripts();
|
void loadDefaultScripts();
|
||||||
void setScriptsLocation(const QString& scriptsLocation);
|
void reloadLocalFiles();
|
||||||
|
|
||||||
QStringList getRunningScripts();
|
QStringList getRunningScripts();
|
||||||
ScriptEnginePointer getScriptEngine(const QUrl& scriptHash);
|
ScriptEnginePointer getScriptEngine(const QUrl& scriptHash);
|
||||||
|
|
||||||
|
@ -115,7 +115,6 @@ protected:
|
||||||
QSet<ScriptEnginePointer> _allKnownScriptEngines;
|
QSet<ScriptEnginePointer> _allKnownScriptEngines;
|
||||||
QMutex _allScriptsMutex;
|
QMutex _allScriptsMutex;
|
||||||
std::list<ScriptInitializer> _scriptInitializers;
|
std::list<ScriptInitializer> _scriptInitializers;
|
||||||
mutable Setting::Handle<QString> _scriptsLocationHandle;
|
|
||||||
ScriptsModel _scriptsModel;
|
ScriptsModel _scriptsModel;
|
||||||
ScriptsModelFilter _scriptsModelFilter;
|
ScriptsModelFilter _scriptsModelFilter;
|
||||||
std::atomic<bool> _isStopped { false };
|
std::atomic<bool> _isStopped { false };
|
||||||
|
|
|
@ -100,6 +100,7 @@ QVariant ScriptsModel::data(const QModelIndex& index, int role) const {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
if (node->getType() == TREE_NODE_TYPE_SCRIPT) {
|
if (node->getType() == TREE_NODE_TYPE_SCRIPT) {
|
||||||
|
|
||||||
TreeNodeScript* script = static_cast<TreeNodeScript*>(node);
|
TreeNodeScript* script = static_cast<TreeNodeScript*>(node);
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
return QVariant(script->getName() + (script->getOrigin() == SCRIPT_ORIGIN_LOCAL ? " (local)" : ""));
|
return QVariant(script->getName() + (script->getOrigin() == SCRIPT_ORIGIN_LOCAL ? " (local)" : ""));
|
||||||
|
@ -133,7 +134,6 @@ void ScriptsModel::updateScriptsLocation(const QString& newPath) {
|
||||||
_fsWatcher.addPath(_localDirectory.absolutePath());
|
_fsWatcher.addPath(_localDirectory.absolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadLocalFiles();
|
reloadLocalFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +305,7 @@ void ScriptsModel::rebuildTree() {
|
||||||
_treeNodes.removeAt(i);
|
_treeNodes.removeAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QString, TreeNodeFolder*> folders;
|
QHash<QString, TreeNodeFolder*> folders;
|
||||||
for (int i = 0; i < _treeNodes.size(); i++) {
|
for (int i = 0; i < _treeNodes.size(); i++) {
|
||||||
TreeNodeBase* node = _treeNodes.at(i);
|
TreeNodeBase* node = _treeNodes.at(i);
|
||||||
|
|
|
@ -12,14 +12,14 @@
|
||||||
#ifndef hifi_BitVectorHelpers_h
|
#ifndef hifi_BitVectorHelpers_h
|
||||||
#define hifi_BitVectorHelpers_h
|
#define hifi_BitVectorHelpers_h
|
||||||
|
|
||||||
size_t calcBitVectorSize(int numBits) {
|
int calcBitVectorSize(int numBits) {
|
||||||
return ((numBits - 1) >> 3) + 1;
|
return ((numBits - 1) >> 3) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// func should be of type bool func(int index)
|
// func should be of type bool func(int index)
|
||||||
template <typename F>
|
template <typename F>
|
||||||
size_t writeBitVector(uint8_t* destinationBuffer, int numBits, const F& func) {
|
int writeBitVector(uint8_t* destinationBuffer, int numBits, const F& func) {
|
||||||
size_t totalBytes = ((numBits - 1) >> 3) + 1;
|
int totalBytes = calcBitVectorSize(numBits);
|
||||||
uint8_t* cursor = destinationBuffer;
|
uint8_t* cursor = destinationBuffer;
|
||||||
uint8_t byte = 0;
|
uint8_t byte = 0;
|
||||||
uint8_t bit = 0;
|
uint8_t bit = 0;
|
||||||
|
@ -34,13 +34,19 @@ size_t writeBitVector(uint8_t* destinationBuffer, int numBits, const F& func) {
|
||||||
bit = 0;
|
bit = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// write the last byte, if necessary
|
||||||
|
if (bit != 0) {
|
||||||
|
*cursor++ = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert((int)(cursor - destinationBuffer) == totalBytes);
|
||||||
return totalBytes;
|
return totalBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// func should be of type 'void func(int index, bool value)'
|
// func should be of type 'void func(int index, bool value)'
|
||||||
template <typename F>
|
template <typename F>
|
||||||
size_t readBitVector(const uint8_t* sourceBuffer, int numBits, const F& func) {
|
int readBitVector(const uint8_t* sourceBuffer, int numBits, const F& func) {
|
||||||
size_t totalBytes = ((numBits - 1) >> 3) + 1;
|
int totalBytes = calcBitVectorSize(numBits);
|
||||||
const uint8_t* cursor = sourceBuffer;
|
const uint8_t* cursor = sourceBuffer;
|
||||||
uint8_t bit = 0;
|
uint8_t bit = 0;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include "shared/GlobalAppProperties.h"
|
#include "shared/GlobalAppProperties.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
|
@ -41,8 +40,15 @@ QString TEMP_DIR_FORMAT { "%1-%2-%3" };
|
||||||
#if defined(Q_OS_OSX)
|
#if defined(Q_OS_OSX)
|
||||||
static bool USE_SOURCE_TREE_RESOURCES = true;
|
static bool USE_SOURCE_TREE_RESOURCES = true;
|
||||||
#else
|
#else
|
||||||
static const QString USE_SOURCE_TREE_RESOURCES_FLAG("HIFI_USE_SOURCE_TREE_RESOURCES");
|
static bool USE_SOURCE_TREE_RESOURCES() {
|
||||||
static bool USE_SOURCE_TREE_RESOURCES = QProcessEnvironment::systemEnvironment().contains(USE_SOURCE_TREE_RESOURCES_FLAG);
|
static bool result = false;
|
||||||
|
static std::once_flag once;
|
||||||
|
std::call_once(once, [&] {
|
||||||
|
const QString USE_SOURCE_TREE_RESOURCES_FLAG("HIFI_USE_SOURCE_TREE_RESOURCES");
|
||||||
|
result = QProcessEnvironment::systemEnvironment().contains(USE_SOURCE_TREE_RESOURCES_FLAG);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -77,7 +83,7 @@ const QString& PathUtils::resourcesPath() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
||||||
if (USE_SOURCE_TREE_RESOURCES) {
|
if (USE_SOURCE_TREE_RESOURCES()) {
|
||||||
// For dev builds, optionally load content from the Git source tree
|
// For dev builds, optionally load content from the Git source tree
|
||||||
staticResourcePath = projectRootPath() + "/interface/resources/";
|
staticResourcePath = projectRootPath() + "/interface/resources/";
|
||||||
}
|
}
|
||||||
|
@ -100,7 +106,7 @@ const QString& PathUtils::resourcesUrl() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
||||||
if (USE_SOURCE_TREE_RESOURCES) {
|
if (USE_SOURCE_TREE_RESOURCES()) {
|
||||||
// For dev builds, optionally load content from the Git source tree
|
// For dev builds, optionally load content from the Git source tree
|
||||||
staticResourcePath = QUrl::fromLocalFile(projectRootPath() + "/interface/resources/").toString();
|
staticResourcePath = QUrl::fromLocalFile(projectRootPath() + "/interface/resources/").toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
set(TARGET_NAME gl-test)
|
set(TARGET_NAME gl-test)
|
||||||
# This is not a testcase -- just set it up as a regular hifi project
|
# This is not a testcase -- just set it up as a regular hifi project
|
||||||
setup_hifi_project(Quick Gui OpenGL)
|
setup_hifi_project(Quick Gui OpenGL)
|
||||||
|
setup_memory_debugger()
|
||||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||||
link_hifi_libraries(shared gl)
|
link_hifi_libraries(shared gl)
|
||||||
package_libraries_for_deployment()
|
package_libraries_for_deployment()
|
||||||
|
|
80
tests/shared/src/BitVectorHelperTests.cpp
Normal file
80
tests/shared/src/BitVectorHelperTests.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
//
|
||||||
|
// BitVectorHelperTests.cpp
|
||||||
|
// tests/shared/src
|
||||||
|
//
|
||||||
|
// Copyright 2018 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 "BitVectorHelperTests.h"
|
||||||
|
|
||||||
|
#include <SharedLogging.h>
|
||||||
|
|
||||||
|
#include "../QTestExtensions.h"
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
#include <StreamUtils.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <BitVectorHelpers.h>
|
||||||
|
|
||||||
|
QTEST_MAIN(BitVectorHelperTests)
|
||||||
|
|
||||||
|
const int BITS_IN_BYTE = 8;
|
||||||
|
|
||||||
|
void BitVectorHelperTests::sizeTest() {
|
||||||
|
std::vector<int> sizes = {0, 6, 7, 8, 30, 31, 32, 33, 87, 88, 89, 90, 90, 91, 92, 93};
|
||||||
|
for (auto& size : sizes) {
|
||||||
|
const int oldWay = (int)ceil((float)size / (float)BITS_IN_BYTE);
|
||||||
|
const int newWay = (int)calcBitVectorSize(size);
|
||||||
|
QCOMPARE(oldWay, newWay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readWriteHelper(const std::vector<bool>& src) {
|
||||||
|
|
||||||
|
int numBits = (int)src.size();
|
||||||
|
int numBytes = calcBitVectorSize(numBits);
|
||||||
|
uint8_t* bytes = new uint8_t[numBytes];
|
||||||
|
memset(bytes, numBytes, sizeof(uint8_t));
|
||||||
|
int numBytesWritten = writeBitVector(bytes, numBits, [&](int i) {
|
||||||
|
return src[i];
|
||||||
|
});
|
||||||
|
QCOMPARE(numBytesWritten, numBytes);
|
||||||
|
|
||||||
|
std::vector<bool> dst;
|
||||||
|
int numBytesRead = readBitVector(bytes, numBits, [&](int i, bool value) {
|
||||||
|
dst.push_back(value);
|
||||||
|
});
|
||||||
|
QCOMPARE(numBytesRead, numBytes);
|
||||||
|
|
||||||
|
QCOMPARE(numBits, (int)src.size());
|
||||||
|
QCOMPARE(numBits, (int)dst.size());
|
||||||
|
for (int i = 0; i < numBits; i++) {
|
||||||
|
bool a = src[i];
|
||||||
|
bool b = dst[i];
|
||||||
|
QCOMPARE(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitVectorHelperTests::readWriteTest() {
|
||||||
|
std::vector<int> sizes = {0, 6, 7, 8, 30, 31, 32, 33, 87, 88, 89, 90, 90, 91, 92, 93};
|
||||||
|
|
||||||
|
for (auto& size : sizes) {
|
||||||
|
std::vector<bool> allTrue(size, true);
|
||||||
|
std::vector<bool> allFalse(size, false);
|
||||||
|
std::vector<bool> evenSet;
|
||||||
|
evenSet.reserve(size);
|
||||||
|
std::vector<bool> oddSet;
|
||||||
|
oddSet.reserve(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
bool isOdd = (i & 0x1) > 0;
|
||||||
|
evenSet.push_back(!isOdd);
|
||||||
|
oddSet.push_back(isOdd);
|
||||||
|
}
|
||||||
|
readWriteHelper(allTrue);
|
||||||
|
readWriteHelper(allFalse);
|
||||||
|
readWriteHelper(evenSet);
|
||||||
|
readWriteHelper(oddSet);
|
||||||
|
}
|
||||||
|
}
|
23
tests/shared/src/BitVectorHelperTests.h
Normal file
23
tests/shared/src/BitVectorHelperTests.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// BitVectorHelperTests.h
|
||||||
|
// tests/shared/src
|
||||||
|
//
|
||||||
|
// Copyright 2018 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_BitVectorHelperTests_h
|
||||||
|
#define hifi_BitVectorHelperTests_h
|
||||||
|
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
|
class BitVectorHelperTests : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void sizeTest();
|
||||||
|
void readWriteTest();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_BitVectorHelperTests_h
|
|
@ -306,8 +306,8 @@ void Test::evaluateTestsRecursively(bool interactiveMode, QProgressBar* progress
|
||||||
zipAndDeleteTestResultsFolder();
|
zipAndDeleteTestResultsFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Test::importTest(QTextStream& textStream, const QString& testPathname, int testNumber) {
|
void Test::importTest(QTextStream& textStream, const QString& testPathname) {
|
||||||
textStream << "var test" << testNumber << " = Script.require(\"" << "file:///" << testPathname + "\");" << endl;
|
textStream << "Script.include(\"" << "file:///" << testPathname + "?raw=true\");" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a single script in a user-selected folder.
|
// Creates a single script in a user-selected folder.
|
||||||
|
@ -330,12 +330,14 @@ void Test::createRecursiveScript() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextStream textStream(&allTestsFilename);
|
QTextStream textStream(&allTestsFilename);
|
||||||
textStream << "// This is an automatically generated file, created by auto-tester" << endl;
|
textStream << "// This is an automatically generated file, created by auto-tester" << endl << endl;
|
||||||
|
|
||||||
|
textStream << "var autoTester = Script.require(\"https://github.com/highfidelity/hifi_tests/blob/master/tests/utils/autoTester.js?raw=true\");" << endl;
|
||||||
|
textStream << "autoTester.enableRecursive();" << endl << endl;
|
||||||
|
|
||||||
// The main will call each test after the previous test is completed
|
// The main will call each test after the previous test is completed
|
||||||
// This is implemented with an interval timer that periodically tests if a
|
// This is implemented with an interval timer that periodically tests if a
|
||||||
// running test has increment a testNumber variable that it received as an input.
|
// running test has increment a testNumber variable that it received as an input.
|
||||||
int testNumber = 1;
|
|
||||||
QVector<QString> testPathnames;
|
QVector<QString> testPathnames;
|
||||||
|
|
||||||
// First test if top-level folder has a test.js file
|
// First test if top-level folder has a test.js file
|
||||||
|
@ -343,8 +345,7 @@ void Test::createRecursiveScript() {
|
||||||
QFileInfo fileInfo(testPathname);
|
QFileInfo fileInfo(testPathname);
|
||||||
if (fileInfo.exists()) {
|
if (fileInfo.exists()) {
|
||||||
// Current folder contains a test
|
// Current folder contains a test
|
||||||
importTest(textStream, testPathname, testNumber);
|
importTest(textStream, testPathname);
|
||||||
++testNumber;
|
|
||||||
|
|
||||||
testPathnames << testPathname;
|
testPathnames << testPathname;
|
||||||
}
|
}
|
||||||
|
@ -363,8 +364,7 @@ void Test::createRecursiveScript() {
|
||||||
QFileInfo fileInfo(testPathname);
|
QFileInfo fileInfo(testPathname);
|
||||||
if (fileInfo.exists()) {
|
if (fileInfo.exists()) {
|
||||||
// Current folder contains a test
|
// Current folder contains a test
|
||||||
importTest(textStream, testPathname, testNumber);
|
importTest(textStream, testPathname);
|
||||||
++testNumber;
|
|
||||||
|
|
||||||
testPathnames << testPathname;
|
testPathnames << testPathname;
|
||||||
}
|
}
|
||||||
|
@ -377,79 +377,9 @@ void Test::createRecursiveScript() {
|
||||||
}
|
}
|
||||||
|
|
||||||
textStream << endl;
|
textStream << endl;
|
||||||
|
textStream << "autoTester.runRecursive();" << endl;
|
||||||
// Define flags for each test
|
|
||||||
for (int i = 1; i <= testPathnames.length(); ++i) {
|
|
||||||
textStream << "var test" << i << "HasNotStarted = true;" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leave a blank line in the main
|
|
||||||
textStream << endl;
|
|
||||||
|
|
||||||
const int TEST_PERIOD = 1000; // in milliseconds
|
|
||||||
const QString tab = " ";
|
|
||||||
|
|
||||||
textStream << "// Check every second if the current test is complete and the next test can be run" << endl;
|
|
||||||
textStream << "var testTimer = Script.setInterval(" << endl;
|
|
||||||
textStream << tab << "function() {" << endl;
|
|
||||||
|
|
||||||
const QString testFunction = "test";
|
|
||||||
for (int i = 1; i <= testPathnames.length(); ++i) {
|
|
||||||
// First test starts immediately, all other tests wait for the previous test to complete.
|
|
||||||
// The script produced will look as follows:
|
|
||||||
// if (test1HasNotStarted) {
|
|
||||||
// test1HasNotStarted = false;
|
|
||||||
// test1.test("auto");
|
|
||||||
// print("******started test 1******");
|
|
||||||
// }
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// if (test5.complete && test6HasNotStarted) {
|
|
||||||
// test6HasNotStarted = false;
|
|
||||||
// test7.test();
|
|
||||||
// print("******started test 6******");
|
|
||||||
// }
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// if (test12.complete) {
|
|
||||||
// print("******stopping******");
|
|
||||||
// Script.stop();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
if (i == 1) {
|
|
||||||
textStream << tab << tab << "if (test1HasNotStarted) {" << endl;
|
|
||||||
} else {
|
|
||||||
textStream << tab << tab << "if (test" << i - 1 << ".complete && test" << i << "HasNotStarted) {" << endl;
|
|
||||||
}
|
|
||||||
textStream << tab << tab << tab << "test" << i << "HasNotStarted = false;" << endl;
|
|
||||||
textStream << tab << tab << tab << "test" << i << "." << testFunction << "(\"auto\");" << endl;
|
|
||||||
textStream << tab << tab << tab << "print(\"******started test " << i << "******\");" << endl;
|
|
||||||
|
|
||||||
textStream << tab << tab << "}" << endl << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add extra step to stop the script
|
|
||||||
textStream << tab << tab << "if (test" << testPathnames.length() << ".complete) {" << endl;
|
|
||||||
textStream << tab << tab << tab << "print(\"******stopping******\");" << endl;
|
|
||||||
textStream << tab << tab << tab << "Script.stop();" << endl;
|
|
||||||
textStream << tab << tab << "}" << endl << endl;
|
|
||||||
|
|
||||||
textStream << tab << "}," << endl;
|
|
||||||
textStream << endl;
|
|
||||||
textStream << tab << TEST_PERIOD << endl;
|
|
||||||
textStream << ");" << endl << endl;
|
|
||||||
|
|
||||||
textStream << "// Stop the timer and clear the module cache" << endl;
|
|
||||||
textStream << "Script.scriptEnding.connect(" << endl;
|
|
||||||
textStream << tab << "function() {" << endl;
|
|
||||||
textStream << tab << tab << "Script.clearInterval(testTimer);" << endl;
|
|
||||||
textStream << tab << tab << "Script.require.cache = {};" << endl;
|
|
||||||
textStream << tab << "}" << endl;
|
|
||||||
textStream << ");" << endl;
|
|
||||||
|
|
||||||
allTestsFilename.close();
|
allTestsFilename.close();
|
||||||
|
|
||||||
messageBox.information(0, "Success", "Script has been created");
|
messageBox.information(0, "Success", "Script has been created");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
bool isInSnapshotFilenameFormat(QString filename);
|
bool isInSnapshotFilenameFormat(QString filename);
|
||||||
bool isInExpectedImageFilenameFormat(QString filename);
|
bool isInExpectedImageFilenameFormat(QString filename);
|
||||||
|
|
||||||
void importTest(QTextStream& textStream, const QString& testPathname, int testNumber);
|
void importTest(QTextStream& textStream, const QString& testPathname);
|
||||||
|
|
||||||
void appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage);
|
void appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue