Merge branch 'master' into 21815

# Conflicts:
#	tools/jsdoc/plugins/hifi.js
This commit is contained in:
David Rowe 2018-04-17 11:54:56 +12:00
commit c1ede6ef58
49 changed files with 1073 additions and 368 deletions

View file

@ -363,7 +363,9 @@ void EntityServer::nodeAdded(SharedNodePointer node) {
void EntityServer::nodeKilled(SharedNodePointer node) {
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
tree->deleteDescendantsOfAvatar(node->getUUID());
tree->withWriteLock([&] {
tree->deleteDescendantsOfAvatar(node->getUUID());
});
tree->forgetAvatarID(node->getUUID());
OctreeServer::nodeKilled(node);
}
@ -451,8 +453,6 @@ void EntityServer::domainSettingsRequestFailed() {
void EntityServer::startDynamicDomainVerification() {
qCDebug(entities) << "Starting Dynamic Domain Verification...";
QString thisDomainID = DependencyManager::get<AddressManager>()->getDomainID().remove(QRegExp("\\{|\\}"));
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
QHash<QString, EntityItemID> localMap(tree->getEntityCertificateIDMap());
@ -460,15 +460,19 @@ void EntityServer::startDynamicDomainVerification() {
qCDebug(entities) << localMap.size() << "entities in _entityCertificateIDMap";
while (i.hasNext()) {
i.next();
const auto& certificateID = i.key();
const auto& entityID = i.value();
EntityItemPointer entity = tree->findEntityByEntityItemID(i.value());
EntityItemPointer entity = tree->findEntityByEntityItemID(entityID);
if (entity) {
if (!entity->getProperties().verifyStaticCertificateProperties()) {
qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << i.value() << "failed"
qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << entityID << "failed"
<< "static certificate verification.";
// Delete the entity if it doesn't pass static certificate verification
tree->deleteEntity(i.value(), true);
tree->withWriteLock([&] {
tree->deleteEntity(entityID, true);
});
} else {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest;
@ -477,39 +481,46 @@ void EntityServer::startDynamicDomainVerification() {
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/location");
QJsonObject request;
request["certificate_id"] = i.key();
request["certificate_id"] = certificateID;
networkRequest.setUrl(requestURL);
QNetworkReply* networkReply = NULL;
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
connect(networkReply, &QNetworkReply::finished, this, [this, entityID, networkReply] {
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
connect(networkReply, &QNetworkReply::finished, [=]() {
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
jsonObject = jsonObject["data"].toObject();
if (networkReply->error() == QNetworkReply::NoError) {
QString thisDomainID = DependencyManager::get<AddressManager>()->getDomainID().remove(QRegExp("\\{|\\}"));
if (jsonObject["domain_id"].toString() != thisDomainID) {
EntityItemPointer entity = tree->findEntityByEntityItemID(entityID);
if (entity->getAge() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) {
qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString()
<< "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value();
tree->deleteEntity(i.value(), true);
<< "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << entityID;
tree->withWriteLock([&] {
tree->deleteEntity(entityID, true);
});
} else {
qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << i.value();
qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << entityID;
}
} else {
qCDebug(entities) << "Entity passed dynamic domain verification:" << i.value();
qCDebug(entities) << "Entity passed dynamic domain verification:" << entityID;
}
} else {
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << i.value()
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << entityID
<< "More info:" << jsonObject;
tree->deleteEntity(i.value(), true);
tree->withWriteLock([&] {
tree->deleteEntity(entityID, true);
});
}
networkReply->deleteLater();
});
}
} else {
qCWarning(entities) << "During DDV, an entity with ID" << i.value() << "was NOT found in the Entity Tree!";
qCWarning(entities) << "During DDV, an entity with ID" << entityID << "was NOT found in the Entity Tree!";
}
}

View file

@ -400,7 +400,9 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode*
if (shouldTraverseAndSend(nodeData)) {
quint64 start = usecTimestampNow();
traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene);
_myServer->getOctree()->withReadLock([&]{
traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene);
});
// Here's where we can/should allow the server to send other data...
// send the environment packet

View file

@ -1,25 +0,0 @@
# FindGVerb.cmake
#
# Try to find the Gverb library.
#
# You must provide a GVERB_ROOT_DIR which contains src and include directories
#
# Once done this will define
#
# GVERB_FOUND - system found Gverb
# GVERB_INCLUDE_DIRS - the Gverb include directory
#
# Copyright 2014 High Fidelity, Inc.
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("gverb")
find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS})
find_library(GVERB_LIBRARIES gverb PATH_SUFFIXES lib HINTS ${GVERB_SEARCH_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Gverb DEFAULT_MSG GVERB_INCLUDE_DIRS GVERB_LIBRARIES)

View file

@ -1,5 +1,5 @@
//
// DefaultFrame.qml
// Decoration.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.

View file

@ -490,7 +490,7 @@ public:
// Don't actually crash in debug builds, in case this apparent deadlock is simply from
// the developer actively debugging code
#ifdef NDEBUG
deadlockDetectionCrash();
deadlockDetectionCrash();
#endif
}
}
@ -801,7 +801,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
steamClient->init();
}
DependencyManager::set<tracing::Tracer>();
PROFILE_SET_THREAD_NAME("Main Thread");
#if defined(Q_OS_WIN)
@ -986,10 +985,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
{
const QString TEST_SCRIPT = "--testScript";
const QString TRACE_FILE = "--traceFile";
const QStringList args = arguments();
for (int i = 0; i < args.size() - 1; ++i) {
if (args.at(i) == TEST_SCRIPT) {
@ -997,10 +994,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
if (QFileInfo(testScriptPath).exists()) {
setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath));
}
} else if (args.at(i) == TRACE_FILE) {
QString traceFilePath = args.at(i + 1);
setProperty(hifi::properties::TRACING, traceFilePath);
DependencyManager::get<tracing::Tracer>()->startTracing();
}
}
}
@ -1046,6 +1039,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto nodeList = DependencyManager::get<NodeList>();
nodeList->startThread();
const char** constArgv = const_cast<const char**>(argv);
if (cmdOptionExists(argc, constArgv, "--disableWatchdog")) {
DISABLE_WATCHDOG = true;
}
// Set up a watchdog thread to intentionally crash the application on deadlocks
if (!DISABLE_WATCHDOG) {
(new DeadlockWatchdogThread())->start();
@ -1255,7 +1252,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, &Application::addingEntityWithCertificate);
const char** constArgv = const_cast<const char**>(argv);
QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads");
bool success;
int concurrentDownloads = concurrentDownloadsStr.toInt(&success);

View file

