mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 02:23:57 +02:00
Merge branch 'master' into 21255
# Conflicts: # interface/src/Application.cpp
This commit is contained in:
commit
ae9a928740
118 changed files with 2780 additions and 1076 deletions
8
cmake/externals/nvtt/CMakeLists.txt
vendored
8
cmake/externals/nvtt/CMakeLists.txt
vendored
|
@ -8,8 +8,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/nvtt-win-2.1.0.zip
|
||||
URL_MD5 3ea6eeadbcc69071acf9c49ba565760e
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/nvtt-win-2.1.0.hifi.zip
|
||||
URL_MD5 10da01cf601f88f6dc12a6bc13c89136
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
|
@ -29,8 +29,8 @@ else ()
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/nvidia-texture-tools-2.1.0.zip
|
||||
URL_MD5 81b8fa6a9ee3f986088eb6e2215d6a57
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/nvidia-texture-tools-2.1.0.hifi.zip
|
||||
URL_MD5 5794b950f8b265a9a41b2839b3bf7ebb
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DNVTT_SHARED=1 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
|
|
Binary file not shown.
|
@ -11,6 +11,9 @@
|
|||
|
||||
#include "Application.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
@ -144,6 +147,7 @@
|
|||
#include "InterfaceLogging.h"
|
||||
#include "LODManager.h"
|
||||
#include "ModelPackager.h"
|
||||
#include "networking/CloseEventSender.h"
|
||||
#include "networking/HFWebEngineProfile.h"
|
||||
#include "networking/HFTabletWebEngineProfile.h"
|
||||
#include "networking/FileTypeProfile.h"
|
||||
|
@ -536,6 +540,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<AvatarBookmarks>();
|
||||
DependencyManager::set<LocationBookmarks>();
|
||||
DependencyManager::set<Snapshot>();
|
||||
DependencyManager::set<CloseEventSender>();
|
||||
|
||||
return previousSessionCrashed;
|
||||
}
|
||||
|
@ -1600,6 +1605,14 @@ void Application::aboutToQuit() {
|
|||
&& _autoSwitchDisplayModeSupportedHMDPlugin->isStandBySessionActive()) {
|
||||
_autoSwitchDisplayModeSupportedHMDPlugin->endStandBySession();
|
||||
}
|
||||
// use the CloseEventSender via a QThread to send an event that says the user asked for the app to close
|
||||
auto closeEventSender = DependencyManager::get<CloseEventSender>();
|
||||
QThread* closureEventThread = new QThread(this);
|
||||
closeEventSender->moveToThread(closureEventThread);
|
||||
// sendQuitEventAsync will bail immediately if the UserActivityLogger is not enabled
|
||||
connect(closureEventThread, &QThread::started, closeEventSender.data(), &CloseEventSender::sendQuitEventAsync);
|
||||
closureEventThread->start();
|
||||
|
||||
// Hide Running Scripts dialog so that it gets destroyed in an orderly manner; prevents warnings at shutdown.
|
||||
DependencyManager::get<OffscreenUi>()->hide("RunningScripts");
|
||||
|
||||
|
@ -1713,6 +1726,10 @@ Application::~Application() {
|
|||
|
||||
_physicsEngine->setCharacterController(nullptr);
|
||||
|
||||
// the _shapeManager should have zero references
|
||||
_shapeManager.collectGarbage();
|
||||
assert(_shapeManager.getNumShapes() == 0);
|
||||
|
||||
// shutdown render engine
|
||||
_main3DScene = nullptr;
|
||||
_renderEngine = nullptr;
|
||||
|
@ -1764,6 +1781,15 @@ Application::~Application() {
|
|||
|
||||
_window->deleteLater();
|
||||
|
||||
// make sure that the quit event has finished sending before we take the application down
|
||||
auto closeEventSender = DependencyManager::get<CloseEventSender>();
|
||||
while (!closeEventSender->hasFinishedQuitEvent() && !closeEventSender->hasTimedOutQuitEvent()) {
|
||||
// sleep a little so we're not spinning at 100%
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
// quit the thread used by the closure event sender
|
||||
closeEventSender->thread()->quit();
|
||||
|
||||
// Can't log to file passed this point, FileLogger about to be deleted
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
}
|
||||
|
@ -2215,6 +2241,9 @@ void Application::paintGL() {
|
|||
});
|
||||
renderArgs._context->setStereoProjections(eyeProjections);
|
||||
renderArgs._context->setStereoViews(eyeOffsets);
|
||||
|
||||
// Configure the type of display / stereo
|
||||
renderArgs._displayMode = (isHMDMode() ? RenderArgs::STEREO_HMD : RenderArgs::STEREO_MONITOR);
|
||||
}
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
displaySide(&renderArgs, _myCamera);
|
||||
|
@ -2414,15 +2443,16 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
|
||||
// Check HMD use (may be technically available without being in use)
|
||||
bool hasHMD = PluginUtils::isHMDAvailable();
|
||||
bool isUsingHMD = hasHMD && hasHandControllers && _displayPlugin->isHmd();
|
||||
bool isUsingHMD = _displayPlugin->isHmd();
|
||||
bool isUsingHMDAndHandControllers = hasHMD && hasHandControllers && isUsingHMD;
|
||||
|
||||
Setting::Handle<bool> tutorialComplete{ "tutorialComplete", false };
|
||||
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
|
||||
|
||||
bool isTutorialComplete = tutorialComplete.get();
|
||||
bool shouldGoToTutorial = isUsingHMD && hasTutorialContent && !isTutorialComplete;
|
||||
bool shouldGoToTutorial = isUsingHMDAndHandControllers && hasTutorialContent && !isTutorialComplete;
|
||||
|
||||
qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMD;
|
||||
qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers;
|
||||
qCDebug(interfaceapp) << "Tutorial version:" << contentVersion << ", sufficient:" << hasTutorialContent <<
|
||||
", complete:" << isTutorialComplete << ", should go:" << shouldGoToTutorial;
|
||||
|
||||
|
@ -2436,10 +2466,18 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
|
||||
const QString TUTORIAL_PATH = "/tutorial_begin";
|
||||
|
||||
static const QString SENT_TO_TUTORIAL = "tutorial";
|
||||
static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location";
|
||||
static const QString SENT_TO_ENTRY = "entry";
|
||||
static const QString SENT_TO_SANDBOX = "sandbox";
|
||||
|
||||
QString sentTo;
|
||||
|
||||
if (shouldGoToTutorial) {
|
||||
if (sandboxIsRunning) {
|
||||
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
|
||||
DependencyManager::get<AddressManager>()->goToLocalSandbox(TUTORIAL_PATH);
|
||||
sentTo = SENT_TO_TUTORIAL;
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
|
||||
if (firstRun.get()) {
|
||||
|
@ -2447,8 +2485,10 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
}
|
||||
if (addressLookupString.isEmpty()) {
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
sentTo = SENT_TO_ENTRY;
|
||||
} else {
|
||||
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
|
||||
sentTo = SENT_TO_PREVIOUS_LOCATION;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2461,23 +2501,40 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
|
||||
// If this is a first run we short-circuit the address passed in
|
||||
if (isFirstRun) {
|
||||
if (isUsingHMD) {
|
||||
if (isUsingHMDAndHandControllers) {
|
||||
if (sandboxIsRunning) {
|
||||
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
|
||||
DependencyManager::get<AddressManager>()->goToLocalSandbox();
|
||||
sentTo = SENT_TO_SANDBOX;
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
sentTo = SENT_TO_ENTRY;
|
||||
}
|
||||
} else {
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
sentTo = SENT_TO_ENTRY;
|
||||
}
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);
|
||||
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
|
||||
sentTo = SENT_TO_PREVIOUS_LOCATION;
|
||||
}
|
||||
}
|
||||
|
||||
UserActivityLogger::getInstance().logAction("startup_sent_to", {
|
||||
{ "sent_to", sentTo },
|
||||
{ "sandbox_is_running", sandboxIsRunning },
|
||||
{ "has_hmd", hasHMD },
|
||||
{ "has_hand_controllers", hasHandControllers },
|
||||
{ "is_using_hmd", isUsingHMD },
|
||||
{ "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers },
|
||||
{ "content_version", contentVersion },
|
||||
{ "is_tutorial_complete", isTutorialComplete },
|
||||
{ "has_tutorial_content", hasTutorialContent },
|
||||
{ "should_go_to_tutorial", shouldGoToTutorial }
|
||||
});
|
||||
|
||||
_connectionMonitor.init();
|
||||
|
||||
// After all of the constructor is completed, then set firstRun to false.
|
||||
|
@ -2806,6 +2863,17 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (isShifted && isMeta && !isOption) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::SuppressShortTimings);
|
||||
} else if (!isOption && !isShifted && isMeta) {
|
||||
AudioInjectorOptions options;
|
||||
options.localOnly = true;
|
||||
options.stereo = true;
|
||||
|
||||
if (_snapshotSoundInjector) {
|
||||
_snapshotSoundInjector->setOptions(options);
|
||||
_snapshotSoundInjector->restart();
|
||||
} else {
|
||||
QByteArray samples = _snapshotSound->getByteArray();
|
||||
_snapshotSoundInjector = AudioInjector::playSound(samples, options);
|
||||
}
|
||||
takeSnapshot(true);
|
||||
}
|
||||
break;
|
||||
|
@ -4520,12 +4588,13 @@ void Application::update(float deltaTime) {
|
|||
|
||||
getEntities()->getTree()->withWriteLock([&] {
|
||||
PerformanceTimer perfTimer("handleOutgoingChanges");
|
||||
const VectorOfMotionStates& deactivations = _physicsEngine->getDeactivatedMotionStates();
|
||||
_entitySimulation->handleDeactivatedMotionStates(deactivations);
|
||||
|
||||
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
|
||||
_entitySimulation->handleChangedMotionStates(outgoingChanges);
|
||||
avatarManager->handleChangedMotionStates(outgoingChanges);
|
||||
|
||||
const VectorOfMotionStates& deactivations = _physicsEngine->getDeactivatedMotionStates();
|
||||
_entitySimulation->handleDeactivatedMotionStates(deactivations);
|
||||
});
|
||||
|
||||
if (!_aboutToQuit) {
|
||||
|
@ -6337,21 +6406,6 @@ void Application::loadAddAvatarBookmarkDialog() const {
|
|||
}
|
||||
|
||||
void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio) {
|
||||
|
||||
//keep sound thread out of event loop scope
|
||||
|
||||
AudioInjectorOptions options;
|
||||
options.localOnly = true;
|
||||
options.stereo = true;
|
||||
|
||||
if (_snapshotSoundInjector) {
|
||||
_snapshotSoundInjector->setOptions(options);
|
||||
_snapshotSoundInjector->restart();
|
||||
} else {
|
||||
QByteArray samples = _snapshotSound->getByteArray();
|
||||
_snapshotSoundInjector = AudioInjector::playSound(samples, options);
|
||||
}
|
||||
|
||||
postLambdaEvent([notify, includeAnimated, aspectRatio, this] {
|
||||
// Get a screenshot and save it
|
||||
QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio));
|
||||
|
|
|
@ -407,6 +407,12 @@ Menu::Menu() {
|
|||
#endif
|
||||
|
||||
|
||||
{
|
||||
auto action = addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderClearKtxCache);
|
||||
connect(action, &QAction::triggered, []{
|
||||
Setting::Handle<int>(KTXCache::SETTING_VERSION_NAME, KTXCache::INVALID_VERSION).set(KTXCache::INVALID_VERSION);
|
||||
});
|
||||
}
|
||||
|
||||
// Developer > Render > LOD Tools
|
||||
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0,
|
||||
|
|
|
@ -145,6 +145,7 @@ namespace MenuOption {
|
|||
const QString Quit = "Quit";
|
||||
const QString ReloadAllScripts = "Reload All Scripts";
|
||||
const QString ReloadContent = "Reload Content (Clears all caches)";
|
||||
const QString RenderClearKtxCache = "Clear KTX Cache (requires restart)";
|
||||
const QString RenderMaxTextureMemory = "Maximum Texture Memory";
|
||||
const QString RenderMaxTextureAutomatic = "Automatic Texture Memory";
|
||||
const QString RenderMaxTexture4MB = "4 MB";
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <SandboxUtils.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
|
||||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
@ -191,7 +190,7 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
int exitCode;
|
||||
{
|
||||
RunningMarker runningMarker(nullptr, RUNNING_MARKER_FILENAME);
|
||||
RunningMarker runningMarker(RUNNING_MARKER_FILENAME);
|
||||
bool runningMarkerExisted = runningMarker.fileExists();
|
||||
runningMarker.writeRunningMarkerFile();
|
||||
|
||||
|
@ -200,14 +199,11 @@ int main(int argc, const char* argv[]) {
|
|||
bool serverContentPathOptionIsSet = parser.isSet(serverContentPathOption);
|
||||
QString serverContentPath = serverContentPathOptionIsSet ? parser.value(serverContentPathOption) : QString();
|
||||
if (runServer) {
|
||||
SandboxUtils::runLocalSandbox(serverContentPath, true, RUNNING_MARKER_FILENAME, noUpdater);
|
||||
SandboxUtils::runLocalSandbox(serverContentPath, true, noUpdater);
|
||||
}
|
||||
|
||||
Application app(argc, const_cast<char**>(argv), startupTime, runningMarkerExisted);
|
||||
|
||||
// Now that the main event loop is setup, launch running marker thread
|
||||
runningMarker.startRunningMarker();
|
||||
|
||||
// If we failed the OpenGLVersion check, log it.
|
||||
if (override) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
|
90
interface/src/networking/CloseEventSender.cpp
Normal file
90
interface/src/networking/CloseEventSender.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// CloseEventSender.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Stephen Birarda on 5/31/17.
|
||||
// Copyright 2017 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 <QtCore/QDateTime>
|
||||
#include <QtCore/QEventLoop>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <NetworkLogging.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "CloseEventSender.h"
|
||||
|
||||
QNetworkRequest createNetworkRequest() {
|
||||
|
||||
QNetworkRequest request;
|
||||
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
requestURL.setPath(USER_ACTIVITY_URL);
|
||||
|
||||
request.setUrl(requestURL);
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
if (accountManager->hasValidAccessToken()) {
|
||||
request.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER,
|
||||
accountManager->getAccountInfo().getAccessToken().authorizationHeaderValue());
|
||||
}
|
||||
|
||||
request.setRawHeader(METAVERSE_SESSION_ID_HEADER,
|
||||
uuidStringWithoutCurlyBraces(accountManager->getSessionID()).toLocal8Bit());
|
||||
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
request.setPriority(QNetworkRequest::HighPriority);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
QByteArray postDataForAction(QString action) {
|
||||
return QString("{\"action_name\": \"" + action + "\"}").toUtf8();
|
||||
}
|
||||
|
||||
QNetworkReply* replyForAction(QString action) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
return networkAccessManager.post(createNetworkRequest(), postDataForAction(action));
|
||||
}
|
||||
|
||||
void CloseEventSender::sendQuitEventAsync() {
|
||||
if (UserActivityLogger::getInstance().isEnabled()) {
|
||||
QNetworkReply* reply = replyForAction("quit");
|
||||
connect(reply, &QNetworkReply::finished, this, &CloseEventSender::handleQuitEventFinished);
|
||||
_quitEventStartTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||
} else {
|
||||
_hasFinishedQuitEvent = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CloseEventSender::handleQuitEventFinished() {
|
||||
_hasFinishedQuitEvent = true;
|
||||
|
||||
auto reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
qCDebug(networking) << "Quit event sent successfully";
|
||||
} else {
|
||||
qCDebug(networking) << "Failed to send quit event -" << reply->errorString();
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
bool CloseEventSender::hasTimedOutQuitEvent() {
|
||||
const int CLOSURE_EVENT_TIMEOUT_MS = 5000;
|
||||
return _quitEventStartTimestamp != 0
|
||||
&& QDateTime::currentMSecsSinceEpoch() - _quitEventStartTimestamp > CLOSURE_EVENT_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
|
41
interface/src/networking/CloseEventSender.h
Normal file
41
interface/src/networking/CloseEventSender.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// CloseEventSender.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Stephen Birarda on 5/31/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_CloseEventSender_h
|
||||
#define hifi_CloseEventSender_h
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
class CloseEventSender : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
bool hasTimedOutQuitEvent();
|
||||
bool hasFinishedQuitEvent() { return _hasFinishedQuitEvent; }
|
||||
|
||||
public slots:
|
||||
void sendQuitEventAsync();
|
||||
|
||||
private slots:
|
||||
void handleQuitEventFinished();
|
||||
|
||||
private:
|
||||
std::atomic<bool> _hasFinishedQuitEvent { false };
|
||||
std::atomic<int64_t> _quitEventStartTimestamp;
|
||||
};
|
||||
|
||||
#endif // hifi_CloseEventSender_h
|
|
@ -1135,9 +1135,9 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
|
|||
}
|
||||
|
||||
glm::vec3 headUp = headQuat * Vectors::UNIT_Y;
|
||||
glm::vec3 z, y, x;
|
||||
generateBasisVectors(lookAtVector, headUp, z, y, x);
|
||||
glm::mat3 m(glm::cross(y, z), y, z);
|
||||
glm::vec3 z, y, zCrossY;
|
||||
generateBasisVectors(lookAtVector, headUp, z, y, zCrossY);
|
||||
glm::mat3 m(-zCrossY, y, z);
|
||||
glm::quat desiredQuat = glm::normalize(glm::quat_cast(m));
|
||||
|
||||
glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <QStandardPaths>
|
||||
#include <PathUtils.h>
|
||||
#include <QUrl>
|
||||
#include <Gzip.h>
|
||||
|
||||
#include <BuildInfo.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
@ -27,7 +28,7 @@
|
|||
|
||||
QString SAVE_DIRECTORY = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + BuildInfo::MODIFIED_ORGANIZATION + "/" + BuildInfo::INTERFACE_NAME + "/hifi-input-recordings/";
|
||||
QString FILE_PREFIX_NAME = "input-recording-";
|
||||
QString COMPRESS_EXTENSION = "json.gz";
|
||||
QString COMPRESS_EXTENSION = ".json.gz";
|
||||
namespace controller {
|
||||
|
||||
QJsonObject poseToJsonObject(const Pose pose) {
|
||||
|
@ -93,23 +94,26 @@ namespace controller {
|
|||
}
|
||||
|
||||
|
||||
void exportToFile(const QJsonObject& object) {
|
||||
void exportToFile(const QJsonObject& object, const QString& fileName) {
|
||||
if (!QDir(SAVE_DIRECTORY).exists()) {
|
||||
QDir().mkdir(SAVE_DIRECTORY);
|
||||
}
|
||||
|
||||
QString timeStamp = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
timeStamp.replace(":", "-");
|
||||
QString fileName = SAVE_DIRECTORY + FILE_PREFIX_NAME + timeStamp + COMPRESS_EXTENSION;
|
||||
qDebug() << fileName;
|
||||
|
||||
QFile saveFile (fileName);
|
||||
if (!saveFile.open(QIODevice::WriteOnly)) {
|
||||
qWarning() << "could not open file: " << fileName;
|
||||
return;
|
||||
}
|
||||
QJsonDocument saveData(object);
|
||||
QByteArray compressedData = qCompress(saveData.toJson(QJsonDocument::Compact));
|
||||
saveFile.write(compressedData);
|
||||
QByteArray jsonData = saveData.toJson(QJsonDocument::Indented);
|
||||
QByteArray jsonDataForFile;
|
||||
|
||||
if (!gzip(jsonData, jsonDataForFile, -1)) {
|
||||
qCritical("unable to gzip while saving to json.");
|
||||
return;
|
||||
}
|
||||
|
||||
saveFile.write(jsonDataForFile);
|
||||
saveFile.close();
|
||||
}
|
||||
|
||||
|
@ -121,8 +125,16 @@ namespace controller {
|
|||
status = false;
|
||||
return object;
|
||||
}
|
||||
QByteArray compressedData = qUncompress(openFile.readAll());
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(compressedData);
|
||||
QByteArray compressedData = openFile.readAll();
|
||||
QByteArray jsonData;
|
||||
|
||||
if (!gunzip(compressedData, jsonData)) {
|
||||
qCritical() << "json file not in gzip format: " << file;
|
||||
status = false;
|
||||
return object;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
|
||||
object = jsonDoc.object();
|
||||
status = true;
|
||||
openFile.close();
|
||||
|
@ -153,7 +165,7 @@ namespace controller {
|
|||
QJsonObject InputRecorder::recordDataToJson() {
|
||||
QJsonObject data;
|
||||
data["frameCount"] = _framesRecorded;
|
||||
data["version"] = "1.0";
|
||||
data["version"] = "0.0";
|
||||
|
||||
QJsonArray actionArrayList;
|
||||
QJsonArray poseArrayList;
|
||||
|
@ -187,7 +199,10 @@ namespace controller {
|
|||
|
||||
void InputRecorder::saveRecording() {
|
||||
QJsonObject jsonData = recordDataToJson();
|
||||
exportToFile(jsonData);
|
||||
QString timeStamp = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
timeStamp.replace(":", "-");
|
||||
QString fileName = SAVE_DIRECTORY + FILE_PREFIX_NAME + timeStamp + COMPRESS_EXTENSION;
|
||||
exportToFile(jsonData, fileName);
|
||||
}
|
||||
|
||||
void InputRecorder::loadRecording(const QString& path) {
|
||||
|
@ -202,10 +217,12 @@ namespace controller {
|
|||
QString filePath = urlPath.toLocalFile();
|
||||
QFileInfo info(filePath);
|
||||
QString extension = info.suffix();
|
||||
|
||||
if (extension != "gz") {
|
||||
qWarning() << "can not load file with exentsion of " << extension;
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
QJsonObject data = openFile(filePath, success);
|
||||
auto keyValue = data.find("version");
|
||||
|
@ -233,34 +250,7 @@ namespace controller {
|
|||
_poseStateList.push_back(_currentFramePoses);
|
||||
_currentFramePoses.clear();
|
||||
}
|
||||
} else if (success) {
|
||||
//convert recording to new reacording standard and rewrite file
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
_framesRecorded = data["frameCount"].toInt();
|
||||
QJsonArray actionArrayList = data["actionList"].toArray();
|
||||
QJsonArray poseArrayList = data["poseList"].toArray();
|
||||
|
||||
for (int actionIndex = 0; actionIndex < actionArrayList.size(); actionIndex++) {
|
||||
QJsonArray actionState = actionArrayList[actionIndex].toArray();
|
||||
for (int index = 0; index < actionState.size(); index++) {
|
||||
QString actionName = userInputMapper->getActionName(Action(index));
|
||||
_currentFrameActions[actionName] = actionState[index].toDouble();
|
||||
}
|
||||
_actionStateList.push_back(_currentFrameActions);
|
||||
_currentFrameActions.clear();
|
||||
}
|
||||
|
||||
for (int poseIndex = 0; poseIndex < poseArrayList.size(); poseIndex++) {
|
||||
QJsonArray poseState = poseArrayList[poseIndex].toArray();
|
||||
for (int index = 0; index < poseState.size(); index++) {
|
||||
QString actionName = userInputMapper->getActionName(Action(index));
|
||||
_currentFramePoses[actionName] = jsonObjectToPose(poseState[index].toObject());
|
||||
}
|
||||
_poseStateList.push_back(_currentFramePoses);
|
||||
_currentFramePoses.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -329,6 +329,16 @@ QString UserInputMapper::getActionName(Action action) const {
|
|||
return QString();
|
||||
}
|
||||
|
||||
QString UserInputMapper::getStandardPoseName(uint16_t pose) {
|
||||
Locker locker(_lock);
|
||||
for (auto posePair : getStandardInputs()) {
|
||||
if (posePair.first.channel == pose && posePair.first.getType() == ChannelType::POSE) {
|
||||
return posePair.second;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QVector<QString> UserInputMapper::getActionNames() const {
|
||||
Locker locker(_lock);
|
||||
QVector<QString> result;
|
||||
|
|
|
@ -80,6 +80,7 @@ namespace controller {
|
|||
|
||||
QVector<Action> getAllActions() const;
|
||||
QString getActionName(Action action) const;
|
||||
QString getStandardPoseName(uint16_t pose);
|
||||
float getActionState(Action action) const { return _actionStates[toInt(action)]; }
|
||||
Pose getPoseState(Action action) const;
|
||||
int findAction(const QString& actionName) const;
|
||||
|
|
|
@ -36,9 +36,6 @@ void ActionEndpoint::apply(const Pose& value, const Pointer& source) {
|
|||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
QString actionName = userInputMapper->getActionName(Action(_input.getChannel()));
|
||||
inputRecorder->setActionState(actionName, _currentPose);
|
||||
if (inputRecorder->isPlayingback()) {
|
||||
_currentPose = inputRecorder->getPoseState(actionName);
|
||||
}
|
||||
|
||||
if (!_currentPose.isValid()) {
|
||||
return;
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "../../InputRecorder.h"
|
||||
#include "../../UserInputMapper.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class StandardEndpoint : public VirtualEndpoint {
|
||||
|
@ -40,6 +45,12 @@ public:
|
|||
|
||||
virtual Pose pose() override {
|
||||
_read = true;
|
||||
InputRecorder* inputRecorder = InputRecorder::getInstance();
|
||||
if (inputRecorder->isPlayingback()) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
QString actionName = userInputMapper->getStandardPoseName(_input.getChannel());
|
||||
return inputRecorder->getPoseState(actionName);
|
||||
}
|
||||
return VirtualEndpoint::pose();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <PerfStat.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <StencilMaskPass.h>
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#include "EntitiesRendererLogging.h"
|
||||
|
||||
|
@ -292,6 +293,7 @@ void RenderableParticleEffectEntityItem::createPipelines() {
|
|||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert));
|
||||
auto fragShader = gpu::Shader::createPixel(std::string(untextured_particle_frag));
|
||||
|
@ -305,6 +307,7 @@ void RenderableParticleEffectEntityItem::createPipelines() {
|
|||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert));
|
||||
auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag));
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <GeometryCache.h>
|
||||
#include <StencilMaskPass.h>
|
||||
#include <TextureCache.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
|
@ -69,6 +70,7 @@ void RenderablePolyLineEntityItem::createPipeline() {
|
|||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMask(*state);
|
||||
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);
|
||||
|
|
|
@ -46,6 +46,9 @@
|
|||
#endif
|
||||
|
||||
#include "model/Geometry.h"
|
||||
|
||||
#include "StencilMaskPass.h"
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
#include "polyvox_vert.h"
|
||||
#include "polyvox_frag.h"
|
||||
|
@ -743,6 +746,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
|
||||
|
@ -750,6 +754,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
wireframeState->setCullMode(gpu::State::CULL_BACK);
|
||||
wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
wireframeState->setFillMode(gpu::State::FILL_LINE);
|
||||
PrepareStencil::testMaskDrawShape(*wireframeState);
|
||||
|
||||
_wireframePipeline = gpu::Pipeline::create(program, wireframeState);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <gpu/Batch.h>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <StencilMaskPass.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
|
@ -93,6 +94,7 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
|
|||
_procedural->_fragmentSource = simple_frag;
|
||||
_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);
|
||||
|
|
|
@ -681,7 +681,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
// and pretend that we own it (we assume we'll recover it soon)
|
||||
|
||||
// However, for now, when the server uses a newer time than what we sent, listen to what we're told.
|
||||
if (overwriteLocalData) weOwnSimulation = false;
|
||||
if (overwriteLocalData) {
|
||||
weOwnSimulation = false;
|
||||
}
|
||||
} else if (_simulationOwner.set(newSimOwner)) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
somethingChanged = true;
|
||||
|
@ -1293,27 +1295,15 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
|
|||
properties._accelerationChanged = true;
|
||||
}
|
||||
|
||||
void EntityItem::pokeSimulationOwnership() {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_POKE);
|
||||
void EntityItem::flagForOwnershipBid(uint8_t priority) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
|
||||
// we already own it
|
||||
_simulationOwner.promotePriority(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
_simulationOwner.promotePriority(priority);
|
||||
} else {
|
||||
// we don't own it yet
|
||||
_simulationOwner.setPendingPriority(SCRIPT_POKE_SIMULATION_PRIORITY, usecTimestampNow());
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::grabSimulationOwnership() {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
|
||||
// we already own it
|
||||
_simulationOwner.promotePriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
} else {
|
||||
// we don't own it yet
|
||||
_simulationOwner.setPendingPriority(SCRIPT_GRAB_SIMULATION_PRIORITY, usecTimestampNow());
|
||||
_simulationOwner.setPendingPriority(priority, usecTimestampNow());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -321,6 +321,7 @@ public:
|
|||
void updateSimulationOwner(const SimulationOwner& owner);
|
||||
void clearSimulationOwnership();
|
||||
void setPendingOwnershipPriority(quint8 priority, const quint64& timestamp);
|
||||
uint8_t getPendingOwnershipPriority() const { return _simulationOwner.getPendingPriority(); }
|
||||
void rememberHasSimulationOwnershipBid() const;
|
||||
|
||||
QString getMarketplaceID() const;
|
||||
|
@ -394,8 +395,7 @@ public:
|
|||
|
||||
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
|
||||
|
||||
void pokeSimulationOwnership();
|
||||
void grabSimulationOwnership();
|
||||
void flagForOwnershipBid(uint8_t priority);
|
||||
void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
|
||||
|
||||
QString actionsToDebugString();
|
||||
|
|
|
@ -230,6 +230,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
|
|||
}
|
||||
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
// since we're creating this object we will immediately volunteer to own its simulation
|
||||
entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY);
|
||||
propertiesWithSimID.setLastEdited(entity->getLastEdited());
|
||||
} else {
|
||||
qCDebug(entities) << "script failed to add new Entity to local Octree";
|
||||
|
@ -440,7 +442,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
} else {
|
||||
// we make a bid for simulation ownership
|
||||
properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
entity->pokeSimulationOwnership();
|
||||
entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
entity->rememberHasSimulationOwnershipBid();
|
||||
}
|
||||
}
|
||||
|
@ -1194,7 +1196,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
|
|||
}
|
||||
action->setIsMine(true);
|
||||
success = entity->addAction(simulation, action);
|
||||
entity->grabSimulationOwnership();
|
||||
entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||
});
|
||||
if (success) {
|
||||
|
@ -1210,7 +1212,7 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid&
|
|||
return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) {
|
||||
bool success = entity->updateAction(simulation, actionID, arguments);
|
||||
if (success) {
|
||||
entity->grabSimulationOwnership();
|
||||
entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
}
|
||||
return success;
|
||||
});
|
||||
|
@ -1224,7 +1226,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid&
|
|||
success = entity->removeAction(simulation, actionID);
|
||||
if (success) {
|
||||
// reduce from grab to poke
|
||||
entity->pokeSimulationOwnership();
|
||||
entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
}
|
||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||
});
|
||||
|
|
|
@ -26,12 +26,10 @@ namespace Simulation {
|
|||
const uint32_t DIRTY_MATERIAL = 0x00400;
|
||||
const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine
|
||||
const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_FOR_POKE = 0x2000; // bid for simulation ownership at "poke"
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB = 0x4000; // bid for simulation ownership at "grab"
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
|
||||
|
||||
const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
|
||||
const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = DIRTY_SIMULATION_OWNERSHIP_FOR_POKE | DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB;
|
||||
};
|
||||
|
||||
#endif // hifi_SimulationFlags_h
|
||||
|
|
|
@ -26,9 +26,9 @@ const int SimulationOwner::NUM_BYTES_ENCODED = NUM_BYTES_RFC4122_UUID + 1;
|
|||
SimulationOwner::SimulationOwner() :
|
||||
_id(),
|
||||
_expiry(0),
|
||||
_pendingTimestamp(0),
|
||||
_pendingBidTimestamp(0),
|
||||
_priority(0),
|
||||
_pendingPriority(0),
|
||||
_pendingBidPriority(0),
|
||||
_pendingState(PENDING_STATE_NOTHING)
|
||||
{
|
||||
}
|
||||
|
@ -36,9 +36,9 @@ SimulationOwner::SimulationOwner() :
|
|||
SimulationOwner::SimulationOwner(const QUuid& id, quint8 priority) :
|
||||
_id(id),
|
||||
_expiry(0),
|
||||
_pendingTimestamp(0),
|
||||
_pendingBidTimestamp(0),
|
||||
_priority(priority),
|
||||
_pendingPriority(0)
|
||||
_pendingBidPriority(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -61,9 +61,9 @@ bool SimulationOwner::fromByteArray(const QByteArray& data) {
|
|||
void SimulationOwner::clear() {
|
||||
_id = QUuid();
|
||||
_expiry = 0;
|
||||
_pendingTimestamp = 0;
|
||||
_pendingBidTimestamp = 0;
|
||||
_priority = 0;
|
||||
_pendingPriority = 0;
|
||||
_pendingBidPriority = 0;
|
||||
_pendingState = PENDING_STATE_NOTHING;
|
||||
}
|
||||
|
||||
|
@ -102,9 +102,9 @@ bool SimulationOwner::set(const SimulationOwner& owner) {
|
|||
}
|
||||
|
||||
void SimulationOwner::setPendingPriority(quint8 priority, const quint64& timestamp) {
|
||||
_pendingPriority = priority;
|
||||
_pendingTimestamp = timestamp;
|
||||
_pendingState = (_pendingPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE;
|
||||
_pendingBidPriority = priority;
|
||||
_pendingBidTimestamp = timestamp;
|
||||
_pendingState = (_pendingBidPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE;
|
||||
}
|
||||
|
||||
void SimulationOwner::updateExpiry() {
|
||||
|
@ -113,11 +113,11 @@ void SimulationOwner::updateExpiry() {
|
|||
}
|
||||
|
||||
bool SimulationOwner::pendingRelease(const quint64& timestamp) {
|
||||
return _pendingPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingTimestamp >= timestamp;
|
||||
return _pendingBidPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingBidTimestamp >= timestamp;
|
||||
}
|
||||
|
||||
bool SimulationOwner::pendingTake(const quint64& timestamp) {
|
||||
return _pendingPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingTimestamp >= timestamp;
|
||||
return _pendingBidPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingBidTimestamp >= timestamp;
|
||||
}
|
||||
|
||||
void SimulationOwner::clearCurrentOwner() {
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
|
||||
bool hasExpired() const { return usecTimestampNow() > _expiry; }
|
||||
|
||||
uint8_t getPendingPriority() const { return _pendingBidPriority; }
|
||||
bool pendingRelease(const quint64& timestamp); // return true if valid pending RELEASE
|
||||
bool pendingTake(const quint64& timestamp); // return true if valid pending TAKE
|
||||
void clearCurrentOwner();
|
||||
|
@ -84,9 +85,9 @@ public:
|
|||
private:
|
||||
QUuid _id; // owner
|
||||
quint64 _expiry; // time when ownership can transition at equal priority
|
||||
quint64 _pendingTimestamp; // time when pending update was set
|
||||
quint64 _pendingBidTimestamp; // time when pending bid was set
|
||||
quint8 _priority; // priority of current owner
|
||||
quint8 _pendingPriority; // priority of pendingTake
|
||||
quint8 _pendingBidPriority; // priority at which we'd like to own it
|
||||
quint8 _pendingState; // NOTHING, TAKE, or RELEASE
|
||||
};
|
||||
|
||||
|
|
28
libraries/gpu/src/gpu/DrawTransformVertexPosition.slv
Normal file
28
libraries/gpu/src/gpu/DrawTransformVertexPosition.slv
Normal file
|
@ -0,0 +1,28 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Draw and transform the fed vertex position with the standard MVP stack
|
||||
// Output the clip position
|
||||
//
|
||||
// Created by Sam Gateau on 5/30/2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
layout(location = 0) in vec4 inPosition;
|
||||
|
||||
out vec3 varWorldPos;
|
||||
|
||||
void main(void) {
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
|
||||
}
|
|
@ -2,25 +2,18 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// hit_effect.vert
|
||||
// vertex shader
|
||||
// Draw the fed vertex position, pass straight as clip pos
|
||||
// Output the clip position
|
||||
//
|
||||
// Created by Eric Levin on 7/20/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
// Created by Sam Gateau on 5/30/2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec2 varQuadPosition;
|
||||
layout(location = 0) in vec4 inPosition;
|
||||
|
||||
void main(void) {
|
||||
varQuadPosition = inPosition.xy;
|
||||
gl_Position = inPosition;
|
||||
}
|
||||
}
|
|
@ -2,15 +2,17 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// drawOpaqueStencil.frag
|
||||
// fragment shader
|
||||
// Draw white
|
||||
//
|
||||
// Created by Sam Gateau on 9/29/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
// Created by Sam Gateau on 5/30/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = vec4(1.0);
|
||||
}
|
|
@ -16,6 +16,12 @@
|
|||
#include "DrawTransformUnitQuad_vert.h"
|
||||
#include "DrawTexcoordRectTransformUnitQuad_vert.h"
|
||||
#include "DrawViewportQuadTransformTexcoord_vert.h"
|
||||
#include "DrawVertexPosition_vert.h"
|
||||
#include "DrawTransformVertexPosition_vert.h"
|
||||
|
||||
const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple...
|
||||
|
||||
#include "DrawWhite_frag.h"
|
||||
#include "DrawTexture_frag.h"
|
||||
#include "DrawTextureOpaque_frag.h"
|
||||
#include "DrawColoredTexture_frag.h"
|
||||
|
@ -26,6 +32,10 @@ ShaderPointer StandardShaderLib::_drawUnitQuadTexcoordVS;
|
|||
ShaderPointer StandardShaderLib::_drawTransformUnitQuadVS;
|
||||
ShaderPointer StandardShaderLib::_drawTexcoordRectTransformUnitQuadVS;
|
||||
ShaderPointer StandardShaderLib::_drawViewportQuadTransformTexcoordVS;
|
||||
ShaderPointer StandardShaderLib::_drawVertexPositionVS;
|
||||
ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS;
|
||||
ShaderPointer StandardShaderLib::_drawNadaPS;
|
||||
ShaderPointer StandardShaderLib::_drawWhitePS;
|
||||
ShaderPointer StandardShaderLib::_drawTexturePS;
|
||||
ShaderPointer StandardShaderLib::_drawTextureOpaquePS;
|
||||
ShaderPointer StandardShaderLib::_drawColoredTexturePS;
|
||||
|
@ -85,6 +95,34 @@ ShaderPointer StandardShaderLib::getDrawViewportQuadTransformTexcoordVS() {
|
|||
return _drawViewportQuadTransformTexcoordVS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawVertexPositionVS() {
|
||||
if (!_drawVertexPositionVS) {
|
||||
_drawVertexPositionVS = gpu::Shader::createVertex(std::string(DrawVertexPosition_vert));
|
||||
}
|
||||
return _drawVertexPositionVS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawTransformVertexPositionVS() {
|
||||
if (!_drawTransformVertexPositionVS) {
|
||||
_drawTransformVertexPositionVS = gpu::Shader::createVertex(std::string(DrawTransformVertexPosition_vert));
|
||||
}
|
||||
return _drawTransformVertexPositionVS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawNadaPS() {
|
||||
if (!_drawNadaPS) {
|
||||
_drawNadaPS = gpu::Shader::createPixel(std::string(DrawNada_frag));
|
||||
}
|
||||
return _drawNadaPS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawWhitePS() {
|
||||
if (!_drawWhitePS) {
|
||||
_drawWhitePS = gpu::Shader::createPixel(std::string(DrawWhite_frag));
|
||||
}
|
||||
return _drawWhitePS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawTexturePS() {
|
||||
if (!_drawTexturePS) {
|
||||
_drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag));
|
||||
|
@ -99,8 +137,6 @@ ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() {
|
|||
return _drawTextureOpaquePS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawColoredTexturePS() {
|
||||
if (!_drawColoredTexturePS) {
|
||||
_drawColoredTexturePS = gpu::Shader::createPixel(std::string(DrawColoredTexture_frag));
|
||||
|
|
|
@ -37,6 +37,15 @@ public:
|
|||
// Shader draws the unit quad in the full viewport clipPos = ([(-1,-1),(1,1)]) and transform the texcoord = [(0,0),(1,1)] by the model transform.
|
||||
static ShaderPointer getDrawViewportQuadTransformTexcoordVS();
|
||||
|
||||
// Shader draw the fed vertex position and transform it by the full model transform stack (Model, View, Proj).
|
||||
// simply output the world pos and the clip pos to the next stage
|
||||
static ShaderPointer getDrawVertexPositionVS();
|
||||
static ShaderPointer getDrawTransformVertexPositionVS();
|
||||
|
||||
// PShader does nothing, no really nothing, but still needed for defining a program triggering rasterization
|
||||
static ShaderPointer getDrawNadaPS();
|
||||
|
||||
static ShaderPointer getDrawWhitePS();
|
||||
static ShaderPointer getDrawTexturePS();
|
||||
static ShaderPointer getDrawTextureOpaquePS();
|
||||
static ShaderPointer getDrawColoredTexturePS();
|
||||
|
@ -51,6 +60,12 @@ protected:
|
|||
static ShaderPointer _drawTransformUnitQuadVS;
|
||||
static ShaderPointer _drawTexcoordRectTransformUnitQuadVS;
|
||||
static ShaderPointer _drawViewportQuadTransformTexcoordVS;
|
||||
|
||||
static ShaderPointer _drawVertexPositionVS;
|
||||
static ShaderPointer _drawTransformVertexPositionVS;
|
||||
|
||||
static ShaderPointer _drawNadaPS;
|
||||
static ShaderPointer _drawWhitePS;
|
||||
static ShaderPointer _drawTexturePS;
|
||||
static ShaderPointer _drawTextureOpaquePS;
|
||||
static ShaderPointer _drawColoredTexturePS;
|
||||
|
|
|
@ -11,14 +11,28 @@
|
|||
|
||||
#include "KTXCache.h"
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include <ktx/KTX.h>
|
||||
|
||||
using File = cache::File;
|
||||
using FilePointer = cache::FilePointer;
|
||||
|
||||
// Whenever a change is made to the serialized format for the KTX cache that isn't backward compatible,
|
||||
// this value should be incremented. This will force the KTX cache to be wiped
|
||||
const int KTXCache::CURRENT_VERSION = 0x01;
|
||||
const int KTXCache::INVALID_VERSION = 0x00;
|
||||
const char* KTXCache::SETTING_VERSION_NAME = "hifi.ktx.cache_version";
|
||||
|
||||
KTXCache::KTXCache(const std::string& dir, const std::string& ext) :
|
||||
FileCache(dir, ext) {
|
||||
initialize();
|
||||
|
||||
Setting::Handle<int> cacheVersionHandle(SETTING_VERSION_NAME, INVALID_VERSION);
|
||||
auto cacheVersion = cacheVersionHandle.get();
|
||||
if (cacheVersion != CURRENT_VERSION) {
|
||||
wipe();
|
||||
cacheVersionHandle.set(CURRENT_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
KTXFilePointer KTXCache::writeFile(const char* data, Metadata&& metadata) {
|
||||
|
|
|
@ -27,6 +27,12 @@ class KTXCache : public cache::FileCache {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// Whenever a change is made to the serialized format for the KTX cache that isn't backward compatible,
|
||||
// this value should be incremented. This will force the KTX cache to be wiped
|
||||
static const int CURRENT_VERSION;
|
||||
static const int INVALID_VERSION;
|
||||
static const char* SETTING_VERSION_NAME;
|
||||
|
||||
KTXCache(const std::string& dir, const std::string& ext);
|
||||
|
||||
KTXFilePointer writeFile(const char* data, Metadata&& metadata);
|
||||
|
|
|
@ -241,6 +241,42 @@ void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
|
|||
}
|
||||
}
|
||||
|
||||
MeshPointer Mesh::createIndexedTriangles_P3F(uint32_t numVertices, uint32_t numIndices, const glm::vec3* vertices, const uint32_t* indices) {
|
||||
MeshPointer mesh;
|
||||
if (numVertices == 0) { return mesh; }
|
||||
if (numIndices < 3) { return mesh; }
|
||||
|
||||
mesh = std::make_shared<Mesh>();
|
||||
|
||||
// Vertex buffer
|
||||
mesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(numVertices * sizeof(glm::vec3), (gpu::Byte*) vertices), gpu::Element::VEC3F_XYZ));
|
||||
|
||||
// trim down the indices to shorts if possible
|
||||
if (numIndices < std::numeric_limits<uint16_t>::max()) {
|
||||
Indices16 shortIndicesVector;
|
||||
int16_t* shortIndices = nullptr;
|
||||
if (indices) {
|
||||
shortIndicesVector.resize(numIndices);
|
||||
for (uint32_t i = 0; i < numIndices; i++) {
|
||||
shortIndicesVector[i] = indices[i];
|
||||
}
|
||||
shortIndices = shortIndicesVector.data();
|
||||
}
|
||||
|
||||
mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(numIndices * sizeof(uint16_t), (gpu::Byte*) shortIndices), gpu::Element::INDEX_UINT16));
|
||||
} else {
|
||||
|
||||
mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(numIndices * sizeof(uint32_t), (gpu::Byte*) indices), gpu::Element::INDEX_INT32));
|
||||
}
|
||||
|
||||
|
||||
std::vector<model::Mesh::Part> parts;
|
||||
parts.push_back(model::Mesh::Part(0, numIndices, 0, model::Mesh::TRIANGLES));
|
||||
mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
Geometry::Geometry() {
|
||||
}
|
||||
|
@ -256,3 +292,5 @@ Geometry::~Geometry() {
|
|||
void Geometry::setMesh(const MeshPointer& mesh) {
|
||||
_mesh = mesh;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -65,6 +65,9 @@ public:
|
|||
const gpu::BufferStream& getVertexStream() const { return _vertexStream; }
|
||||
|
||||
// Index Buffer
|
||||
using Indices16 = std::vector<int16_t>;
|
||||
using Indices32 = std::vector<int32_t>;
|
||||
|
||||
void setIndexBuffer(const BufferView& buffer);
|
||||
const BufferView& getIndexBuffer() const { return _indexBuffer; }
|
||||
size_t getNumIndices() const { return _indexBuffer.getNumElements(); }
|
||||
|
@ -127,6 +130,9 @@ public:
|
|||
std::function<void(glm::vec3)> normalFunc,
|
||||
std::function<void(uint32_t)> indexFunc);
|
||||
|
||||
|
||||
static MeshPointer createIndexedTriangles_P3F(uint32_t numVertices, uint32_t numTriangles, const glm::vec3* vertices = nullptr, const uint32_t* indices = nullptr);
|
||||
|
||||
protected:
|
||||
|
||||
gpu::Stream::FormatPointer _vertexFormat;
|
||||
|
|
|
@ -97,7 +97,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
}
|
||||
|
||||
auto skyState = std::make_shared<gpu::State>();
|
||||
skyState->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
skyState->setStencilTest(true, 0xFF, gpu::State::StencilTest(1, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
|
||||
thePipeline = gpu::Pipeline::create(skyShader, skyState);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ Q_DECLARE_METATYPE(QNetworkAccessManager::Operation)
|
|||
Q_DECLARE_METATYPE(JSONCallbackParameters)
|
||||
|
||||
const QString ACCOUNTS_GROUP = "accounts";
|
||||
static const auto METAVERSE_SESSION_ID_HEADER = QString("HFM-SessionID").toLocal8Bit();
|
||||
|
||||
JSONCallbackParameters::JSONCallbackParameters(QObject* jsonCallbackReceiver, const QString& jsonCallbackMethod,
|
||||
QObject* errorCallbackReceiver, const QString& errorCallbackMethod,
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace AccountManagerAuth {
|
|||
Q_DECLARE_METATYPE(AccountManagerAuth::Type);
|
||||
|
||||
const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization";
|
||||
const auto METAVERSE_SESSION_ID_HEADER = QString("HFM-SessionID").toLocal8Bit();
|
||||
|
||||
using UserAgentGetter = std::function<QString()>;
|
||||
|
||||
|
|
|
@ -236,6 +236,28 @@ namespace cache {
|
|||
};
|
||||
}
|
||||
|
||||
void FileCache::eject(const FilePointer& file) {
|
||||
file->_cache = nullptr;
|
||||
const auto& length = file->getLength();
|
||||
const auto& key = file->getKey();
|
||||
|
||||
{
|
||||
Lock lock(_filesMutex);
|
||||
if (0 != _files.erase(key)) {
|
||||
_numTotalFiles -= 1;
|
||||
_totalFilesSize -= length;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Lock unusedLock(_unusedFilesMutex);
|
||||
if (0 != _unusedFiles.erase(file)) {
|
||||
_numUnusedFiles -= 1;
|
||||
_unusedFilesSize -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileCache::clean() {
|
||||
size_t overbudgetAmount = getOverbudgetAmount();
|
||||
|
||||
|
@ -250,28 +272,23 @@ void FileCache::clean() {
|
|||
for (const auto& file : _unusedFiles) {
|
||||
queue.push(file);
|
||||
}
|
||||
|
||||
while (!queue.empty() && overbudgetAmount > 0) {
|
||||
auto file = queue.top();
|
||||
queue.pop();
|
||||
eject(file);
|
||||
auto length = file->getLength();
|
||||
|
||||
unusedLock.unlock();
|
||||
{
|
||||
file->_cache = nullptr;
|
||||
Lock lock(_filesMutex);
|
||||
_files.erase(file->getKey());
|
||||
}
|
||||
unusedLock.lock();
|
||||
|
||||
_unusedFiles.erase(file);
|
||||
_numTotalFiles -= 1;
|
||||
_numUnusedFiles -= 1;
|
||||
_totalFilesSize -= length;
|
||||
_unusedFilesSize -= length;
|
||||
overbudgetAmount -= std::min(length, overbudgetAmount);
|
||||
}
|
||||
}
|
||||
|
||||
void FileCache::wipe() {
|
||||
Lock unusedFilesLock(_unusedFilesMutex);
|
||||
while (!_unusedFiles.empty()) {
|
||||
eject(*_unusedFiles.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void FileCache::clear() {
|
||||
// Eliminate any overbudget files
|
||||
clean();
|
||||
|
|
|
@ -46,6 +46,9 @@ public:
|
|||
FileCache(const std::string& dirname, const std::string& ext, QObject* parent = nullptr);
|
||||
virtual ~FileCache();
|
||||
|
||||
// Remove all unlocked items from the cache
|
||||
void wipe();
|
||||
|
||||
size_t getNumTotalFiles() const { return _numTotalFiles; }
|
||||
size_t getNumCachedFiles() const { return _numUnusedFiles; }
|
||||
size_t getSizeTotalFiles() const { return _totalFilesSize; }
|
||||
|
@ -95,6 +98,9 @@ public:
|
|||
private:
|
||||
using Mutex = std::recursive_mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
using Map = std::unordered_map<Key, std::weak_ptr<File>>;
|
||||
using Set = std::unordered_set<FilePointer>;
|
||||
using KeySet = std::unordered_set<Key>;
|
||||
|
||||
friend class File;
|
||||
|
||||
|
@ -105,6 +111,8 @@ private:
|
|||
void removeUnusedFile(const FilePointer& file);
|
||||
void clean();
|
||||
void clear();
|
||||
// Remove a file from the cache
|
||||
void eject(const FilePointer& file);
|
||||
|
||||
size_t getOverbudgetAmount() const;
|
||||
|
||||
|
@ -122,10 +130,10 @@ private:
|
|||
std::string _dirpath;
|
||||
bool _initialized { false };
|
||||
|
||||
std::unordered_map<Key, std::weak_ptr<File>> _files;
|
||||
Map _files;
|
||||
Mutex _filesMutex;
|
||||
|
||||
std::unordered_set<FilePointer> _unusedFiles;
|
||||
Set _unusedFiles;
|
||||
Mutex _unusedFilesMutex;
|
||||
};
|
||||
|
||||
|
@ -136,8 +144,8 @@ public:
|
|||
using Key = FileCache::Key;
|
||||
using Metadata = FileCache::Metadata;
|
||||
|
||||
Key getKey() const { return _key; }
|
||||
size_t getLength() const { return _length; }
|
||||
const Key& getKey() const { return _key; }
|
||||
const size_t& getLength() const { return _length; }
|
||||
std::string getFilepath() const { return _filepath; }
|
||||
|
||||
virtual ~File();
|
||||
|
|
|
@ -52,9 +52,8 @@ bool readStatus(QByteArray statusData) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void runLocalSandbox(QString contentPath, bool autoShutdown, QString runningMarkerName, bool noUpdater) {
|
||||
void runLocalSandbox(QString contentPath, bool autoShutdown, bool noUpdater) {
|
||||
QString serverPath = "./server-console/server-console.exe";
|
||||
qCDebug(networking) << "Running marker path is: " << runningMarkerName;
|
||||
qCDebug(networking) << "Server path is: " << serverPath;
|
||||
qCDebug(networking) << "autoShutdown: " << autoShutdown;
|
||||
qCDebug(networking) << "noUpdater: " << noUpdater;
|
||||
|
@ -74,8 +73,8 @@ void runLocalSandbox(QString contentPath, bool autoShutdown, QString runningMark
|
|||
}
|
||||
|
||||
if (autoShutdown) {
|
||||
QString interfaceRunningStateFile = RunningMarker::getMarkerFilePath(runningMarkerName);
|
||||
args << "--shutdownWatcher" << interfaceRunningStateFile;
|
||||
auto pid = QCoreApplication::applicationPid();
|
||||
args << "--shutdownWith" << QString::number(pid);
|
||||
}
|
||||
|
||||
if (noUpdater) {
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace SandboxUtils {
|
|||
|
||||
QNetworkReply* getStatus();
|
||||
bool readStatus(QByteArray statusData);
|
||||
void runLocalSandbox(QString contentPath, bool autoShutdown, QString runningMarkerName, bool noUpdater);
|
||||
void runLocalSandbox(QString contentPath, bool autoShutdown, bool noUpdater);
|
||||
};
|
||||
|
||||
#endif // hifi_SandboxUtils_h
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include <DependencyManager.h>
|
||||
#include "AddressManager.h"
|
||||
|
||||
static const QString USER_ACTIVITY_URL = "/api/v1/user_activities";
|
||||
|
||||
UserActivityLogger& UserActivityLogger::getInstance() {
|
||||
static UserActivityLogger sharedInstance;
|
||||
return sharedInstance;
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <SettingHandle.h>
|
||||
#include "AddressManager.h"
|
||||
|
||||
const QString USER_ACTIVITY_URL = "/api/v1/user_activities";
|
||||
|
||||
class UserActivityLogger : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ void UserActivityLoggerScriptingInterface::palAction(QString action, QString tar
|
|||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::palOpened(float secondsOpened) {
|
||||
doLogAction("pal_opened", {
|
||||
doLogAction("pal_opened", {
|
||||
{ "seconds_opened", secondsOpened }
|
||||
});
|
||||
}
|
||||
|
@ -71,6 +71,14 @@ void UserActivityLoggerScriptingInterface::makeUserConnection(QString otherID, b
|
|||
doLogAction("makeUserConnection", payload);
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::bubbleToggled(bool newValue) {
|
||||
doLogAction(newValue ? "bubbleOn" : "bubbleOff");
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::bubbleActivated() {
|
||||
doLogAction("bubbleActivated");
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::logAction(QString action, QVariantMap details) {
|
||||
doLogAction(action, QJsonObject::fromVariantMap(details));
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ public:
|
|||
Q_INVOKABLE void palAction(QString action, QString target);
|
||||
Q_INVOKABLE void palOpened(float secondsOpen);
|
||||
Q_INVOKABLE void makeUserConnection(QString otherUser, bool success, QString details = "");
|
||||
Q_INVOKABLE void bubbleToggled(bool newValue);
|
||||
Q_INVOKABLE void bubbleActivated();
|
||||
Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{});
|
||||
private:
|
||||
void doLogAction(QString action, QJsonObject details = {});
|
||||
|
|
|
@ -65,8 +65,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
|
|||
_lastStep(0),
|
||||
_loopsWithoutOwner(0),
|
||||
_accelerationNearlyGravityCount(0),
|
||||
_numInactiveUpdates(1),
|
||||
_outgoingPriority(0)
|
||||
_numInactiveUpdates(1)
|
||||
{
|
||||
_type = MOTIONSTATE_TYPE_ENTITY;
|
||||
assert(_entity);
|
||||
|
@ -75,6 +74,8 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
|
|||
// we need the side-effects of EntityMotionState::setShape() so we call it explicitly here
|
||||
// rather than pass the legit shape pointer to the ObjectMotionState ctor above.
|
||||
setShape(shape);
|
||||
|
||||
_outgoingPriority = _entity->getPendingOwnershipPriority();
|
||||
}
|
||||
|
||||
EntityMotionState::~EntityMotionState() {
|
||||
|
@ -84,7 +85,7 @@ EntityMotionState::~EntityMotionState() {
|
|||
|
||||
void EntityMotionState::updateServerPhysicsVariables() {
|
||||
assert(entityTreeIsLocked());
|
||||
if (_entity->getSimulatorID() == Physics::getSessionUUID()) {
|
||||
if (isLocallyOwned()) {
|
||||
// don't slam these values if we are the simulation owner
|
||||
return;
|
||||
}
|
||||
|
@ -114,6 +115,7 @@ void EntityMotionState::handleDeactivation() {
|
|||
|
||||
// virtual
|
||||
void EntityMotionState::handleEasyChanges(uint32_t& flags) {
|
||||
assert(_entity);
|
||||
assert(entityTreeIsLocked());
|
||||
updateServerPhysicsVariables();
|
||||
ObjectMotionState::handleEasyChanges(flags);
|
||||
|
@ -135,23 +137,23 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) {
|
|||
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
|
||||
}
|
||||
_loopsWithoutOwner = 0;
|
||||
} else if (_entity->getSimulatorID() == Physics::getSessionUUID()) {
|
||||
_numInactiveUpdates = 0;
|
||||
} else if (isLocallyOwned()) {
|
||||
// we just inherited ownership, make sure our desired priority matches what we have
|
||||
upgradeOutgoingPriority(_entity->getSimulationPriority());
|
||||
} else {
|
||||
_outgoingPriority = 0;
|
||||
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
|
||||
_numInactiveUpdates = 0;
|
||||
}
|
||||
}
|
||||
if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) {
|
||||
// The DIRTY_SIMULATOR_OWNERSHIP_PRIORITY bits really mean "we should bid for ownership because
|
||||
// a local script has been changing physics properties, or we should adjust our own ownership priority".
|
||||
// The desired priority is determined by which bits were set.
|
||||
if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB) {
|
||||
_outgoingPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
||||
} else {
|
||||
_outgoingPriority = SCRIPT_POKE_SIMULATION_PRIORITY;
|
||||
}
|
||||
// The DIRTY_SIMULATOR_OWNERSHIP_PRIORITY bit means one of the following:
|
||||
// (1) we own it but may need to change the priority OR...
|
||||
// (2) we don't own it but should bid (because a local script has been changing physics properties)
|
||||
uint8_t newPriority = isLocallyOwned() ? _entity->getSimulationOwner().getPriority() : _entity->getSimulationOwner().getPendingPriority();
|
||||
_outgoingPriority = glm::max(_outgoingPriority, newPriority);
|
||||
|
||||
// reset bid expiry so that we bid ASAP
|
||||
_nextOwnershipBid = 0;
|
||||
}
|
||||
|
@ -170,6 +172,7 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) {
|
|||
|
||||
// virtual
|
||||
bool EntityMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) {
|
||||
assert(_entity);
|
||||
updateServerPhysicsVariables();
|
||||
return ObjectMotionState::handleHardAndEasyChanges(flags, engine);
|
||||
}
|
||||
|
@ -315,7 +318,7 @@ bool EntityMotionState::isCandidateForOwnership() const {
|
|||
assert(_entity);
|
||||
assert(entityTreeIsLocked());
|
||||
return _outgoingPriority != 0
|
||||
|| Physics::getSessionUUID() == _entity->getSimulatorID()
|
||||
|| isLocallyOwned()
|
||||
|| _entity->dynamicDataNeedsTransmit();
|
||||
}
|
||||
|
||||
|
@ -489,7 +492,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_entity->getSimulatorID() != Physics::getSessionUUID()) {
|
||||
if (!isLocallyOwned()) {
|
||||
// we don't own the simulation
|
||||
|
||||
// NOTE: we do not volunteer to own kinematic or static objects
|
||||
|
@ -597,7 +600,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
properties.clearSimulationOwner();
|
||||
_outgoingPriority = 0;
|
||||
_entity->setPendingOwnershipPriority(_outgoingPriority, now);
|
||||
} else if (Physics::getSessionUUID() != _entity->getSimulatorID()) {
|
||||
} else if (!isLocallyOwned()) {
|
||||
// we don't own the simulation for this entity yet, but we're sending a bid for it
|
||||
quint8 bidPriority = glm::max<uint8_t>(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY);
|
||||
properties.setSimulationOwner(Physics::getSessionUUID(), bidPriority);
|
||||
|
@ -786,6 +789,10 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma
|
|||
_entity->computeCollisionGroupAndFinalMask(group, mask);
|
||||
}
|
||||
|
||||
bool EntityMotionState::isLocallyOwned() const {
|
||||
return _entity->getSimulatorID() == Physics::getSessionUUID();
|
||||
}
|
||||
|
||||
bool EntityMotionState::shouldBeLocallyOwned() const {
|
||||
return (_outgoingPriority > VOLUNTEER_SIMULATION_PRIORITY && _outgoingPriority > _entity->getSimulationPriority()) ||
|
||||
_entity->getSimulatorID() == Physics::getSessionUUID();
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
|
||||
virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override;
|
||||
|
||||
bool isLocallyOwned() const override;
|
||||
bool shouldBeLocallyOwned() const override;
|
||||
|
||||
friend class PhysicalEntitySimulation;
|
||||
|
|
|
@ -202,6 +202,7 @@ void ObjectMotionState::setShape(const btCollisionShape* shape) {
|
|||
}
|
||||
|
||||
void ObjectMotionState::handleEasyChanges(uint32_t& flags) {
|
||||
assert(_body && _shape);
|
||||
if (flags & Simulation::DIRTY_POSITION) {
|
||||
btTransform worldTrans = _body->getWorldTransform();
|
||||
btVector3 newPosition = glmToBullet(getObjectPosition());
|
||||
|
@ -282,6 +283,7 @@ void ObjectMotionState::handleEasyChanges(uint32_t& flags) {
|
|||
}
|
||||
|
||||
bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) {
|
||||
assert(_body && _shape);
|
||||
if (flags & Simulation::DIRTY_SHAPE) {
|
||||
// make sure the new shape is valid
|
||||
if (!isReadyToComputeShape()) {
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
static ShapeManager* getShapeManager();
|
||||
|
||||
ObjectMotionState(const btCollisionShape* shape);
|
||||
~ObjectMotionState();
|
||||
virtual ~ObjectMotionState();
|
||||
|
||||
virtual void handleEasyChanges(uint32_t& flags);
|
||||
virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine);
|
||||
|
@ -146,6 +146,7 @@ public:
|
|||
void dirtyInternalKinematicChanges() { _hasInternalKinematicChanges = true; }
|
||||
void clearInternalKinematicChanges() { _hasInternalKinematicChanges = false; }
|
||||
|
||||
virtual bool isLocallyOwned() const { return false; }
|
||||
virtual bool shouldBeLocallyOwned() const { return false; }
|
||||
|
||||
friend class PhysicsEngine;
|
||||
|
|
|
@ -130,7 +130,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() {
|
|||
}
|
||||
|
||||
// then remove the objects (aka MotionStates) from physics
|
||||
_physicsEngine->removeObjects(_physicalObjects);
|
||||
_physicsEngine->removeSetOfObjects(_physicalObjects);
|
||||
|
||||
// delete the MotionStates
|
||||
// TODO: after we invert the entities/physics lib dependencies we will let EntityItem delete
|
||||
|
|
|
@ -129,6 +129,9 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
|
|||
}
|
||||
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||
body->updateInertiaTensor();
|
||||
if (motionState->isLocallyOwned()) {
|
||||
_activeStaticBodies.insert(body);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -174,19 +177,9 @@ void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) {
|
|||
// frame (because the framerate is faster than our physics simulation rate). When this happens we must scan
|
||||
// _activeStaticBodies for objects that were recently deleted so we don't try to access a dangling pointer.
|
||||
for (auto object : objects) {
|
||||
btRigidBody* body = object->getRigidBody();
|
||||
|
||||
std::vector<btRigidBody*>::reverse_iterator itr = _activeStaticBodies.rbegin();
|
||||
while (itr != _activeStaticBodies.rend()) {
|
||||
if (body == *itr) {
|
||||
if (*itr != *(_activeStaticBodies.rbegin())) {
|
||||
// swap with rbegin
|
||||
*itr = *(_activeStaticBodies.rbegin());
|
||||
}
|
||||
_activeStaticBodies.pop_back();
|
||||
break;
|
||||
}
|
||||
++itr;
|
||||
std::set<btRigidBody*>::iterator itr = _activeStaticBodies.find(object->getRigidBody());
|
||||
if (itr != _activeStaticBodies.end()) {
|
||||
_activeStaticBodies.erase(itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +200,7 @@ void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) {
|
|||
}
|
||||
|
||||
// Same as above, but takes a Set instead of a Vector. Should only be called during teardown.
|
||||
void PhysicsEngine::removeObjects(const SetOfMotionStates& objects) {
|
||||
void PhysicsEngine::removeSetOfObjects(const SetOfMotionStates& objects) {
|
||||
_contactMap.clear();
|
||||
for (auto object : objects) {
|
||||
btRigidBody* body = object->getRigidBody();
|
||||
|
@ -245,14 +238,16 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob
|
|||
object->clearIncomingDirtyFlags();
|
||||
}
|
||||
if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) {
|
||||
_activeStaticBodies.push_back(object->getRigidBody());
|
||||
_activeStaticBodies.insert(object->getRigidBody());
|
||||
}
|
||||
}
|
||||
// active static bodies have changed (in an Easy way) and need their Aabbs updated
|
||||
// but we've configured Bullet to NOT update them automatically (for improved performance)
|
||||
// so we must do it ourselves
|
||||
for (size_t i = 0; i < _activeStaticBodies.size(); ++i) {
|
||||
_dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]);
|
||||
std::set<btRigidBody*>::const_iterator itr = _activeStaticBodies.begin();
|
||||
while (itr != _activeStaticBodies.end()) {
|
||||
_dynamicsWorld->updateSingleAabb(*itr);
|
||||
++itr;
|
||||
}
|
||||
return stillNeedChange;
|
||||
}
|
||||
|
@ -496,13 +491,23 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() {
|
|||
|
||||
const VectorOfMotionStates& PhysicsEngine::getChangedMotionStates() {
|
||||
BT_PROFILE("copyOutgoingChanges");
|
||||
|
||||
_dynamicsWorld->synchronizeMotionStates();
|
||||
|
||||
// Bullet will not deactivate static objects (it doesn't expect them to be active)
|
||||
// so we must deactivate them ourselves
|
||||
for (size_t i = 0; i < _activeStaticBodies.size(); ++i) {
|
||||
_activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING);
|
||||
std::set<btRigidBody*>::const_iterator itr = _activeStaticBodies.begin();
|
||||
while (itr != _activeStaticBodies.end()) {
|
||||
btRigidBody* body = *itr;
|
||||
body->forceActivationState(ISLAND_SLEEPING);
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(body->getUserPointer());
|
||||
if (motionState) {
|
||||
_dynamicsWorld->addChangedMotionState(motionState);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
_activeStaticBodies.clear();
|
||||
_dynamicsWorld->synchronizeMotionStates();
|
||||
|
||||
_hasOutgoingChanges = false;
|
||||
return _dynamicsWorld->getChangedMotionStates();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_PhysicsEngine_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <QUuid>
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
uint32_t getNumSubsteps();
|
||||
|
||||
void removeObjects(const VectorOfMotionStates& objects);
|
||||
void removeObjects(const SetOfMotionStates& objects); // only called during teardown
|
||||
void removeSetOfObjects(const SetOfMotionStates& objects); // only called during teardown
|
||||
|
||||
void addObjects(const VectorOfMotionStates& objects);
|
||||
VectorOfMotionStates changeObjects(const VectorOfMotionStates& objects);
|
||||
|
@ -114,7 +115,7 @@ private:
|
|||
CollisionEvents _collisionEvents;
|
||||
QHash<QUuid, EntityDynamicPointer> _objectDynamics;
|
||||
QHash<btRigidBody*, QSet<QUuid>> _objectDynamicsByBody;
|
||||
std::vector<btRigidBody*> _activeStaticBodies;
|
||||
std::set<btRigidBody*> _activeStaticBodies;
|
||||
|
||||
glm::vec3 _originOffset;
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ public:
|
|||
const VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; }
|
||||
const VectorOfMotionStates& getDeactivatedMotionStates() const { return _deactivatedStates; }
|
||||
|
||||
void addChangedMotionState(ObjectMotionState* motionState) { _changedMotionStates.push_back(motionState); }
|
||||
|
||||
private:
|
||||
// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
|
||||
void synchronizeMotionState(btRigidBody* body);
|
||||
|
|
|
@ -23,7 +23,7 @@ ProceduralSkybox::ProceduralSkybox() : model::Skybox() {
|
|||
_procedural._fragmentSource = skybox_frag;
|
||||
// Adjust the pipeline state for background using the stencil test
|
||||
_procedural.setDoesFade(false);
|
||||
_procedural._opaqueState->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
_procedural._opaqueState->setStencilTest(true, 0xFF, gpu::State::StencilTest(1, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
}
|
||||
|
||||
bool ProceduralSkybox::empty() {
|
||||
|
|
|
@ -260,7 +260,7 @@ static void addLink(const AnimPose& rootPose, const AnimPose& pose, const AnimPo
|
|||
// there is room, so lets draw a nice bone
|
||||
|
||||
glm::vec3 uAxis, vAxis, wAxis;
|
||||
generateBasisVectors(boneAxis0, glm::vec3(1, 0, 0), uAxis, vAxis, wAxis);
|
||||
generateBasisVectors(boneAxis0, glm::vec3(1.0f, 0.0f, 0.0f), uAxis, vAxis, wAxis);
|
||||
|
||||
glm::vec3 boneBaseCorners[NUM_BASE_CORNERS];
|
||||
boneBaseCorners[0] = pose0 * ((uAxis * radius) + (vAxis * radius) + (wAxis * radius));
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <gpu/Context.h>
|
||||
|
||||
#include "AntialiasingEffect.h"
|
||||
#include "StencilMaskPass.h"
|
||||
#include "TextureCache.h"
|
||||
#include "FramebufferCache.h"
|
||||
#include "DependencyManager.h"
|
||||
|
@ -70,6 +71,8 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
|||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
state->setDepthTest(false, false, gpu::LESS_EQUAL);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
|
@ -93,6 +96,7 @@ const gpu::PipelinePointer& Antialiasing::getBlendPipeline() {
|
|||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setDepthTest(false, false, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_blendPipeline = gpu::Pipeline::create(program, state);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include "StencilMaskPass.h"
|
||||
#include "AbstractViewStateInterface.h"
|
||||
#include "GeometryCache.h"
|
||||
#include "TextureCache.h"
|
||||
|
@ -27,18 +28,15 @@
|
|||
#include "deferred_light_point_vert.h"
|
||||
#include "deferred_light_spot_vert.h"
|
||||
|
||||
#include "directional_light_frag.h"
|
||||
#include "directional_ambient_light_frag.h"
|
||||
#include "directional_skybox_light_frag.h"
|
||||
|
||||
#include "directional_light_shadow_frag.h"
|
||||
#include "directional_ambient_light_shadow_frag.h"
|
||||
#include "directional_skybox_light_shadow_frag.h"
|
||||
|
||||
#include "local_lights_shading_frag.h"
|
||||
#include "local_lights_drawOutline_frag.h"
|
||||
#include "point_light_frag.h"
|
||||
#include "spot_light_frag.h"
|
||||
|
||||
|
||||
using namespace render;
|
||||
|
||||
|
@ -82,48 +80,26 @@ enum DeferredShader_BufferSlot {
|
|||
};
|
||||
|
||||
static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations);
|
||||
static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& program, LightLocationsPtr& locations);
|
||||
|
||||
const char no_light_frag[] =
|
||||
R"SCRIBE(
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
_fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
}
|
||||
)SCRIBE"
|
||||
;
|
||||
|
||||
void DeferredLightingEffect::init() {
|
||||
_directionalLightLocations = std::make_shared<LightLocations>();
|
||||
_directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
|
||||
_directionalSkyboxLightLocations = std::make_shared<LightLocations>();
|
||||
|
||||
_directionalLightShadowLocations = std::make_shared<LightLocations>();
|
||||
_directionalAmbientSphereLightShadowLocations = std::make_shared<LightLocations>();
|
||||
_directionalSkyboxLightShadowLocations = std::make_shared<LightLocations>();
|
||||
|
||||
_localLightLocations = std::make_shared<LightLocations>();
|
||||
_localLightOutlineLocations = std::make_shared<LightLocations>();
|
||||
_pointLightLocations = std::make_shared<LightLocations>();
|
||||
_spotLightLocations = std::make_shared<LightLocations>();
|
||||
|
||||
loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations);
|
||||
|
||||
loadLightProgram(deferred_light_vert, directional_light_shadow_frag, false, _directionalLightShadow, _directionalLightShadowLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_frag, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations);
|
||||
|
||||
loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations);
|
||||
loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations);
|
||||
|
||||
loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, false, _pointLightBack, _pointLightLocations);
|
||||
loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, true, _pointLightFront, _pointLightLocations);
|
||||
loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, false, _spotLightBack, _spotLightLocations);
|
||||
loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, true, _spotLightFront, _spotLightLocations);
|
||||
|
||||
// Light Stage and clusters
|
||||
_lightStage = std::make_shared<LightStage>();
|
||||
|
||||
|
@ -160,11 +136,11 @@ void DeferredLightingEffect::init() {
|
|||
|
||||
|
||||
lp->setAmbientIntensity(0.5f);
|
||||
lp->setAmbientMap(_defaultSkyboxAmbientTexture);
|
||||
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
|
||||
if (irradianceSH) {
|
||||
lp->setAmbientSphere((*irradianceSH));
|
||||
}
|
||||
lp->setAmbientMap(_defaultSkyboxAmbientTexture);
|
||||
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
|
||||
if (irradianceSH) {
|
||||
lp->setAmbientSphere((*irradianceSH));
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {
|
||||
|
@ -267,7 +243,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
|
|||
state->setColorWriteMask(true, true, true, false);
|
||||
|
||||
if (lightVolume) {
|
||||
state->setStencilTest(true, 0x00, gpu::State::StencilTest(1, 0xFF, gpu::LESS_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
PrepareStencil::testShape(*state);
|
||||
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
// state->setCullMode(gpu::State::CULL_FRONT);
|
||||
|
@ -280,7 +256,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
|
|||
|
||||
} else {
|
||||
// Stencil test all the light passes for objects pixels only, not the background
|
||||
state->setStencilTest(true, 0x00, gpu::State::StencilTest(0, 0x01, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
PrepareStencil::testShape(*state);
|
||||
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
// additive blending
|
||||
|
@ -290,39 +266,6 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
|
|||
|
||||
}
|
||||
|
||||
|
||||
static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) {
|
||||
gpu::ShaderPointer program = makeLightProgram(vertSource, fragSource, locations);
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
|
||||
// Stencil test all the light passes for objects pixels only, not the background
|
||||
|
||||
if (front) {
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_DECR, gpu::State::STENCIL_OP_KEEP));
|
||||
|
||||
// state->setDepthClampEnable(true);
|
||||
// TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases
|
||||
// additive blending
|
||||
// state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
//state->setColorWriteMask(true, true, true, false);
|
||||
state->setColorWriteMask(false, false, false, false);
|
||||
} else {
|
||||
state->setCullMode(gpu::State::CULL_FRONT);
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR, gpu::State::STENCIL_OP_KEEP));
|
||||
// additive blending
|
||||
// state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
// state->setColorWriteMask(true, true, true, false);
|
||||
state->setColorWriteMask(false, false, false, false);
|
||||
}
|
||||
pipeline = gpu::Pipeline::create(program, state);
|
||||
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) {
|
||||
/* auto globalLight = _allocatedLights.front();
|
||||
globalLight->setDirection(light->getDirection());
|
||||
|
@ -535,7 +478,7 @@ void PrepareDeferred::run(const RenderContextPointer& renderContext, const Input
|
|||
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 | gpu::Framebuffer::BUFFER_COLOR3 |
|
||||
gpu::Framebuffer::BUFFER_DEPTH |
|
||||
gpu::Framebuffer::BUFFER_STENCIL,
|
||||
vec4(vec3(0), 0), 1.0, 0.0, true);
|
||||
vec4(vec3(0), 0), 1.0, 1, true);
|
||||
|
||||
// For the rest of the rendering, bind the lighting model
|
||||
batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, lightingModel->getParametersBuffer());
|
||||
|
@ -619,8 +562,8 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
|
|||
batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow->map);
|
||||
}
|
||||
|
||||
auto& program = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadow : deferredLightingEffect->_directionalLight;
|
||||
LightLocationsPtr locations = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadowLocations : deferredLightingEffect->_directionalLightLocations;
|
||||
auto& program = deferredLightingEffect->_directionalSkyboxLight;
|
||||
LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations;
|
||||
const auto& keyLight = deferredLightingEffect->_allocatedLights[deferredLightingEffect->_globalLights.front()];
|
||||
|
||||
// Setup the global directional pass pipeline
|
||||
|
|
|
@ -82,32 +82,21 @@ private:
|
|||
|
||||
gpu::PipelinePointer _directionalSkyboxLight;
|
||||
gpu::PipelinePointer _directionalAmbientSphereLight;
|
||||
gpu::PipelinePointer _directionalLight;
|
||||
|
||||
gpu::PipelinePointer _directionalSkyboxLightShadow;
|
||||
gpu::PipelinePointer _directionalAmbientSphereLightShadow;
|
||||
gpu::PipelinePointer _directionalLightShadow;
|
||||
|
||||
gpu::PipelinePointer _localLight;
|
||||
gpu::PipelinePointer _localLightOutline;
|
||||
|
||||
gpu::PipelinePointer _pointLightBack;
|
||||
gpu::PipelinePointer _pointLightFront;
|
||||
gpu::PipelinePointer _spotLightBack;
|
||||
gpu::PipelinePointer _spotLightFront;
|
||||
|
||||
LightLocationsPtr _directionalSkyboxLightLocations;
|
||||
LightLocationsPtr _directionalAmbientSphereLightLocations;
|
||||
LightLocationsPtr _directionalLightLocations;
|
||||
|
||||
LightLocationsPtr _directionalSkyboxLightShadowLocations;
|
||||
LightLocationsPtr _directionalAmbientSphereLightShadowLocations;
|
||||
LightLocationsPtr _directionalLightShadowLocations;
|
||||
|
||||
LightLocationsPtr _localLightLocations;
|
||||
LightLocationsPtr _localLightOutlineLocations;
|
||||
LightLocationsPtr _pointLightLocations;
|
||||
LightLocationsPtr _spotLightLocations;
|
||||
|
||||
using Lights = std::vector<model::LightPointer>;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "TextureCache.h"
|
||||
#include "RenderUtilsLogging.h"
|
||||
#include "StencilMaskPass.h"
|
||||
|
||||
#include "gpu/StandardShaderLib.h"
|
||||
|
||||
|
@ -1610,6 +1611,9 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const
|
|||
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);
|
||||
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("lineData"), LINE_DATA_SLOT));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
@ -1663,11 +1667,14 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
|
|||
|
||||
// enable decal blend
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
_standardDrawPipeline = gpu::Pipeline::create(program, state);
|
||||
|
||||
|
||||
auto stateNoBlend = std::make_shared<gpu::State>();
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
|
||||
auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS();
|
||||
auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS);
|
||||
gpu::Shader::makeProgram((*programNoBlend));
|
||||
|
@ -1690,12 +1697,14 @@ void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bo
|
|||
|
||||
auto stateLayered = std::make_shared<gpu::State>();
|
||||
stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
PrepareStencil::testMask(*stateLayered);
|
||||
_gridPipelineLayered = gpu::Pipeline::create(program, stateLayered);
|
||||
|
||||
auto state = std::make_shared<gpu::State>(stateLayered->getValues());
|
||||
const float DEPTH_BIAS = 0.001f;
|
||||
state->setDepthBias(DEPTH_BIAS);
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
_gridPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
|
@ -1773,6 +1782,11 @@ static void buildWebShader(const std::string& vertShaderText, const std::string&
|
|||
state->setBlendFunction(blendEnable,
|
||||
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);
|
||||
if (blendEnable) {
|
||||
PrepareStencil::testMask(*state);
|
||||
} else {
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
}
|
||||
|
||||
pipelinePointerOut = gpu::Pipeline::create(shaderPointerOut, state);
|
||||
}
|
||||
|
@ -1858,6 +1872,12 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
|
|||
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);
|
||||
|
||||
if (config.isTransparent()) {
|
||||
PrepareStencil::testMask(*state);
|
||||
} else {
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
}
|
||||
|
||||
gpu::ShaderPointer program = (config.isUnlit()) ? _unlitShader : _simpleShader;
|
||||
gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state);
|
||||
_simplePrograms.insert(config, pipeline);
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
//
|
||||
// HitEffect.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Andrzej Kapolka on 7/14/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
|
||||
|
||||
|
||||
#include <glm/gtc/random.hpp>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <PathUtils.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "AbstractViewStateInterface.h"
|
||||
#include "HitEffect.h"
|
||||
|
||||
#include "TextureCache.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "GeometryCache.h"
|
||||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include "hit_effect_vert.h"
|
||||
#include "hit_effect_frag.h"
|
||||
|
||||
|
||||
HitEffect::HitEffect() {
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
HitEffect::~HitEffect() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (_geometryId && geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() {
|
||||
if (!_hitEffectPipeline) {
|
||||
auto vs = gpu::Shader::createVertex(std::string(hit_effect_vert));
|
||||
auto ps = gpu::Shader::createPixel(std::string(hit_effect_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setDepthTest(false, false, gpu::LESS_EQUAL);
|
||||
|
||||
// Blend on transparent
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_hitEffectPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _hitEffectPipeline;
|
||||
}
|
||||
|
||||
void HitEffect::run(const render::RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||
args->getViewFrustum().evalViewTransform(viewMat);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
batch.setPipeline(getHitEffectPipeline());
|
||||
|
||||
static const glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
static const glm::vec2 bottomLeft(-1.0f, -1.0f);
|
||||
static const glm::vec2 topRight(1.0f, 1.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, color, _geometryId);
|
||||
});
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
//
|
||||
// hitEffect.h
|
||||
// hifi
|
||||
//
|
||||
// Created by eric levin on 7/17/15.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef hifi_hitEffect_h
|
||||
#define hifi_hitEffect_h
|
||||
|
||||
#include <render/DrawTask.h>
|
||||
|
||||
class HitEffectConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled)
|
||||
public:
|
||||
HitEffectConfig() : render::Job::Config(false) {}
|
||||
};
|
||||
|
||||
class HitEffect {
|
||||
public:
|
||||
using Config = HitEffectConfig;
|
||||
using JobModel = render::Job::Model<HitEffect, Config>;
|
||||
|
||||
HitEffect();
|
||||
~HitEffect();
|
||||
void configure(const Config& config) {}
|
||||
void run(const render::RenderContextPointer& renderContext);
|
||||
|
||||
const gpu::PipelinePointer& getHitEffectPipeline();
|
||||
|
||||
private:
|
||||
int _geometryId { 0 };
|
||||
gpu::PipelinePointer _hitEffectPipeline;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include "StencilMaskPass.h"
|
||||
|
||||
#include "lightClusters_drawGrid_vert.h"
|
||||
#include "lightClusters_drawGrid_frag.h"
|
||||
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
#include <render/BlurTask.h>
|
||||
|
||||
#include "LightingModel.h"
|
||||
#include "StencilMaskPass.h"
|
||||
#include "DebugDeferredBuffer.h"
|
||||
#include "DeferredFramebuffer.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
#include "SurfaceGeometryPass.h"
|
||||
#include "FramebufferCache.h"
|
||||
#include "HitEffect.h"
|
||||
#include "TextureCache.h"
|
||||
#include "ZoneRenderer.h"
|
||||
|
||||
|
@ -43,8 +43,6 @@
|
|||
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include "drawOpaqueStencil_frag.h"
|
||||
|
||||
|
||||
using namespace render;
|
||||
extern void initOverlay3DPipelines(render::ShapePlumber& plumber);
|
||||
|
@ -85,13 +83,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0);
|
||||
const auto lightingFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(1);
|
||||
|
||||
// draw a stencil mask in hidden regions of the framebuffer.
|
||||
task.addJob<PrepareStencil>("PrepareStencil", primaryFramebuffer);
|
||||
|
||||
// Render opaque objects in DeferredBuffer
|
||||
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying();
|
||||
task.addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber);
|
||||
|
||||
// Once opaque is all rendered create stencil background
|
||||
task.addJob<DrawStencilDeferred>("DrawOpaqueStencil", deferredFramebuffer);
|
||||
|
||||
task.addJob<EndGPURangeTimer>("OpaqueRangeTimer", opaqueRangeTimer);
|
||||
|
||||
|
||||
|
@ -387,88 +385,6 @@ void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs&
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
gpu::PipelinePointer DrawStencilDeferred::getOpaquePipeline() {
|
||||
if (!_opaquePipeline) {
|
||||
const gpu::int8 STENCIL_OPAQUE = 1;
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(drawOpaqueStencil_frag));
|
||||
auto program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram((*program));
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_KEEP));
|
||||
state->setColorWriteMask(0);
|
||||
|
||||
_opaquePipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _opaquePipeline;
|
||||
}
|
||||
|
||||
void DrawStencilDeferred::run(const RenderContextPointer& renderContext, const DeferredFramebufferPointer& deferredFramebuffer) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
|
||||
// from the touched pixel generate the stencil buffer
|
||||
RenderArgs* args = renderContext->args;
|
||||
doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
|
||||
auto deferredFboColorDepthStencil = deferredFramebuffer->getDeferredFramebufferDepthColor();
|
||||
|
||||
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setFramebuffer(deferredFboColorDepthStencil);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
batch.setPipeline(getOpaquePipeline());
|
||||
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
batch.setResourceTexture(0, nullptr);
|
||||
|
||||
});
|
||||
args->_batch = nullptr;
|
||||
}
|
||||
|
||||
void DrawBackgroundDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
|
||||
const auto& inItems = inputs.get0();
|
||||
const auto& lightingModel = inputs.get1();
|
||||
if (!lightingModel->isBackgroundEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
// _gpuTimer.begin(batch);
|
||||
|
||||
batch.enableSkybox(true);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||
args->getViewFrustum().evalViewTransform(viewMat);
|
||||
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
renderItems(renderContext, inItems);
|
||||
// _gpuTimer.end(batch);
|
||||
});
|
||||
args->_batch = nullptr;
|
||||
|
||||
// std::static_pointer_cast<Config>(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage();
|
||||
}
|
||||
|
||||
void Blit::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_context);
|
||||
|
@ -538,3 +454,4 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -120,35 +120,6 @@ protected:
|
|||
bool _stateSort;
|
||||
};
|
||||
|
||||
class DeferredFramebuffer;
|
||||
class DrawStencilDeferred {
|
||||
public:
|
||||
using JobModel = render::Job::ModelI<DrawStencilDeferred, std::shared_ptr<DeferredFramebuffer>>;
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, const std::shared_ptr<DeferredFramebuffer>& deferredFramebuffer);
|
||||
|
||||
protected:
|
||||
gpu::PipelinePointer _opaquePipeline;
|
||||
|
||||
gpu::PipelinePointer getOpaquePipeline();
|
||||
};
|
||||
|
||||
using DrawBackgroundDeferredConfig = render::GPUJobConfig;
|
||||
|
||||
class DrawBackgroundDeferred {
|
||||
public:
|
||||
using Inputs = render::VaryingSet2 <render::ItemBounds, LightingModelPointer>;
|
||||
|
||||
using Config = DrawBackgroundDeferredConfig;
|
||||
using JobModel = render::Job::ModelI<DrawBackgroundDeferred, Inputs, Config>;
|
||||
|
||||
void configure(const Config& config) {}
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
protected:
|
||||
gpu::RangeTimerPointer _gpuTimer;
|
||||
};
|
||||
|
||||
class DrawOverlay3DConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <gpu/Context.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include "StencilMaskPass.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
#include "TextureCache.h"
|
||||
#include "render/DrawTask.h"
|
||||
|
@ -330,6 +331,7 @@ void addPlumberPipeline(ShapePlumber& plumber,
|
|||
bool isWireframed = (i & 4);
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
|
||||
// Depth test depends on transparency
|
||||
state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL);
|
||||
|
|
126
libraries/render-utils/src/StencilMaskPass.cpp
Normal file
126
libraries/render-utils/src/StencilMaskPass.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
//
|
||||
// StencilMaskPass.cpp
|
||||
// render-utils/src/
|
||||
//
|
||||
// Created by Sam Gateau on 5/31/17.
|
||||
// Copyright 2016 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 "StencilMaskPass.h"
|
||||
|
||||
#include <RenderArgs.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include "stencil_drawMask_frag.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
void PrepareStencil::configure(const Config& config) {
|
||||
_maskMode = config.maskMode;
|
||||
_forceDraw = config.forceDraw;
|
||||
}
|
||||
|
||||
model::MeshPointer PrepareStencil::getMesh() {
|
||||
if (!_mesh) {
|
||||
|
||||
std::vector<glm::vec3> vertices {
|
||||
{ -1.0f, -1.0f, 0.0f }, { -1.0f, 0.0f, 0.0f },
|
||||
{ -1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f },
|
||||
{ 1.0f, 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f },
|
||||
{ 1.0f, -1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f } };
|
||||
|
||||
std::vector<uint32_t> indices { 0, 7, 1, 1, 3, 2, 3, 5, 4, 5, 7, 6 };
|
||||
_mesh = model::Mesh::createIndexedTriangles_P3F((uint32_t) vertices.size(), (uint32_t) indices.size(), vertices.data(), indices.data());
|
||||
}
|
||||
return _mesh;
|
||||
}
|
||||
|
||||
gpu::PipelinePointer PrepareStencil::getMeshStencilPipeline() {
|
||||
if (!_meshStencilPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawVertexPositionVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawNadaPS();
|
||||
auto program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram((*program));
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
drawMask(*state);
|
||||
state->setColorWriteMask(0);
|
||||
|
||||
_meshStencilPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _meshStencilPipeline;
|
||||
}
|
||||
|
||||
gpu::PipelinePointer PrepareStencil::getPaintStencilPipeline() {
|
||||
if (!_paintStencilPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(stencil_drawMask_frag));
|
||||
auto program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram((*program));
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
drawMask(*state);
|
||||
state->setColorWriteMask(0);
|
||||
|
||||
_paintStencilPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _paintStencilPipeline;
|
||||
}
|
||||
|
||||
void PrepareStencil::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer) {
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
// Only draw the stencil mask if in HMD mode or not forced.
|
||||
if (!_forceDraw && (args->_displayMode != RenderArgs::STEREO_HMD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
|
||||
if (_maskMode < 0) {
|
||||
batch.setPipeline(getMeshStencilPipeline());
|
||||
|
||||
auto mesh = getMesh();
|
||||
batch.setIndexBuffer(mesh->getIndexBuffer());
|
||||
batch.setInputFormat((mesh->getVertexFormat()));
|
||||
batch.setInputStream(0, mesh->getVertexStream());
|
||||
|
||||
// Draw
|
||||
auto part = mesh->getPartBuffer().get<model::Mesh::Part>(0);
|
||||
batch.drawIndexed(gpu::TRIANGLES, part._numIndices, part._startIndex);
|
||||
} else {
|
||||
batch.setPipeline(getPaintStencilPipeline());
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PrepareStencil::drawMask(gpu::State& state) {
|
||||
state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE));
|
||||
}
|
||||
|
||||
void PrepareStencil::testMask(gpu::State& state) {
|
||||
state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
}
|
||||
|
||||
void PrepareStencil::testBackground(gpu::State& state) {
|
||||
state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_BACKGROUND, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
}
|
||||
|
||||
void PrepareStencil::testMaskDrawShape(gpu::State& state) {
|
||||
state.setStencilTest(true, 0xFF, gpu::State::StencilTest(PrepareStencil::STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_ZERO));
|
||||
}
|
||||
|
||||
void PrepareStencil::testShape(gpu::State& state) {
|
||||
state.setStencilTest(true, 0x00, gpu::State::StencilTest(PrepareStencil::STENCIL_SHAPE, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
}
|
71
libraries/render-utils/src/StencilMaskPass.h
Normal file
71
libraries/render-utils/src/StencilMaskPass.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// StencilMaskPass.h
|
||||
// render-utils/src/
|
||||
//
|
||||
// Created by Sam Gateau on 5/31/17.
|
||||
// Copyright 20154 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
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_StencilMaskPass_h
|
||||
#define hifi_StencilMaskPass_h
|
||||
|
||||
#include <render/Engine.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <model/Geometry.h>
|
||||
|
||||
class PrepareStencilConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int maskMode MEMBER maskMode NOTIFY dirty)
|
||||
Q_PROPERTY(bool forceDraw MEMBER forceDraw NOTIFY dirty)
|
||||
|
||||
public:
|
||||
PrepareStencilConfig(bool enabled = true) : JobConfig(enabled) {}
|
||||
|
||||
int maskMode { 0 };
|
||||
bool forceDraw { false };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class PrepareStencil {
|
||||
public:
|
||||
using Config = PrepareStencilConfig;
|
||||
|
||||
using JobModel = render::Job::ModelI<PrepareStencil, gpu::FramebufferPointer, Config>;
|
||||
|
||||
void configure(const Config& config);
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& dstFramebuffer);
|
||||
|
||||
static const gpu::int8 STENCIL_MASK = 2;
|
||||
static const gpu::int8 STENCIL_BACKGROUND = 1;
|
||||
static const gpu::int8 STENCIL_SHAPE = 0;
|
||||
|
||||
|
||||
static void drawMask(gpu::State& state);
|
||||
static void testMask(gpu::State& state);
|
||||
static void testBackground(gpu::State& state);
|
||||
static void testMaskDrawShape(gpu::State& state);
|
||||
static void testShape(gpu::State& state);
|
||||
|
||||
|
||||
private:
|
||||
gpu::PipelinePointer _meshStencilPipeline;
|
||||
gpu::PipelinePointer getMeshStencilPipeline();
|
||||
|
||||
gpu::PipelinePointer _paintStencilPipeline;
|
||||
gpu::PipelinePointer getPaintStencilPipeline();
|
||||
|
||||
model::MeshPointer _mesh;
|
||||
model::MeshPointer getMesh();
|
||||
|
||||
int _maskMode { 0 };
|
||||
bool _forceDraw { false };
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_StencilMaskPass_h
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include "StencilMaskPass.h"
|
||||
|
||||
const int DepthLinearPass_FrameTransformSlot = 0;
|
||||
const int DepthLinearPass_DepthMapSlot = 0;
|
||||
|
@ -224,7 +224,7 @@ const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() {
|
|||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
// Stencil test the curvature pass for objects pixels only, not the background
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
PrepareStencil::testShape(*state);
|
||||
|
||||
state->setColorWriteMask(true, false, false, false);
|
||||
|
||||
|
@ -250,6 +250,7 @@ const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline() {
|
|||
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
PrepareStencil::testShape(*state);
|
||||
|
||||
state->setColorWriteMask(true, true, true, false);
|
||||
|
||||
|
@ -554,7 +555,7 @@ const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline() {
|
|||
|
||||
#ifdef USE_STENCIL_TEST
|
||||
// Stencil test the curvature pass for objects pixels only, not the background
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
PrepareStencil::testShape(*state);
|
||||
#endif
|
||||
// Good to go add the brand new pipeline
|
||||
_curvaturePipeline = gpu::Pipeline::create(program, state);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include <RenderArgs.h>
|
||||
|
||||
#include "StencilMaskPass.h"
|
||||
#include "FramebufferCache.h"
|
||||
|
||||
#include "toneMapping_frag.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <render/FilterTask.h>
|
||||
#include <render/DrawTask.h>
|
||||
|
||||
#include "StencilMaskPass.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
#include "zone_drawKeyLight_frag.h"
|
||||
|
@ -74,6 +75,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {
|
|||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
PrepareStencil::testMask(*state);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_keyLightPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
@ -95,6 +97,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getAmbientPipeline() {
|
|||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
PrepareStencil::testMask(*state);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_ambientPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
@ -115,6 +118,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getBackgroundPipeline() {
|
|||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
PrepareStencil::testMask(*state);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_backgroundPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// directional_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/3/14.
|
||||
// Copyright 2016 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 DeferredBufferRead.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalLightmappedColor()$>
|
||||
<$declareEvalAmbientGlobalColor()$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
|
||||
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
||||
|
||||
float shadowAttenuation = 1.0;
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
discard;
|
||||
} else {
|
||||
vec3 color = evalAmbientGlobalColor(
|
||||
getViewInverse(),
|
||||
shadowAttenuation,
|
||||
frag.obscurance,
|
||||
frag.position.xyz,
|
||||
frag.normal,
|
||||
frag.albedo,
|
||||
frag.fresnel,
|
||||
frag.metallic,
|
||||
frag.roughness);
|
||||
_fragColor = vec4(color, 1.0);
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// directional_light_shadow.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Zach Pomerantz on 1/18/2016.
|
||||
// Copyright 2016 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 Shadow.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalLightmappedColor()$>
|
||||
<$declareEvalAmbientGlobalColor()$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
|
||||
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
||||
|
||||
vec4 worldPos = getViewInverse() * vec4(frag.position.xyz, 1.0);
|
||||
float shadowAttenuation = evalShadowAttenuation(worldPos);
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
discard;
|
||||
} else {
|
||||
vec3 color = evalAmbientGlobalColor(
|
||||
getViewInverse(),
|
||||
shadowAttenuation,
|
||||
frag.obscurance,
|
||||
frag.position.xyz,
|
||||
frag.normal,
|
||||
frag.albedo,
|
||||
frag.fresnel,
|
||||
frag.metallic,
|
||||
frag.roughness);
|
||||
_fragColor = vec4(color, 1.0);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
|
||||
// hit_effect.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Eric Levin on 7/20
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
in vec2 varQuadPosition;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
vec2 center = vec2(0.0, 0.0);
|
||||
float distFromCenter = distance( vec2(0.0, 0.0), varQuadPosition);
|
||||
float alpha = mix(0.0, 0.5, pow(distFromCenter,5.));
|
||||
outFragColor = vec4(1.0, 0.0, 0.0, alpha);
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// point_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 9/18/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
|
||||
//
|
||||
<!
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBufferRead.slh@>
|
||||
|
||||
<$declareDeferredCurvature()$>
|
||||
|
||||
// Everything about light
|
||||
<@include model/Light.slh@>
|
||||
<$declareLightBuffer()$>
|
||||
|
||||
<@include LightingModel.slh@>
|
||||
|
||||
<@include LightPoint.slh@>
|
||||
<$declareLightingPoint(supportScattering)$>
|
||||
|
||||
|
||||
uniform vec4 texcoordFrameTransform;
|
||||
|
||||
in vec4 _texCoord0;!>
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
_fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
<!
|
||||
DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
|
||||
|
||||
// Grab the fragment data from the uv
|
||||
vec2 texCoord = _texCoord0.st / _texCoord0.q;
|
||||
texCoord *= texcoordFrameTransform.zw;
|
||||
texCoord += texcoordFrameTransform.xy;
|
||||
|
||||
DeferredFragment frag = unpackDeferredFragment(deferredTransform, texCoord);
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// Need the light now
|
||||
Light light = getLight();
|
||||
|
||||
// Frag pos in world
|
||||
mat4 invViewMat = getViewInverse();
|
||||
vec4 fragPos = invViewMat * frag.position;
|
||||
|
||||
// Clip againgst the light volume and Make the Light vector going from fragment to light center in world space
|
||||
vec4 fragLightVecLen2;
|
||||
if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// Frag to eye vec
|
||||
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
|
||||
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
||||
|
||||
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
vec4 midNormalCurvature;
|
||||
vec4 lowNormalCurvature;
|
||||
if (frag.mode == FRAG_MODE_SCATTERING) {
|
||||
unpackMidLowNormalCurvature(texCoord, midNormalCurvature, lowNormalCurvature);
|
||||
}
|
||||
evalLightingPoint(diffuse, specular, light,
|
||||
fragLightVecLen2.xyz, fragEyeDir, frag.normal, frag.roughness,
|
||||
frag.metallic, frag.fresnel, frag.albedo, 1.0,
|
||||
frag.scattering, midNormalCurvature, lowNormalCurvature);
|
||||
|
||||
_fragColor.rgb += diffuse;
|
||||
_fragColor.rgb += specular;
|
||||
!>
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// spot_light.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 9/18/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
|
||||
//
|
||||
|
||||
// Everything about deferred buffer
|
||||
<!<@include DeferredBufferRead.slh@>
|
||||
|
||||
<$declareDeferredCurvature()$>
|
||||
|
||||
// Everything about light
|
||||
<@include model/Light.slh@>
|
||||
<$declareLightBuffer(256)$>
|
||||
uniform lightIndexBuffer {
|
||||
int lightIndex[256];
|
||||
};
|
||||
<@include LightingModel.slh@>
|
||||
|
||||
<@include LightPoint.slh@>
|
||||
<$declareLightingPoint(supportScattering)$>
|
||||
<@include LightSpot.slh@>
|
||||
<$declareLightingSpot(supportScattering)$>
|
||||
|
||||
//uniform vec4 texcoordFrameTransform;
|
||||
!>
|
||||
|
||||
|
||||
//in vec4 _texCoord0;
|
||||
//flat in int instanceID;
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
_fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
// DeferredFrameTransform deferredTransform = getDeferredFrameTransform();
|
||||
|
||||
// Grab the fragment data from the uv
|
||||
//vec2 texCoord = _texCoord0.st;/* / _texCoord0.q;
|
||||
/*texCoord *= texcoordFrameTransform.zw;
|
||||
texCoord += texcoordFrameTransform.xy;*/
|
||||
/*
|
||||
vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord);
|
||||
DeferredFragment frag = unpackDeferredFragmentNoPosition(texCoord);
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
}
|
||||
|
||||
|
||||
// frag.depthVal = depthValue;
|
||||
frag.position = fragPosition;
|
||||
|
||||
vec4 midNormalCurvature;
|
||||
vec4 lowNormalCurvature;
|
||||
if (frag.mode == FRAG_MODE_SCATTERING) {
|
||||
unpackMidLowNormalCurvature(texCoord, midNormalCurvature, lowNormalCurvature);
|
||||
}
|
||||
|
||||
// Frag pos in world
|
||||
mat4 invViewMat = getViewInverse();
|
||||
vec4 fragPos = invViewMat * fragPosition;
|
||||
|
||||
// Frag to eye vec
|
||||
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
|
||||
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
||||
|
||||
int numLights = lightIndex[0];
|
||||
for (int i = 0; i < numLights; i++) {
|
||||
// Need the light now
|
||||
Light light = getLight(lightIndex[i + 1]);
|
||||
bool isSpot = light_isSpot(light);
|
||||
// Clip againgst the light volume and Make the Light vector going from fragment to light center in world space
|
||||
vec4 fragLightVecLen2;
|
||||
vec4 fragLightDirLen;
|
||||
float cosSpotAngle;
|
||||
if (isSpot) {
|
||||
if (!clipFragToLightVolumeSpot(light, fragPos.xyz, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!clipFragToLightVolumePoint(light, fragPos.xyz, fragLightVecLen2)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
|
||||
if (isSpot) {
|
||||
evalLightingSpot(diffuse, specular, light,
|
||||
fragLightDirLen.xyzw, cosSpotAngle, fragEyeDir, frag.normal, frag.roughness,
|
||||
frag.metallic, frag.fresnel, frag.albedo, 1.0,
|
||||
frag.scattering, midNormalCurvature, lowNormalCurvature);
|
||||
} else {
|
||||
evalLightingPoint(diffuse, specular, light,
|
||||
fragLightVecLen2.xyz, fragEyeDir, frag.normal, frag.roughness,
|
||||
frag.metallic, frag.fresnel, frag.albedo, 1.0,
|
||||
frag.scattering, midNormalCurvature, lowNormalCurvature);
|
||||
}
|
||||
|
||||
_fragColor.rgb += diffuse;
|
||||
_fragColor.rgb += specular;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
23
libraries/render-utils/src/stencil_drawMask.slf
Normal file
23
libraries/render-utils/src/stencil_drawMask.slf
Normal file
|
@ -0,0 +1,23 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// stencil_drawMask.slf
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 5/31/17.
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
|
||||
float aspectRatio = 0.95;
|
||||
|
||||
void main(void) {
|
||||
vec2 pos = varTexCoord0 * 2.0 - vec2(1.0);
|
||||
pos.x = aspectRatio * (pos.x * (pos.x > 0.0 ? 2.0 : -2.0) - 1.0);
|
||||
if (1.0 - dot(pos.xy, pos.xy) > 0.0 ) discard;
|
||||
}
|
|
@ -69,7 +69,7 @@ public:
|
|||
glm::vec3 size() const { return maximum - minimum; }
|
||||
float largestDimension() const { return glm::compMax(size()); }
|
||||
|
||||
/// \return new Extents which is original rotated around orign by rotation
|
||||
/// \return new Extents which is original rotated around origin by rotation
|
||||
Extents getRotated(const glm::quat& rotation) const {
|
||||
Extents temp(minimum, maximum);
|
||||
temp.rotate(rotation);
|
||||
|
|
|
@ -49,7 +49,7 @@ const mat4 Matrices::Z_180 { createMatFromQuatAndPos(Quaternions::Z_180, Vectors
|
|||
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
|
||||
float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
|
||||
float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1;
|
||||
|
||||
|
||||
// adjust signs if necessary
|
||||
if (cosa < 0.0f) {
|
||||
cosa = -cosa;
|
||||
|
@ -58,19 +58,19 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
|
|||
oz = -oz;
|
||||
ow = -ow;
|
||||
}
|
||||
|
||||
|
||||
// calculate coefficients; if the angle is too close to zero, we must fall back
|
||||
// to linear interpolation
|
||||
if ((1.0f - cosa) > EPSILON) {
|
||||
float angle = acosf(cosa), sina = sinf(angle);
|
||||
s0 = sinf((1.0f - proportion) * angle) / sina;
|
||||
s1 = sinf(proportion * angle) / sina;
|
||||
|
||||
|
||||
} else {
|
||||
s0 = 1.0f - proportion;
|
||||
s1 = proportion;
|
||||
}
|
||||
|
||||
|
||||
return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz));
|
||||
}
|
||||
|
||||
|
@ -105,10 +105,10 @@ int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm
|
|||
|
||||
int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) {
|
||||
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0f);
|
||||
|
||||
|
||||
uint16_t angleHolder = floorf((degrees + 180.0f) * ANGLE_CONVERSION_RATIO);
|
||||
memcpy(buffer, &angleHolder, sizeof(uint16_t));
|
||||
|
||||
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput
|
|||
quatParts[1] = floorf((quatNormalized.y + 1.0f) * QUAT_PART_CONVERSION_RATIO);
|
||||
quatParts[2] = floorf((quatNormalized.z + 1.0f) * QUAT_PART_CONVERSION_RATIO);
|
||||
quatParts[3] = floorf((quatNormalized.w + 1.0f) * QUAT_PART_CONVERSION_RATIO);
|
||||
|
||||
|
||||
memcpy(buffer, &quatParts, sizeof(quatParts));
|
||||
return sizeof(quatParts);
|
||||
}
|
||||
|
@ -133,12 +133,12 @@ int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput
|
|||
int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) {
|
||||
uint16_t quatParts[4];
|
||||
memcpy(&quatParts, buffer, sizeof(quatParts));
|
||||
|
||||
|
||||
quatOutput.x = ((quatParts[0] / (float) std::numeric_limits<uint16_t>::max()) * 2.0f) - 1.0f;
|
||||
quatOutput.y = ((quatParts[1] / (float) std::numeric_limits<uint16_t>::max()) * 2.0f) - 1.0f;
|
||||
quatOutput.z = ((quatParts[2] / (float) std::numeric_limits<uint16_t>::max()) * 2.0f) - 1.0f;
|
||||
quatOutput.w = ((quatParts[3] / (float) std::numeric_limits<uint16_t>::max()) * 2.0f) - 1.0f;
|
||||
|
||||
|
||||
return sizeof(quatParts);
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) {
|
|||
atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)),
|
||||
asinf(sy),
|
||||
atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z)));
|
||||
|
||||
|
||||
} else {
|
||||
// not a unique solution; x + z = atan2(-m21, m11)
|
||||
eulers = glm::vec3(
|
||||
|
@ -250,7 +250,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) {
|
|||
PI_OVER_TWO,
|
||||
-atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
|
||||
}
|
||||
|
||||
|
||||
// adjust so that z, rather than y, is in [-pi/2, pi/2]
|
||||
if (eulers.z < -PI_OVER_TWO) {
|
||||
if (eulers.x < 0.0f) {
|
||||
|
@ -265,7 +265,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) {
|
|||
eulers.y -= PI;
|
||||
}
|
||||
eulers.z += PI;
|
||||
|
||||
|
||||
} else if (eulers.z > PI_OVER_TWO) {
|
||||
if (eulers.x < 0.0f) {
|
||||
eulers.x += PI;
|
||||
|
@ -320,7 +320,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
|
|||
for (int i = 0; i < 10; i++) {
|
||||
// store the results of the previous iteration
|
||||
glm::mat3 previous = upper;
|
||||
|
||||
|
||||
// compute average of the matrix with its inverse transpose
|
||||
float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2];
|
||||
float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2];
|
||||
|
@ -334,15 +334,15 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
|
|||
upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f;
|
||||
upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f;
|
||||
upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f;
|
||||
|
||||
|
||||
upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f;
|
||||
upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f;
|
||||
upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f;
|
||||
|
||||
|
||||
upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f;
|
||||
upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f;
|
||||
upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f;
|
||||
|
||||
|
||||
// compute the difference; if it's small enough, we're done
|
||||
glm::mat3 diff = upper - previous;
|
||||
if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] +
|
||||
|
@ -352,7 +352,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// now that we have a nice orthogonal matrix, we can extract the rotation quaternion
|
||||
// using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions
|
||||
float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]);
|
||||
|
@ -473,7 +473,7 @@ glm::mat4 createMatFromScaleQuatAndPos(const glm::vec3& scale, const glm::quat&
|
|||
glm::vec4(zAxis, 0.0f), glm::vec4(trans, 1.0f));
|
||||
}
|
||||
|
||||
// cancel out roll
|
||||
// cancel out roll
|
||||
glm::quat cancelOutRoll(const glm::quat& q) {
|
||||
glm::vec3 forward = q * Vectors::FRONT;
|
||||
return glm::quat_cast(glm::inverse(glm::lookAt(Vectors::ZERO, forward, Vectors::UP)));
|
||||
|
@ -538,17 +538,16 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda
|
|||
uAxisOut = glm::normalize(primaryAxis);
|
||||
glm::vec3 normSecondary = glm::normalize(secondaryAxis);
|
||||
|
||||
// if secondaryAxis is parallel with the primaryAxis, pick another axis.
|
||||
// if normSecondary is parallel with the primaryAxis, pick another secondary.
|
||||
const float EPSILON = 1.0e-4f;
|
||||
if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) {
|
||||
// pick a better secondaryAxis.
|
||||
normSecondary = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) {
|
||||
normSecondary = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
if (fabsf(fabsf(glm::dot(uAxisOut, normSecondary)) - 1.0f) < EPSILON) {
|
||||
normSecondary = Vectors::UNIT_X;
|
||||
if (fabsf(fabsf(glm::dot(uAxisOut, normSecondary)) - 1.0f) < EPSILON) {
|
||||
normSecondary = Vectors::UNIT_Y;
|
||||
}
|
||||
}
|
||||
|
||||
wAxisOut = glm::normalize(glm::cross(uAxisOut, secondaryAxis));
|
||||
wAxisOut = glm::normalize(glm::cross(uAxisOut, normSecondary));
|
||||
vAxisOut = glm::cross(wAxisOut, uAxisOut);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
class RenderArgs {
|
||||
public:
|
||||
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE };
|
||||
enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT };
|
||||
enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD };
|
||||
enum DebugFlags {
|
||||
RENDER_DEBUG_NONE = 0,
|
||||
RENDER_DEBUG_HULLS = 1
|
||||
|
@ -87,7 +87,7 @@ public:
|
|||
float sizeScale = 1.0f,
|
||||
int boundaryLevelAdjust = 0,
|
||||
RenderMode renderMode = DEFAULT_RENDER_MODE,
|
||||
RenderSide renderSide = MONO,
|
||||
DisplayMode displayMode = MONO,
|
||||
DebugFlags debugFlags = RENDER_DEBUG_NONE,
|
||||
gpu::Batch* batch = nullptr) :
|
||||
_context(context),
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
_sizeScale(sizeScale),
|
||||
_boundaryLevelAdjust(boundaryLevelAdjust),
|
||||
_renderMode(renderMode),
|
||||
_renderSide(renderSide),
|
||||
_displayMode(displayMode),
|
||||
_debugFlags(debugFlags),
|
||||
_batch(batch) {
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ public:
|
|||
float _sizeScale = 1.0f;
|
||||
int _boundaryLevelAdjust = 0;
|
||||
RenderMode _renderMode = DEFAULT_RENDER_MODE;
|
||||
RenderSide _renderSide = MONO;
|
||||
DisplayMode _displayMode = MONO;
|
||||
DebugFlags _debugFlags = RENDER_DEBUG_NONE;
|
||||
gpu::Batch* _batch = nullptr;
|
||||
|
||||
|
|
|
@ -13,44 +13,16 @@
|
|||
|
||||
#include <QFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include "PathUtils.h"
|
||||
|
||||
RunningMarker::RunningMarker(QObject* parent, QString name) :
|
||||
_parent(parent),
|
||||
RunningMarker::RunningMarker(QString name) :
|
||||
_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
void RunningMarker::startRunningMarker() {
|
||||
static const int RUNNING_STATE_CHECK_IN_MSECS = MSECS_PER_SECOND;
|
||||
|
||||
// start the nodeThread so its event loop is running
|
||||
_runningMarkerThread = new QThread(_parent);
|
||||
_runningMarkerThread->setObjectName("Running Marker Thread");
|
||||
_runningMarkerThread->start();
|
||||
|
||||
writeRunningMarkerFile(); // write the first file, even before timer
|
||||
|
||||
_runningMarkerTimer = new QTimer();
|
||||
QObject::connect(_runningMarkerTimer, &QTimer::timeout, [=](){
|
||||
writeRunningMarkerFile();
|
||||
});
|
||||
_runningMarkerTimer->start(RUNNING_STATE_CHECK_IN_MSECS);
|
||||
|
||||
// put the time on the thread
|
||||
_runningMarkerTimer->moveToThread(_runningMarkerThread);
|
||||
}
|
||||
|
||||
RunningMarker::~RunningMarker() {
|
||||
deleteRunningMarkerFile();
|
||||
QMetaObject::invokeMethod(_runningMarkerTimer, "stop", Qt::BlockingQueuedConnection);
|
||||
_runningMarkerThread->quit();
|
||||
_runningMarkerTimer->deleteLater();
|
||||
_runningMarkerThread->deleteLater();
|
||||
}
|
||||
|
||||
bool RunningMarker::fileExists() const {
|
||||
|
@ -77,8 +49,3 @@ void RunningMarker::deleteRunningMarkerFile() {
|
|||
QString RunningMarker::getFilePath() const {
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + _name;
|
||||
}
|
||||
|
||||
QString RunningMarker::getMarkerFilePath(QString name) {
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + name;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,21 +12,14 @@
|
|||
#ifndef hifi_RunningMarker_h
|
||||
#define hifi_RunningMarker_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class QThread;
|
||||
class QTimer;
|
||||
|
||||
class RunningMarker {
|
||||
public:
|
||||
RunningMarker(QObject* parent, QString name);
|
||||
RunningMarker(QString name);
|
||||
~RunningMarker();
|
||||
|
||||
void startRunningMarker();
|
||||
|
||||
QString getFilePath() const;
|
||||
static QString getMarkerFilePath(QString name);
|
||||
|
||||
bool fileExists() const;
|
||||
|
||||
|
@ -34,10 +27,7 @@ public:
|
|||
void deleteRunningMarkerFile();
|
||||
|
||||
private:
|
||||
QObject* _parent { nullptr };
|
||||
QString _name;
|
||||
QThread* _runningMarkerThread { nullptr };
|
||||
QTimer* _runningMarkerTimer { nullptr };
|
||||
};
|
||||
|
||||
#endif // hifi_RunningMarker_h
|
||||
|
|
Binary file not shown.
|
@ -10,7 +10,7 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
/* global Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation */
|
||||
/* global Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation, UserActivityLogger */
|
||||
|
||||
(function () { // BEGIN LOCAL_SCOPE
|
||||
var button;
|
||||
|
@ -76,6 +76,7 @@
|
|||
// Called from the C++ scripting interface to show the bubble overlay
|
||||
function enteredIgnoreRadius() {
|
||||
createOverlays();
|
||||
UserActivityLogger.bubbleActivated();
|
||||
}
|
||||
|
||||
// Used to set the state of the bubble HUD button
|
||||
|
@ -139,10 +140,14 @@
|
|||
}
|
||||
|
||||
// When the space bubble is toggled...
|
||||
function onBubbleToggled() {
|
||||
var bubbleActive = Users.getIgnoreRadiusEnabled();
|
||||
writeButtonProperties(bubbleActive);
|
||||
if (bubbleActive) {
|
||||
// NOTE: the c++ calls this with just the first param -- we added a second
|
||||
// just for not logging the initial state of the bubble when we startup.
|
||||
function onBubbleToggled(enabled, doNotLog) {
|
||||
writeButtonProperties(enabled);
|
||||
if (doNotLog !== true) {
|
||||
UserActivityLogger.bubbleToggled(enabled);
|
||||
}
|
||||
if (enabled) {
|
||||
createOverlays();
|
||||
} else {
|
||||
hideOverlays();
|
||||
|
@ -163,7 +168,7 @@
|
|||
sortOrder: 4
|
||||
});
|
||||
|
||||
onBubbleToggled();
|
||||
onBubbleToggled(Users.getIgnoreRadiusEnabled(), true); // pass in true so we don't log this initial one in the UserActivity table
|
||||
|
||||
button.clicked.connect(Users.toggleIgnoreRadius);
|
||||
Users.ignoreRadiusEnabledChanged.connect(onBubbleToggled);
|
||||
|
|
|
@ -217,6 +217,32 @@ function hideMarketplace() {
|
|||
// }
|
||||
// }
|
||||
|
||||
function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
|
||||
// Adjust the position such that the bounding box (registration, dimenions, and orientation) lies behind the original
|
||||
// position in the given direction.
|
||||
var CORNERS = [
|
||||
{ x: 0, y: 0, z: 0 },
|
||||
{ x: 0, y: 0, z: 1 },
|
||||
{ x: 0, y: 1, z: 0 },
|
||||
{ x: 0, y: 1, z: 1 },
|
||||
{ x: 1, y: 0, z: 0 },
|
||||
{ x: 1, y: 0, z: 1 },
|
||||
{ x: 1, y: 1, z: 0 },
|
||||
{ x: 1, y: 1, z: 1 },
|
||||
];
|
||||
|
||||
// Go through all corners and find least (most negative) distance in front of position.
|
||||
var distance = 0;
|
||||
for (var i = 0, length = CORNERS.length; i < length; i++) {
|
||||
var cornerVector =
|
||||
Vec3.multiplyQbyV(orientation, Vec3.multiplyVbyV(Vec3.subtract(CORNERS[i], registration), dimensions));
|
||||
var cornerDistance = Vec3.dot(cornerVector, direction);
|
||||
distance = Math.min(cornerDistance, distance);
|
||||
}
|
||||
position = Vec3.sum(Vec3.multiply(distance, direction), position);
|
||||
return position;
|
||||
}
|
||||
|
||||
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
|
||||
var GRABBABLE_ENTITIES_MENU_CATEGORY = "Edit";
|
||||
var GRABBABLE_ENTITIES_MENU_ITEM = "Create Entities As Grabbable";
|
||||
|
@ -234,6 +260,32 @@ var toolBar = (function () {
|
|||
var position = getPositionToCreateEntity();
|
||||
var entityID = null;
|
||||
if (position !== null && position !== undefined) {
|
||||
var direction;
|
||||
if (Camera.mode === "entity" || Camera.mode === "independent") {
|
||||
direction = Camera.orientation;
|
||||
} else {
|
||||
direction = MyAvatar.orientation;
|
||||
}
|
||||
direction = Vec3.multiplyQbyV(direction, Vec3.UNIT_Z);
|
||||
|
||||
var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"];
|
||||
if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
|
||||
// Adjust position of entity per bounding box prior to creating it.
|
||||
var registration = properties.registration;
|
||||
if (registration === undefined) {
|
||||
var DEFAULT_REGISTRATION = { x: 0.5, y: 0.5, z: 0.5 };
|
||||
registration = DEFAULT_REGISTRATION;
|
||||
}
|
||||
|
||||
var orientation = properties.orientation;
|
||||
if (orientation === undefined) {
|
||||
var DEFAULT_ORIENTATION = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||
orientation = DEFAULT_ORIENTATION;
|
||||
}
|
||||
|
||||
position = adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation);
|
||||
}
|
||||
|
||||
position = grid.snapToSurface(grid.snapToGrid(position, false, dimensions), dimensions);
|
||||
properties.position = position;
|
||||
if (Menu.isOptionChecked(GRABBABLE_ENTITIES_MENU_ITEM)) {
|
||||
|
@ -243,6 +295,32 @@ var toolBar = (function () {
|
|||
if (properties.type == "ParticleEffect") {
|
||||
selectParticleEntity(entityID);
|
||||
}
|
||||
|
||||
var POST_ADJUST_ENTITY_TYPES = ["Model"];
|
||||
if (POST_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
|
||||
// Adjust position of entity per bounding box after it has been created and auto-resized.
|
||||
var initialDimensions = Entities.getEntityProperties(entityID, ["dimensions"]).dimensions;
|
||||
var DIMENSIONS_CHECK_INTERVAL = 200;
|
||||
var MAX_DIMENSIONS_CHECKS = 10;
|
||||
var dimensionsCheckCount = 0;
|
||||
var dimensionsCheckFunction = function () {
|
||||
dimensionsCheckCount++;
|
||||
var properties = Entities.getEntityProperties(entityID, ["dimensions", "registrationPoint", "rotation"]);
|
||||
if (!Vec3.equal(properties.dimensions, initialDimensions)) {
|
||||
position = adjustPositionPerBoundingBox(position, direction, properties.registrationPoint,
|
||||
properties.dimensions, properties.rotation);
|
||||
position = grid.snapToSurface(grid.snapToGrid(position, false, properties.dimensions),
|
||||
properties.dimensions);
|
||||
Entities.editEntity(entityID, {
|
||||
position: position
|
||||
});
|
||||
selectionManager._update();
|
||||
} else if (dimensionsCheckCount < MAX_DIMENSIONS_CHECKS) {
|
||||
Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
|
||||
}
|
||||
};
|
||||
Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
|
||||
}
|
||||
} else {
|
||||
Window.notifyEditError("Can't create " + properties.type + ": " +
|
||||
properties.type + " would be out of bounds.");
|
||||
|
@ -564,6 +642,8 @@ var toolBar = (function () {
|
|||
enabled: active
|
||||
}));
|
||||
isActive = active;
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
||||
if (!isActive) {
|
||||
entityListTool.setVisible(false);
|
||||
gridTool.setVisible(false);
|
||||
|
@ -572,8 +652,8 @@ var toolBar = (function () {
|
|||
selectionManager.clearSelections();
|
||||
cameraManager.disable();
|
||||
selectionDisplay.triggerMapping.disable();
|
||||
tablet.landscape = false;
|
||||
} else {
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
tablet.loadQMLSource("Edit.qml");
|
||||
UserActivityLogger.enabledEdit();
|
||||
entityListTool.setVisible(true);
|
||||
|
@ -581,6 +661,8 @@ var toolBar = (function () {
|
|||
grid.setEnabled(true);
|
||||
propertiesTool.setVisible(true);
|
||||
selectionDisplay.triggerMapping.enable();
|
||||
print("starting tablet in landscape mode")
|
||||
tablet.landscape = true;
|
||||
// Not sure what the following was meant to accomplish, but it currently causes
|
||||
// everybody else to think that Interface has lost focus overall. fogbugzid:558
|
||||
// Window.setFocus();
|
||||
|
@ -1407,40 +1489,26 @@ function handeMenuEvent(menuItem) {
|
|||
}
|
||||
tooltip.show(false);
|
||||
}
|
||||
function getPositionToCreateEntity() {
|
||||
var HALF_TREE_SCALE = 16384;
|
||||
var direction = Quat.getForward(MyAvatar.orientation);
|
||||
var distance = 1;
|
||||
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, distance));
|
||||
|
||||
var HALF_TREE_SCALE = 16384;
|
||||
|
||||
function getPositionToCreateEntity(extra) {
|
||||
var CREATE_DISTANCE = 2;
|
||||
var position;
|
||||
var delta = extra !== undefined ? extra : 0;
|
||||
if (Camera.mode === "entity" || Camera.mode === "independent") {
|
||||
position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), distance));
|
||||
position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), CREATE_DISTANCE + delta));
|
||||
} else {
|
||||
position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), CREATE_DISTANCE + delta));
|
||||
position.y += 0.5;
|
||||
}
|
||||
position.y += 0.5;
|
||||
|
||||
if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
|
||||
return null;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
function getPositionToImportEntity() {
|
||||
var dimensions = Clipboard.getContentsDimensions();
|
||||
var HALF_TREE_SCALE = 16384;
|
||||
var direction = Quat.getForward(MyAvatar.orientation);
|
||||
var longest = 1;
|
||||
longest = Math.sqrt(Math.pow(dimensions.x, 2) + Math.pow(dimensions.z, 2));
|
||||
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, longest));
|
||||
|
||||
if (Camera.mode === "entity" || Camera.mode === "independent") {
|
||||
position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), longest));
|
||||
}
|
||||
|
||||
if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
function importSVO(importURL) {
|
||||
if (!Entities.canRez() && !Entities.canRezTmp()) {
|
||||
Window.notifyEditError(INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG);
|
||||
|
@ -1458,22 +1526,73 @@ function importSVO(importURL) {
|
|||
|
||||
if (success) {
|
||||
var VERY_LARGE = 10000;
|
||||
var position = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
if (Clipboard.getClipboardContentsLargestDimension() < VERY_LARGE) {
|
||||
position = getPositionToImportEntity();
|
||||
var isLargeImport = Clipboard.getClipboardContentsLargestDimension() >= VERY_LARGE;
|
||||
var position = Vec3.ZERO;
|
||||
if (!isLargeImport) {
|
||||
position = getPositionToCreateEntity(Clipboard.getClipboardContentsLargestDimension() / 2);
|
||||
}
|
||||
if (position !== null && position !== undefined) {
|
||||
var pastedEntityIDs = Clipboard.pasteEntities(position);
|
||||
if (!isLargeImport) {
|
||||
// The first entity in Clipboard gets the specified position with the rest being relative to it. Therefore, move
|
||||
// entities after they're imported so that they're all the correct distance in front of and with geometric mean
|
||||
// centered on the avatar/camera direction.
|
||||
var deltaPosition = Vec3.ZERO;
|
||||
|
||||
var properties = Entities.getEntityProperties(pastedEntityIDs[0], ["type"]);
|
||||
var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect"];
|
||||
if (NO_ADJUST_ENTITY_TYPES.indexOf(properties.type) === -1) {
|
||||
var targetDirection;
|
||||
if (Camera.mode === "entity" || Camera.mode === "independent") {
|
||||
targetDirection = Camera.orientation;
|
||||
} else {
|
||||
targetDirection = MyAvatar.orientation;
|
||||
}
|
||||
targetDirection = Vec3.multiplyQbyV(targetDirection, Vec3.UNIT_Z);
|
||||
|
||||
var targetPosition = getPositionToCreateEntity();
|
||||
var deltaParallel = HALF_TREE_SCALE; // Distance to move entities parallel to targetDirection.
|
||||
var deltaPerpendicular = Vec3.ZERO; // Distance to move entities perpendicular to targetDirection.
|
||||
var entityPositions = [];
|
||||
for (var i = 0, length = pastedEntityIDs.length; i < length; i++) {
|
||||
var properties = Entities.getEntityProperties(pastedEntityIDs[i], ["position", "dimensions",
|
||||
"registrationPoint", "rotation"]);
|
||||
var adjustedPosition = adjustPositionPerBoundingBox(targetPosition, targetDirection,
|
||||
properties.registrationPoint, properties.dimensions, properties.rotation);
|
||||
var delta = Vec3.subtract(adjustedPosition, properties.position);
|
||||
var distance = Vec3.dot(delta, targetDirection);
|
||||
deltaParallel = Math.min(distance, deltaParallel);
|
||||
deltaPerpendicular = Vec3.sum(Vec3.subtract(delta, Vec3.multiply(distance, targetDirection)),
|
||||
deltaPerpendicular);
|
||||
entityPositions[i] = properties.position;
|
||||
}
|
||||
deltaPerpendicular = Vec3.multiply(1 / pastedEntityIDs.length, deltaPerpendicular);
|
||||
deltaPosition = Vec3.sum(Vec3.multiply(deltaParallel, targetDirection), deltaPerpendicular);
|
||||
}
|
||||
|
||||
if (grid.getSnapToGrid()) {
|
||||
var properties = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions",
|
||||
"registrationPoint"]);
|
||||
var position = Vec3.sum(deltaPosition, properties.position);
|
||||
position = grid.snapToSurface(grid.snapToGrid(position, false, properties.dimensions,
|
||||
properties.registrationPoint), properties.dimensions, properties.registrationPoint);
|
||||
deltaPosition = Vec3.subtract(position, properties.position);
|
||||
}
|
||||
|
||||
if (!Vec3.equal(deltaPosition, Vec3.ZERO)) {
|
||||
for (var i = 0, length = pastedEntityIDs.length; i < length; i++) {
|
||||
Entities.editEntity(pastedEntityIDs[i], {
|
||||
position: Vec3.sum(deltaPosition, entityPositions[i])
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isActive) {
|
||||
selectionManager.setSelections(pastedEntityIDs);
|
||||
}
|
||||
} else {
|
||||
Window.notifyEditError("Can't import objects: objects would be out of bounds.");
|
||||
Window.notifyEditError("Can't import entities: entities would be out of bounds.");
|
||||
}
|
||||
} else {
|
||||
Window.notifyEditError("There was an error importing the entity file.");
|
||||
|
|
|
@ -20,7 +20,8 @@ var ICON_FOR_TYPE = {
|
|||
Light: "p",
|
||||
Zone: "o",
|
||||
PolyVox: "",
|
||||
Multiple: ""
|
||||
Multiple: "",
|
||||
PolyLine: ""
|
||||
}
|
||||
|
||||
var EDITOR_TIMEOUT_DURATION = 1500;
|
||||
|
|
|
@ -22,7 +22,9 @@ var DEFAULT_WIDTH = 0.4375;
|
|||
var DEFAULT_VERTICAL_FIELD_OF_VIEW = 45; // degrees
|
||||
var SENSOR_TO_ROOM_MATRIX = -2;
|
||||
var CAMERA_MATRIX = -7;
|
||||
var ROT_Y_180 = {x: 0, y: 1, z: 0, w: 0};
|
||||
var ROT_Y_180 = {x: 0.0, y: 1.0, z: 0, w: 0};
|
||||
var ROT_LANDSCAPE = {x: 1.0, y: 1.0, z: 0, w: 0};
|
||||
var ROT_LANDSCAPE_WINDOW = {x: 0.0, y: 0.0, z: 0.0, w: 0};
|
||||
var ROT_IDENT = {x: 0, y: 0, z: 0, w: 1};
|
||||
var TABLET_TEXTURE_RESOLUTION = { x: 480, y: 706 };
|
||||
var INCHES_TO_METERS = 1 / 39.3701;
|
||||
|
@ -243,29 +245,29 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
|||
};
|
||||
|
||||
WebTablet.prototype.getDimensions = function() {
|
||||
if (this.landscape) {
|
||||
return { x: this.width * 2, y: this.height, z: this.depth };
|
||||
} else {
|
||||
return { x: this.width, y: this.height, z: this.depth };
|
||||
}
|
||||
return { x: this.width, y: this.height, z: this.depth };
|
||||
};
|
||||
|
||||
WebTablet.prototype.getTabletTextureResolution = function() {
|
||||
if (this.landscape) {
|
||||
return { x: TABLET_TEXTURE_RESOLUTION.x * 2, y: TABLET_TEXTURE_RESOLUTION.y };
|
||||
return { x: TABLET_TEXTURE_RESOLUTION.y , y: TABLET_TEXTURE_RESOLUTION.x };
|
||||
} else {
|
||||
return TABLET_TEXTURE_RESOLUTION;
|
||||
}
|
||||
};
|
||||
|
||||
WebTablet.prototype.setLandscape = function(newLandscapeValue) {
|
||||
if (this.landscape == newLandscapeValue) {
|
||||
if (this.landscape === newLandscapeValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.landscape = newLandscapeValue;
|
||||
Overlays.editOverlay(this.tabletEntityID, { dimensions: this.getDimensions() });
|
||||
Overlays.editOverlay(this.tabletEntityID,
|
||||
{ rotation: this.landscape ? Quat.multiply(Camera.orientation, ROT_LANDSCAPE) :
|
||||
Quat.multiply(Camera.orientation, ROT_Y_180) });
|
||||
Overlays.editOverlay(this.webOverlayID, {
|
||||
resolution: this.getTabletTextureResolution()
|
||||
resolution: this.getTabletTextureResolution(),
|
||||
rotation: Quat.multiply(Camera.orientation, ROT_LANDSCAPE_WINDOW)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -407,7 +409,7 @@ WebTablet.prototype.calculateWorldAttitudeRelativeToCamera = function (windowPos
|
|||
|
||||
return {
|
||||
position: worldMousePosition,
|
||||
rotation: Quat.multiply(Camera.orientation, ROT_Y_180)
|
||||
rotation: this.landscape ? Quat.multiply(Camera.orientation, ROT_LANDSCAPE) : Quat.multiply(Camera.orientation, ROT_Y_180)
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ Grid = function(opts) {
|
|||
}
|
||||
}
|
||||
|
||||
that.snapToSurface = function(position, dimensions) {
|
||||
that.snapToSurface = function(position, dimensions, registration) {
|
||||
if (!snapToGrid) {
|
||||
return position;
|
||||
}
|
||||
|
@ -88,14 +88,18 @@ Grid = function(opts) {
|
|||
dimensions = { x: 0, y: 0, z: 0 };
|
||||
}
|
||||
|
||||
if (registration === undefined) {
|
||||
registration = { x: 0.5, y: 0.5, z: 0.5 };
|
||||
}
|
||||
|
||||
return {
|
||||
x: position.x,
|
||||
y: origin.y + (dimensions.y / 2),
|
||||
y: origin.y + (registration.y * dimensions.y),
|
||||
z: position.z
|
||||
};
|
||||
}
|
||||
|
||||
that.snapToGrid = function(position, majorOnly, dimensions) {
|
||||
that.snapToGrid = function(position, majorOnly, dimensions, registration) {
|
||||
if (!snapToGrid) {
|
||||
return position;
|
||||
}
|
||||
|
@ -104,6 +108,10 @@ Grid = function(opts) {
|
|||
dimensions = { x: 0, y: 0, z: 0 };
|
||||
}
|
||||
|
||||
if (registration === undefined) {
|
||||
registration = { x: 0.5, y: 0.5, z: 0.5 };
|
||||
}
|
||||
|
||||
var spacing = majorOnly ? majorGridEvery : minorGridEvery;
|
||||
|
||||
position = Vec3.subtract(position, origin);
|
||||
|
@ -112,7 +120,7 @@ Grid = function(opts) {
|
|||
position.y = Math.round(position.y / spacing) * spacing;
|
||||
position.z = Math.round(position.z / spacing) * spacing;
|
||||
|
||||
return Vec3.sum(Vec3.sum(position, Vec3.multiply(0.5, dimensions)), origin);
|
||||
return Vec3.sum(Vec3.sum(position, Vec3.multiplyVbyV(registration, dimensions)), origin);
|
||||
}
|
||||
|
||||
that.snapToSpacing = function(delta, majorOnly) {
|
||||
|
@ -161,9 +169,9 @@ Grid = function(opts) {
|
|||
|
||||
if (data.origin) {
|
||||
var pos = data.origin;
|
||||
pos.x = pos.x === undefined ? origin.x : pos.x;
|
||||
pos.y = pos.y === undefined ? origin.y : pos.y;
|
||||
pos.z = pos.z === undefined ? origin.z : pos.z;
|
||||
pos.x = pos.x === undefined ? origin.x : parseFloat(pos.x);
|
||||
pos.y = pos.y === undefined ? origin.y : parseFloat(pos.y);
|
||||
pos.z = pos.z === undefined ? origin.z : parseFloat(pos.z);
|
||||
that.setPosition(pos, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -410,8 +410,15 @@ function takeSnapshot() {
|
|||
Menu.setIsOptionChecked("Overlays", false);
|
||||
}
|
||||
|
||||
var snapActivateSound = SoundCache.getSound(Script.resolvePath("../../resources/sounds/snap.wav"));
|
||||
|
||||
// take snapshot (with no notification)
|
||||
Script.setTimeout(function () {
|
||||
Audio.playSound(snapActivateSound, {
|
||||
position: { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z },
|
||||
localOnly: true,
|
||||
volume: 1.0
|
||||
});
|
||||
HMD.closeTablet();
|
||||
Script.setTimeout(function () {
|
||||
Window.takeSnapshot(false, includeAnimated, 1.91);
|
||||
|
|
|
@ -191,16 +191,12 @@
|
|||
gTablet.updateAudioBar(currentMicLevel);
|
||||
}
|
||||
|
||||
if (validCheckTime - now > MSECS_PER_SEC/4) {
|
||||
//each 250ms should be just fine
|
||||
if (now - validCheckTime > MSECS_PER_SEC) {
|
||||
validCheckTime = now;
|
||||
updateTabletWidthFromSettings();
|
||||
if (UIWebTablet) {
|
||||
UIWebTablet.setLandscape(landscape);
|
||||
}
|
||||
}
|
||||
|
||||
if (validCheckTime - now > MSECS_PER_SEC) {
|
||||
validCheckTime = now;
|
||||
if (tabletRezzed && UIWebTablet && !tabletIsValid()) {
|
||||
// when we switch domains, the tablet entity gets destroyed and recreated. this causes
|
||||
// the overlay to be deleted, but not recreated. If the overlay is deleted for this or any
|
||||
|
|
|
@ -821,6 +821,17 @@ for (var key in trayIcons) {
|
|||
|
||||
const notificationIcon = path.join(__dirname, '../resources/console-notification.png');
|
||||
|
||||
function isProcessRunning(pid) {
|
||||
try {
|
||||
// Sending a signal of 0 is effectively a NOOP.
|
||||
// If sending the signal is successful, kill will return true.
|
||||
// If the process is not running, an exception will be thrown.
|
||||
return process.kill(pid, 0);
|
||||
} catch (e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function onContentLoaded() {
|
||||
// Disable splash window for now.
|
||||
// maybeShowSplash();
|
||||
|
@ -882,31 +893,18 @@ function onContentLoaded() {
|
|||
startInterface();
|
||||
}
|
||||
|
||||
// If we were launched with the shutdownWatcher option, then we need to watch for the interface app
|
||||
// shutting down. The interface app will regularly update a running state file which we will check.
|
||||
// If the file doesn't exist or stops updating for a significant amount of time, we will shut down.
|
||||
if (argv.shutdownWatcher) {
|
||||
log.debug("Shutdown watcher requested... argv.shutdownWatcher:", argv.shutdownWatcher);
|
||||
var MAX_TIME_SINCE_EDIT = 5000; // 5 seconds between updates
|
||||
var firstAttemptToCheck = new Date().getTime();
|
||||
var shutdownWatchInterval = setInterval(function(){
|
||||
var stats = fs.stat(argv.shutdownWatcher, function(err, stats) {
|
||||
if (err) {
|
||||
var sinceFirstCheck = new Date().getTime() - firstAttemptToCheck;
|
||||
if (sinceFirstCheck > MAX_TIME_SINCE_EDIT) {
|
||||
log.debug("Running state file is missing, assume interface has shutdown... shutting down snadbox.");
|
||||
forcedShutdown();
|
||||
clearTimeout(shutdownWatchInterval);
|
||||
}
|
||||
} else {
|
||||
var sinceEdit = new Date().getTime() - stats.mtime.getTime();
|
||||
if (sinceEdit > MAX_TIME_SINCE_EDIT) {
|
||||
log.debug("Running state of interface hasn't updated in MAX time... shutting down.");
|
||||
forcedShutdown();
|
||||
clearTimeout(shutdownWatchInterval);
|
||||
}
|
||||
}
|
||||
});
|
||||
// If we were launched with the shutdownWith option, then we need to shutdown when that process (pid)
|
||||
// is no longer running.
|
||||
if (argv.shutdownWith) {
|
||||
let pid = argv.shutdownWith;
|
||||
console.log("Shutting down with process: ", pid);
|
||||
let checkProcessInterval = setInterval(function() {
|
||||
let isRunning = isProcessRunning(pid);
|
||||
if (!isRunning) {
|
||||
log.debug("Watched process is no longer running, shutting down");
|
||||
clearTimeout(checkProcessInterval);
|
||||
forcedShutdown();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,18 +113,21 @@ void FileCacheTests::testUnusedFiles() {
|
|||
QVERIFY(!file.get());
|
||||
}
|
||||
|
||||
QThread::msleep(1000);
|
||||
// Test files 90 to 99 are present
|
||||
for (int i = 90; i < 100; ++i) {
|
||||
std::string key = getFileKey(i);
|
||||
auto file = cache->getFile(key);
|
||||
QVERIFY(file.get());
|
||||
inUseFiles.push_back(file);
|
||||
// Each access touches the file, so we need to sleep here to ensure that the files are
|
||||
// spaced out in numeric order, otherwise later tests can't reliably determine the order
|
||||
// for cache ejection
|
||||
QThread::msleep(1000);
|
||||
|
||||
if (i == 94) {
|
||||
// Each access touches the file, so we need to sleep here to ensure that the the last 5 files
|
||||
// have later times for cache ejection priority, otherwise the test runs too fast to reliably
|
||||
// differentiate
|
||||
QThread::msleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)0);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)10);
|
||||
inUseFiles.clear();
|
||||
|
@ -165,6 +168,20 @@ void FileCacheTests::testFreeSpacePreservation() {
|
|||
}
|
||||
}
|
||||
|
||||
void FileCacheTests::testWipe() {
|
||||
// Reset the cache
|
||||
auto cache = makeFileCache(_testDir.path());
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)5);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)5);
|
||||
cache->wipe();
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)0);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)0);
|
||||
QVERIFY(getCacheDirectorySize() > 0);
|
||||
forceDeletes();
|
||||
QCOMPARE(getCacheDirectorySize(), (size_t)0);
|
||||
}
|
||||
|
||||
|
||||
void FileCacheTests::cleanupTestCase() {
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ private slots:
|
|||
void testUnusedFiles();
|
||||
void testFreeSpacePreservation();
|
||||
void cleanupTestCase();
|
||||
void testWipe();
|
||||
|
||||
private:
|
||||
size_t getFreeSpace() const;
|
||||
|
|
|
@ -31,13 +31,9 @@
|
|||
#include <render-utils/deferred_light_point_vert.h>
|
||||
#include <render-utils/deferred_light_spot_vert.h>
|
||||
|
||||
#include <render-utils/directional_light_frag.h>
|
||||
#include <render-utils/directional_ambient_light_frag.h>
|
||||
#include <render-utils/directional_skybox_light_frag.h>
|
||||
|
||||
#include <render-utils/point_light_frag.h>
|
||||
#include <render-utils/spot_light_frag.h>
|
||||
|
||||
#include <render-utils/standardTransformPNTC_vert.h>
|
||||
#include <render-utils/standardDrawTexture_frag.h>
|
||||
|
||||
|
@ -66,9 +62,6 @@
|
|||
#include <entities-renderer/textured_particle_frag.h>
|
||||
#include <entities-renderer/textured_particle_vert.h>
|
||||
|
||||
#include <render-utils/hit_effect_vert.h>
|
||||
#include <render-utils/hit_effect_frag.h>
|
||||
|
||||
#include <render-utils/overlay3D_vert.h>
|
||||
#include <render-utils/overlay3D_frag.h>
|
||||
|
||||
|
@ -155,11 +148,8 @@ void QTestWindow::draw() {
|
|||
testShaderBuild(simple_vert, simple_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_unlit_frag);
|
||||
testShaderBuild(deferred_light_vert, directional_light_frag);
|
||||
testShaderBuild(deferred_light_vert, directional_ambient_light_frag);
|
||||
testShaderBuild(deferred_light_vert, directional_skybox_light_frag);
|
||||
testShaderBuild(deferred_light_point_vert, point_light_frag);
|
||||
testShaderBuild(deferred_light_spot_vert, spot_light_frag);
|
||||
testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag);
|
||||
testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag);
|
||||
|
||||
|
@ -190,7 +180,6 @@ void QTestWindow::draw() {
|
|||
testShaderBuild(ambient_occlusion_vert, ambient_occlusion_frag);
|
||||
testShaderBuild(ambient_occlusion_vert, occlusion_blend_frag);
|
||||
*/
|
||||
testShaderBuild(hit_effect_vert, hit_effect_frag);
|
||||
|
||||
testShaderBuild(overlay3D_vert, overlay3D_frag);
|
||||
|
||||
|
|
|
@ -140,3 +140,77 @@ void GLMHelpersTests::testSimd() {
|
|||
}
|
||||
qDebug() << "Done ";
|
||||
}
|
||||
|
||||
void GLMHelpersTests::testGenerateBasisVectors() {
|
||||
{ // very simple case: primary along X, secondary is linear combination of X and Y
|
||||
glm::vec3 u(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 v(1.0f, 1.0f, 0.0f);
|
||||
glm::vec3 w;
|
||||
|
||||
generateBasisVectors(u, v, u, v, w);
|
||||
|
||||
QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_X, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_Y, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(w, Vectors::UNIT_Z, EPSILON);
|
||||
}
|
||||
|
||||
{ // point primary along Y instead of X
|
||||
glm::vec3 u(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 v(1.0f, 1.0f, 0.0f);
|
||||
glm::vec3 w;
|
||||
|
||||
generateBasisVectors(u, v, u, v, w);
|
||||
|
||||
QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_Y, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_X, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(w, -Vectors::UNIT_Z, EPSILON);
|
||||
}
|
||||
|
||||
{ // pass bad data (both vectors along Y). The helper will guess X for secondary.
|
||||
glm::vec3 u(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 v(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 w;
|
||||
|
||||
generateBasisVectors(u, v, u, v, w);
|
||||
|
||||
QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_Y, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_X, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(w, -Vectors::UNIT_Z, EPSILON);
|
||||
}
|
||||
|
||||
{ // pass bad data (both vectors along X). The helper will guess X for secondary, fail, then guess Y.
|
||||
glm::vec3 u(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 v(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 w;
|
||||
|
||||
generateBasisVectors(u, v, u, v, w);
|
||||
|
||||
QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_X, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_Y, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(w, Vectors::UNIT_Z, EPSILON);
|
||||
}
|
||||
|
||||
{ // general case for arbitrary rotation
|
||||
float angle = 1.234f;
|
||||
glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));
|
||||
glm::quat rotation = glm::angleAxis(angle, axis);
|
||||
|
||||
// expected values
|
||||
glm::vec3 x = rotation * Vectors::UNIT_X;
|
||||
glm::vec3 y = rotation * Vectors::UNIT_Y;
|
||||
glm::vec3 z = rotation * Vectors::UNIT_Z;
|
||||
|
||||
// primary is along x
|
||||
// secondary is linear combination of x and y
|
||||
// tertiary is unknown
|
||||
glm::vec3 u = 1.23f * x;
|
||||
glm::vec3 v = 2.34f * x + 3.45f * y;
|
||||
glm::vec3 w;
|
||||
|
||||
generateBasisVectors(u, v, u, v, w);
|
||||
|
||||
QCOMPARE_WITH_ABS_ERROR(u, x, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(v, y, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR(w, z, EPSILON);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ private slots:
|
|||
void testEulerDecomposition();
|
||||
void testSixByteOrientationCompression();
|
||||
void testSimd();
|
||||
void testGenerateBasisVectors();
|
||||
};
|
||||
|
||||
float getErrorDifference(const float& a, const float& b);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "StorageTests.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
QTEST_MAIN(StorageTests)
|
||||
|
||||
using namespace storage;
|
||||
|
@ -32,8 +34,8 @@ void StorageTests::testConversion() {
|
|||
QFileInfo fileInfo(_testFile);
|
||||
QCOMPARE(fileInfo.exists(), false);
|
||||
}
|
||||
StoragePointer storagePointer = std::make_unique<MemoryStorage>(_testData.size(), _testData.data());
|
||||
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
|
||||
StoragePointer storagePointer = std::unique_ptr<MemoryStorage>(new MemoryStorage(_testData.size(), _testData.data()));
|
||||
QCOMPARE(storagePointer->size(), _testData.size());
|
||||
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
|
||||
// Convert to a file
|
||||
storagePointer = storagePointer->toFileStorage(_testFile);
|
||||
|
@ -42,12 +44,12 @@ void StorageTests::testConversion() {
|
|||
QCOMPARE(fileInfo.exists(), true);
|
||||
QCOMPARE(fileInfo.size(), (qint64)_testData.size());
|
||||
}
|
||||
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
|
||||
QCOMPARE(storagePointer->size(), _testData.size());
|
||||
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
|
||||
|
||||
// Convert to memory
|
||||
storagePointer = storagePointer->toMemoryStorage();
|
||||
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
|
||||
QCOMPARE(storagePointer->size(), _testData.size());
|
||||
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
|
||||
{
|
||||
// ensure the file is unaffected
|
||||
|
@ -58,13 +60,13 @@ void StorageTests::testConversion() {
|
|||
|
||||
// truncate the data as a new memory object
|
||||
auto newSize = _testData.size() / 2;
|
||||
storagePointer = std::make_unique<MemoryStorage>(newSize, storagePointer->data());
|
||||
QCOMPARE(storagePointer->size(), (quint64)newSize);
|
||||
storagePointer = std::unique_ptr<Storage>(new MemoryStorage(newSize, storagePointer->data()));
|
||||
QCOMPARE(storagePointer->size(), newSize);
|
||||
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), newSize), 0);
|
||||
|
||||
// Convert back to file
|
||||
storagePointer = storagePointer->toFileStorage(_testFile);
|
||||
QCOMPARE(storagePointer->size(), (quint64)newSize);
|
||||
QCOMPARE(storagePointer->size(), newSize);
|
||||
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), newSize), 0);
|
||||
{
|
||||
// ensure the file is truncated
|
||||
|
|
1262
unpublishedScripts/marketplace/record/html/css/edit-style.css
Normal file
1262
unpublishedScripts/marketplace/record/html/css/edit-style.css
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue