Merge branch 'master' of https://github.com/highfidelity/hifi into seth-branch

This commit is contained in:
Sam Gateau 2018-01-25 18:33:37 -08:00
commit 23b99f04cd
60 changed files with 836 additions and 466 deletions

View file

@ -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) {

View file

@ -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));

View file

@ -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;

View file

@ -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();
} }

View file

@ -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

View file

@ -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";
} }

View file

@ -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
}
}

View file

@ -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

View file

@ -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;
} }

View file

@ -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;
} }

View file

@ -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;
} }

View file

@ -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());
} }

View file

@ -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, [] {

View file

@ -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

View file

@ -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());
} }

View file

@ -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);
}
} }
} }

View file

@ -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);
} }

View file

@ -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;
} }

View file

@ -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();
} }

View file

@ -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);

View file

@ -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 };

View file

@ -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];

View file

@ -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;
} }

View file

@ -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@>

View file

@ -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);

View file

@ -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; }

View file

@ -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));

View file

@ -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

View file

@ -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);

View file

@ -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@>

View 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;
}

View file

@ -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());

View file

@ -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());

View file

@ -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>;

View file

@ -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);
} }

View file

@ -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));

View file

@ -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);

View file

@ -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);

View file

@ -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;
}
} }

View file

@ -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);
} }

View 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)$>
}

View file

@ -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);
} }

View 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)$>
}

View file

@ -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);

View file

@ -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);

View file

@ -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));

View file

@ -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);

View file

@ -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)) {

View file

@ -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);

View file

@ -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>;

View file

@ -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() {

View file

@ -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 };

View file

@ -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);

View file

@ -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;

View file

@ -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();
} }

View file

@ -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()

View 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);
}
}

View 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

View file

@ -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");
} }

View file

@ -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);