@ -31,6 +31,8 @@
#include "UserActivityLogger.h"
#include "MainWindow.h"
#include "Profile.h"
#ifdef Q_OS_WIN
extern "C" {
typedef int(__stdcall * CHECKMINSPECPROC) ();
@ -40,6 +42,26 @@ extern "C" {
int main(int argc, const char* argv[]) {
setupHifiApplication(BuildInfo::INTERFACE_NAME);
// Early check for --traceFile argument
auto tracer = DependencyManager::set<tracing::Tracer>();
const char * traceFile = nullptr;
const QString traceFileFlag("--traceFile");
float traceDuration = 0.0f;
for (int a = 1; a < argc; ++a) {
if (traceFileFlag == argv[a] && argc > a + 1) {
traceFile = argv[a + 1];
if (argc > a + 2) {
traceDuration = atof(argv[a + 2]);
}
break;
}
}
if (traceFile != nullptr) {
tracer->startTracing();
}
PROFILE_SYNC_BEGIN(startup, "main startup", "");
#ifdef Q_OS_LINUX
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
#endif
@ -235,7 +257,18 @@ int main(int argc, const char* argv[]) {
argvExtended.push_back("--ignore-gpu-blacklist");
int argcExtended = (int)argvExtended.size();
PROFILE_SYNC_END(startup, "main startup", "");
PROFILE_SYNC_BEGIN(startup, "app full ctor", "");
Application app(argcExtended, const_cast<char**>(argvExtended.data()), startupTime, runningMarkerExisted);
PROFILE_SYNC_END(startup, "app full ctor", "");
QTimer exitTimer;
if (traceDuration > 0.0f) {
exitTimer.setSingleShot(true);
QObject::connect(&exitTimer, &QTimer::timeout, &app, &Application::quit);
exitTimer.start(int(1000 * traceDuration));
}
#if 0
// If we failed the OpenGLVersion check, log it.
@ -273,6 +306,11 @@ int main(int argc, const char* argv[]) {
qCDebug(interfaceapp, "Created QT Application.");
exitCode = app.exec();
server.close();
if (traceFile != nullptr) {
tracer->stopTracing();
tracer->serialize(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/" + traceFile);
}
}
Application::shutdownPlugins();

View file

@ -24,6 +24,36 @@ class QScriptEngine;
#include <QReadWriteLock>
/**jsdoc
* The HMD API provides access to the HMD used in VR display mode.
*
* @namespace HMD
* @property {Vec3} position - The position of the HMD if currently in VR display mode, otherwise
* {@link Vec3(0)|Vec3.ZERO}. <em>Read-only.</em>
* @property {Quat} orientation - The orientation of the HMD if currently in VR display mode, otherwise
* {@link Quat(0)|Quat.IDENTITY}. <em>Read-only.</em>
* @property {boolean} active - <code>true</code> if the display mode is HMD, otherwise <code>false</code>. <em>Read-only.</em>
* @property {boolean} mounted - <code>true</code> if currently in VR display mode and the HMD is being worn, otherwise
* <code>false</code>. <em>Read-only.</em>
*
* @property {number} playerHeight - The real-world height of the user. <em>Read-only.</em> <em>Currently always returns a
* value of <code>1.755</code>.</em>
* @property {number} eyeHeight - The real-world height of the user's eyes. <em>Read-only.</em> <em>Currently always returns a
* value of <code>1.655</code>.</em>
* @property {number} ipd - The inter-pupillary distance (distance between eyes) of the user, used for rendering. Defaults to
* the human average of <code>0.064</code> unless set by the HMD. <em>Read-only.</em>
* @property {number} ipdScale=1.0 - A scale factor applied to the <code>ipd</code> property value.
*
* @property {boolean} showTablet - <code>true</code> if the tablet is being displayed, <code>false</code> otherwise.
* <em>Read-only.</em>
* @property {boolean} tabletContextualMode - <code>true</code> if the tablet has been opened in contextual mode, otherwise
* <code>false</code>. In contextual mode, the tablet has been opened at a specific world position and orientation rather
* than at a position and orientation relative to the user. <em>Read-only.</em>
* @property {Uuid} tabletID - The UUID of the tablet body model overlay.
* @property {Uuid} tabletScreenID - The UUID of the tablet's screen overlay.
* @property {Uuid} homeButtonID - The UUID of the tablet's "home" button overlay.
* @property {Uuid} homeButtonHighlightID - The UUID of the tablet's "home" button highlight overlay.
*/
class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency {
Q_OBJECT
Q_PROPERTY(glm::vec3 position READ getPosition)
@ -37,26 +67,217 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen
Q_PROPERTY(QUuid tabletScreenID READ getCurrentTabletScreenID WRITE setCurrentTabletScreenID)
public:
/**jsdoc
* Calculate the intersection of a ray with the HUD overlay.
* @function HMD.calculateRayUICollisionPoint
* @param {Vec3} position - The origin of the ray.
* @param {Vec3} direction - The direction of the ray.
* @returns {Vec3} The point of intersection with the HUD overlay if it intersects, otherwise {@link Vec3(0)|Vec3.ZERO}.
* @example <caption>Draw a square on the HUD overlay in the direction you're looking.</caption>
* var hudIntersection = HMD.calculateRayUICollisionPoint(MyAvatar.getHeadPosition(),
* Quat.getForward(MyAvatar.headOrientation));
* var hudPoint = HMD.overlayFromWorldPoint(hudIntersection);
*
* var DIMENSIONS = { x: 50, y: 50 };
* var square = Overlays.addOverlay("rectangle", {
* x: hudPoint.x - DIMENSIONS.x / 2,
* y: hudPoint.y - DIMENSIONS.y / 2,
* width: DIMENSIONS.x,
* height: DIMENSIONS.y,
* color: { red: 255, green: 0, blue: 0 }
* });
*
* Script.scriptEnding.connect(function () {
* Overlays.deleteOverlay(square);
* });
*/
Q_INVOKABLE glm::vec3 calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction) const;
/**jsdoc
* Get the 2D HUD overlay coordinates of a 3D point on the HUD overlay.
* 2D HUD overlay coordinates are pixels with the origin at the top left of the overlay.
* @function HMD.overlayFromWorldPoint
* @param {Vec3} position - The point on the HUD overlay in world coordinates.
* @returns {Vec2} The point on the HUD overlay in HUD coordinates.
* @example <caption>Draw a square on the HUD overlay in the direction you're looking.</caption>
* var hudIntersection = HMD.calculateRayUICollisionPoint(MyAvatar.getHeadPosition(),
* Quat.getForward(MyAvatar.headOrientation));
* var hudPoint = HMD.overlayFromWorldPoint(hudIntersection);
*
* var DIMENSIONS = { x: 50, y: 50 };
* var square = Overlays.addOverlay("rectangle", {
* x: hudPoint.x - DIMENSIONS.x / 2,
* y: hudPoint.y - DIMENSIONS.y / 2,
* width: DIMENSIONS.x,
* height: DIMENSIONS.y,
* color: { red: 255, green: 0, blue: 0 }
* });
*
* Script.scriptEnding.connect(function () {
* Overlays.deleteOverlay(square);
* });
*/
Q_INVOKABLE glm::vec2 overlayFromWorldPoint(const glm::vec3& position) const;
/**jsdoc
* Get the 3D world coordinates of a 2D point on the HUD overlay.
* 2D HUD overlay coordinates are pixels with the origin at the top left of the overlay.
* @function HMD.worldPointFromOverlay
* @param {Vec2} coordinates - The point on the HUD overlay in HUD coordinates.
* @returns {Vec3} The point on the HUD overlay in world coordinates.
*/
Q_INVOKABLE glm::vec3 worldPointFromOverlay(const glm::vec2& overlay) const;
/**jsdoc
* Get the 2D point on the HUD overlay represented by given spherical coordinates.
* 2D HUD overlay coordinates are pixels with the origin at the top left of the overlay.
* Spherical coordinates are polar coordinates in radians with <code>{ x: 0, y: 0 }</code> being the center of the HUD
* overlay.
* @function HMD.sphericalToOverlay
* @param {Vec2} sphericalPos - The point on the HUD overlay in spherical coordinates.
* @returns {Vec2} The point on the HUD overlay in HUD coordinates.
*/
Q_INVOKABLE glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const;
/**jsdoc
* Get the spherical coordinates of a 2D point on the HUD overlay.
* 2D HUD overlay coordinates are pixels with the origin at the top left of the overlay.
* Spherical coordinates are polar coordinates in radians with <code>{ x: 0, y: 0 }</code> being the center of the HUD
* overlay.
* @function HMD.overlayToSpherical
* @param {Vec2} overlayPos - The point on the HUD overlay in HUD coordinates.
* @returns {Vec2} The point on the HUD overlay in spherical coordinates.
*/
Q_INVOKABLE glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const;
/**jsdoc
* Recenter the HMD HUD to the current HMD position and orientation.
* @function HMD.centerUI
*/
Q_INVOKABLE void centerUI();
/**jsdoc
* Get the name of the HMD audio input device.
* @function HMD.preferredAudioInput
* @returns {string} The name of the HMD audio input device if in HMD mode, otherwise an empty string.
*/
Q_INVOKABLE QString preferredAudioInput() const;
/**jsdoc
* Get the name of the HMD audio output device.
* @function HMD.preferredAudioOutput
* @returns {string} The name of the HMD audio output device if in HMD mode, otherwise an empty string.
*/
Q_INVOKABLE QString preferredAudioOutput() const;
/**jsdoc
* Check whether there is an HMD available.
* @function HMD.isHMDAvailable
* @param {string} [name=""] - The name of the HMD to check for, e.g., <code>"Oculus Rift"</code>. The name is the same as
* may be displayed in Interface's "Display" menu. If no name is specified then any HMD matches.
* @returns {boolean} <code>true</code> if an HMD of the specified <code>name</code> is available, otherwise
* <code>false</code>.
* @example <caption>Report on HMD availability.</caption>
* print("Is any HMD available: " + HMD.isHMDAvailable());
* print("Is an Oculus Rift HMD available: " + HMD.isHMDAvailable("Oculus Rift"));
* print("Is a Vive HMD available: " + HMD.isHMDAvailable("OpenVR (Vive)"));
*/
Q_INVOKABLE bool isHMDAvailable(const QString& name = "");
/**jsdoc
* Check whether there is an HMD head controller available.
* @function HMD.isHeadControllerAvailable
* @param {string} [name=""] - The name of the HMD head controller to check for, e.g., <code>"Oculus"</code>. If no name is
* specified then any HMD head controller matches.
* @returns {boolean} <code>true</code> if an HMD head controller of the specified <code>name</code> is available,
* otherwise <code>false</code>.
* @example <caption>Report HMD head controller availability.</caption>
* print("Is any HMD head controller available: " + HMD.isHeadControllerAvailable());
* print("Is an Oculus head controller available: " + HMD.isHeadControllerAvailable("Oculus"));
* print("Is a Vive head controller available: " + HMD.isHeadControllerAvailable("OpenVR"));
*/
Q_INVOKABLE bool isHeadControllerAvailable(const QString& name = "");
/**jsdoc
* Check whether there are HMD hand controllers available.
* @function HMD.isHandControllerAvailable
* @param {string} [name=""] - The name of the HMD hand controller to check for, e.g., <code>"Oculus"</code>. If no name is
* specified then any HMD hand controller matches.
* @returns {boolean} <code>true</code> if an HMD hand controller of the specified <code>name</code> is available,
* otherwise <code>false</code>.
* @example <caption>Report HMD hand controller availability.</caption>
* print("Are any HMD hand controllers available: " + HMD.isHandControllerAvailable());
* print("Are Oculus hand controllers available: " + HMD.isHandControllerAvailable("Oculus"));
* print("Are Vive hand controllers available: " + HMD.isHandControllerAvailable("OpenVR"));
*/
Q_INVOKABLE bool isHandControllerAvailable(const QString& name = "");
/**jsdoc
* Check whether there are specific HMD controllers available.
* @function HMD.isSubdeviceContainingNameAvailable
* @param {string} name - The name of the HMD controller to check for, e.g., <code>"OculusTouch"</code>.
* @returns {boolean} <code>true</code> if an HMD controller with a name containing the specified <code>name</code> is
* available, otherwise <code>false</code>.
* @example <caption>Report if particular Oculus controllers are available.</caption>
* print("Is an Oculus Touch controller available: " + HMD.isSubdeviceContainingNameAvailable("Touch"));
* print("Is an Oculus Remote controller available: " + HMD.isSubdeviceContainingNameAvailable("Remote"));
*/
Q_INVOKABLE bool isSubdeviceContainingNameAvailable(const QString& name);
/**jsdoc
* Signal that models of the HMD hand controllers being used should be displayed. The models are displayed at their actual,
* real-world locations.
* @function HMD.requestShowHandControllers
* @example <caption>Show your hand controllers for 10 seconds.</caption>
* HMD.requestShowHandControllers();
* Script.setTimeout(function () {
* HMD.requestHideHandControllers();
* }, 10000);
*/
Q_INVOKABLE void requestShowHandControllers();
/**jsdoc
* Signal that it is no longer necessary to display models of the HMD hand controllers being used. If no other scripts
* want the models displayed then they are no longer displayed.
* @function HMD.requestHideHandControllers
*/
Q_INVOKABLE void requestHideHandControllers();
/**jsdoc
* Check whether any script wants models of the HMD hand controllers displayed. Requests are made and canceled using
* {@link HMD.requestShowHandControllers|requestShowHandControllers} and
* {@link HMD.requestHideHandControllers|requestHideHandControllers}.
* @function HMD.shouldShowHandControllers
* @returns {boolean} <code>true</code> if any script is requesting that HMD hand controller models be displayed.
*/
Q_INVOKABLE bool shouldShowHandControllers() const;
/**jsdoc
* Causes the borders in HUD windows to be enlarged when the laser intersects them in HMD mode. By default, borders are not
* enlarged.
* @function HMD.activateHMDHandMouse
*/
Q_INVOKABLE void activateHMDHandMouse();
/**jsdoc
* Causes the border in HUD windows to no longer be enlarged when the laser intersects them in HMD mode. By default,
* borders are not enlarged.
* @function HMD.deactivateHMDHandMouse
*/
Q_INVOKABLE void deactivateHMDHandMouse();
/**jsdoc
* Suppress the activation of the HMD-provided keyboard, if any. Successful calls should be balanced with a call to
* {@link HMD.unspressKeyboard|unspressKeyboard} within a reasonable amount of time.
* @function HMD.suppressKeyboard
* @returns {boolean} <code>true</code> if the current HMD provides a keyboard and it was successfully suppressed (e.g., it
* isn't being displayed), otherwise <code>false</code>.
*/
/// Suppress the activation of any on-screen keyboard so that a script operation will
/// not be interrupted by a keyboard popup
/// Returns false if there is already an active keyboard displayed.
@ -65,21 +286,68 @@ public:
/// call to unsuppressKeyboard() within a reasonable amount of time
Q_INVOKABLE bool suppressKeyboard();
/**jsdoc
* Unsuppress the activation of the HMD-provided keyboard, if any.
* @function HMD.unsuppressKeyboard
*/
/// Enable the keyboard following a suppressKeyboard call
Q_INVOKABLE void unsuppressKeyboard();
/**jsdoc
* Check whether the HMD-provided keyboard, if any, is visible.
* @function HMD.isKeyboardVisible
* @returns {boolean} <code>true</code> if the current HMD provides a keyboard and it is visible, otherwise
* <code>false</code>.
*/
/// Query the display plugin to determine the current VR keyboard visibility
Q_INVOKABLE bool isKeyboardVisible();
// rotate the overlay UI sphere so that it is centered about the the current HMD position and orientation
Q_INVOKABLE void centerUI();
/**jsdoc
* Closes the tablet if it is open.
* @function HMD.closeTablet
*/
Q_INVOKABLE void closeTablet();
/**jsdoc
* Opens the tablet if the tablet is used in the current display mode and it isn't already showing, and sets the tablet to
* contextual mode if requested. In contextual mode, the page displayed on the tablet is wholly controlled by script (i.e.,
* the user cannot navigate to another).
* @function HMD.openTablet
* @param {boolean} [contextualMode=false] - If <code>true</code> then the tablet is opened at a specific position and
* orientation already set by the script, otherwise it opens at a position and orientation relative to the user. For
* contextual mode, set the world or local position and orientation of the <code>HMD.tabletID</code> overlay.
*/
Q_INVOKABLE void openTablet(bool contextualMode = false);
signals:
/**jsdoc
* Triggered when a request to show or hide models of the HMD hand controllers is made using
* {@link HMD.requestShowHandControllers|requestShowHandControllers} or
* {@link HMD.requestHideHandControllers|requestHideHandControllers}.
* @function HMD.shouldShowHandControllersChanged
* @returns {Signal}
* @example <caption>Report when showing of hand controllers changes.</caption>
* function onShouldShowHandControllersChanged() {
* print("Should show hand controllers: " + HMD.shouldShowHandControllers());
* }
* HMD.shouldShowHandControllersChanged.connect(onShouldShowHandControllersChanged);
*
* HMD.requestShowHandControllers();
* Script.setTimeout(function () {
* HMD.requestHideHandControllers();
* }, 10000);
*/
bool shouldShowHandControllersChanged();
/**jsdoc
* Triggered when the <code>HMD.mounted</code> property value changes.
* @function HMD.mountedChanged
* @returns {Signal}
* @example <caption>Report when there's a change in the HMD being worn.</caption>
* HMD.mountedChanged.connect(function () {
* print("Mounted changed. HMD is mounted: " + HMD.mounted);
* });
*/
void mountedChanged();
public:

View file

@ -12,6 +12,7 @@
#include <GLMHelpers.h>
// These properties have JSDoc documentation in HMDScriptingInterface.h.
class AbstractHMDScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(bool active READ isHMDMode)
@ -30,7 +31,27 @@ public:
bool isHMDMode() const;
signals:
/**jsdoc
* Triggered when the <code>HMD.ipdScale</code> property value changes.
* @function HMD.IPDScaleChanged
* @returns {Signal}
*/
void IPDScaleChanged();
/**jsdoc
* Triggered when Interface's display mode changes and when the user puts on or takes off their HMD.
* @function HMD.displayModeChanged
* @param {boolean} isHMDMode - <code>true</code> if the display mode is HMD, otherwise <code>false</code>. This is the
* same value as provided by <code>HMD.active</code>.
* @returns {Signal}
* @example <caption>Report when the display mode changes.</caption>
* HMD.displayModeChanged.connect(function (isHMDMode) {
* print("Display mode changed");
* print("isHMD = " + isHMDMode);
* print("HMD.active = " + HMD.active);
* print("HMD.mounted = " + HMD.mounted);
* });
*/
void displayModeChanged(bool isHMDMode);
private:

View file

@ -18,6 +18,9 @@
#include "render-utils/simple_vert.h"
#include "render-utils/simple_frag.h"
#include "render-utils/simple_transparent_frag.h"
#include "render-utils/forward_simple_frag.h"
#include "render-utils/forward_simple_transparent_frag.h"
#include "RenderPipelines.h"
@ -35,13 +38,23 @@ static const float SPHERE_ENTITY_SCALE = 0.5f;
ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
_procedural._vertexSource = simple_vert::getSource();
_procedural._fragmentSource = simple_frag::getSource();
// FIXME: Setup proper uniform slots and use correct pipelines for forward rendering
_procedural._opaquefragmentSource = simple_frag::getSource();
// FIXME: Transparent procedural entities only seem to work if they use the opaque pipelines
//_procedural._transparentfragmentSource = simple_transparent_frag::getSource();
_procedural._transparentfragmentSource = simple_frag::getSource();
_procedural._opaqueState->setCullMode(gpu::State::CULL_NONE);
_procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*_procedural._opaqueState);
_procedural._opaqueState->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_procedural._transparentState->setCullMode(gpu::State::CULL_BACK);
_procedural._transparentState->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMask(*_procedural._transparentState);
_procedural._transparentState->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
}
bool ShapeEntityRenderer::needsRenderUpdate() const {
@ -218,9 +231,9 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
if (mat) {
outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity());
if (_procedural.isReady()) {
_procedural.prepare(batch, _position, _dimensions, _orientation);
outColor = _procedural.getColor(outColor);
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f;
_procedural.prepare(batch, _position, _dimensions, _orientation, outColor);
proceduralRender = true;
}
}

View file

@ -477,18 +477,19 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {boolean} visible=true - Whether or not the entity is rendered. If <code>true</code> then the entity is rendered.
* @property {boolean} canCastShadows=true - Whether or not the entity casts shadows. Currently applicable only to
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities. Shadows are cast if inside a
* {@link Entities.EntityType|Zone} entity with <code>castShadows</code> enabled in its {@link Entities.EntityProperties-Zone|keyLight} property.
* {@link Entities.EntityType|Zone} entity with <code>castShadows</code> enabled in its
* {@link Entities.EntityProperties-Zone|keyLight} property.
*
* @property {Vec3} position=0,0,0 - The position of the entity.
* @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates.
* @property {Vec3} registrationPoint=0.5,0.5,0.5 - The point in the entity that is set to the entity's position and is rotated
* about, {@link Vec3|Vec3.ZERO} &ndash; {@link Vec3|Vec3.ONE}. A value of {@link Vec3|Vec3.ZERO} is the entity's
* minimum x, y, z corner; a value of {@link Vec3|Vec3.ONE} is the entity's maximum x, y, z corner.
* about, {@link Vec3(0)|Vec3.ZERO} &ndash; {@link Vec3(0)|Vec3.ONE}. A value of {@link Vec3(0)|Vec3.ZERO} is the entity's
* minimum x, y, z corner; a value of {@link Vec3(0)|Vec3.ONE} is the entity's maximum x, y, z corner.
*
* @property {Vec3} naturalPosition=0,0,0 - The center of the entity's unscaled mesh model if it has one, otherwise
* {@link Vec3|Vec3.ZERO}. <em>Read-only.</em>
* {@link Vec3(0)|Vec3.ZERO}. <em>Read-only.</em>
* @property {Vec3} naturalDimensions - The dimensions of the entity's unscaled mesh model if it has one, otherwise
* {@link Vec3|Vec3.ONE}. <em>Read-only.</em>
* {@link Vec3(0)|Vec3.ONE}. <em>Read-only.</em>
*
* @property {Vec3} velocity=0,0,0 - The linear velocity of the entity in m/s with respect to world coordinates.
* @property {number} damping=0.39347 - How much to slow down the linear velocity of an entity over time, <code>0.0</code>
@ -505,13 +506,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {Vec3} gravity=0,0,0 - The acceleration due to gravity in m/s<sup>2</sup> that the entity should move with, in
* world coordinates. Set to <code>{ x: 0, y: -9.8, z: 0 }</code> to simulate Earth's gravity. Gravity is applied to an
* entity's motion only if its <code>dynamic</code> property is <code>true</code>. If changing an entity's
* <code>gravity</code> from {@link Vec3|Vec3.ZERO}, you need to give it a small <code>velocity</code> in order to kick off
* physics simulation.
* <code>gravity</code> from {@link Vec3(0)|Vec3.ZERO}, you need to give it a small <code>velocity</code> in order to kick
* off physics simulation.
* The <code>gravity</code> value is applied in addition to the <code>acceleration</code> value.
* @property {Vec3} acceleration=0,0,0 - A general acceleration in m/s<sup>2</sup> that the entity should move with, in world
* coordinates. The acceleration is applied to an entity's motion only if its <code>dynamic</code> property is
* <code>true</code>. If changing an entity's <code>acceleration</code> from {@link Vec3|Vec3.ZERO}, you need to give it a
* small <code>velocity</code> in order to kick off physics simulation.
* <code>true</code>. If changing an entity's <code>acceleration</code> from {@link Vec3(0)|Vec3.ZERO}, you need to give it
* a small <code>velocity</code> in order to kick off physics simulation.
* The <code>acceleration</code> value is applied in addition to the <code>gravity</code> value.
* @property {number} restitution=0.5 - The "bounciness" of an entity when it collides, <code>0.0</code> &ndash;
* <code>0.99</code>. The higher the value, the more bouncy.

View file

@ -694,7 +694,7 @@ public slots:
* @param {Uuid} entityID - The ID of the {@link Entities.EntityType|PolyVox} entity.
* @param {Vec3} voxelCoords - The voxel coordinates. May be fractional and outside the entity's bounding box.
* @returns {Vec3} The world coordinates of the <code>voxelCoords</code> if the <code>entityID</code> is a
* {@link Entities.EntityType|PolyVox} entity, otherwise {@link Vec3|Vec3.ZERO}.
* {@link Entities.EntityType|PolyVox} entity, otherwise {@link Vec3(0)|Vec3.ZERO}.
* @example <caption>Create a PolyVox cube with the 0,0,0 voxel replaced by a sphere.</caption>
* // Cube PolyVox with 0,0,0 voxel missing.
* var polyVox = Entities.addEntity({
@ -729,7 +729,7 @@ public slots:
* @param {Uuid} entityID - The ID of the {@link Entities.EntityType|PolyVox} entity.
* @param {Vec3} worldCoords - The world coordinates. May be outside the entity's bounding box.
* @returns {Vec3} The voxel coordinates of the <code>worldCoords</code> if the <code>entityID</code> is a
* {@link Entities.EntityType|PolyVox} entity, otherwise {@link Vec3|Vec3.ZERO}. The value may be fractional.
* {@link Entities.EntityType|PolyVox} entity, otherwise {@link Vec3(0)|Vec3.ZERO}. The value may be fractional.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::vec3 worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords);
@ -741,7 +741,7 @@ public slots:
* @param {Uuid} entityID - The ID of the {@link Entities.EntityType|PolyVox} entity.
* @param {Vec3} voxelCoords - The voxel coordinates. May be fractional and outside the entity's bounding box.
* @returns {Vec3} The local coordinates of the <code>voxelCoords</code> if the <code>entityID</code> is a
* {@link Entities.EntityType|PolyVox} entity, otherwise {@link Vec3|Vec3.ZERO}.
* {@link Entities.EntityType|PolyVox} entity, otherwise {@link Vec3(0)|Vec3.ZERO}.
* @example <caption>Get the world dimensions of a voxel in a PolyVox entity.</caption>
* var polyVox = Entities.addEntity({
* type: "PolyVox",
@ -763,7 +763,7 @@ public slots:
* @param {Uuid} entityID - The ID of the {@link Entities.EntityType|PolyVox} entity.
* @param {Vec3} localCoords - The local coordinates. May be outside the entity's bounding box.
* @returns {Vec3} The voxel coordinates of the <code>worldCoords</code> if the <code>entityID</code> is a
* {@link Entities.EntityType|PolyVox} entity, otherwise {@link Vec3|Vec3.ZERO}. The value may be fractional.
* {@link Entities.EntityType|PolyVox} entity, otherwise {@link Vec3(0)|Vec3.ZERO}. The value may be fractional.
*/
// FIXME move to a renderable entity interface
Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords);

View file

@ -1155,7 +1155,9 @@ void EntityTree::startChallengeOwnershipTimer(const EntityItemID& entityItemID)
});
connect(_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() {
qCDebug(entities) << "Ownership challenge timed out, deleting entity" << entityItemID;
deleteEntity(entityItemID, true);
withWriteLock([&] {
deleteEntity(entityItemID, true);
});
if (_challengeOwnershipTimeoutTimer) {
_challengeOwnershipTimeoutTimer->stop();
_challengeOwnershipTimeoutTimer->deleteLater();
@ -1263,7 +1265,9 @@ void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QStri
if (text == "") {
qCDebug(entities) << "CRITICAL ERROR: Couldn't compute nonce. Deleting entity...";
deleteEntity(entityItemID, true);
withWriteLock([&] {
deleteEntity(entityItemID, true);
});
} else {
qCDebug(entities) << "Challenging ownership of Cert ID" << certID;
// 2. Send the nonce to the rezzing avatar's node
@ -1326,8 +1330,7 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
request["certificate_id"] = certID;
networkRequest.setUrl(requestURL);
QNetworkReply* networkReply = NULL;
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
connect(networkReply, &QNetworkReply::finished, [=]() {
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
@ -1336,14 +1339,20 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
if (networkReply->error() == QNetworkReply::NoError) {
if (!jsonObject["invalid_reason"].toString().isEmpty()) {
qCDebug(entities) << "invalid_reason not empty, deleting entity" << entityItemID;
deleteEntity(entityItemID, true);
withWriteLock([&] {
deleteEntity(entityItemID, true);
});
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
qCDebug(entities) << "'transfer_status' is 'failed', deleting entity" << entityItemID;
deleteEntity(entityItemID, true);
withWriteLock([&] {
deleteEntity(entityItemID, true);
});
} else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
if (isRetryingValidation) {
qCDebug(entities) << "'transfer_status' is 'pending' after retry, deleting entity" << entityItemID;
deleteEntity(entityItemID, true);
withWriteLock([&] {
deleteEntity(entityItemID, true);
});
} else {
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "startPendingTransferStatusTimer",
@ -1366,7 +1375,9 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
} else {
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << entityItemID
<< "More info:" << jsonObject;
deleteEntity(entityItemID, true);
withWriteLock([&] {
deleteEntity(entityItemID, true);
});
}
networkReply->deleteLater();
@ -1800,9 +1811,9 @@ void EntityTree::addToNeedsParentFixupList(EntityItemPointer entity) {
void EntityTree::update(bool simulate) {
PROFILE_RANGE(simulation_physics, "UpdateTree");
fixupNeedsParentFixups();
if (simulate && _simulation) {
withWriteLock([&] {
withWriteLock([&] {
fixupNeedsParentFixups();
if (simulate && _simulation) {
_simulation->updateEntities();
{
PROFILE_RANGE(simulation_physics, "Deletes");
@ -1820,8 +1831,8 @@ void EntityTree::update(bool simulate) {
deleteEntities(idsToDelete, true);
}
}
});
}
}
});
}
quint64 EntityTree::getAdjustedConsiderSince(quint64 sinceTime) {
@ -2290,7 +2301,9 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer
QScriptEngine scriptEngine;
RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues,
skipThoseWithBadParents, _myAvatar);
recurseTreeWithOperator(&theOperator);
withReadLock([&] {
recurseTreeWithOperator(&theOperator);
});
return true;
}

View file

@ -37,8 +37,13 @@ void SimpleEntitySimulation::clearOwnership(const QUuid& ownerID) {
// remove ownership and dirty all the tree elements that contain the it
entity->clearSimulationOwnership();
entity->markAsChangedOnServer();
DirtyOctreeElementOperator op(entity->getElement());
getEntityTree()->recurseTreeWithOperator(&op);
if (auto element = entity->getElement()) {
auto tree = getEntityTree();
tree->withReadLock([&] {
DirtyOctreeElementOperator op(element);
tree->recurseTreeWithOperator(&op);
});
}
} else {
++itemItr;
}

View file

@ -129,6 +129,7 @@ void Context::executeFrame(const FramePointer& frame) const {
}
bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler) {
PROFILE_RANGE_EX(app, "makeProgram", 0xff4040c0, shader.getID());
// If we're running in another DLL context, we need to fetch the program callback out of the application
// FIXME find a way to do this without reliance on Qt app properties
if (!_makeProgramCallback) {

View file

@ -75,6 +75,7 @@ Shader::Pointer Shader::createGeometry(const Source& source) {
}
ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
PROFILE_RANGE(app, "createOrReuseProgramShader");
ProgramMapKey key(0);
if (vertexShader && vertexShader->getType() == VERTEX) {

View file

@ -219,7 +219,29 @@ bool Procedural::isReady() const {
return true;
}
void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation) {
std::string Procedural::replaceProceduralBlock(const std::string& fragmentSource) {
std::string fragmentShaderSource = fragmentSource;
size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK);
if (replaceIndex != std::string::npos) {
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), ProceduralCommon_frag::getSource());
}
replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION);
if (replaceIndex != std::string::npos) {
if (_data.version == 1) {
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V1 1");
} else if (_data.version == 2) {
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V2 1");
}
}
replaceIndex = fragmentShaderSource.find(PROCEDURAL_BLOCK);
if (replaceIndex != std::string::npos) {
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data());
}
return fragmentShaderSource;
}
void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const glm::vec4& color) {
_entityDimensions = size;
_entityPosition = position;
_entityOrientation = glm::mat3_cast(orientation);
@ -242,58 +264,48 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
}
// Build the fragment shader
std::string fragmentShaderSource = _fragmentSource;
size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK);
if (replaceIndex != std::string::npos) {
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), ProceduralCommon_frag::getSource());
}
replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION);
if (replaceIndex != std::string::npos) {
if (_data.version == 1) {
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V1 1");
} else if (_data.version == 2) {
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V2 1");
}
}
replaceIndex = fragmentShaderSource.find(PROCEDURAL_BLOCK);
if (replaceIndex != std::string::npos) {
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data());
}
std::string opaqueShaderSource = replaceProceduralBlock(_opaquefragmentSource);
std::string transparentShaderSource = replaceProceduralBlock(_transparentfragmentSource);
// Leave this here for debugging
// qCDebug(procedural) << "FragmentShader:\n" << fragmentShaderSource.c_str();
_fragmentShader = gpu::Shader::createPixel(fragmentShaderSource);
_shader = gpu::Shader::createProgram(_vertexShader, _fragmentShader);
_opaqueFragmentShader = gpu::Shader::createPixel(opaqueShaderSource);
_opaqueShader = gpu::Shader::createProgram(_vertexShader, _opaqueFragmentShader);
_transparentFragmentShader = gpu::Shader::createPixel(transparentShaderSource);
_transparentShader = gpu::Shader::createProgram(_vertexShader, _transparentFragmentShader);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0));
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel1"), 1));
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel2"), 2));
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3));
gpu::Shader::makeProgram(*_shader, slotBindings);
gpu::Shader::makeProgram(*_opaqueShader, slotBindings);
gpu::Shader::makeProgram(*_transparentShader, slotBindings);
_opaquePipeline = gpu::Pipeline::create(_shader, _opaqueState);
_transparentPipeline = gpu::Pipeline::create(_shader, _transparentState);
_opaquePipeline = gpu::Pipeline::create(_opaqueShader, _opaqueState);
_transparentPipeline = gpu::Pipeline::create(_transparentShader, _transparentState);
for (size_t i = 0; i < NUM_STANDARD_UNIFORMS; ++i) {
const std::string& name = STANDARD_UNIFORM_NAMES[i];
_standardUniformSlots[i] = _shader->getUniforms().findLocation(name);
_standardOpaqueUniformSlots[i] = _opaqueShader->getUniforms().findLocation(name);
_standardTransparentUniformSlots[i] = _transparentShader->getUniforms().findLocation(name);
}
_start = usecTimestampNow();
_frameCount = 0;
}
batch.setPipeline(isFading() ? _transparentPipeline : _opaquePipeline);
bool transparent = color.a < 1.0f;
batch.setPipeline(transparent ? _transparentPipeline : _opaquePipeline);
if (_shaderDirty || _uniformsDirty) {
setupUniforms();
if (_shaderDirty || _uniformsDirty || _prevTransparent != transparent) {
setupUniforms(transparent);
}
if (_shaderDirty || _uniformsDirty || _channelsDirty) {
setupChannels(_shaderDirty || _uniformsDirty);
if (_shaderDirty || _uniformsDirty || _channelsDirty || _prevTransparent != transparent) {
setupChannels(_shaderDirty || _uniformsDirty, transparent);
}
_prevTransparent = transparent;
_shaderDirty = _uniformsDirty = _channelsDirty = false;
for (auto lambda : _uniforms) {
@ -319,12 +331,12 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
}
}
void Procedural::setupUniforms() {
void Procedural::setupUniforms(bool transparent) {
_uniforms.clear();
// Set any userdata specified uniforms
foreach(QString key, _data.uniforms.keys()) {
std::string uniformName = key.toLocal8Bit().data();
int32_t slot = _shader->getUniforms().findLocation(uniformName);
int32_t slot = (transparent ? _transparentShader : _opaqueShader)->getUniforms().findLocation(uniformName);
if (gpu::Shader::INVALID_LOCATION == slot) {
continue;
}
@ -385,15 +397,17 @@ void Procedural::setupUniforms() {
}
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[TIME]) {
auto uniformSlots = transparent ? _standardTransparentUniformSlots : _standardOpaqueUniformSlots;
if (gpu::Shader::INVALID_LOCATION != uniformSlots[TIME]) {
_uniforms.push_back([=](gpu::Batch& batch) {
// Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds
float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND;
batch._glUniform(_standardUniformSlots[TIME], time);
batch._glUniform(uniformSlots[TIME], time);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[DATE]) {
if (gpu::Shader::INVALID_LOCATION != uniformSlots[DATE]) {
_uniforms.push_back([=](gpu::Batch& batch) {
QDateTime now = QDateTime::currentDateTimeUtc();
QDate date = now.date();
@ -406,40 +420,41 @@ void Procedural::setupUniforms() {
v.z = date.day();
float fractSeconds = (time.msec() / 1000.0f);
v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds;
batch._glUniform(_standardUniformSlots[DATE], v);
batch._glUniform(uniformSlots[DATE], v);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[FRAME_COUNT]) {
if (gpu::Shader::INVALID_LOCATION != uniformSlots[FRAME_COUNT]) {
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform(_standardUniformSlots[FRAME_COUNT], ++_frameCount);
batch._glUniform(uniformSlots[FRAME_COUNT], ++_frameCount);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[SCALE]) {
if (gpu::Shader::INVALID_LOCATION != uniformSlots[SCALE]) {
// FIXME move into the 'set once' section, since this doesn't change over time
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform(_standardUniformSlots[SCALE], _entityDimensions);
batch._glUniform(uniformSlots[SCALE], _entityDimensions);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[ORIENTATION]) {
if (gpu::Shader::INVALID_LOCATION != uniformSlots[ORIENTATION]) {
// FIXME move into the 'set once' section, since this doesn't change over time
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform(_standardUniformSlots[ORIENTATION], _entityOrientation);
batch._glUniform(uniformSlots[ORIENTATION], _entityOrientation);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[POSITION]) {
if (gpu::Shader::INVALID_LOCATION != uniformSlots[POSITION]) {
// FIXME move into the 'set once' section, since this doesn't change over time
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform(_standardUniformSlots[POSITION], _entityPosition);
batch._glUniform(uniformSlots[POSITION], _entityPosition);
});
}
}
void Procedural::setupChannels(bool shouldCreate) {
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[CHANNEL_RESOLUTION]) {
void Procedural::setupChannels(bool shouldCreate, bool transparent) {
auto uniformSlots = transparent ? _standardTransparentUniformSlots : _standardOpaqueUniformSlots;
if (gpu::Shader::INVALID_LOCATION != uniformSlots[CHANNEL_RESOLUTION]) {
if (!shouldCreate) {
// Instead of modifying the last element, just remove and recreate it.
_uniforms.pop_back();
@ -451,7 +466,7 @@ void Procedural::setupChannels(bool shouldCreate) {
channelSizes[i] = vec3(_channels[i]->getWidth(), _channels[i]->getHeight(), 1.0);
}
}
batch._glUniform3fv(_standardUniformSlots[CHANNEL_RESOLUTION], MAX_PROCEDURAL_TEXTURE_CHANNELS, &channelSizes[0].x);
batch._glUniform3fv(uniformSlots[CHANNEL_RESOLUTION], MAX_PROCEDURAL_TEXTURE_CHANNELS, &channelSizes[0].x);
});
}
}

View file

@ -55,8 +55,8 @@ public:
bool isReady() const;
bool isEnabled() const { return _enabled; }
void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation);
const gpu::ShaderPointer& getShader() const { return _shader; }
void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const glm::vec4& color = glm::vec4(1));
const gpu::ShaderPointer& getOpaqueShader() const { return _opaqueShader; }
glm::vec4 getColor(const glm::vec4& entityColor);
quint64 getFadeStartTime() const { return _fadeStartTime; }
@ -65,7 +65,8 @@ public:
void setDoesFade(bool doesFade) { _doesFade = doesFade; }
std::string _vertexSource;
std::string _fragmentSource;
std::string _opaquefragmentSource;
std::string _transparentfragmentSource;
gpu::StatePointer _opaqueState { std::make_shared<gpu::State>() };
gpu::StatePointer _transparentState { std::make_shared<gpu::State>() };
@ -101,13 +102,16 @@ protected:
// Rendering objects
UniformLambdas _uniforms;
int32_t _standardUniformSlots[NUM_STANDARD_UNIFORMS];
int32_t _standardOpaqueUniformSlots[NUM_STANDARD_UNIFORMS];
int32_t _standardTransparentUniformSlots[NUM_STANDARD_UNIFORMS];
NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
gpu::PipelinePointer _opaquePipeline;
gpu::PipelinePointer _transparentPipeline;
gpu::ShaderPointer _vertexShader;
gpu::ShaderPointer _fragmentShader;
gpu::ShaderPointer _shader;
gpu::ShaderPointer _opaqueFragmentShader;
gpu::ShaderPointer _transparentFragmentShader;
gpu::ShaderPointer _opaqueShader;
gpu::ShaderPointer _transparentShader;
// Entity metadata
glm::vec3 _entityDimensions;
@ -116,13 +120,16 @@ protected:
private:
// This should only be called from the render thread, as it shares data with Procedural::prepare
void setupUniforms();
void setupChannels(bool shouldCreate);
void setupUniforms(bool transparent);
void setupChannels(bool shouldCreate, bool transparent);
std::string replaceProceduralBlock(const std::string& fragmentSource);
mutable quint64 _fadeStartTime { 0 };
mutable bool _hasStartedFade { false };
mutable bool _isFading { false };
bool _doesFade { true };
bool _prevTransparent { false };
};
#endif

View file

@ -20,7 +20,7 @@
ProceduralSkybox::ProceduralSkybox() : graphics::Skybox() {
_procedural._vertexSource = skybox_vert::getSource();
_procedural._fragmentSource = skybox_frag::getSource();
_procedural._opaquefragmentSource = skybox_frag::getSource();
// Adjust the pipeline state for background using the stencil test
_procedural.setDoesFade(false);
// Must match PrepareStencil::STENCIL_BACKGROUND
@ -61,8 +61,8 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum,
auto& procedural = skybox._procedural;
procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat());
auto textureSlot = procedural.getShader()->getTextures().findLocation("cubeMap");
auto bufferSlot = procedural.getShader()->getUniformBuffers().findLocation("skyboxBuffer");
auto textureSlot = procedural.getOpaqueShader()->getTextures().findLocation("cubeMap");
auto bufferSlot = procedural.getOpaqueShader()->getUniformBuffers().findLocation("skyboxBuffer");
skybox.prepare(batch, textureSlot, bufferSlot);
batch.draw(gpu::TRIANGLE_STRIP, 4);
}

View file

@ -27,6 +27,8 @@
#include "impl/SharedObject.h"
#include "impl/TextureCache.h"
#include "Profile.h"
using namespace hifi::qml;
using namespace hifi::qml::impl;
@ -284,6 +286,7 @@ void OffscreenSurface::loadInternal(const QUrl& qmlSource,
bool createNewContext,
QQuickItem* parent,
const QmlContextObjectCallback& callback) {
PROFILE_RANGE_EX(app, "OffscreenSurface::loadInternal", 0xffff00ff, 0, { std::make_pair("url", qmlSource.toDisplayString()) });
if (QThread::currentThread() != thread()) {
qFatal("Called load on a non-surface thread");
}
@ -304,7 +307,11 @@ void OffscreenSurface::loadInternal(const QUrl& qmlSource,
}
auto targetContext = contextForUrl(finalQmlSource, parent, createNewContext);
auto qmlComponent = new QQmlComponent(getSurfaceContext()->engine(), finalQmlSource, QQmlComponent::PreferSynchronous);
QQmlComponent* qmlComponent;
{
PROFILE_RANGE(app, "new QQmlComponent");
qmlComponent = new QQmlComponent(getSurfaceContext()->engine(), finalQmlSource, QQmlComponent::PreferSynchronous);
}
if (qmlComponent->isLoading()) {
connect(qmlComponent, &QQmlComponent::statusChanged, this,
[=](QQmlComponent::Status) { finishQmlLoad(qmlComponent, targetContext, parent, callback); });
@ -318,6 +325,7 @@ void OffscreenSurface::finishQmlLoad(QQmlComponent* qmlComponent,
QQmlContext* qmlContext,
QQuickItem* parent,
const QmlContextObjectCallback& callback) {
PROFILE_RANGE(app, "finishQmlLoad");
disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0);
if (qmlComponent->isError()) {
for (const auto& error : qmlComponent->errors()) {

View file

@ -105,7 +105,10 @@ void SharedObject::create(OffscreenSurface* surface) {
// Create a QML engine.
auto qmlEngine = acquireEngine(surface);
_qmlContext = new QQmlContext(qmlEngine->rootContext(), qmlEngine);
{
PROFILE_RANGE(startup, "new QQmlContext");
_qmlContext = new QQmlContext(qmlEngine->rootContext(), qmlEngine);
}
surface->onRootContextCreated(_qmlContext);
emit surface->rootContextCreated(_qmlContext);
@ -175,6 +178,7 @@ static size_t globalEngineRefCount{ 0 };
#endif
QQmlEngine* SharedObject::acquireEngine(OffscreenSurface* surface) {
PROFILE_RANGE(startup, "acquireEngine");
Q_ASSERT(QThread::currentThread() == qApp->thread());
QQmlEngine* result = nullptr;

View file

@ -0,0 +1,23 @@
<!
// DefaultMaterials.slh
// libraries/render-utils/src
//
// Created by Sam Gondelman on 3/22/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
!>
<@if not DEFAULT_MATERIAL_SLH@>
<@def DEFAULT_MATERIAL_SLH@>
const float DEFAULT_ROUGHNESS = 0.9;
const float DEFAULT_SHININESS = 10.0;
const float DEFAULT_METALLIC = 0.0;
const vec3 DEFAULT_SPECULAR = vec3(0.1);
const vec3 DEFAULT_EMISSIVE = vec3(0.0);
const float DEFAULT_OCCLUSION = 1.0;
const float DEFAULT_SCATTERING = 0.0;
const vec3 DEFAULT_FRESNEL = DEFAULT_EMISSIVE;
<@endif@>

View file

@ -26,14 +26,7 @@ float evalOpaqueFinalAlpha(float alpha, float mapAlpha) {
return mix(alpha, 1.0 - alpha, step(mapAlpha, alphaThreshold));
}
const float DEFAULT_ROUGHNESS = 0.9;
const float DEFAULT_SHININESS = 10.0;
const float DEFAULT_METALLIC = 0.0;
const vec3 DEFAULT_SPECULAR = vec3(0.1);
const vec3 DEFAULT_EMISSIVE = vec3(0.0);
const float DEFAULT_OCCLUSION = 1.0;
const float DEFAULT_SCATTERING = 0.0;
const vec3 DEFAULT_FRESNEL = DEFAULT_EMISSIVE;
<@include DefaultMaterials.slh@>
void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 emissive, float occlusion, float scattering) {
if (alpha != 1.0) {

View file

@ -40,6 +40,7 @@
#include "simple_vert.h"
#include "simple_textured_frag.h"
#include "simple_transparent_textured_frag.h"
#include "simple_textured_unlit_frag.h"
#include "simple_fade_vert.h"
#include "simple_textured_fade_frag.h"
@ -49,6 +50,19 @@
#include "glowLine_vert.h"
#include "glowLine_frag.h"
#include "forward_simple_textured_frag.h"
#include "forward_simple_textured_transparent_frag.h"
#include "forward_simple_textured_unlit_frag.h"
#include "DeferredLightingEffect.h"
#if defined(USE_GLES)
static bool DISABLE_DEFERRED = true;
#else
static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" };
static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
#endif
#include "grid_frag.h"
//#define WANT_DEBUG
@ -679,6 +693,7 @@ gpu::Stream::FormatPointer& getInstancedSolidFadeStreamFormat() {
QHash<SimpleProgramKey, gpu::PipelinePointer> GeometryCache::_simplePrograms;
gpu::ShaderPointer GeometryCache::_simpleShader;
gpu::ShaderPointer GeometryCache::_transparentShader;
gpu::ShaderPointer GeometryCache::_unlitShader;
gpu::ShaderPointer GeometryCache::_simpleFadeShader;
gpu::ShaderPointer GeometryCache::_unlitFadeShader;
@ -774,8 +789,12 @@ render::ShapePipelinePointer GeometryCache::getShapePipeline(bool textured, bool
bool unlit, bool depthBias) {
return std::make_shared<render::ShapePipeline>(getSimplePipeline(textured, transparent, culled, unlit, depthBias, false, true), nullptr,
[](const render::ShapePipeline& , gpu::Batch& batch, render::Args*) {
[](const render::ShapePipeline& pipeline, gpu::Batch& batch, render::Args* args) {
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, DependencyManager::get<TextureCache>()->getWhiteTexture());
DependencyManager::get<DeferredLightingEffect>()->setupKeyLightBatch(args, batch,
pipeline.pipeline->getProgram()->getUniformBuffers().findLocation("keyLightBuffer"),
pipeline.pipeline->getProgram()->getUniformBuffers().findLocation("lightAmbientBuffer"),
pipeline.pipeline->getProgram()->getUniformBuffers().findLocation("skyboxMap"));
}
);
}
@ -798,7 +817,7 @@ render::ShapePipelinePointer GeometryCache::getOpaqueShapePipeline(bool isFading
return isFading ? _simpleOpaqueFadePipeline : _simpleOpaquePipeline;
}
render::ShapePipelinePointer GeometryCache::getTransparentShapePipeline(bool isFading) {
render::ShapePipelinePointer GeometryCache::getTransparentShapePipeline(bool isFading) {
return isFading ? _simpleTransparentFadePipeline : _simpleTransparentPipeline;
}
@ -843,7 +862,7 @@ void GeometryCache::renderWireShapeInstances(gpu::Batch& batch, Shape shape, siz
_shapes[shape].drawWireInstances(batch, count);
}
void setupBatchFadeInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer,
void setupBatchFadeInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer,
gpu::BufferPointer fadeBuffer1, gpu::BufferPointer fadeBuffer2, gpu::BufferPointer fadeBuffer3) {
gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);
gpu::BufferView texCoord2View(fadeBuffer1, TEXCOORD4_ELEMENT);
@ -2003,7 +2022,7 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const
auto program = gpu::Shader::createProgram(VS, PS);
state->setCullMode(gpu::State::CULL_NONE);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setBlendFunction(true,
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
@ -2231,29 +2250,41 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
static std::once_flag once;
std::call_once(once, [&]() {
auto VS = simple_vert::getShader();
auto PS = simple_textured_frag::getShader();
auto PSUnlit = simple_textured_unlit_frag::getShader();
auto PS = DISABLE_DEFERRED ? forward_simple_textured_frag::getShader() : simple_textured_frag::getShader();
// Use the forward pipeline for both here, otherwise transparents will be unlit
auto PSTransparent = DISABLE_DEFERRED ? forward_simple_textured_transparent_frag::getShader() : forward_simple_textured_transparent_frag::getShader();
auto PSUnlit = DISABLE_DEFERRED ? forward_simple_textured_unlit_frag::getShader() : simple_textured_unlit_frag::getShader();
_simpleShader = gpu::Shader::createProgram(VS, PS);
_transparentShader = gpu::Shader::createProgram(VS, PSTransparent);
_unlitShader = gpu::Shader::createProgram(VS, PSUnlit);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), render::ShapePipeline::Slot::MAP::ALBEDO));
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), render::ShapePipeline::Slot::LIGHTING_MODEL));
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), render::ShapePipeline::Slot::KEY_LIGHT));
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), render::ShapePipeline::Slot::LIGHT_AMBIENT_BUFFER));
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), render::ShapePipeline::Slot::MAP::LIGHT_AMBIENT));
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
gpu::Shader::makeProgram(*_transparentShader, slotBindings);
gpu::Shader::makeProgram(*_unlitShader, slotBindings);
});
} else {
static std::once_flag once;
std::call_once(once, [&]() {
auto VS = simple_fade_vert::getShader();
auto PS = simple_textured_fade_frag::getShader();
auto PSUnlit = simple_textured_unlit_fade_frag::getShader();
auto PS = DISABLE_DEFERRED ? forward_simple_textured_frag::getShader() : simple_textured_fade_frag::getShader();
auto PSUnlit = DISABLE_DEFERRED ? forward_simple_textured_unlit_frag::getShader() : simple_textured_unlit_fade_frag::getShader();
_simpleFadeShader = gpu::Shader::createProgram(VS, PS);
_unlitFadeShader = gpu::Shader::createProgram(VS, PSUnlit);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), render::ShapePipeline::Slot::MAP::ALBEDO));
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), render::ShapePipeline::Slot::LIGHTING_MODEL));
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), render::ShapePipeline::Slot::KEY_LIGHT));
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), render::ShapePipeline::Slot::LIGHT_AMBIENT_BUFFER));
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), render::ShapePipeline::Slot::MAP::LIGHT_AMBIENT));
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), render::ShapePipeline::Slot::MAP::FADE_MASK));
gpu::Shader::makeProgram(*_simpleFadeShader, slotBindings);
gpu::Shader::makeProgram(*_unlitFadeShader, slotBindings);
@ -2282,7 +2313,8 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
PrepareStencil::testMaskDrawShapeNoAA(*state);
}
gpu::ShaderPointer program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _unlitShader) : (config.isFading() ? _simpleFadeShader : _simpleShader);
gpu::ShaderPointer program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _unlitShader) :
(config.isFading() ? _simpleFadeShader : (config.isTransparent() ? _transparentShader : _simpleShader));
gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state);
_simplePrograms.insert(config, pipeline);
return pipeline;
@ -2363,11 +2395,11 @@ void renderFadeInstances(RenderArgs* args, gpu::Batch& batch, const glm::vec4& c
pipeline->prepare(batch, args);
if (isWire) {
DependencyManager::get<GeometryCache>()->renderWireFadeShapeInstances(batch, shape, data.count(),
DependencyManager::get<GeometryCache>()->renderWireFadeShapeInstances(batch, shape, data.count(),
buffers[INSTANCE_COLOR_BUFFER], buffers[INSTANCE_FADE_BUFFER1], buffers[INSTANCE_FADE_BUFFER2], buffers[INSTANCE_FADE_BUFFER3]);
}
else {
DependencyManager::get<GeometryCache>()->renderFadeShapeInstances(batch, shape, data.count(),
DependencyManager::get<GeometryCache>()->renderFadeShapeInstances(batch, shape, data.count(),
buffers[INSTANCE_COLOR_BUFFER], buffers[INSTANCE_FADE_BUFFER1], buffers[INSTANCE_FADE_BUFFER2], buffers[INSTANCE_FADE_BUFFER3]);
}
});
@ -2383,15 +2415,15 @@ void GeometryCache::renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch,
renderInstances(args, batch, color, true, pipeline, shape);
}
void GeometryCache::renderSolidFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color,
int fadeCategory, float fadeThreshold, const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
void GeometryCache::renderSolidFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color,
int fadeCategory, float fadeThreshold, const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
renderFadeInstances(args, batch, color, fadeCategory, fadeThreshold, fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, false, pipeline, shape);
}
void GeometryCache::renderWireFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color,
int fadeCategory, float fadeThreshold, const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
void GeometryCache::renderWireFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color,
int fadeCategory, float fadeThreshold, const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
renderFadeInstances(args, batch, color, fadeCategory, fadeThreshold, fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, true, pipeline, shape);

View file

@ -471,6 +471,7 @@ private:
QHash<int, GridBuffer> _registeredGridBuffers;
static gpu::ShaderPointer _simpleShader;
static gpu::ShaderPointer _transparentShader;
static gpu::ShaderPointer _unlitShader;
static gpu::ShaderPointer _simpleFadeShader;
static gpu::ShaderPointer _unlitFadeShader;
@ -478,8 +479,6 @@ private:
static render::ShapePipelinePointer _simpleTransparentPipeline;
static render::ShapePipelinePointer _simpleOpaqueFadePipeline;
static render::ShapePipelinePointer _simpleTransparentFadePipeline;
static render::ShapePipelinePointer _simpleOpaqueOverlayPipeline;
static render::ShapePipelinePointer _simpleTransparentOverlayPipeline;
static render::ShapePipelinePointer _simpleWirePipeline;
gpu::PipelinePointer _glowLinePipeline;

View file

@ -111,15 +111,11 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie
}
<@endif@>
if (!(isObscuranceEnabled() > 0.0)) {
obscurance = 1.0;
}
obscurance = mix(1.0, obscurance, isObscuranceEnabled());
float lightEnergy = obscurance * getLightAmbientIntensity(ambient);
if (isAlbedoEnabled() > 0.0) {
diffuse *= albedo;
}
diffuse *= mix(vec3(1), albedo, isAlbedoEnabled());
lightEnergy *= isAmbientEnabled();
diffuse *= lightEnergy * isDiffuseEnabled();

View file

@ -13,11 +13,19 @@
<@func declareLightingModel()@>
#ifndef PRECISIONQ
#ifdef GL_ES
#define PRECISIONQ highp
#else
#define PRECISIONQ
#endif
#endif
struct LightingModel {
vec4 _UnlitEmissiveLightmapBackground;
vec4 _ScatteringDiffuseSpecularAlbedo;
vec4 _AmbientDirectionalPointSpot;
vec4 _ShowContourObscuranceWireframe;
PRECISIONQ vec4 _UnlitEmissiveLightmapBackground;
PRECISIONQ vec4 _ScatteringDiffuseSpecularAlbedo;
PRECISIONQ vec4 _AmbientDirectionalPointSpot;
PRECISIONQ vec4 _ShowContourObscuranceWireframe;
};
uniform lightingModelBuffer{
@ -256,9 +264,7 @@ void evalFragShading(out vec3 diffuse, out vec3 specular,
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo) {
vec4 shading = evalPBRShading(metallic, fresnel, surface);
diffuse = vec3(shading.w);
if (isAlbedoEnabled() > 0.0) {
diffuse *= albedo;
}
diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled());
specular = shading.xyz;
}

View file

@ -1,10 +1,8 @@
// glsl / C++ compatible source as interface for Shadows
#ifdef __cplusplus
# define MAT4 glm::mat4
# define VEC3 glm::vec3
#else
# define MAT4 mat4
# define VEC3 vec3
#endif
#define SHADOW_CASCADE_MAX_COUNT 4

View file

@ -0,0 +1,83 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// forward_simple.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/15/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DefaultMaterials.slh@>
<@include ForwardGlobalLight.slh@>
<$declareEvalSkyboxGlobalColor()$>
// the interpolated normal
in vec3 _normal;
in vec3 _modelNormal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _position;
in vec4 _eyePosition;
layout(location = 0) out vec4 _fragColor0;
//PROCEDURAL_COMMON_BLOCK
#line 1001
//PROCEDURAL_BLOCK
#line 2030
void main(void) {
vec3 normal = normalize(_normal.xyz);
vec3 diffuse = _color.rgb;
vec3 specular = DEFAULT_SPECULAR;
float shininess = DEFAULT_SHININESS;
float emissiveAmount = 0.0;
#ifdef PROCEDURAL
#ifdef PROCEDURAL_V1
specular = getProceduralColor().rgb;
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
//specular = pow(specular, vec3(2.2));
emissiveAmount = 1.0;
#else
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
#endif
#endif
TransformCamera cam = getTransformCamera();
vec3 fragPosition = _eyePosition.xyz;
if (emissiveAmount > 0.0) {
_fragColor0 = vec4(evalSkyboxGlobalColor(
cam._viewInverse,
1.0,
DEFAULT_OCCLUSION,
fragPosition,
normal,
diffuse,
specular,
DEFAULT_METALLIC,
max(0.0, 1.0 - shininess / 128.0)),
1.0);
} else {
_fragColor0 = vec4(evalSkyboxGlobalColor(
cam._viewInverse,
1.0,
DEFAULT_OCCLUSION,
fragPosition,
normal,
diffuse,
DEFAULT_FRESNEL,
length(specular),
max(0.0, 1.0 - shininess / 128.0)),
1.0);
}
}

View file

@ -0,0 +1,51 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// forward_simple_textured.slf
// fragment shader
//
// Created by Clément Brisset on 5/29/15.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DefaultMaterials.slh@>
<@include ForwardGlobalLight.slh@>
<$declareEvalSkyboxGlobalColor()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
// the albedo texture
uniform sampler2D originalTexture;
// the interpolated normal
in vec3 _normal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _eyePosition;
layout(location = 0) out vec4 _fragColor0;
void main(void) {
vec4 texel = texture(originalTexture, _texCoord0);
float colorAlpha = _color.a * texel.a;
TransformCamera cam = getTransformCamera();
vec3 fragPosition = _eyePosition.xyz;
_fragColor0 = vec4(evalSkyboxGlobalColor(
cam._viewInverse,
1.0,
DEFAULT_OCCLUSION,
fragPosition,
normalize(_normal),
_color.rgb * texel.rgb,
DEFAULT_FRESNEL,
DEFAULT_METALLIC,
DEFAULT_ROUGHNESS),
1.0);
}

View file

@ -0,0 +1,52 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// forward_simple_textured_transparent.slf
// fragment shader
//
// Created by Clément Brisset on 5/29/15.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DefaultMaterials.slh@>
<@include ForwardGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
// the albedo texture
uniform sampler2D originalTexture;
// the interpolated normal
in vec3 _normal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _eyePosition;
layout(location = 0) out vec4 _fragColor0;
void main(void) {
vec4 texel = texture(originalTexture, _texCoord0);
float colorAlpha = _color.a * texel.a;
TransformCamera cam = getTransformCamera();
vec3 fragPosition = _eyePosition.xyz;
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
DEFAULT_OCCLUSION,
fragPosition,
normalize(_normal),
_color.rgb * texel.rgb,
DEFAULT_FRESNEL,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE,
DEFAULT_ROUGHNESS, colorAlpha),
colorAlpha);
}

View file

@ -0,0 +1,31 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// simple_textured_unlit.frag
// fragment shader
//
// Created by Clément Brisset on 5/29/15.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include LightingModel.slh@>
<@include gpu/Color.slh@>
layout(location = 0) out vec4 _fragColor0;
// the albedo texture
uniform sampler2D originalTexture;
in vec4 _color;
in vec2 _texCoord0;
void main(void) {
vec4 texel = texture(originalTexture, _texCoord0.st);
float colorAlpha = _color.a * texel.a;
_fragColor0 = vec4(_color.rgb * texel.rgb * isUnlitEnabled(), colorAlpha);
}

View file

@ -0,0 +1,84 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// forward_simple_transparent.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/15/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DefaultMaterials.slh@>
<@include ForwardGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
// the interpolated normal
in vec3 _normal;
in vec3 _modelNormal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _eyePosition;
layout(location = 0) out vec4 _fragColor0;
//PROCEDURAL_COMMON_BLOCK
#line 1001
//PROCEDURAL_BLOCK
#line 2030
void main(void) {
vec3 normal = normalize(_normal.xyz);
vec3 diffuse = _color.rgb;
vec3 specular = DEFAULT_SPECULAR;
float shininess = DEFAULT_SHININESS;
float emissiveAmount = 0.0;
#ifdef PROCEDURAL
#ifdef PROCEDURAL_V1
specular = getProceduralColor().rgb;
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
//specular = pow(specular, vec3(2.2));
emissiveAmount = 1.0;
#else
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
#endif
#endif
TransformCamera cam = getTransformCamera();
vec3 fragPosition = _eyePosition.xyz;
if (emissiveAmount > 0.0) {
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
DEFAULT_OCCLUSION,
fragPosition,
normal,
specular,
DEFAULT_FRESNEL,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE,
DEFAULT_ROUGHNESS, _color.a),
_color.a);
} else {
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
DEFAULT_OCCLUSION,
fragPosition,
normal,
diffuse,
DEFAULT_FRESNEL,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE,
DEFAULT_ROUGHNESS, _color.a),
_color.a);
}
}

View file

@ -13,7 +13,6 @@
//
<@include DeferredBufferWrite.slh@>
<@include graphics/Material.slh@>
// the interpolated normal
in vec3 _normal;
@ -29,9 +28,8 @@ in vec4 _position;
#line 2030
void main(void) {
Material material = getMaterial();
vec3 normal = normalize(_normal.xyz);
vec3 diffuse = _color.rgb;
vec3 normal = normalize(_normal.xyz);
vec3 diffuse = _color.rgb;
vec3 specular = DEFAULT_SPECULAR;
float shininess = DEFAULT_SHININESS;
float emissiveAmount = 0.0;
@ -43,49 +41,30 @@ void main(void) {
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
//specular = pow(specular, vec3(2.2));
emissiveAmount = 1.0;
#else
#else
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
#endif
#endif
const float ALPHA_THRESHOLD = 0.999;
if (_color.a < ALPHA_THRESHOLD) {
if (emissiveAmount > 0.0) {
packDeferredFragmentTranslucent(
normal,
_color.a,
specular,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
} else {
packDeferredFragmentTranslucent(
normal,
_color.a,
diffuse,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
}
if (emissiveAmount > 0.0) {
packDeferredFragmentLightmap(
normal,
1.0,
diffuse,
max(0.0, 1.0 - shininess / 128.0),
DEFAULT_METALLIC,
specular,
vec3(clamp(emissiveAmount, 0.0, 1.0)));
} else {
if (emissiveAmount > 0.0) {
packDeferredFragmentLightmap(
normal,
1.0,
diffuse,
max(0.0, 1.0 - shininess / 128.0),
DEFAULT_METALLIC,
specular,
vec3(clamp(emissiveAmount, 0.0, 1.0)));
} else {
packDeferredFragment(
normal,
1.0,
diffuse,
max(0.0, 1.0 - shininess / 128.0),
length(specular),
DEFAULT_EMISSIVE,
DEFAULT_OCCLUSION,
DEFAULT_SCATTERING);
}
packDeferredFragment(
normal,
1.0,
diffuse,
max(0.0, 1.0 - shininess / 128.0),
length(specular),
DEFAULT_EMISSIVE,
DEFAULT_OCCLUSION,
DEFAULT_SCATTERING);
}
}

View file

@ -23,6 +23,7 @@ out vec3 _modelNormal;
out vec4 _color;
out vec2 _texCoord0;
out vec4 _position;
out vec4 _eyePosition;
void main(void) {
_color = color_sRGBAToLinear(inColor);
@ -33,6 +34,6 @@ void main(void) {
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _eyePosition, gl_Position)$>
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
}

View file

@ -13,7 +13,6 @@
//
<@include DeferredBufferWrite.slh@>
<@include graphics/Material.slh@>
<@include Fade.slh@>
<$declareFadeFragmentInstanced()$>
@ -39,7 +38,6 @@ void main(void) {
<$fetchFadeObjectParamsInstanced(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material material = getMaterial();
vec3 normal = normalize(_normal.xyz);
vec3 diffuse = _color.rgb;
vec3 specular = DEFAULT_SPECULAR;

View file

@ -26,6 +26,7 @@ out vec3 _modelNormal;
out vec4 _color;
out vec2 _texCoord0;
out vec4 _position;
out vec4 _eyePosition;
out vec4 _worldPosition;
void main(void) {
@ -37,7 +38,7 @@ void main(void) {
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _eyePosition, gl_Position)$>
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
<$passThroughFadeObjectParams()$>

View file

@ -12,9 +12,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Color.slh@>
<@include DeferredBufferWrite.slh@>
<@include graphics/Material.slh@>
// the albedo texture
uniform sampler2D originalTexture;
@ -26,29 +24,14 @@ in vec2 _texCoord0;
void main(void) {
vec4 texel = texture(originalTexture, _texCoord0);
float colorAlpha = _color.a;
if (_color.a <= 0.0) {
texel = color_sRGBAToLinear(texel);
colorAlpha = -_color.a;
}
const float ALPHA_THRESHOLD = 0.999;
if (colorAlpha * texel.a < ALPHA_THRESHOLD) {
packDeferredFragmentTranslucent(
normalize(_normal),
colorAlpha * texel.a,
_color.rgb * texel.rgb,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
} else {
packDeferredFragment(
normalize(_normal),
1.0,
_color.rgb * texel.rgb,
DEFAULT_ROUGHNESS,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE,
DEFAULT_OCCLUSION,
DEFAULT_SCATTERING);
}
packDeferredFragment(
normalize(_normal),
1.0,
_color.rgb * texel.rgb,
DEFAULT_ROUGHNESS,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE,
DEFAULT_OCCLUSION,
DEFAULT_SCATTERING);
}

View file

@ -14,7 +14,6 @@
<@include gpu/Color.slh@>
<@include DeferredBufferWrite.slh@>
<@include graphics/Material.slh@>
<@include Fade.slh@>

View file

@ -0,0 +1,65 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// simple_transparent.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/15/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
// the interpolated normal
in vec3 _normal;
in vec3 _modelNormal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _position;
//PROCEDURAL_COMMON_BLOCK
#line 1001
//PROCEDURAL_BLOCK
#line 2030
void main(void) {
vec3 normal = normalize(_normal.xyz);
vec3 diffuse = _color.rgb;
vec3 specular = DEFAULT_SPECULAR;
float shininess = DEFAULT_SHININESS;
float emissiveAmount = 0.0;
#ifdef PROCEDURAL
#ifdef PROCEDURAL_V1
specular = getProceduralColor().rgb;
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
//specular = pow(specular, vec3(2.2));
emissiveAmount = 1.0;
#else
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
#endif
#endif
if (emissiveAmount > 0.0) {
packDeferredFragmentTranslucent(
normal,
_color.a,
specular,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
} else {
packDeferredFragmentTranslucent(
normal,
_color.a,
diffuse,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
}
}

View file

@ -12,51 +12,24 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Color.slh@>
<@include DeferredBufferWrite.slh@>
<@include DeferredGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
// the albedo texture
uniform sampler2D originalTexture;
// the interpolated normal
in vec4 _position;
in vec3 _normal;
in vec4 _color;
in vec2 _texCoord0;
void main(void) {
vec4 texel = texture(originalTexture, _texCoord0.st);
float opacity = _color.a;
if (_color.a <= 0.0) {
texel = color_sRGBAToLinear(texel);
opacity = -_color.a;
}
opacity *= texel.a;
vec3 albedo = _color.rgb * texel.rgb;
vec4 texel = texture(originalTexture, _texCoord0);
float colorAlpha = _color.a * texel.a;
vec3 fragPosition = _position.xyz;
vec3 fragNormal = normalize(_normal);
TransformCamera cam = getTransformCamera();
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
cam._viewInverse,
1.0,
1.0,
fragPosition,
fragNormal,
albedo,
packDeferredFragmentTranslucent(
normalize(_normal),
colorAlpha,
_color.rgb * texel.rgb,
DEFAULT_FRESNEL,
0.0,
vec3(0.0f),
DEFAULT_ROUGHNESS,
opacity),
opacity);
DEFAULT_ROUGHNESS);
}

View file

@ -36,7 +36,7 @@ public:
}
};
Engine::Engine() : Task("Engine", EngineTask::JobModel::create()),
Engine::Engine() : Task(EngineTask::JobModel::create("Engine")),
_renderContext(std::make_shared<RenderContext>())
{
}

View file

@ -134,9 +134,12 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
locations->lightClusterFrustumBufferUnit = -1;
}
auto gpuPipeline = gpu::Pipeline::create(program, state);
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter, itemSetter);
addPipelineHelper(filter, key, 0, shapePipeline);
{
PROFILE_RANGE(app, "Pipeline::create");
auto gpuPipeline = gpu::Pipeline::create(program, state);
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter, itemSetter);
addPipelineHelper(filter, key, 0, shapePipeline);
}
}
const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Key& key) const {

View file

@ -27,6 +27,7 @@ Q_LOGGING_CATEGORY(trace_simulation_animation, "trace.simulation.animation")
Q_LOGGING_CATEGORY(trace_simulation_animation_detail, "trace.simulation.animation.detail")
Q_LOGGING_CATEGORY(trace_simulation_physics, "trace.simulation.physics")
Q_LOGGING_CATEGORY(trace_simulation_physics_detail, "trace.simulation.physics.detail")
Q_LOGGING_CATEGORY(trace_startup, "trace.startup")
Q_LOGGING_CATEGORY(trace_workload, "trace.workload")
#if defined(NSIGHT_FOUND)

View file

@ -32,6 +32,7 @@ Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation_detail)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics_detail)
Q_DECLARE_LOGGING_CATEGORY(trace_startup)
Q_DECLARE_LOGGING_CATEGORY(trace_workload)
class Duration {

View file

@ -47,7 +47,7 @@ protected:
bool _doAbortTask{ false };
};
// JobContext class is the base calss for the context object which is passed through all the Job::run calls thoughout the graph of jobs
// JobContext class is the base class for the context object which is passed through all the Job::run calls thoughout the graph of jobs
// It is used to communicate to the job::run its context and various state information the job relies on.
// It specifically provide access to:
// - The taskFlow object allowing for messaging control flow commands from within a Job::run
@ -73,19 +73,21 @@ class JobConcept {
public:
using Config = JobConfig;
JobConcept(QConfigPointer config) : _config(config) {}
JobConcept(const std::string& name, QConfigPointer config) : _config(config), _name(name) {}
virtual ~JobConcept() = default;
const std::string& getName() const { return _name; }
virtual const Varying getInput() const { return Varying(); }
virtual const Varying getOutput() const { return Varying(); }
virtual QConfigPointer& getConfiguration() { return _config; }
virtual void applyConfiguration() = 0;
void setCPURunTime(double mstime) { std::static_pointer_cast<Config>(_config)->setCPURunTime(mstime); }
QConfigPointer _config;
protected:
const std::string _name;
};
@ -122,7 +124,7 @@ public:
class Concept : public JobConcept {
public:
Concept(QConfigPointer config) : JobConcept(config) {}
Concept(const std::string& name, QConfigPointer config) : JobConcept(name, config) {}
virtual ~Concept() = default;
virtual void run(const ContextPointer& jobContext) = 0;
@ -143,8 +145,8 @@ public:
const Varying getOutput() const override { return _output; }
template <class... A>
Model(const Varying& input, QConfigPointer config, A&&... args) :
Concept(config),
Model(const std::string& name, const Varying& input, QConfigPointer config, A&&... args) :
Concept(name, config),
_data(Data(std::forward<A>(args)...)),
_input(input),
_output(Output()) {
@ -152,12 +154,14 @@ public:
}
template <class... A>
static std::shared_ptr<Model> create(const Varying& input, A&&... args) {
return std::make_shared<Model>(input, std::make_shared<C>(), std::forward<A>(args)...);
static std::shared_ptr<Model> create(const std::string& name, const Varying& input, A&&... args) {
return std::make_shared<Model>(name, input, std::make_shared<C>(), std::forward<A>(args)...);
}
void applyConfiguration() override {
Duration profileRange(trace_render(), ("configure::" + JobConcept::getName()).c_str());
jobConfigure(_data, *std::static_pointer_cast<C>(Concept::_config));
}
@ -173,8 +177,9 @@ public:
template <class T, class O, class C = Config> using ModelO = Model<T, C, None, O>;
template <class T, class I, class O, class C = Config> using ModelIO = Model<T, C, I, O>;
Job(std::string name, ConceptPointer concept) : _concept(concept), _name(name) {}
Job(ConceptPointer concept) : _concept(concept) {}
const std::string& getName() const { return _concept->getName(); }
const Varying getInput() const { return _concept->getInput(); }
const Varying getOutput() const { return _concept->getOutput(); }
QConfigPointer& getConfiguration() const { return _concept->getConfiguration(); }
@ -193,9 +198,9 @@ public:
}
virtual void run(const ContextPointer& jobContext) {
PerformanceTimer perfTimer(_name.c_str());
PerformanceTimer perfTimer(getName().c_str());
// NOTE: rather than use the PROFILE_RANGE macro, we create a Duration manually
Duration profileRange(jobContext->profileCategory, _name.c_str());
Duration profileRange(jobContext->profileCategory, ("run::" + getName()).c_str());
auto start = usecTimestampNow();
_concept->run(jobContext);
@ -203,11 +208,8 @@ public:
_concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0);
}
const std::string& getName() const { return _name; }
protected:
ConceptPointer _concept;
std::string _name = "";
};
@ -230,7 +232,7 @@ public:
using ConceptPointer = typename JobType::ConceptPointer;
using Jobs = std::vector<JobType>;
Task(std::string name, ConceptPointer concept) : JobType(name, concept) {}
Task(ConceptPointer concept) : JobType(concept) {}
class TaskConcept : public Concept {
public:
@ -259,11 +261,11 @@ public:
return jobIt;
}
TaskConcept(const Varying& input, QConfigPointer config) : Concept(config), _input(input) {}
TaskConcept(const std::string& name, const Varying& input, QConfigPointer config) : Concept(name, config), _input(input) {}
// Create a new job in the container's queue; returns the job's output
template <class NT, class... NA> const Varying addJob(std::string name, const Varying& input, NA&&... args) {
_jobs.emplace_back(name, (NT::JobModel::create(input, std::forward<NA>(args)...)));
_jobs.emplace_back((NT::JobModel::create(name, input, std::forward<NA>(args)...)));
// Conect the child config to this task's config
std::static_pointer_cast<TaskConfig>(Concept::getConfiguration())->connectChildConfig(_jobs.back().getConfiguration(), name);
@ -284,16 +286,18 @@ public:
Data _data;
TaskModel(const Varying& input, QConfigPointer config) :
TaskConcept(input, config),
TaskModel(const std::string& name, const Varying& input, QConfigPointer config) :
TaskConcept(name, input, config),
_data(Data()) {}
template <class... A>
static std::shared_ptr<TaskModel> create(const Varying& input, A&&... args) {
auto model = std::make_shared<TaskModel>(input, std::make_shared<C>());
model->_data.build(*(model), model->_input, model->_output, std::forward<A>(args)...);
static std::shared_ptr<TaskModel> create(const std::string& name, const Varying& input, A&&... args) {
auto model = std::make_shared<TaskModel>(name, input, std::make_shared<C>());
{
Duration profileRange(trace_render(), ("build::" + model->getName()).c_str());
model->_data.build(*(model), model->_input, model->_output, std::forward<A>(args)...);
}
// Recreate the Config to use the templated type
model->createConfiguration();
model->applyConfiguration();
@ -302,9 +306,9 @@ public:
}
template <class... A>
static std::shared_ptr<TaskModel> create(A&&... args) {
static std::shared_ptr<TaskModel> create(const std::string& name, A&&... args) {
const auto input = Varying(Input());
return create(input, std::forward<A>(args)...);
return create(name, input, std::forward<A>(args)...);
}
void createConfiguration() {
@ -326,6 +330,7 @@ public:
}
void applyConfiguration() override {
Duration profileRange(trace_render(), ("configure::" + JobConcept::getName()).c_str());
jobConfigure(_data, *std::static_pointer_cast<C>(Concept::_config));
for (auto& job : TaskConcept::_jobs) {
job.applyConfiguration();

View file

@ -256,6 +256,15 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) {
#if !defined(Q_OS_ANDROID)
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
{
PROFILE_RANGE(startup, "FileTypeProfile");
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
}
{
PROFILE_RANGE(startup, "HFWebEngineProfile");
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
}
#endif
rootContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
rootContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());

View file

@ -12,6 +12,7 @@
#include <PathUtils.h>
#include "OffscreenQmlSurface.h"
#include "Profile.h"
OffscreenQmlSurfaceCache::OffscreenQmlSurfaceCache() {
}
@ -38,6 +39,7 @@ void OffscreenQmlSurfaceCache::reserve(const QString& rootSource, int count) {
}
void OffscreenQmlSurfaceCache::release(const QString& rootSource, const QSharedPointer<OffscreenQmlSurface>& surface) {
PROFILE_RANGE(app, "buildSurface");
surface->pause();
_cache[rootSource].push_back(surface);
}

View file

@ -1,43 +0,0 @@
//
// audioReverbOn.js
// examples
//
// Copyright 2014 High Fidelity, Inc.
//
//
// Gives the ability to be set various reverb settings.
//
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings
var audioOptions = new AudioEffectOptions({
// Square Meters
maxRoomSize: 50,
roomSize: 50,
// Seconds
reverbTime: 10,
// Between 0 - 1
damping: 0.50,
inputBandwidth: 0.75,
// dB
earlyLevel: -22,
tailLevel: -28,
dryLevel: 0,
wetLevel: 6
});
AudioDevice.setReverbOptions(audioOptions);
AudioDevice.setReverb(true);
print("Reverb is now on with the updated options.");
function scriptEnding() {
AudioDevice.setReverb(false);
print("Reberb is now off.");
}
Script.scriptEnding.connect(scriptEnding);

View file

@ -25,12 +25,13 @@ exports.handlers = {
'../../libraries/avatars/src',
'../../libraries/controllers/src/controllers/',
'../../libraries/controllers/src/controllers/impl/',
'../../libraries/graphics-scripting/src/graphics-scripting/',
'../../libraries/display-plugins/src/display-plugins/',
'../../libraries/entities/src',
'../../libraries/graphics-scripting/src/graphics-scripting/',
'../../libraries/input-plugins/src/input-plugins',
'../../libraries/model-networking/src/model-networking/',
'../../libraries/octree/src',
'../../libraries/networking/src',
'../../libraries/octree/src',
'../../libraries/physics/src',
'../../libraries/pointers/src',
'../../libraries/script-engine/src',