mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 21:33:09 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into exportToTestRail1
This commit is contained in:
commit
65f8cdd00a
77 changed files with 709 additions and 719 deletions
|
@ -368,7 +368,6 @@ void Agent::executeScript() {
|
|||
// give scripts access to the Users object
|
||||
_scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
|
||||
|
||||
auto player = DependencyManager::get<recording::Deck>();
|
||||
connect(player.data(), &recording::Deck::playbackStateChanged, [=] {
|
||||
if (player->isPlaying()) {
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "AssignmentClientApp.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QtCore/QCommandLineParser>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QStandardPaths>
|
||||
|
@ -42,9 +44,8 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
// parse command-line
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("High Fidelity Assignment Client");
|
||||
parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
const QCommandLineOption versionOption = parser.addVersionOption();
|
||||
|
||||
QString typeDescription = "run single assignment client of given type\n# | Type\n============================";
|
||||
for (Assignment::Type type = Assignment::FirstType;
|
||||
|
@ -97,11 +98,16 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
parser.addOption(parentPIDOption);
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qCritical() << parser.errorText() << endl;
|
||||
std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (parser.isSet(versionOption)) {
|
||||
parser.showVersion();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (parser.isSet(helpOption)) {
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
|
|
|
@ -643,6 +643,7 @@ void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage>
|
|||
auto start = usecTimestampNow();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
|
||||
|
||||
bool addToIgnore;
|
||||
message->readPrimitive(&addToIgnore);
|
||||
while (message->getBytesLeftToRead()) {
|
||||
|
@ -650,17 +651,22 @@ void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage>
|
|||
QUuid ignoredUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
if (nodeList->nodeWithUUID(ignoredUUID)) {
|
||||
// Reset the lastBroadcastTime for the ignored avatar to 0
|
||||
// so the AvatarMixer knows it'll have to send identity data about the ignored avatar
|
||||
// to the ignorer if the ignorer unignores.
|
||||
nodeData->setLastBroadcastTime(ignoredUUID, 0);
|
||||
if (nodeData) {
|
||||
// Reset the lastBroadcastTime for the ignored avatar to 0
|
||||
// so the AvatarMixer knows it'll have to send identity data about the ignored avatar
|
||||
// to the ignorer if the ignorer unignores.
|
||||
nodeData->setLastBroadcastTime(ignoredUUID, 0);
|
||||
}
|
||||
|
||||
|
||||
// Reset the lastBroadcastTime for the ignorer (FROM THE PERSPECTIVE OF THE IGNORED) to 0
|
||||
// so the AvatarMixer knows it'll have to send identity data about the ignorer
|
||||
// to the ignored if the ignorer unignores.
|
||||
auto ignoredNode = nodeList->nodeWithUUID(ignoredUUID);
|
||||
AvatarMixerClientData* ignoredNodeData = reinterpret_cast<AvatarMixerClientData*>(ignoredNode->getLinkedData());
|
||||
ignoredNodeData->setLastBroadcastTime(senderNode->getUUID(), 0);
|
||||
if (ignoredNodeData) {
|
||||
ignoredNodeData->setLastBroadcastTime(senderNode->getUUID(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (addToIgnore) {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <iostream>
|
||||
|
||||
#include <QDir>
|
||||
#include <QJsonDocument>
|
||||
|
@ -69,6 +70,14 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.com";
|
|||
const QString ICE_SERVER_DEFAULT_HOSTNAME = "dev-ice.highfidelity.com";
|
||||
#endif
|
||||
|
||||
QString DomainServer::_iceServerAddr { ICE_SERVER_DEFAULT_HOSTNAME };
|
||||
int DomainServer::_iceServerPort { ICE_SERVER_DEFAULT_PORT };
|
||||
bool DomainServer::_overrideDomainID { false };
|
||||
QUuid DomainServer::_overridingDomainID;
|
||||
bool DomainServer::_getTempName { false };
|
||||
QString DomainServer::_userConfigFilename;
|
||||
int DomainServer::_parentPID { -1 };
|
||||
|
||||
bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||
const QString& metaversePath,
|
||||
const QString& requestSubobjectKey,
|
||||
|
@ -148,24 +157,13 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
|||
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv),
|
||||
_gatekeeper(this),
|
||||
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
||||
_allAssignments(),
|
||||
_unfulfilledAssignments(),
|
||||
_isUsingDTLS(false),
|
||||
_oauthProviderURL(),
|
||||
_oauthClientID(),
|
||||
_hostname(),
|
||||
_ephemeralACScripts(),
|
||||
_webAuthenticationStateSet(),
|
||||
_cookieSessionHash(),
|
||||
_automaticNetworkingSetting(),
|
||||
_settingsManager(),
|
||||
_iceServerAddr(ICE_SERVER_DEFAULT_HOSTNAME),
|
||||
_iceServerPort(ICE_SERVER_DEFAULT_PORT)
|
||||
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this)
|
||||
{
|
||||
PathUtils::removeTemporaryApplicationDirs();
|
||||
if (_parentPID != -1) {
|
||||
watchParentProcess(_parentPID);
|
||||
}
|
||||
|
||||
parseCommandLine();
|
||||
PathUtils::removeTemporaryApplicationDirs();
|
||||
|
||||
DependencyManager::set<tracing::Tracer>();
|
||||
DependencyManager::set<StatTracker>();
|
||||
|
@ -185,9 +183,16 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
// (need this since domain-server can restart itself and maintain static variables)
|
||||
DependencyManager::set<AccountManager>();
|
||||
|
||||
auto args = arguments();
|
||||
|
||||
_settingsManager.setupConfigMap(args);
|
||||
// load the user config
|
||||
QString userConfigFilename;
|
||||
if (!_userConfigFilename.isEmpty()) {
|
||||
userConfigFilename = _userConfigFilename;
|
||||
} else {
|
||||
// we weren't passed a user config path
|
||||
static const QString USER_CONFIG_FILE_NAME = "config.json";
|
||||
userConfigFilename = PathUtils::getAppDataFilePath(USER_CONFIG_FILE_NAME);
|
||||
}
|
||||
_settingsManager.setupConfigMap(userConfigFilename);
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
|
@ -246,8 +251,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
}
|
||||
|
||||
// check for the temporary name parameter
|
||||
const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name";
|
||||
if (args.contains(GET_TEMPORARY_NAME_SWITCH)) {
|
||||
if (_getTempName) {
|
||||
getTemporaryName();
|
||||
}
|
||||
|
||||
|
@ -316,28 +320,45 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
connect(_contentManager.get(), &DomainContentBackupManager::recoveryCompleted, this, &DomainServer::restart);
|
||||
}
|
||||
|
||||
void DomainServer::parseCommandLine() {
|
||||
void DomainServer::parseCommandLine(int argc, char* argv[]) {
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("High Fidelity Domain Server");
|
||||
parser.addHelpOption();
|
||||
const QCommandLineOption versionOption = parser.addVersionOption();
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption iceServerAddressOption("i", "ice-server address", "IP:PORT or HOSTNAME:PORT");
|
||||
parser.addOption(iceServerAddressOption);
|
||||
|
||||
const QCommandLineOption domainIDOption("d", "domain-server uuid");
|
||||
const QCommandLineOption domainIDOption("d", "domain-server uuid", "uuid");
|
||||
parser.addOption(domainIDOption);
|
||||
|
||||
const QCommandLineOption getTempNameOption("get-temp-name", "Request a temporary domain-name");
|
||||
parser.addOption(getTempNameOption);
|
||||
|
||||
const QCommandLineOption masterConfigOption("master-config", "Deprecated config-file option");
|
||||
parser.addOption(masterConfigOption);
|
||||
const QCommandLineOption userConfigOption("user-config", "Pass user config file pass", "path");
|
||||
parser.addOption(userConfigOption);
|
||||
|
||||
const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid");
|
||||
parser.addOption(parentPIDOption);
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qWarning() << parser.errorText() << endl;
|
||||
|
||||
QStringList arguments;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
arguments << argv[i];
|
||||
}
|
||||
if (!parser.parse(arguments)) {
|
||||
std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam
|
||||
QCoreApplication mockApp(argc, argv); // required for call to showHelp()
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (parser.isSet(versionOption)) {
|
||||
parser.showVersion();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
if (parser.isSet(helpOption)) {
|
||||
QCoreApplication mockApp(argc, argv); // required for call to showHelp()
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
@ -354,7 +375,7 @@ void DomainServer::parseCommandLine() {
|
|||
|
||||
if (_iceServerAddr.isEmpty()) {
|
||||
qWarning() << "Could not parse an IP address and port combination from" << hostnamePortString;
|
||||
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
|
||||
::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,14 +385,21 @@ void DomainServer::parseCommandLine() {
|
|||
qDebug() << "domain-server ID is" << _overridingDomainID;
|
||||
}
|
||||
|
||||
if (parser.isSet(getTempNameOption)) {
|
||||
_getTempName = true;
|
||||
}
|
||||
|
||||
if (parser.isSet(userConfigOption)) {
|
||||
_userConfigFilename = parser.value(userConfigOption);
|
||||
}
|
||||
|
||||
if (parser.isSet(parentPIDOption)) {
|
||||
bool ok = false;
|
||||
int parentPID = parser.value(parentPIDOption).toInt(&ok);
|
||||
|
||||
if (ok) {
|
||||
qDebug() << "Parent process PID is" << parentPID;
|
||||
watchParentProcess(parentPID);
|
||||
_parentPID = parentPID;
|
||||
qDebug() << "Parent process PID is" << _parentPID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ public:
|
|||
DomainServer(int argc, char* argv[]);
|
||||
~DomainServer();
|
||||
|
||||
static void parseCommandLine(int argc, char* argv[]);
|
||||
|
||||
enum DomainType {
|
||||
NonMetaverse,
|
||||
MetaverseDomain,
|
||||
|
@ -138,7 +140,6 @@ signals:
|
|||
|
||||
private:
|
||||
QUuid getID();
|
||||
void parseCommandLine();
|
||||
|
||||
QString getContentBackupDir();
|
||||
QString getEntitiesDirPath();
|
||||
|
@ -228,7 +229,7 @@ private:
|
|||
QQueue<SharedAssignmentPointer> _unfulfilledAssignments;
|
||||
TransactionHash _pendingAssignmentCredits;
|
||||
|
||||
bool _isUsingDTLS;
|
||||
bool _isUsingDTLS { false };
|
||||
|
||||
QUrl _oauthProviderURL;
|
||||
QString _oauthClientID;
|
||||
|
@ -265,10 +266,13 @@ private:
|
|||
friend class DomainGatekeeper;
|
||||
friend class DomainMetadata;
|
||||
|
||||
QString _iceServerAddr;
|
||||
int _iceServerPort;
|
||||
bool _overrideDomainID { false }; // should we override the domain-id from settings?
|
||||
QUuid _overridingDomainID { QUuid() }; // what should we override it with?
|
||||
static QString _iceServerAddr;
|
||||
static int _iceServerPort;
|
||||
static bool _overrideDomainID; // should we override the domain-id from settings?
|
||||
static QUuid _overridingDomainID; // what should we override it with?
|
||||
static bool _getTempName;
|
||||
static QString _userConfigFilename;
|
||||
static int _parentPID;
|
||||
|
||||
bool _sendICEServerAddressToMetaverseAPIInProgress { false };
|
||||
bool _sendICEServerAddressToMetaverseAPIRedo { false };
|
||||
|
|
|
@ -191,13 +191,12 @@ void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer<Re
|
|||
nodeList->sendPacketList(std::move(packetList), message->getSenderSockAddr());
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) {
|
||||
void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilename) {
|
||||
// since we're called from the DomainServerSettingsManager constructor, we don't take a write lock here
|
||||
// even though we change the underlying config map
|
||||
|
||||
_argumentList = argumentList;
|
||||
|
||||
_configMap.loadConfig(_argumentList);
|
||||
_configMap.setUserConfigFilename(userConfigFilename);
|
||||
_configMap.loadConfig();
|
||||
|
||||
static const auto VERSION_SETTINGS_KEYPATH = "version";
|
||||
QVariant* versionVariant = _configMap.valueForKeyPath(VERSION_SETTINGS_KEYPATH);
|
||||
|
@ -1736,7 +1735,7 @@ void DomainServerSettingsManager::persistToFile() {
|
|||
// failed to write, reload whatever the current config state is
|
||||
// with a write lock since we're about to overwrite the config map
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
_configMap.loadConfig(_argumentList);
|
||||
_configMap.loadConfig();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
DomainServerSettingsManager();
|
||||
bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url);
|
||||
|
||||
void setupConfigMap(const QStringList& argumentList);
|
||||
void setupConfigMap(const QString& userConfigFilename);
|
||||
|
||||
// each of the three methods in this group takes a read lock of _settingsLock
|
||||
// and cannot be called when the a write lock is held by the same thread
|
||||
|
@ -144,8 +144,6 @@ private slots:
|
|||
void processUsernameFromIDRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
||||
|
||||
private:
|
||||
QStringList _argumentList;
|
||||
|
||||
QJsonArray filteredDescriptionArray(bool isContentSettings);
|
||||
void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
|
||||
const QJsonObject& settingDescription);
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
int main(int argc, char* argv[]) {
|
||||
setupHifiApplication(BuildInfo::DOMAIN_SERVER_NAME);
|
||||
|
||||
DomainServer::parseCommandLine(argc, argv);
|
||||
|
||||
Setting::init();
|
||||
|
||||
int currentExitCode = 0;
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
|
@ -1247,7 +1247,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
|
||||
|
||||
// use our MyAvatar position and quat for address manager path
|
||||
addressManager->setPositionGetter([this]{ return getMyAvatar()->getWorldPosition(); });
|
||||
addressManager->setPositionGetter([this]{ return getMyAvatar()->getWorldFeetPosition(); });
|
||||
addressManager->setOrientationGetter([this]{ return getMyAvatar()->getWorldOrientation(); });
|
||||
|
||||
connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle);
|
||||
|
@ -5285,6 +5285,7 @@ void Application::reloadResourceCaches() {
|
|||
queryOctree(NodeType::EntityServer, PacketType::EntityQuery);
|
||||
|
||||
DependencyManager::get<AssetClient>()->clearCache();
|
||||
DependencyManager::get<ScriptCache>()->clearCache();
|
||||
|
||||
DependencyManager::get<AnimationCache>()->refreshAll();
|
||||
DependencyManager::get<ModelCache>()->refreshAll();
|
||||
|
|
|
@ -154,7 +154,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
|
||||
// connect to AddressManager signal for location jumps
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
this, static_cast<SlotType>(&MyAvatar::goToLocation));
|
||||
this, static_cast<SlotType>(&MyAvatar::goToFeetLocation));
|
||||
|
||||
// handle scale constraints imposed on us by the domain-server
|
||||
auto& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
|
@ -2623,6 +2623,49 @@ void MyAvatar::goToLocation(const QVariant& propertiesVar) {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::goToFeetLocation(const glm::vec3& newPosition,
|
||||
bool hasOrientation, const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation) {
|
||||
|
||||
qCDebug(interfaceapp).nospace() << "MyAvatar goToFeetLocation - moving to " << newPosition.x << ", "
|
||||
<< newPosition.y << ", " << newPosition.z;
|
||||
|
||||
ShapeInfo shapeInfo;
|
||||
computeShapeInfo(shapeInfo);
|
||||
glm::vec3 halfExtents = shapeInfo.getHalfExtents();
|
||||
glm::vec3 localFeetPos = shapeInfo.getOffset() - glm::vec3(0.0f, halfExtents.y + halfExtents.x, 0.0f);
|
||||
glm::mat4 localFeet = createMatFromQuatAndPos(Quaternions::IDENTITY, localFeetPos);
|
||||
|
||||
glm::mat4 worldFeet = createMatFromQuatAndPos(Quaternions::IDENTITY, newPosition);
|
||||
|
||||
glm::mat4 avatarMat = worldFeet * glm::inverse(localFeet);
|
||||
|
||||
glm::vec3 adjustedPosition = extractTranslation(avatarMat);
|
||||
|
||||
_goToPending = true;
|
||||
_goToPosition = adjustedPosition;
|
||||
_goToOrientation = getWorldOrientation();
|
||||
if (hasOrientation) {
|
||||
qCDebug(interfaceapp).nospace() << "MyAvatar goToFeetLocation - new orientation is "
|
||||
<< newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;
|
||||
|
||||
// orient the user to face the target
|
||||
glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation);
|
||||
|
||||
if (shouldFaceLocation) {
|
||||
quatOrientation = newOrientation * glm::angleAxis(PI, Vectors::UP);
|
||||
|
||||
// move the user a couple units away
|
||||
const float DISTANCE_TO_USER = 2.0f;
|
||||
_goToPosition = adjustedPosition - quatOrientation * IDENTITY_FORWARD * DISTANCE_TO_USER;
|
||||
}
|
||||
|
||||
_goToOrientation = quatOrientation;
|
||||
}
|
||||
|
||||
emit transformChanged();
|
||||
}
|
||||
|
||||
void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
||||
bool hasOrientation, const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation) {
|
||||
|
|
|
@ -1133,6 +1133,20 @@ public slots:
|
|||
*/
|
||||
float getGravity();
|
||||
|
||||
/**jsdoc
|
||||
* Move the avatar to a new position and/or orientation in the domain, while taking into account Avatar leg-length.
|
||||
* @function MyAvatar.goToFeetLocation
|
||||
* @param {Vec3} position - The new position for the avatar, in world coordinates.
|
||||
* @param {boolean} [hasOrientation=false] - Set to <code>true</code> to set the orientation of the avatar.
|
||||
* @param {Quat} [orientation=Quat.IDENTITY] - The new orientation for the avatar.
|
||||
* @param {boolean} [shouldFaceLocation=false] - Set to <code>true</code> to position the avatar a short distance away from
|
||||
* the new position and orientate the avatar to face the position.
|
||||
*/
|
||||
|
||||
void goToFeetLocation(const glm::vec3& newPosition,
|
||||
bool hasOrientation, const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation);
|
||||
|
||||
/**jsdoc
|
||||
* Move the avatar to a new position and/or orientation in the domain.
|
||||
* @function MyAvatar.goToLocation
|
||||
|
|
|
@ -42,6 +42,48 @@ extern "C" {
|
|||
int main(int argc, const char* argv[]) {
|
||||
setupHifiApplication(BuildInfo::INTERFACE_NAME);
|
||||
|
||||
QStringList arguments;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
arguments << argv[i];
|
||||
}
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("High Fidelity Interface");
|
||||
QCommandLineOption versionOption = parser.addVersionOption();
|
||||
QCommandLineOption helpOption = parser.addHelpOption();
|
||||
|
||||
QCommandLineOption urlOption("url", "", "value");
|
||||
QCommandLineOption noUpdaterOption("no-updater", "Do not show auto-updater");
|
||||
QCommandLineOption checkMinSpecOption("checkMinSpec", "Check if machine meets minimum specifications");
|
||||
QCommandLineOption runServerOption("runServer", "Whether to run the server");
|
||||
QCommandLineOption serverContentPathOption("serverContentPath", "Where to find server content", "serverContentPath");
|
||||
QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run");
|
||||
QCommandLineOption overrideAppLocalDataPathOption("cache", "set test cache <dir>", "dir");
|
||||
QCommandLineOption overrideScriptsPathOption(SCRIPTS_SWITCH, "set scripts <path>", "path");
|
||||
|
||||
parser.addOption(urlOption);
|
||||
parser.addOption(noUpdaterOption);
|
||||
parser.addOption(checkMinSpecOption);
|
||||
parser.addOption(runServerOption);
|
||||
parser.addOption(serverContentPathOption);
|
||||
parser.addOption(overrideAppLocalDataPathOption);
|
||||
parser.addOption(overrideScriptsPathOption);
|
||||
parser.addOption(allowMultipleInstancesOption);
|
||||
|
||||
if (!parser.parse(arguments)) {
|
||||
std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam
|
||||
}
|
||||
|
||||
if (parser.isSet(versionOption)) {
|
||||
parser.showVersion();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
if (parser.isSet(helpOption)) {
|
||||
QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp()
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
// Early check for --traceFile argument
|
||||
auto tracer = DependencyManager::set<tracing::Tracer>();
|
||||
const char * traceFile = nullptr;
|
||||
|
@ -95,30 +137,6 @@ int main(int argc, const char* argv[]) {
|
|||
qDebug() << "Crash handler started:" << crashHandlerStarted;
|
||||
}
|
||||
|
||||
QStringList arguments;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
arguments << argv[i];
|
||||
}
|
||||
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption urlOption("url", "", "value");
|
||||
QCommandLineOption noUpdaterOption("no-updater", "Do not show auto-updater");
|
||||
QCommandLineOption checkMinSpecOption("checkMinSpec", "Check if machine meets minimum specifications");
|
||||
QCommandLineOption runServerOption("runServer", "Whether to run the server");
|
||||
QCommandLineOption serverContentPathOption("serverContentPath", "Where to find server content", "serverContentPath");
|
||||
QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run");
|
||||
QCommandLineOption overrideAppLocalDataPathOption("cache", "set test cache <dir>", "dir");
|
||||
QCommandLineOption overrideScriptsPathOption(SCRIPTS_SWITCH, "set scripts <path>", "path");
|
||||
parser.addOption(urlOption);
|
||||
parser.addOption(noUpdaterOption);
|
||||
parser.addOption(checkMinSpecOption);
|
||||
parser.addOption(runServerOption);
|
||||
parser.addOption(serverContentPathOption);
|
||||
parser.addOption(overrideAppLocalDataPathOption);
|
||||
parser.addOption(overrideScriptsPathOption);
|
||||
parser.addOption(allowMultipleInstancesOption);
|
||||
parser.parse(arguments);
|
||||
|
||||
|
||||
const QString& applicationName = getInterfaceSharedMemoryName();
|
||||
bool instanceMightBeRunning = true;
|
||||
|
|
|
@ -115,8 +115,6 @@ ParabolaPointer::RenderState::RenderState(const OverlayID& startID, const Overla
|
|||
_pathWidth = pathWidth;
|
||||
if (render::Item::isValidID(_pathID)) {
|
||||
auto renderItem = std::make_shared<ParabolaRenderItem>(pathColor, pathAlpha, pathWidth, isVisibleInSecondaryCamera, pathEnabled);
|
||||
// TODO: update bounds properly
|
||||
renderItem->editBound().setBox(glm::vec3(-16000.0f), 32000.0f);
|
||||
transaction.resetItem(_pathID, std::make_shared<ParabolaRenderItem::Payload>(renderItem));
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
@ -180,6 +178,7 @@ void ParabolaPointer::RenderState::update(const glm::vec3& origin, const glm::ve
|
|||
item.setAcceleration(acceleration);
|
||||
item.setParabolicDistance(parabolicDistance);
|
||||
item.setWidth(width);
|
||||
item.updateBounds();
|
||||
});
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
@ -302,10 +301,10 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::setVisible(bool visible)
|
|||
}
|
||||
|
||||
void ParabolaPointer::RenderState::ParabolaRenderItem::updateKey() {
|
||||
// FIXME: There's no way to designate a render item as non-shadow-reciever, and since a parabola's bounding box covers the entire domain,
|
||||
// it seems to block all shadows. I think this is a bug with shadows.
|
||||
//auto builder = _parabolaData.color.a < 1.0f ? render::ItemKey::Builder::transparentShape() : render::ItemKey::Builder::opaqueShape();
|
||||
auto builder = render::ItemKey::Builder::transparentShape();
|
||||
auto builder = _parabolaData.color.a < 1.0f ? render::ItemKey::Builder::transparentShape() : render::ItemKey::Builder::opaqueShape();
|
||||
|
||||
// TODO: parabolas should cast shadows, but they're so thin that the cascaded shadow maps make them look pretty bad
|
||||
//builder.withShadowCaster();
|
||||
|
||||
if (_enabled && _visible) {
|
||||
builder.withVisible();
|
||||
|
@ -322,6 +321,33 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::updateKey() {
|
|||
_key = builder.build();
|
||||
}
|
||||
|
||||
void ParabolaPointer::RenderState::ParabolaRenderItem::updateBounds() {
|
||||
glm::vec3 max = _origin;
|
||||
glm::vec3 min = _origin;
|
||||
|
||||
glm::vec3 end = _origin + _parabolaData.velocity * _parabolaData.parabolicDistance +
|
||||
0.5f * _parabolaData.acceleration * _parabolaData.parabolicDistance * _parabolaData.parabolicDistance;
|
||||
max = glm::max(max, end);
|
||||
min = glm::min(min, end);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (fabsf(_parabolaData.velocity[i]) > EPSILON && fabsf(_parabolaData.acceleration[i]) > EPSILON) {
|
||||
float maxT = -_parabolaData.velocity[i] / _parabolaData.acceleration[i];
|
||||
if (maxT > 0.0f && maxT < _parabolaData.parabolicDistance) {
|
||||
glm::vec3 maxPoint = _origin + _parabolaData.velocity * maxT + 0.5f * _parabolaData.acceleration * maxT * maxT;
|
||||
max = glm::max(max, maxPoint);
|
||||
min = glm::min(min, maxPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 halfWidth = glm::vec3(0.5f * _parabolaData.width);
|
||||
max += halfWidth;
|
||||
min -= halfWidth;
|
||||
|
||||
_bound = AABox(min, max - min);
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
|
||||
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
void setVisible(bool visible);
|
||||
void updateKey();
|
||||
void updateUniformBuffer() { _uniformBuffer->setSubData(0, _parabolaData); }
|
||||
void updateBounds();
|
||||
|
||||
void setColor(const glm::vec3& color) { _parabolaData.color = glm::vec4(color, _parabolaData.color.a); }
|
||||
void setAlpha(const float& alpha) { _parabolaData.color.a = alpha; }
|
||||
|
|
|
@ -138,7 +138,7 @@ public:
|
|||
* @property {Vec3} intersection The intersection point in world-space.
|
||||
* @property {Vec3} surfaceNormal The surface normal at the intersected point. All NANs if type == INTERSECTED_HUD.
|
||||
* @property {Variant} extraInfo Additional intersection details when available for Model objects.
|
||||
* @property {StylusTip} parabola The PickParabola that was used. Valid even if there was no intersection.
|
||||
* @property {PickParabola} parabola The PickParabola that was used. Valid even if there was no intersection.
|
||||
*/
|
||||
|
||||
/**jsdoc
|
||||
|
|
|
@ -92,7 +92,7 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
|
|||
* @typedef {object} Pointers.LaserPointerProperties
|
||||
* @property {boolean} [faceAvatar=false] If true, the end of the Pointer will always rotate to face the avatar.
|
||||
* @property {boolean} [centerEndY=true] If false, the end of the Pointer will be moved up by half of its height.
|
||||
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the laser is pointing.
|
||||
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the pointer is pointing.
|
||||
* @property {boolean} [distanceScaleEnd=false] If true, the dimensions of the end of the Pointer will scale linearly with distance.
|
||||
* @property {boolean} [scaleWithAvatar=false] If true, the width of the Pointer's path will scale linearly with your avatar's scale.
|
||||
* @property {boolean} [followNormal=false] If true, the end of the Pointer will rotate to follow the normal of the intersected surface.
|
||||
|
@ -207,9 +207,10 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope
|
|||
* The rendering properties of the parabolic path
|
||||
*
|
||||
* @typedef {object} Pointers.ParabolaProperties
|
||||
* @property {Color} color The color of the parabola.
|
||||
* @property {number} alpha The alpha of the parabola.
|
||||
* @property {number} width The width of the parabola, in meters.
|
||||
* @property {Color} color=255,255,255 The color of the parabola.
|
||||
* @property {number} alpha=1.0 The alpha of the parabola.
|
||||
* @property {number} width=0.01 The width of the parabola, in meters.
|
||||
* @property {boolean} isVisibleInSecondaryCamera=false The width of the parabola, in meters.
|
||||
*/
|
||||
/**jsdoc
|
||||
* A set of properties used to define the visual aspect of a Parabola Pointer in the case that the Pointer is not intersecting something. Same as a {@link Pointers.ParabolaPointerRenderState},
|
||||
|
@ -232,10 +233,10 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope
|
|||
*/
|
||||
/**jsdoc
|
||||
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.
|
||||
* @typedef {object} Pointers.LaserPointerProperties
|
||||
* @typedef {object} Pointers.ParabolaPointerProperties
|
||||
* @property {boolean} [faceAvatar=false] If true, the end of the Pointer will always rotate to face the avatar.
|
||||
* @property {boolean} [centerEndY=true] If false, the end of the Pointer will be moved up by half of its height.
|
||||
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the laser is pointing.
|
||||
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the pointer is pointing.
|
||||
* @property {boolean} [distanceScaleEnd=false] If true, the dimensions of the end of the Pointer will scale linearly with distance.
|
||||
* @property {boolean} [scaleWithAvatar=false] If true, the width of the Pointer's path will scale linearly with your avatar's scale.
|
||||
* @property {boolean} [followNormal=false] If true, the end of the Pointer will rotate to follow the normal of the intersected surface.
|
||||
|
|
|
@ -56,8 +56,7 @@ class QScriptEngine;
|
|||
* @property {Uuid} tabletID - The UUID of the tablet body model overlay.
|
||||
* @property {Uuid} tabletScreenID - The UUID of the tablet's screen overlay.
|
||||
* @property {Uuid} homeButtonID - The UUID of the tablet's "home" button overlay.
|
||||
* @property {Uuid} homeButtonHighlightMaterialID - The UUID of the material entity used to highlight tablet button
|
||||
* @property {Uuid} homeButtonUnhighlightMaterialID - The UUID of the material entity use to unhighlight the entity
|
||||
* @property {Uuid} homeButtonHighlightID - The UUID of the tablet's "home" button highlight overlay.
|
||||
*/
|
||||
class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -69,11 +68,10 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen
|
|||
Q_PROPERTY(QUuid tabletID READ getCurrentTabletFrameID WRITE setCurrentTabletFrameID)
|
||||
Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonID WRITE setCurrentHomeButtonID)
|
||||
Q_PROPERTY(QUuid tabletScreenID READ getCurrentTabletScreenID WRITE setCurrentTabletScreenID)
|
||||
Q_PROPERTY(QUuid homeButtonHighlightMaterialID READ getCurrentHomeButtonHighlightMaterialID WRITE setCurrentHomeButtonHighlightMaterialID)
|
||||
Q_PROPERTY(QUuid homeButtonUnhighlightMaterialID READ getCurrentHomeButtonUnhighlightMaterialID WRITE setCurrentHomeButtonUnhighlightMaterialID)
|
||||
Q_PROPERTY(QUuid homeButtonHighlightID READ getCurrentHomeButtonHighlightID WRITE setCurrentHomeButtonHighlightID)
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* Calculate the intersection of a ray with the HUD overlay.
|
||||
* @function HMD.calculateRayUICollisionPoint
|
||||
|
@ -365,15 +363,12 @@ public:
|
|||
void setCurrentHomeButtonID(QUuid homeButtonID) { _homeButtonID = homeButtonID; }
|
||||
QUuid getCurrentHomeButtonID() const { return _homeButtonID; }
|
||||
|
||||
void setCurrentHomeButtonHighlightID(QUuid homeButtonHighlightID) { _homeButtonHighlightID = homeButtonHighlightID; }
|
||||
QUuid getCurrentHomeButtonHighlightID() const { return _homeButtonHighlightID; }
|
||||
|
||||
void setCurrentTabletScreenID(QUuid tabletID) { _tabletScreenID = tabletID; }
|
||||
QUuid getCurrentTabletScreenID() const { return _tabletScreenID; }
|
||||
|
||||
void setCurrentHomeButtonHighlightMaterialID(QUuid homeButtonHighlightMaterialID) { _homeButtonHighlightMaterialID = homeButtonHighlightMaterialID; }
|
||||
QUuid getCurrentHomeButtonHighlightMaterialID() { return _homeButtonHighlightMaterialID; }
|
||||
|
||||
void setCurrentHomeButtonUnhighlightMaterialID(QUuid homeButtonUnhighlightMaterialID) { _homeButtonUnhighlightMaterialID = homeButtonUnhighlightMaterialID; }
|
||||
QUuid getCurrentHomeButtonUnhighlightMaterialID() { return _homeButtonUnhighlightMaterialID; }
|
||||
|
||||
private:
|
||||
bool _showTablet { false };
|
||||
bool _tabletContextualMode { false };
|
||||
|
@ -381,8 +376,7 @@ private:
|
|||
QUuid _tabletScreenID; // this is the overlayID which is part of (a child of) the tablet-ui.
|
||||
QUuid _homeButtonID;
|
||||
QUuid _tabletEntityID;
|
||||
QUuid _homeButtonHighlightMaterialID;
|
||||
QUuid _homeButtonUnhighlightMaterialID;
|
||||
QUuid _homeButtonHighlightID;
|
||||
|
||||
// Get the position of the HMD
|
||||
glm::vec3 getPosition() const;
|
||||
|
|
|
@ -431,7 +431,7 @@ void Stats::updateStats(bool force) {
|
|||
// a new Map sorted by average time...
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
QMap<float, QString> sortedRecords;
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
auto allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
|
||||
while (i.hasNext()) {
|
||||
|
@ -479,7 +479,7 @@ void Stats::updateStats(bool force) {
|
|||
bool operator<(const SortableStat& other) const { return priority < other.priority; }
|
||||
};
|
||||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
auto allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
std::priority_queue<SortableStat> idleUpdateStats;
|
||||
auto itr = allRecords.find("/idle/update");
|
||||
if (itr != allRecords.end()) {
|
||||
|
@ -496,7 +496,7 @@ void Stats::updateStats(bool force) {
|
|||
};
|
||||
for (int32_t j = 0; j < categories.size(); ++j) {
|
||||
QString recordKey = "/idle/update/" + categories[j];
|
||||
auto record = PerformanceTimer::getTimerRecord(recordKey);
|
||||
auto& record = allRecords[recordKey];
|
||||
if (record.getCount()) {
|
||||
float dt = (float) record.getMovingAverage() / (float)USECS_PER_MSEC;
|
||||
QString message = QString("\n %1 = %2").arg(categories[j]).arg(dt);
|
||||
|
|
|
@ -481,29 +481,6 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
|||
// reduce angle by a flexCoefficient
|
||||
angle *= target.getFlexCoefficient(chainDepth);
|
||||
deltaRotation = glm::angleAxis(angle, axis);
|
||||
|
||||
// The swing will re-orient the tip but there will tend to be be a non-zero delta between the tip's
|
||||
// new orientation and its target. This is the final parent-relative orientation that the tip joint have
|
||||
// make to achieve its target orientation.
|
||||
glm::quat tipRelativeRotation = glm::inverse(deltaRotation * tipParentOrientation) * target.getRotation();
|
||||
|
||||
// enforce tip's constraint
|
||||
RotationConstraint* constraint = getConstraint(tipIndex);
|
||||
if (constraint) {
|
||||
bool constrained = constraint->apply(tipRelativeRotation);
|
||||
if (constrained) {
|
||||
// The tip's final parent-relative rotation would violate its constraint
|
||||
// so we try to pre-twist this pivot to compensate.
|
||||
glm::quat constrainedTipRotation = deltaRotation * tipParentOrientation * tipRelativeRotation;
|
||||
glm::quat missingRotation = target.getRotation() * glm::inverse(constrainedTipRotation);
|
||||
glm::quat swingPart;
|
||||
glm::quat twistPart;
|
||||
glm::vec3 axis = glm::normalize(deltaRotation * leverArm);
|
||||
swingTwistDecomposition(missingRotation, axis, swingPart, twistPart);
|
||||
const float LIMIT_LEAK_FRACTION = 0.1f;
|
||||
deltaRotation = safeLerp(glm::quat(), twistPart, LIMIT_LEAK_FRACTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (targetType == IKTarget::Type::HmdHead) {
|
||||
|
@ -1255,48 +1232,7 @@ void AnimInverseKinematics::initConstraints() {
|
|||
|
||||
constraint = static_cast<RotationConstraint*>(stConstraint);
|
||||
} else if (0 == baseName.compare("Hand", Qt::CaseSensitive)) {
|
||||
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot());
|
||||
stConstraint->setTwistLimits(0.0f, 0.0f); // max == min, disables twist limits
|
||||
|
||||
/* KEEP THIS CODE for future experimentation -- twist limits for hands
|
||||
const float MAX_HAND_TWIST = 3.0f * PI / 5.0f;
|
||||
const float MIN_HAND_TWIST = -PI / 2.0f;
|
||||
if (isLeft) {
|
||||
stConstraint->setTwistLimits(-MAX_HAND_TWIST, -MIN_HAND_TWIST);
|
||||
} else {
|
||||
stConstraint->setTwistLimits(MIN_HAND_TWIST, MAX_HAND_TWIST);
|
||||
}
|
||||
*/
|
||||
|
||||
/* KEEP THIS CODE for future experimentation -- non-symmetrical swing limits for wrist
|
||||
* a more complicated wrist with asymmetric cone
|
||||
// these directions are approximate swing limits in parent-frame
|
||||
// NOTE: they don't need to be normalized
|
||||
std::vector<glm::vec3> swungDirections;
|
||||
swungDirections.push_back(glm::vec3(1.0f, 1.0f, 0.0f));
|
||||
swungDirections.push_back(glm::vec3(0.75f, 1.0f, -1.0f));
|
||||
swungDirections.push_back(glm::vec3(-0.75f, 1.0f, -1.0f));
|
||||
swungDirections.push_back(glm::vec3(-1.0f, 1.0f, 0.0f));
|
||||
swungDirections.push_back(glm::vec3(-0.75f, 1.0f, 1.0f));
|
||||
swungDirections.push_back(glm::vec3(0.75f, 1.0f, 1.0f));
|
||||
|
||||
// rotate directions into joint-frame
|
||||
glm::quat invRelativeRotation = glm::inverse(_defaultRelativePoses[i].rot);
|
||||
int numDirections = (int)swungDirections.size();
|
||||
for (int j = 0; j < numDirections; ++j) {
|
||||
swungDirections[j] = invRelativeRotation * swungDirections[j];
|
||||
}
|
||||
stConstraint->setSwingLimits(swungDirections);
|
||||
*/
|
||||
|
||||
// simple cone
|
||||
std::vector<float> minDots;
|
||||
const float MAX_HAND_SWING = PI / 2.0f;
|
||||
minDots.push_back(cosf(MAX_HAND_SWING));
|
||||
stConstraint->setSwingLimits(minDots);
|
||||
|
||||
constraint = static_cast<RotationConstraint*>(stConstraint);
|
||||
// hand/wrist constraints have been disabled.
|
||||
} else if (baseName.startsWith("Shoulder", Qt::CaseSensitive)) {
|
||||
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot());
|
||||
|
|
|
@ -1547,16 +1547,18 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex,
|
|||
glm::vec3 backVector = oppositeArmPose.trans() - armPose.trans();
|
||||
glm::vec3 backCenter = armPose.trans() + 0.5f * backVector;
|
||||
|
||||
const float OVER_BACK_HEAD_PERCENTAGE = 0.2f;
|
||||
glm::vec3 frontVector = glm::normalize(glm::cross(backVector, Vectors::UNIT_Y));
|
||||
glm::vec3 topVector = glm::normalize(glm::cross(frontVector, backVector));
|
||||
|
||||
glm::vec3 centerToHand = handPose.trans() - backCenter;
|
||||
glm::vec3 headCenter = backCenter + glm::length(backVector) * topVector;
|
||||
|
||||
glm::vec3 headCenter = backCenter + glm::vec3(0, OVER_BACK_HEAD_PERCENTAGE * backVector.length(), 0);
|
||||
glm::vec3 frontVector = glm::normalize(glm::cross(backVector, glm::vec3(0, 1, 0)));
|
||||
// Make sure is pointing forward
|
||||
frontVector = frontVector.z < 0 ? -frontVector : frontVector;
|
||||
|
||||
float horizontalModule = glm::dot(armToHand, glm::vec3(0, -1, 0));
|
||||
glm::vec3 headForward = headCenter + horizontalModule * frontVector;
|
||||
float horizontalModule = glm::dot(centerToHand, -topVector);
|
||||
|
||||
glm::vec3 headForward = headCenter + glm::max(0.0f, horizontalModule) * frontVector;
|
||||
glm::vec3 armToHead = headForward - armPose.trans();
|
||||
|
||||
float armToHandDistance = glm::length(armToHand);
|
||||
|
@ -1570,8 +1572,10 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex,
|
|||
// How much the hand is reaching for the opposite side
|
||||
float oppositeProjection = glm::dot(armToHandDir, glm::normalize(backVector));
|
||||
|
||||
// Don't use pole vector when the hands are behind
|
||||
if (glm::dot(frontVector, armToHand) < 0 && oppositeProjection < 0.5f * armTotalDistance) {
|
||||
bool isCrossed = glm::dot(centerToHand, backVector) > 0;
|
||||
bool isBehind = glm::dot(frontVector, armToHand) < 0;
|
||||
// Don't use pole vector when the hands are behind the back and the arms are not crossed
|
||||
if (isBehind && !isCrossed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1585,7 +1589,7 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex,
|
|||
glm::vec3 correctionVector = glm::vec3(0, 0, 0);
|
||||
|
||||
const float FORWARD_TRIGGER_PERCENTAGE = 0.2f;
|
||||
const float FORWARD_CORRECTOR_WEIGHT = 3.0f;
|
||||
const float FORWARD_CORRECTOR_WEIGHT = 2.3f;
|
||||
|
||||
float elbowForwardTrigger = FORWARD_TRIGGER_PERCENTAGE * armToHandDistance;
|
||||
|
||||
|
|
|
@ -1577,6 +1577,14 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) {
|
|||
radius = halfExtents.x;
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getWorldFeetPosition() {
|
||||
ShapeInfo shapeInfo;
|
||||
computeShapeInfo(shapeInfo);
|
||||
glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight
|
||||
glm::vec3 localFeet(0.0f, shapeInfo.getOffset().y - halfExtents.y - halfExtents.x, 0.0f);
|
||||
return getWorldOrientation() * localFeet + getWorldPosition();
|
||||
}
|
||||
|
||||
float Avatar::computeMass() {
|
||||
float radius;
|
||||
glm::vec3 start, end;
|
||||
|
|
|
@ -249,6 +249,12 @@ public:
|
|||
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
||||
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
|
||||
float computeMass();
|
||||
/**jsdoc
|
||||
* Get the position of the current avatar's feet (or rather, bottom of its collision capsule) in world coordinates.
|
||||
* @function MyAvatar.getWorldFeetPosition
|
||||
* @returns {Vec3} The position of the avatar's feet in world coordinates.
|
||||
*/
|
||||
Q_INVOKABLE glm::vec3 getWorldFeetPosition();
|
||||
|
||||
void setPositionViaScript(const glm::vec3& position) override;
|
||||
void setOrientationViaScript(const glm::quat& orientation) override;
|
||||
|
|
|
@ -112,11 +112,14 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
|
||||
batch.setModelTransform(renderTransform);
|
||||
drawMaterial->setTextureTransforms(textureTransform);
|
||||
|
||||
// bind the material
|
||||
RenderPipelines::bindMaterial(drawMaterial, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
drawMaterial->setTextureTransforms(textureTransform);
|
||||
|
||||
// bind the material
|
||||
RenderPipelines::bindMaterial(drawMaterial, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
// Draw!
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(batch);
|
||||
|
|
|
@ -35,9 +35,7 @@ ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Pare
|
|||
_procedural._vertexSource = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple);
|
||||
// FIXME: Setup proper uniform slots and use correct pipelines for forward rendering
|
||||
_procedural._opaquefragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple);
|
||||
// FIXME: Transparent procedural entities only seem to work if they use the opaque pipelines
|
||||
//_procedural._transparentfragmentSource = simple_transparent_frag::getSource();
|
||||
_procedural._transparentfragmentSource = _procedural._opaquefragmentSource;
|
||||
_procedural._transparentfragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_transparent);
|
||||
_procedural._opaqueState->setCullMode(gpu::State::CULL_NONE);
|
||||
_procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMaskDrawShape(*_procedural._opaqueState);
|
||||
|
@ -268,8 +266,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||
}
|
||||
} else {
|
||||
RenderPipelines::bindMaterial(mat, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
RenderPipelines::bindMaterial(mat, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
geometryCache->renderShape(batch, geometryShape);
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ void main(void) {
|
|||
vec3 UP = vec3(0, 1, 0);
|
||||
vec3 modelUpWorld;
|
||||
<$transformModelToWorldDir(cam, obj, UP, modelUpWorld)$>
|
||||
vec3 upWorld = mix(UP, normalize(modelUpWorld), particle.rotateWithEntity);
|
||||
vec3 upWorld = mix(UP, normalize(modelUpWorld), float(particle.rotateWithEntity));
|
||||
vec3 upEye = normalize(view3 * upWorld);
|
||||
vec3 FORWARD = vec3(0, 0, -1);
|
||||
vec3 particleRight = normalize(cross(FORWARD, upEye));
|
||||
|
|
|
@ -3743,6 +3743,8 @@ bool EntityItemProperties::verifyStaticCertificateProperties() {
|
|||
void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityIDToClone) {
|
||||
setName(getName() + "-clone-" + entityIDToClone.toString());
|
||||
setLocked(false);
|
||||
setParentID(QUuid());
|
||||
setParentJointIndex(-1);
|
||||
setLifetime(getCloneLifetime());
|
||||
setDynamic(getCloneDynamic());
|
||||
setClientOnly(getCloneAvatarEntity());
|
||||
|
|
|
@ -43,14 +43,6 @@ bool recommendedSparseTextures = (QThread::idealThreadCount() >= MIN_CORES_FOR_I
|
|||
|
||||
std::atomic<bool> Texture::_enableSparseTextures { recommendedSparseTextures };
|
||||
|
||||
struct ReportTextureState {
|
||||
ReportTextureState() {
|
||||
qCDebug(gpulogging) << "[TEXTURE TRANSFER SUPPORT]"
|
||||
<< "\n\tidealThreadCount:" << QThread::idealThreadCount()
|
||||
<< "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures;
|
||||
}
|
||||
} report;
|
||||
|
||||
void Texture::setEnableSparseTextures(bool enabled) {
|
||||
#ifdef Q_OS_WIN
|
||||
qCDebug(gpulogging) << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Sparse Textures and Dynamic Texture Management:" << enabled;
|
||||
|
|
|
@ -269,7 +269,14 @@ vec3 fetchLightmapMap(vec2 uv) {
|
|||
|
||||
<@func discardTransparent(opacity)@>
|
||||
{
|
||||
if (<$opacity$> < 1e-6) {
|
||||
if (<$opacity$> < 1.0) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
<@endfunc@>
|
||||
<@func discardInvisible(opacity)@>
|
||||
{
|
||||
if (<$opacity$> < 1.e-6) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,6 +145,7 @@ public:
|
|||
*
|
||||
* @property {number} Ray Ray Picks intersect a ray with the nearest object in front of them, along a given direction.
|
||||
* @property {number} Stylus Stylus Picks provide "tapping" functionality on/into flat surfaces.
|
||||
* @property {number} Parabola Parabola Picks intersect a parabola with the nearest object in front of them, with a given initial velocity and acceleration.
|
||||
*/
|
||||
/**jsdoc
|
||||
* <table>
|
||||
|
@ -154,6 +155,7 @@ public:
|
|||
* <tbody>
|
||||
* <tr><td><code>{@link PickType(0)|PickType.Ray}</code></td><td></td></tr>
|
||||
* <tr><td><code>{@link PickType(0)|PickType.Stylus}</code></td><td></td></tr>
|
||||
* <tr><td><code>{@link PickType(0)|PickType.Parabola}</code></td><td></td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* @typedef {number} PickType
|
||||
|
|
|
@ -39,7 +39,4 @@ void main(void) {
|
|||
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
|
||||
color = pow(color, vec3(2.2));
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
// FIXME: scribe does not yet scrub out else statements
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -157,8 +157,10 @@ void MeshPartPayload::render(RenderArgs* args) {
|
|||
bindMesh(batch);
|
||||
|
||||
// apply material properties
|
||||
RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
// Draw!
|
||||
{
|
||||
|
@ -417,8 +419,10 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
bindMesh(batch);
|
||||
|
||||
// apply material properties
|
||||
RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
// Draw!
|
||||
{
|
||||
|
|
|
@ -40,7 +40,7 @@ void main(void) {
|
|||
|
||||
float opacity = getMaterialOpacity(mat) * _color.a;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
<$discardInvisible(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
|
|
|
@ -51,9 +51,9 @@ void main(void) {
|
|||
#ifdef PROCEDURAL
|
||||
|
||||
#ifdef PROCEDURAL_V1
|
||||
specular = getProceduralColor().rgb;
|
||||
diffuse = getProceduralColor().rgb;
|
||||
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
|
||||
//specular = pow(specular, vec3(2.2));
|
||||
//diffuse = pow(diffuse, vec3(2.2));
|
||||
emissiveAmount = 1.0;
|
||||
#else
|
||||
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// forward_simple_transparent.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/15/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
<@include DefaultMaterials.slh@>
|
||||
|
||||
<@include ForwardGlobalLight.slh@>
|
||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||
|
||||
// the interpolated normal
|
||||
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS;
|
||||
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normalMS;
|
||||
layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color;
|
||||
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
|
||||
#define _texCoord0 _texCoord01.xy
|
||||
#define _texCoord1 _texCoord01.zw
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _positionMS;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES;
|
||||
|
||||
// For retro-compatibility
|
||||
#define _normal _normalWS
|
||||
#define _modelNormal _normalMS
|
||||
#define _position _positionMS
|
||||
#define _eyePosition _positionES
|
||||
|
||||
layout(location=0) out vec4 _fragColor0;
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
||||
#line 1001
|
||||
//PROCEDURAL_BLOCK
|
||||
|
||||
#line 2030
|
||||
void main(void) {
|
||||
vec3 normal = normalize(_normalWS.xyz);
|
||||
vec3 diffuse = _color.rgb;
|
||||
vec3 specular = DEFAULT_SPECULAR;
|
||||
float shininess = DEFAULT_SHININESS;
|
||||
float emissiveAmount = 0.0;
|
||||
|
||||
#ifdef PROCEDURAL
|
||||
|
||||
#ifdef PROCEDURAL_V1
|
||||
specular = getProceduralColor().rgb;
|
||||
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
|
||||
//specular = pow(specular, vec3(2.2));
|
||||
emissiveAmount = 1.0;
|
||||
#else
|
||||
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 fragPosition = _positionES.xyz;
|
||||
|
||||
if (emissiveAmount > 0.0) {
|
||||
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||
cam._viewInverse,
|
||||
1.0,
|
||||
DEFAULT_OCCLUSION,
|
||||
fragPosition,
|
||||
normal,
|
||||
specular,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_METALLIC,
|
||||
DEFAULT_EMISSIVE,
|
||||
DEFAULT_ROUGHNESS, _color.a),
|
||||
_color.a);
|
||||
} else {
|
||||
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||
cam._viewInverse,
|
||||
1.0,
|
||||
DEFAULT_OCCLUSION,
|
||||
fragPosition,
|
||||
normal,
|
||||
diffuse,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_METALLIC,
|
||||
DEFAULT_EMISSIVE,
|
||||
DEFAULT_ROUGHNESS, _color.a),
|
||||
_color.a);
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ void main(void) {
|
|||
|
||||
float opacity = getMaterialOpacity(mat) * _color.a;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
<$discardInvisible(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
|
|
|
@ -47,7 +47,7 @@ void main(void) {
|
|||
|
||||
float opacity = getMaterialOpacity(mat) * _color.a;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
<$discardInvisible(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
|
|
|
@ -57,7 +57,7 @@ void main(void) {
|
|||
|
||||
float opacity = getMaterialOpacity(mat) * _color.a;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
<$discardInvisible(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
|
|
|
@ -34,7 +34,7 @@ void main(void) {
|
|||
|
||||
float opacity = getMaterialOpacity(mat) * _color.a;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
<$discardInvisible(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
|
|
|
@ -44,7 +44,7 @@ void main(void) {
|
|||
|
||||
float opacity = getMaterialOpacity(mat) * _color.a;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
<$discardInvisible(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
layout(std140, binding=0) uniform parabolaData {
|
||||
struct ParabolaData {
|
||||
vec3 velocity;
|
||||
float parabolicDistance;
|
||||
vec3 acceleration;
|
||||
|
@ -20,34 +20,38 @@ layout(std140, binding=0) uniform parabolaData {
|
|||
vec4 color;
|
||||
int numSections;
|
||||
ivec3 spare;
|
||||
}
|
||||
|
||||
layout(std140, binding=0) uniform parabolaData {
|
||||
ParabolaData _parabolaData;
|
||||
};
|
||||
|
||||
layout(location=0) out vec4 _color;
|
||||
|
||||
void main(void) {
|
||||
_color = color;
|
||||
_color = _parabolaData.color;
|
||||
|
||||
float t = parabolicDistance * (float(gl_VertexID / 2) / float(numSections));
|
||||
float t = _parabolaData.parabolicDistance * (float(gl_VertexID / 2) / float(_parabolaData.numSections));
|
||||
|
||||
vec4 pos = vec4(velocity * t + 0.5 * acceleration * t * t, 1);
|
||||
vec4 pos = vec4(_parabolaData.velocity * t + 0.5 * _parabolaData.acceleration * t * t, 1);
|
||||
const float EPSILON = 0.00001;
|
||||
vec4 normal;
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
if (dot(acceleration, acceleration) < EPSILON) {
|
||||
if (dot(_parabolaData.acceleration, _parabolaData.acceleration) < EPSILON) {
|
||||
// Handle case where acceleration == (0, 0, 0)
|
||||
vec3 eyeUp = vec3(0, 1, 0);
|
||||
vec3 worldUp;
|
||||
<$transformEyeToWorldDir(cam, eyeUp, worldUp)$>
|
||||
normal = vec4(normalize(cross(velocity, worldUp)), 0);
|
||||
normal = vec4(normalize(cross(_parabolaData.velocity, worldUp)), 0);
|
||||
} else {
|
||||
normal = vec4(normalize(cross(velocity, acceleration)), 0);
|
||||
normal = vec4(normalize(cross(_parabolaData.velocity, _parabolaData.acceleration)), 0);
|
||||
}
|
||||
if (gl_VertexID % 2 == 0) {
|
||||
pos += 0.5 * width * normal;
|
||||
pos += 0.5 * _parabolaData.width * normal;
|
||||
} else {
|
||||
pos -= 0.5 * width * normal;
|
||||
pos -= 0.5 * _parabolaData.width * normal;
|
||||
}
|
||||
|
||||
<$transformModelToClipPos(cam, obj, pos, gl_Position)$>
|
||||
|
|
|
@ -48,9 +48,9 @@ void main(void) {
|
|||
#ifdef PROCEDURAL
|
||||
|
||||
#ifdef PROCEDURAL_V1
|
||||
specular = getProceduralColor().rgb;
|
||||
diffuse = getProceduralColor().rgb;
|
||||
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
|
||||
//specular = pow(specular, vec3(2.2));
|
||||
//diffuse = pow(diffuse, vec3(2.2));
|
||||
emissiveAmount = 1.0;
|
||||
#else
|
||||
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
<@include DefaultMaterials.slh@>
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
|
||||
|
||||
<@include render-utils/ShaderConstants.h@>
|
||||
|
||||
|
@ -26,6 +28,8 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
|
|||
layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _positionMS;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES;
|
||||
|
||||
layout(location=0) out vec4 _fragColor0;
|
||||
|
||||
// For retro-compatibility
|
||||
#define _normal _normalWS
|
||||
#define _modelNormal _normalMS
|
||||
|
@ -48,9 +52,9 @@ void main(void) {
|
|||
#ifdef PROCEDURAL
|
||||
|
||||
#ifdef PROCEDURAL_V1
|
||||
specular = getProceduralColor().rgb;
|
||||
diffuse = getProceduralColor().rgb;
|
||||
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
|
||||
//specular = pow(specular, vec3(2.2));
|
||||
//diffuse = pow(diffuse, vec3(2.2));
|
||||
emissiveAmount = 1.0;
|
||||
#else
|
||||
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
|
||||
|
@ -58,19 +62,23 @@ void main(void) {
|
|||
|
||||
#endif
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 fragPosition = _positionES.xyz;
|
||||
|
||||
if (emissiveAmount > 0.0) {
|
||||
packDeferredFragmentTranslucent(
|
||||
normal,
|
||||
_color.a,
|
||||
specular,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_ROUGHNESS);
|
||||
_fragColor0 = vec4(diffuse, _color.a);
|
||||
} else {
|
||||
packDeferredFragmentTranslucent(
|
||||
_fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||
cam._viewInverse,
|
||||
1.0,
|
||||
DEFAULT_OCCLUSION,
|
||||
fragPosition,
|
||||
normal,
|
||||
_color.a,
|
||||
diffuse,
|
||||
DEFAULT_FRESNEL,
|
||||
DEFAULT_ROUGHNESS);
|
||||
length(specular),
|
||||
DEFAULT_EMISSIVE,
|
||||
max(0.0, 1.0 - shininess / 128.0), _color.a),
|
||||
_color.a);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,8 @@
|
|||
|
||||
#include "Args.h"
|
||||
|
||||
|
||||
using namespace render;
|
||||
|
||||
|
||||
const gpu::PipelinePointer DrawSceneOctree::getDrawCellBoundsPipeline() {
|
||||
if (!_drawCellBoundsPipeline) {
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render::program::drawCellBounds);
|
||||
|
@ -71,7 +69,6 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS
|
|||
std::static_pointer_cast<Config>(renderContext->jobConfig)->numAllocatedCells = (int)scene->getSpatialTree().getNumAllocatedCells();
|
||||
std::static_pointer_cast<Config>(renderContext->jobConfig)->numFreeCells = (int)scene->getSpatialTree().getNumFreeCells();
|
||||
|
||||
|
||||
gpu::doInBatch("DrawSceneOctree::run", args->_context, [&](gpu::Batch& batch) {
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
|
@ -86,44 +83,30 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS
|
|||
// bind the one gpu::Pipeline we need
|
||||
batch.setPipeline(getDrawCellBoundsPipeline());
|
||||
|
||||
if (_showVisibleCells) {
|
||||
|
||||
for (const auto& cellID : inSelection.cellSelection.insideCells) {
|
||||
auto drawCellBounds = [this, &scene, &batch](const std::vector<gpu::Stamp>& cells) {
|
||||
for (const auto& cellID : cells) {
|
||||
auto cell = scene->getSpatialTree().getConcreteCell(cellID);
|
||||
auto cellLoc = cell.getlocation();
|
||||
glm::ivec4 cellLocation(cellLoc.pos.x, cellLoc.pos.y, cellLoc.pos.z, cellLoc.depth);
|
||||
|
||||
bool doDraw = true;
|
||||
if (cell.isBrickEmpty() || !cell.hasBrick()) {
|
||||
bool empty = cell.isBrickEmpty() || !cell.hasBrick();
|
||||
if (empty) {
|
||||
if (!_showEmptyCells) {
|
||||
doDraw = false;
|
||||
continue;
|
||||
}
|
||||
cellLocation.w *= -1;
|
||||
cellLocation.w *= -1.0;
|
||||
} else if (!empty && !_showVisibleCells) {
|
||||
continue;
|
||||
}
|
||||
if (doDraw) {
|
||||
batch._glUniform4iv(gpu::slot::uniform::Extra0, 1, ((const int*)(&cellLocation)));
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& cellID : inSelection.cellSelection.partialCells) {
|
||||
auto cell = scene->getSpatialTree().getConcreteCell(cellID);
|
||||
auto cellLoc = cell.getlocation();
|
||||
glm::ivec4 cellLocation(cellLoc.pos.x, cellLoc.pos.y, cellLoc.pos.z, cellLoc.depth);
|
||||
|
||||
bool doDraw = true;
|
||||
if (cell.isBrickEmpty() || !cell.hasBrick()) {
|
||||
if (!_showEmptyCells) {
|
||||
doDraw = false;
|
||||
}
|
||||
cellLocation.w *= -1;
|
||||
}
|
||||
if (doDraw) {
|
||||
batch._glUniform4iv(gpu::slot::uniform::Extra0, 1, ((const int*)(&cellLocation)));
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
batch._glUniform4iv(gpu::slot::uniform::Extra0, 1, ((const int*)(&cellLocation)));
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
drawCellBounds(inSelection.cellSelection.insideCells);
|
||||
drawCellBounds(inSelection.cellSelection.partialCells);
|
||||
|
||||
// Draw the LOD Reticle
|
||||
{
|
||||
float angle = glm::degrees(getPerspectiveAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust));
|
||||
|
@ -142,10 +125,6 @@ const gpu::PipelinePointer DrawItemSelection::getDrawItemBoundPipeline() {
|
|||
if (!_drawItemBoundPipeline) {
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render::program::drawItemBounds);
|
||||
|
||||
//_drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos");
|
||||
//_drawItemBoundDimLoc = program->getUniforms().findLocation("inBoundDim");
|
||||
//_drawCellLocationLoc = program->getUniforms().findLocation("inCellLocation");
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
|
@ -173,6 +152,19 @@ void DrawItemSelection::run(const RenderContextPointer& renderContext, const Ite
|
|||
RenderArgs* args = renderContext->args;
|
||||
auto& scene = renderContext->_scene;
|
||||
|
||||
if (!_boundsBufferInside) {
|
||||
_boundsBufferInside = std::make_shared<gpu::Buffer>(sizeof(render::ItemBound));
|
||||
}
|
||||
if (!_boundsBufferInsideSubcell) {
|
||||
_boundsBufferInsideSubcell = std::make_shared<gpu::Buffer>(sizeof(render::ItemBound));
|
||||
}
|
||||
if (!_boundsBufferPartial) {
|
||||
_boundsBufferPartial = std::make_shared<gpu::Buffer>(sizeof(render::ItemBound));
|
||||
}
|
||||
if (!_boundsBufferPartialSubcell) {
|
||||
_boundsBufferPartialSubcell = std::make_shared<gpu::Buffer>(sizeof(render::ItemBound));
|
||||
}
|
||||
|
||||
gpu::doInBatch("DrawItemSelection::run", args->_context, [&](gpu::Batch& batch) {
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
|
@ -187,63 +179,35 @@ void DrawItemSelection::run(const RenderContextPointer& renderContext, const Ite
|
|||
// bind the one gpu::Pipeline we need
|
||||
batch.setPipeline(getDrawItemBoundPipeline());
|
||||
|
||||
auto drawItemBounds = [&](const render::ItemIDs itemIDs, const gpu::BufferPointer buffer) {
|
||||
render::ItemBounds itemBounds;
|
||||
for (const auto& itemID : itemIDs) {
|
||||
auto& item = scene->getItem(itemID);
|
||||
auto itemBound = item.getBound();
|
||||
if (!itemBound.isInvalid()) {
|
||||
itemBounds.emplace_back(itemID, itemBound);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemBounds.size() > 0) {
|
||||
buffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data());
|
||||
batch.setResourceBuffer(0, buffer);
|
||||
batch.draw(gpu::LINES, (gpu::uint32) itemBounds.size() * 24, 0);
|
||||
}
|
||||
};
|
||||
|
||||
if (_showInsideItems) {
|
||||
for (const auto& itemID : inSelection.insideItems) {
|
||||
auto& item = scene->getItem(itemID);
|
||||
auto itemBound = item.getBound();
|
||||
auto itemCell = scene->getSpatialTree().getCellLocation(item.getCell());
|
||||
glm::ivec4 cellLocation(0, 0, 0, itemCell.depth);
|
||||
|
||||
//batch._glUniform4iv(_drawCellLocationLoc, 1, ((const int*)(&cellLocation)));
|
||||
//batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)(&itemBound.getCorner()));
|
||||
//batch._glUniform3fv(_drawItemBoundDimLoc, 1, (const float*)(&itemBound.getScale()));
|
||||
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
drawItemBounds(inSelection.insideItems, _boundsBufferInside);
|
||||
}
|
||||
|
||||
if (_showInsideSubcellItems) {
|
||||
for (const auto& itemID : inSelection.insideSubcellItems) {
|
||||
auto& item = scene->getItem(itemID);
|
||||
auto itemBound = item.getBound();
|
||||
auto itemCell = scene->getSpatialTree().getCellLocation(item.getCell());
|
||||
glm::ivec4 cellLocation(0, 0, 1, itemCell.depth);
|
||||
|
||||
//batch._glUniform4iv(_drawCellLocationLoc, 1, ((const int*)(&cellLocation)));
|
||||
//batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)(&itemBound.getCorner()));
|
||||
//batch._glUniform3fv(_drawItemBoundDimLoc, 1, (const float*)(&itemBound.getScale()));
|
||||
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
drawItemBounds(inSelection.insideSubcellItems, _boundsBufferInsideSubcell);
|
||||
}
|
||||
|
||||
if (_showPartialItems) {
|
||||
for (const auto& itemID : inSelection.partialItems) {
|
||||
auto& item = scene->getItem(itemID);
|
||||
auto itemBound = item.getBound();
|
||||
auto itemCell = scene->getSpatialTree().getCellLocation(item.getCell());
|
||||
glm::ivec4 cellLocation(0, 0, 0, itemCell.depth);
|
||||
|
||||
//batch._glUniform4iv(_drawCellLocationLoc, 1, ((const int*)(&cellLocation)));
|
||||
//batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)(&itemBound.getCorner()));
|
||||
//batch._glUniform3fv(_drawItemBoundDimLoc, 1, (const float*)(&itemBound.getScale()));
|
||||
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
drawItemBounds(inSelection.partialItems, _boundsBufferPartial);
|
||||
}
|
||||
|
||||
if (_showPartialSubcellItems) {
|
||||
for (const auto& itemID : inSelection.partialSubcellItems) {
|
||||
auto& item = scene->getItem(itemID);
|
||||
auto itemBound = item.getBound();
|
||||
auto itemCell = scene->getSpatialTree().getCellLocation(item.getCell());
|
||||
glm::ivec4 cellLocation(0, 0, 1, itemCell.depth);
|
||||
//batch._glUniform4iv(_drawCellLocationLoc, 1, ((const int*)(&cellLocation)));
|
||||
//batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)(&itemBound.getCorner()));
|
||||
//batch._glUniform3fv(_drawItemBoundDimLoc, 1, (const float*)(&itemBound.getScale()));
|
||||
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
drawItemBounds(inSelection.partialSubcellItems, _boundsBufferPartialSubcell);
|
||||
}
|
||||
batch.setResourceBuffer(0, 0);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ namespace render {
|
|||
|
||||
class DrawSceneOctree {
|
||||
gpu::PipelinePointer _drawCellBoundsPipeline;
|
||||
gpu::BufferPointer _cells;
|
||||
gpu::PipelinePointer _drawLODReticlePipeline;
|
||||
gpu::PipelinePointer _drawItemBoundPipeline;
|
||||
|
||||
|
@ -107,6 +106,10 @@ namespace render {
|
|||
|
||||
class DrawItemSelection {
|
||||
gpu::PipelinePointer _drawItemBoundPipeline;
|
||||
gpu::BufferPointer _boundsBufferInside;
|
||||
gpu::BufferPointer _boundsBufferInsideSubcell;
|
||||
gpu::BufferPointer _boundsBufferPartial;
|
||||
gpu::BufferPointer _boundsBufferPartialSubcell;
|
||||
|
||||
bool _showInsideItems; // initialized by Config
|
||||
bool _showInsideSubcellItems; // initialized by Config
|
||||
|
|
|
@ -33,9 +33,6 @@ void DrawStatusConfig::dirtyHelper() {
|
|||
const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() {
|
||||
if (!_drawItemBoundsPipeline) {
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render::program::drawItemBounds);
|
||||
//_drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos");
|
||||
//_drawItemBoundDimLoc = program->getUniforms().findLocation("inBoundDim");
|
||||
//_drawItemCellLocLoc = program->getUniforms().findLocation("inCellLocation");
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
|
||||
|
@ -54,11 +51,7 @@ const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() {
|
|||
|
||||
const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() {
|
||||
if (!_drawItemStatusPipeline) {
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render::program::blurGaussianDepthAwareV);
|
||||
//_drawItemStatusPosLoc = program->getUniforms().findLocation("");
|
||||
//_drawItemStatusDimLoc = program->getUniforms().findLocation("");
|
||||
//_drawItemStatusValue0Loc = program->getUniforms().findLocation("");
|
||||
//_drawItemStatusValue1Loc = program->getUniforms().findLocation("");
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render::program::drawItemStatus);
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
|
||||
|
@ -99,36 +92,30 @@ void DrawStatus::run(const RenderContextPointer& renderContext, const Input& inp
|
|||
const auto& inItems = input.get0();
|
||||
const auto jitter = input.get1();
|
||||
|
||||
// FIrst thing, we collect the bound and the status for all the items we want to render
|
||||
// First thing, we collect the bound and the status for all the items we want to render
|
||||
int nbItems = 0;
|
||||
render::ItemBounds itemBounds;
|
||||
std::vector<std::pair<glm::ivec4, glm::ivec4>> itemStatus;
|
||||
{
|
||||
_itemBounds.resize(inItems.size());
|
||||
_itemStatus.resize(inItems.size());
|
||||
_itemCells.resize(inItems.size());
|
||||
|
||||
// AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData());
|
||||
// glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
|
||||
// Octree::Location* itemCell = reinterpret_cast<Octree::Location*> (_itemCells->editData());
|
||||
for (size_t i = 0; i < inItems.size(); ++i) {
|
||||
const auto& item = inItems[i];
|
||||
if (!item.bound.isInvalid()) {
|
||||
if (!item.bound.isNull()) {
|
||||
_itemBounds[i] = item.bound;
|
||||
itemBounds.emplace_back(render::ItemBound(item.id, item.bound));
|
||||
} else {
|
||||
_itemBounds[i].setBox(item.bound.getCorner(), 0.1f);
|
||||
itemBounds.emplace_back(item.id, AABox(item.bound.getCorner(), 0.1f));
|
||||
}
|
||||
|
||||
|
||||
auto& itemScene = scene->getItem(item.id);
|
||||
_itemCells[i] = scene->getSpatialTree().getCellLocation(itemScene.getCell());
|
||||
|
||||
auto itemStatusPointer = itemScene.getStatus();
|
||||
if (itemStatusPointer) {
|
||||
itemStatus.push_back(std::pair<glm::ivec4, glm::ivec4>());
|
||||
// Query the current status values, this is where the statusGetter lambda get called
|
||||
auto&& currentStatusValues = itemStatusPointer->getCurrentValues();
|
||||
int valueNum = 0;
|
||||
for (int vec4Num = 0; vec4Num < NUM_STATUS_VEC4_PER_ITEM; vec4Num++) {
|
||||
auto& value = (vec4Num ? _itemStatus[i].first : _itemStatus[i].second);
|
||||
auto& value = (vec4Num ? itemStatus[nbItems].first : itemStatus[nbItems].second);
|
||||
value = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
|
||||
for (int component = 0; component < VEC4_LENGTH; component++) {
|
||||
valueNum = vec4Num * VEC4_LENGTH + component;
|
||||
|
@ -138,7 +125,8 @@ void DrawStatus::run(const RenderContextPointer& renderContext, const Input& inp
|
|||
}
|
||||
}
|
||||
} else {
|
||||
_itemStatus[i].first = _itemStatus[i].second = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
|
||||
auto invalid = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
|
||||
itemStatus.emplace_back(invalid, invalid);
|
||||
}
|
||||
nbItems++;
|
||||
}
|
||||
|
@ -149,7 +137,11 @@ void DrawStatus::run(const RenderContextPointer& renderContext, const Input& inp
|
|||
return;
|
||||
}
|
||||
|
||||
// Allright, something to render let's do it
|
||||
if (!_boundsBuffer) {
|
||||
_boundsBuffer = std::make_shared<gpu::Buffer>(sizeof(render::ItemBound));
|
||||
}
|
||||
|
||||
// Alright, something to render let's do it
|
||||
gpu::doInBatch("DrawStatus::run", args->_context, [&](gpu::Batch& batch) {
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
|
@ -165,32 +157,24 @@ void DrawStatus::run(const RenderContextPointer& renderContext, const Input& inp
|
|||
// bind the one gpu::Pipeline we need
|
||||
batch.setPipeline(getDrawItemBoundsPipeline());
|
||||
|
||||
//AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData());
|
||||
//glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
|
||||
//Octree::Location* itemCell = reinterpret_cast<Octree::Location*> (_itemCells->editData());
|
||||
|
||||
const unsigned int VEC3_ADRESS_OFFSET = 3;
|
||||
_boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data());
|
||||
|
||||
if (_showDisplay) {
|
||||
for (int i = 0; i < nbItems; i++) {
|
||||
//batch._glUniform3fv(gpu::slot::uniform::Extra0, 1, (const float*)&(_itemBounds[i]));
|
||||
//batch._glUniform3fv(gpu::slot::uniform::Extra1, 1, ((const float*)&(_itemBounds[i])) + VEC3_ADRESS_OFFSET);
|
||||
//glm::ivec4 cellLocation(_itemCells[i].pos, _itemCells[i].depth);
|
||||
//batch._glUniform4iv(_drawItemCellLocLoc, 1, ((const int*)(&cellLocation)));
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
batch.setResourceBuffer(0, _boundsBuffer);
|
||||
batch.draw(gpu::LINES, (gpu::uint32) itemBounds.size() * 24, 0);
|
||||
}
|
||||
batch.setResourceBuffer(0, 0);
|
||||
|
||||
batch.setResourceTexture(0, gpu::TextureView(getStatusIconMap(), 0));
|
||||
|
||||
batch.setPipeline(getDrawItemStatusPipeline());
|
||||
|
||||
if (_showNetwork) {
|
||||
for (int i = 0; i < nbItems; i++) {
|
||||
batch._glUniform3fv(gpu::slot::uniform::Extra0, 1, (const float*)&(_itemBounds[i]));
|
||||
batch._glUniform3fv(gpu::slot::uniform::Extra1, 1, ((const float*)&(_itemBounds[i])) + VEC3_ADRESS_OFFSET);
|
||||
batch._glUniform4iv(gpu::slot::uniform::Extra2, 1, (const int*)&(_itemStatus[i].first));
|
||||
batch._glUniform4iv(gpu::slot::uniform::Extra3, 1, (const int*)&(_itemStatus[i].second));
|
||||
for (size_t i = 0; i < itemBounds.size(); i++) {
|
||||
batch._glUniform3fv(gpu::slot::uniform::Extra0, 1, (const float*)&itemBounds[i].bound.getCorner());
|
||||
batch._glUniform3fv(gpu::slot::uniform::Extra1, 1, ((const float*)&itemBounds[i].bound.getScale()));
|
||||
batch._glUniform4iv(gpu::slot::uniform::Extra2, 1, (const int*)&(itemStatus[i].first));
|
||||
batch._glUniform4iv(gpu::slot::uniform::Extra3, 1, (const int*)&(itemStatus[i].second));
|
||||
batch.draw(gpu::TRIANGLES, 24 * NUM_STATUS_VEC4_PER_ITEM, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,12 +62,7 @@ namespace render {
|
|||
gpu::PipelinePointer _drawItemBoundsPipeline;
|
||||
gpu::PipelinePointer _drawItemStatusPipeline;
|
||||
|
||||
std::vector<AABox> _itemBounds;
|
||||
std::vector<std::pair<glm::ivec4, glm::ivec4>> _itemStatus;
|
||||
std::vector<Octree::Location> _itemCells;
|
||||
//gpu::BufferPointer _itemBounds;
|
||||
//gpu::BufferPointer _itemCells;
|
||||
//gpu::BufferPointer _itemStatus;
|
||||
gpu::BufferPointer _boundsBuffer;
|
||||
gpu::TexturePointer _statusIconMap;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -321,6 +321,7 @@ inline QDebug operator<<(QDebug debug, const ItemFilter& me) {
|
|||
// Handy type to just pass the ID and the bound of an item
|
||||
class ItemBound {
|
||||
public:
|
||||
ItemBound() {}
|
||||
ItemBound(ItemID id) : id(id) { }
|
||||
ItemBound(ItemID id, const AABox& bound) : id(id), bound(bound) { }
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ layout(location=GPU_UNIFORM_EXTRA0) uniform ivec4 inCellLocation;
|
|||
|
||||
layout(location=0) out vec4 varColor;
|
||||
|
||||
|
||||
void main(void) {
|
||||
const vec4 UNIT_BOX[8] = vec4[8](
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
|
|
|
@ -20,10 +20,8 @@
|
|||
<@include gpu/Color.slh@>
|
||||
<$declareColorWheel()$>
|
||||
|
||||
|
||||
layout(location=GPU_UNIFORM_COLOR) uniform vec4 inColor;
|
||||
|
||||
|
||||
struct ItemBound {
|
||||
vec4 id_boundPos;
|
||||
vec4 boundDim_s;
|
||||
|
@ -48,8 +46,6 @@ ItemBound getItemBound(int i) {
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
layout(location=0) out vec4 varColor;
|
||||
layout(location=1) out vec2 varTexcoord;
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#include "WebSocketClass.h"
|
||||
#include "RecordingScriptingInterface.h"
|
||||
#include "ScriptEngines.h"
|
||||
#include "StackTestScriptingInterface.h"
|
||||
#include "ModelScriptingInterface.h"
|
||||
|
||||
|
||||
|
@ -762,6 +763,10 @@ void ScriptEngine::init() {
|
|||
qScriptRegisterMetaType(this, meshesToScriptValue, meshesFromScriptValue);
|
||||
|
||||
registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
|
||||
#if DEV_BUILD || PR_BUILD
|
||||
registerGlobalObject("StackTest", new StackTestScriptingInterface(this));
|
||||
#endif
|
||||
}
|
||||
|
||||
void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
|
||||
|
|
31
libraries/script-engine/src/StackTestScriptingInterface.cpp
Normal file
31
libraries/script-engine/src/StackTestScriptingInterface.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// StackTestScriptingInterface.cpp
|
||||
// libraries/script-engine/src
|
||||
//
|
||||
// Created by Clement Brisset on 7/25/18.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "StackTestScriptingInterface.h"
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QCoreApplication>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(stackTest)
|
||||
Q_LOGGING_CATEGORY(stackTest, "hifi.tools.stack-test")
|
||||
|
||||
void StackTestScriptingInterface::pass(QString message) {
|
||||
qCInfo(stackTest) << "PASS" << qPrintable(message);
|
||||
}
|
||||
|
||||
void StackTestScriptingInterface::fail(QString message) {
|
||||
qCInfo(stackTest) << "FAIL" << qPrintable(message);
|
||||
}
|
||||
|
||||
void StackTestScriptingInterface::exit(QString message) {
|
||||
qCInfo(stackTest) << "COMPLETE" << qPrintable(message);
|
||||
qApp->exit();
|
||||
}
|
31
libraries/script-engine/src/StackTestScriptingInterface.h
Normal file
31
libraries/script-engine/src/StackTestScriptingInterface.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// StackTestScriptingInterface.h
|
||||
// libraries/script-engine/src
|
||||
//
|
||||
// Created by Clement Brisset on 7/25/18.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef hifi_StackTestScriptingInterface_h
|
||||
#define hifi_StackTestScriptingInterface_h
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class StackTestScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StackTestScriptingInterface(QObject* parent = nullptr) : QObject(parent) {}
|
||||
|
||||
Q_INVOKABLE void pass(QString message = QString());
|
||||
Q_INVOKABLE void fail(QString message = QString());
|
||||
|
||||
Q_INVOKABLE void exit(QString message = QString());
|
||||
};
|
||||
|
||||
#endif // hifi_StackTestScriptingInterface_h
|
|
@ -294,7 +294,19 @@ glm::vec3 safeEulerAngles(const glm::quat& q) {
|
|||
|
||||
// Helper function returns the positive angle (in radians) between two 3D vectors
|
||||
float angleBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
||||
return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2)));
|
||||
float lengthFactor = glm::length(v1) * glm::length(v2);
|
||||
|
||||
if (lengthFactor < EPSILON) {
|
||||
qWarning() << "DANGER: don't supply zero-length vec3's as arguments";
|
||||
}
|
||||
|
||||
float cosAngle = glm::dot(v1, v2) / lengthFactor;
|
||||
// If v1 and v2 are colinear, then floating point rounding errors might cause
|
||||
// cosAngle to be slightly higher than 1 or slightly lower than -1
|
||||
// which is are values for which acos is not defined and result in a NaN
|
||||
// So we clamp the value to insure the value is in the correct range
|
||||
cosAngle = glm::clamp(cosAngle, -1.0f, 1.0f);
|
||||
return acosf(cosAngle);
|
||||
}
|
||||
|
||||
// Helper function return the rotation from the first vector onto the second
|
||||
|
|
|
@ -91,58 +91,7 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL
|
|||
return mergedMap;
|
||||
}
|
||||
|
||||
void HifiConfigVariantMap::loadConfig(const QStringList& argumentList) {
|
||||
// load the user config
|
||||
const QString USER_CONFIG_FILE_OPTION = "--user-config";
|
||||
static const QString USER_CONFIG_FILE_NAME = "config.json";
|
||||
|
||||
int userConfigIndex = argumentList.indexOf(USER_CONFIG_FILE_OPTION);
|
||||
if (userConfigIndex != -1) {
|
||||
_userConfigFilename = argumentList[userConfigIndex + 1];
|
||||
} else {
|
||||
// we weren't passed a user config path
|
||||
_userConfigFilename = PathUtils::getAppDataFilePath(USER_CONFIG_FILE_NAME);
|
||||
|
||||
// as of 1/19/2016 this path was moved so we attempt a migration for first run post migration here
|
||||
|
||||
// figure out what the old path was
|
||||
|
||||
// if our build version is "dev" we should migrate from a different organization folder
|
||||
|
||||
auto oldConfigFilename = QString("%1/%2/%3/%4").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation),
|
||||
QCoreApplication::organizationName(),
|
||||
QCoreApplication::applicationName(),
|
||||
USER_CONFIG_FILE_NAME);
|
||||
|
||||
oldConfigFilename = oldConfigFilename.replace("High Fidelity - dev", "High Fidelity");
|
||||
|
||||
|
||||
// check if there's already a config file at the new path
|
||||
QFile newConfigFile { _userConfigFilename };
|
||||
if (!newConfigFile.exists()) {
|
||||
|
||||
QFile oldConfigFile { oldConfigFilename };
|
||||
|
||||
if (oldConfigFile.exists()) {
|
||||
// we have the old file and not the new file - time to copy the file
|
||||
|
||||
// make the destination directory if it doesn't exist
|
||||
auto dataDirectory = PathUtils::getAppDataPath();
|
||||
if (QDir().mkpath(dataDirectory)) {
|
||||
if (oldConfigFile.copy(_userConfigFilename)) {
|
||||
qCDebug(shared) << "Migrated config file from" << oldConfigFilename << "to" << _userConfigFilename;
|
||||
} else {
|
||||
qCWarning(shared) << "Could not copy previous config file from" << oldConfigFilename << "to" << _userConfigFilename
|
||||
<< "- please try to copy manually and restart.";
|
||||
}
|
||||
} else {
|
||||
qCWarning(shared) << "Could not create application data directory" << dataDirectory << "- unable to migrate previous config file.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HifiConfigVariantMap::loadConfig() {
|
||||
loadMapFromJSONFile(_userConfig, _userConfigFilename);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class HifiConfigVariantMap {
|
|||
public:
|
||||
static QVariantMap mergeCLParametersWithJSONConfig(const QStringList& argumentList);
|
||||
|
||||
void loadConfig(const QStringList& argumentList);
|
||||
void loadConfig();
|
||||
|
||||
const QVariant value(const QString& key) const { return _userConfig.value(key); }
|
||||
QVariant* valueForKeyPath(const QString& keyPath, bool shouldCreateIfMissing = false)
|
||||
|
@ -30,6 +30,7 @@ public:
|
|||
QVariantMap& getConfig() { return _userConfig; }
|
||||
|
||||
const QString& getUserConfigFilename() const { return _userConfigFilename; }
|
||||
void setUserConfigFilename(const QString& filename) { _userConfigFilename = filename; }
|
||||
private:
|
||||
QString _userConfigFilename;
|
||||
|
||||
|
|
|
@ -33,17 +33,12 @@ LogHandler& LogHandler::getInstance() {
|
|||
}
|
||||
|
||||
LogHandler::LogHandler() {
|
||||
// when the log handler is first setup we should print our timezone
|
||||
QString timezoneString = "Time zone: " + QDateTime::currentDateTime().toString("t");
|
||||
printMessage(LogMsgType::LogInfo, QMessageLogContext(), timezoneString);
|
||||
|
||||
// make sure we setup the repeated message flusher, but do it on the LogHandler thread
|
||||
QMetaObject::invokeMethod(this, "setupRepeatedMessageFlusher");
|
||||
}
|
||||
|
||||
LogHandler::~LogHandler() {
|
||||
flushRepeatedMessages();
|
||||
printMessage(LogMsgType::LogDebug, QMessageLogContext(), "LogHandler shutdown.");
|
||||
}
|
||||
|
||||
const char* stringForLogType(LogMsgType msgType) {
|
||||
|
|
|
@ -90,7 +90,6 @@ const QString& PathUtils::resourcesPath() {
|
|||
staticResourcePath = projectRootPath() + "/interface/resources/";
|
||||
}
|
||||
#endif
|
||||
qDebug() << "Resource path resolved to " << staticResourcePath;
|
||||
});
|
||||
return staticResourcePath;
|
||||
}
|
||||
|
@ -105,7 +104,6 @@ const QString& PathUtils::resourcesUrl() {
|
|||
staticResourcePath = QUrl::fromLocalFile(projectRootPath() + "/interface/resources/").toString();
|
||||
}
|
||||
#endif
|
||||
qDebug() << "Resource url resolved to " << staticResourcePath;
|
||||
});
|
||||
return staticResourcePath;
|
||||
}
|
||||
|
|
|
@ -80,16 +80,19 @@ void PerformanceTimerRecord::tallyResult(const quint64& now) {
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
std::atomic<bool> PerformanceTimer::_isActive(false);
|
||||
std::mutex PerformanceTimer::_mutex;
|
||||
QHash<QThread*, QString> PerformanceTimer::_fullNames;
|
||||
QMap<QString, PerformanceTimerRecord> PerformanceTimer::_records;
|
||||
|
||||
|
||||
PerformanceTimer::PerformanceTimer(const QString& name) {
|
||||
if (_isActive) {
|
||||
_name = name;
|
||||
QString& fullName = _fullNames[QThread::currentThread()];
|
||||
fullName.append("/");
|
||||
fullName.append(_name);
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
QString& fullName = _fullNames[QThread::currentThread()];
|
||||
fullName.append("/");
|
||||
fullName.append(_name);
|
||||
}
|
||||
_start = usecTimestampNow();
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +100,7 @@ PerformanceTimer::PerformanceTimer(const QString& name) {
|
|||
PerformanceTimer::~PerformanceTimer() {
|
||||
if (_isActive && _start != 0) {
|
||||
quint64 elapsedUsec = (usecTimestampNow() - _start);
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
QString& fullName = _fullNames[QThread::currentThread()];
|
||||
PerformanceTimerRecord& namedRecord = _records[fullName];
|
||||
namedRecord.accumulateResult(elapsedUsec);
|
||||
|
@ -111,11 +115,13 @@ bool PerformanceTimer::isActive() {
|
|||
|
||||
// static
|
||||
QString PerformanceTimer::getContextName() {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
return _fullNames[QThread::currentThread()];
|
||||
}
|
||||
|
||||
// static
|
||||
void PerformanceTimer::addTimerRecord(const QString& fullName, quint64 elapsedUsec) {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
PerformanceTimerRecord& namedRecord = _records[fullName];
|
||||
namedRecord.accumulateResult(elapsedUsec);
|
||||
}
|
||||
|
@ -125,6 +131,7 @@ void PerformanceTimer::setActive(bool active) {
|
|||
if (active != _isActive) {
|
||||
_isActive.store(active);
|
||||
if (!active) {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
_fullNames.clear();
|
||||
_records.clear();
|
||||
}
|
||||
|
@ -133,8 +140,15 @@ void PerformanceTimer::setActive(bool active) {
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
QMap<QString, PerformanceTimerRecord> PerformanceTimer::getAllTimerRecords() {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
return _records;
|
||||
};
|
||||
|
||||
// static
|
||||
void PerformanceTimer::tallyAllTimerRecords() {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
QMap<QString, PerformanceTimerRecord>::iterator recordsItr = _records.begin();
|
||||
QMap<QString, PerformanceTimerRecord>::const_iterator recordsEnd = _records.end();
|
||||
quint64 now = usecTimestampNow();
|
||||
|
@ -150,6 +164,7 @@ void PerformanceTimer::tallyAllTimerRecords() {
|
|||
}
|
||||
|
||||
void PerformanceTimer::dumpAllTimerRecords() {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(_records);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
|
|
|
@ -84,8 +84,7 @@ public:
|
|||
|
||||
static QString getContextName();
|
||||
static void addTimerRecord(const QString& fullName, quint64 elapsedUsec);
|
||||
static const PerformanceTimerRecord& getTimerRecord(const QString& name) { return _records[name]; };
|
||||
static const QMap<QString, PerformanceTimerRecord>& getAllTimerRecords() { return _records; };
|
||||
static QMap<QString, PerformanceTimerRecord> getAllTimerRecords();
|
||||
static void tallyAllTimerRecords();
|
||||
static void dumpAllTimerRecords();
|
||||
|
||||
|
@ -93,6 +92,8 @@ private:
|
|||
quint64 _start = 0;
|
||||
QString _name;
|
||||
static std::atomic<bool> _isActive;
|
||||
|
||||
static std::mutex _mutex; // used to guard multi-threaded access to _fullNames and _records
|
||||
static QHash<QThread*, QString> _fullNames;
|
||||
static QMap<QString, PerformanceTimerRecord> _records;
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ Column {
|
|||
|
||||
Component.onCompleted: {
|
||||
sceneOctree.enabled = true;
|
||||
itemSelection.enabled = true;
|
||||
itemSelection.enabled = true;
|
||||
sceneOctree.showVisibleCells = false;
|
||||
sceneOctree.showEmptyCells = false;
|
||||
itemSelection.showInsideItems = false;
|
||||
|
@ -29,9 +29,9 @@ Column {
|
|||
}
|
||||
Component.onDestruction: {
|
||||
sceneOctree.enabled = false;
|
||||
itemSelection.enabled = false;
|
||||
itemSelection.enabled = false;
|
||||
Render.getConfig("RenderMainView.FetchSceneSelection").freezeFrustum = false;
|
||||
Render.getConfig("RenderMainView.CullSceneSelection").freezeFrustum = false;
|
||||
Render.getConfig("RenderMainView.CullSceneSelection").freezeFrustum = false;
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
|
@ -44,7 +44,7 @@ Column {
|
|||
CheckBox {
|
||||
text: "Freeze Culling Frustum"
|
||||
checked: false
|
||||
onCheckedChanged: {
|
||||
onCheckedChanged: {
|
||||
Render.getConfig("RenderMainView.FetchSceneSelection").freezeFrustum = checked;
|
||||
Render.getConfig("RenderMainView.CullSceneSelection").freezeFrustum = checked;
|
||||
}
|
||||
|
@ -88,15 +88,19 @@ Column {
|
|||
text: "Partial Sub-cell Items"
|
||||
checked: false
|
||||
onCheckedChanged: { root.itemSelection.showPartialSubcellItems = checked }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: "Render Items"
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
||||
Column{
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
Repeater {
|
||||
model: [ "Opaque:RenderMainView.DrawOpaqueDeferred", "Transparent:RenderMainView.DrawTransparentDeferred", "Light:RenderMainView.DrawLight",
|
||||
"Opaque Overlays:RenderMainView.DrawOverlay3DOpaque", "Transparent Overlays:RenderMainView.DrawOverlay3DTransparent" ]
|
||||
|
|
|
@ -87,12 +87,18 @@ function AppUi(properties) {
|
|||
defaultButton('activeButton', 'a.svg');
|
||||
defaultButton('normalMessagesButton', 'i-msg.svg');
|
||||
defaultButton('activeMessagesButton', 'a-msg.svg');
|
||||
that.button = that.tablet.addButton({
|
||||
var buttonOptions = {
|
||||
icon: that.normalButton,
|
||||
activeIcon: that.activeButton,
|
||||
text: that.buttonName,
|
||||
sortOrder: that.sortOrder
|
||||
});
|
||||
text: that.buttonName
|
||||
};
|
||||
// `TabletScriptingInterface` looks for the presence of a `sortOrder` key.
|
||||
// What it SHOULD do is look to see if the value inside that key is defined.
|
||||
// To get around the current code, we do this instead.
|
||||
if (that.sortOrder) {
|
||||
buttonOptions.sortOrder = that.sortOrder;
|
||||
}
|
||||
that.button = that.tablet.addButton(buttonOptions);
|
||||
that.ignore = function ignore() { };
|
||||
|
||||
// Handlers
|
||||
|
@ -126,6 +132,7 @@ function AppUi(properties) {
|
|||
// (Although injected javascript still has to use JSON.stringify/JSON.parse.)
|
||||
that.sendToHtml = function (messageObject) { that.tablet.emitScriptEvent(JSON.stringify(messageObject)); };
|
||||
that.fromHtml = function (messageString) { that.onMessage(JSON.parse(messageString)); };
|
||||
that.sendMessage = that.ignore;
|
||||
that.wireEventBridge = function wireEventBridge(on) {
|
||||
// Uniquivocally sets that.sendMessage(messageObject) to do the right thing.
|
||||
// Sets hasEventBridge and wires onMessage to eventSignal as appropriate, IFF onMessage defined.
|
||||
|
|
|
@ -19,7 +19,6 @@ Script.include("/~/system/libraries/utils.js");
|
|||
|
||||
(function () {
|
||||
var MARGIN = 25;
|
||||
var TABLET_MATERIAL_ENTITY_NAME = 'Tablet-Material-Entity';
|
||||
function InEditMode(hand) {
|
||||
this.hand = hand;
|
||||
this.triggerClicked = false;
|
||||
|
@ -77,13 +76,11 @@ Script.include("/~/system/libraries/utils.js");
|
|||
}
|
||||
}
|
||||
if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) {
|
||||
if (!this.isTabletMaterialEntity(this.selectedTarget.objectID)) {
|
||||
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
|
||||
method: "selectEntity",
|
||||
entityID: this.selectedTarget.objectID,
|
||||
hand: hand
|
||||
}));
|
||||
}
|
||||
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
|
||||
method: "selectEntity",
|
||||
entityID: this.selectedTarget.objectID,
|
||||
hand: hand
|
||||
}));
|
||||
} else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) {
|
||||
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
|
||||
method: "selectOverlay",
|
||||
|
@ -98,12 +95,6 @@ Script.include("/~/system/libraries/utils.js");
|
|||
this.sendPointingAtData(controllerData);
|
||||
};
|
||||
|
||||
|
||||
this.isTabletMaterialEntity = function(entityID) {
|
||||
return ((entityID === HMD.homeButtonHighlightMaterialID) ||
|
||||
(entityID === HMD.homeButtonUnhighlightMaterialID));
|
||||
};
|
||||
|
||||
this.sendPointingAtData = function(controllerData) {
|
||||
var rayPick = controllerData.rayPicks[this.hand];
|
||||
var hudRayPick = controllerData.hudRayPicks[this.hand];
|
||||
|
|
|
@ -174,10 +174,12 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
|||
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
||||
this.hapticTargetID = props.id;
|
||||
}
|
||||
// if we've attempted to grab a child, roll up to the root of the tree
|
||||
var groupRootProps = findGroupParent(controllerData, props);
|
||||
if (entityIsGrabbable(groupRootProps)) {
|
||||
return groupRootProps;
|
||||
if (!entityIsCloneable(props)) {
|
||||
// if we've attempted to grab a non-cloneable child, roll up to the root of the tree
|
||||
var groupRootProps = findGroupParent(controllerData, props);
|
||||
if (entityIsGrabbable(groupRootProps)) {
|
||||
return groupRootProps;
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.startNearParentingGrabEntity = function (controllerData, targetProps) {
|
||||
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
||||
unhighlightTargetEntity(this.targetEntityID);
|
||||
this.highlightedEntity = null;
|
||||
var message = {
|
||||
hand: this.hand,
|
||||
entityID: this.targetEntityID
|
||||
|
@ -177,6 +178,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||
}));
|
||||
unhighlightTargetEntity(this.targetEntityID);
|
||||
this.highlightedEntity = null;
|
||||
this.grabbing = false;
|
||||
this.targetEntityID = null;
|
||||
this.robbed = false;
|
||||
|
@ -268,10 +270,12 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
||||
this.hapticTargetID = props.id;
|
||||
}
|
||||
// if we've attempted to grab a child, roll up to the root of the tree
|
||||
var groupRootProps = findGroupParent(controllerData, props);
|
||||
if (entityIsGrabbable(groupRootProps)) {
|
||||
return groupRootProps;
|
||||
if (!entityIsCloneable(props)) {
|
||||
// if we've attempted to grab a non-cloneable child, roll up to the root of the tree
|
||||
var groupRootProps = findGroupParent(controllerData, props);
|
||||
if (entityIsGrabbable(groupRootProps)) {
|
||||
return groupRootProps;
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
@ -304,6 +308,10 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
return makeRunningValues(true, [this.targetEntityID], []);
|
||||
}
|
||||
} else {
|
||||
if (this.highlightedEntity) {
|
||||
unhighlightTargetEntity(this.highlightedEntity);
|
||||
this.highlightedEntity = null;
|
||||
}
|
||||
this.hapticTargetID = null;
|
||||
this.robbed = false;
|
||||
return makeRunningValues(false, [], []);
|
||||
|
@ -322,6 +330,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
if (!props) {
|
||||
// entity was deleted
|
||||
unhighlightTargetEntity(this.targetEntityID);
|
||||
this.highlightedEntity = null;
|
||||
this.grabbing = false;
|
||||
this.targetEntityID = null;
|
||||
this.hapticTargetID = null;
|
||||
|
@ -344,6 +353,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
if (!readiness.active) {
|
||||
this.robbed = false;
|
||||
unhighlightTargetEntity(this.highlightedEntity);
|
||||
this.highlightedEntity = null;
|
||||
return readiness;
|
||||
}
|
||||
if (controllerData.triggerClicks[this.hand] || controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) {
|
||||
|
|
|
@ -22,7 +22,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
var TARGET_MODEL_URL = Script.resolvePath("../../assets/models/teleport-destination.fbx");
|
||||
var TOO_CLOSE_MODEL_URL = Script.resolvePath("../../assets/models/teleport-cancel.fbx");
|
||||
var SEAT_MODEL_URL = Script.resolvePath("../../assets/models/teleport-seat.fbx");
|
||||
|
||||
var TARGET_MODEL_DIMENSIONS = {
|
||||
|
@ -49,8 +48,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
blue: 73
|
||||
};
|
||||
|
||||
var COOL_IN_DURATION = 300;
|
||||
|
||||
var handInfo = {
|
||||
right: {
|
||||
controllerInput: Controller.Standard.RightHand
|
||||
|
@ -61,37 +58,19 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
|
||||
var cancelPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_TELEPORT_CANCEL,
|
||||
ignorePickIntersection: true,
|
||||
alpha: 1,
|
||||
solid: true,
|
||||
drawInFront: true,
|
||||
glow: 1.0
|
||||
width: 0.025
|
||||
};
|
||||
var teleportPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_TELEPORT_CAN_TELEPORT,
|
||||
ignorePickIntersection: true,
|
||||
alpha: 1,
|
||||
solid: true,
|
||||
drawInFront: true,
|
||||
glow: 1.0
|
||||
width: 0.025
|
||||
};
|
||||
var seatPath = {
|
||||
type: "line3d",
|
||||
color: COLORS_TELEPORT_SEAT,
|
||||
ignorePickIntersection: true,
|
||||
alpha: 1,
|
||||
solid: true,
|
||||
drawInFront: true,
|
||||
glow: 1.0
|
||||
};
|
||||
var cancelEnd = {
|
||||
type: "model",
|
||||
url: TOO_CLOSE_MODEL_URL,
|
||||
dimensions: TARGET_MODEL_DIMENSIONS,
|
||||
ignorePickIntersection: true
|
||||
width: 0.025
|
||||
};
|
||||
var teleportEnd = {
|
||||
type: "model",
|
||||
|
@ -107,20 +86,18 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
|
||||
|
||||
var teleportRenderStates = [{name: "cancel", path: cancelPath, end: cancelEnd},
|
||||
var teleportRenderStates = [{name: "cancel", path: cancelPath},
|
||||
{name: "teleport", path: teleportPath, end: teleportEnd},
|
||||
{name: "seat", path: seatPath, end: seatEnd}];
|
||||
|
||||
var DEFAULT_DISTANCE = 50;
|
||||
var DEFAULT_DISTANCE = 8.0;
|
||||
var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}];
|
||||
|
||||
var coolInTimeout = null;
|
||||
var ignoredEntities = [];
|
||||
|
||||
|
||||
var TELEPORTER_STATES = {
|
||||
IDLE: 'idle',
|
||||
COOL_IN: 'cool_in',
|
||||
TARGETTING: 'targetting',
|
||||
TARGETTING_INVALID: 'targetting_invalid'
|
||||
};
|
||||
|
@ -133,7 +110,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
SEAT: 'seat' // The current target is a seat
|
||||
};
|
||||
|
||||
var speed = 7.0;
|
||||
var speed = 12.0;
|
||||
var accelerationAxis = {x: 0.0, y: -5.0, z: 0.0};
|
||||
|
||||
function Teleporter(hand) {
|
||||
|
@ -151,8 +128,10 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
return otherModule;
|
||||
};
|
||||
|
||||
this.teleportParabolaHandVisible = Pointers.createPointer(PickType.Ray, {
|
||||
this.teleportParabolaHandVisible = Pointers.createPointer(PickType.Parabola, {
|
||||
joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||
dirOffset: { x: 0, y: 1, z: 0.1 },
|
||||
posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 },
|
||||
filter: Picks.PICK_ENTITIES,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
|
@ -161,10 +140,13 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
accelerationAxis: accelerationAxis,
|
||||
rotateAccelerationWithAvatar: true,
|
||||
renderStates: teleportRenderStates,
|
||||
defaultRenderStates: teleportDefaultRenderStates
|
||||
defaultRenderStates: teleportDefaultRenderStates,
|
||||
maxDistance: 8.0
|
||||
});
|
||||
this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Ray, {
|
||||
this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Parabola, {
|
||||
joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||
dirOffset: { x: 0, y: 1, z: 0.1 },
|
||||
posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 },
|
||||
filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
|
@ -172,9 +154,10 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
speed: speed,
|
||||
accelerationAxis: accelerationAxis,
|
||||
rotateAccelerationWithAvatar: true,
|
||||
renderStates: teleportRenderStates
|
||||
renderStates: teleportRenderStates,
|
||||
maxDistance: 8.0
|
||||
});
|
||||
this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Ray, {
|
||||
this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, {
|
||||
joint: "Avatar",
|
||||
filter: Picks.PICK_ENTITIES,
|
||||
faceAvatar: true,
|
||||
|
@ -184,9 +167,10 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
accelerationAxis: accelerationAxis,
|
||||
rotateAccelerationWithAvatar: true,
|
||||
renderStates: teleportRenderStates,
|
||||
defaultRenderStates: teleportDefaultRenderStates
|
||||
defaultRenderStates: teleportDefaultRenderStates,
|
||||
maxDistance: 8.0
|
||||
});
|
||||
this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Ray, {
|
||||
this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Parabola, {
|
||||
joint: "Avatar",
|
||||
filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE,
|
||||
faceAvatar: true,
|
||||
|
@ -195,7 +179,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
speed: speed,
|
||||
accelerationAxis: accelerationAxis,
|
||||
rotateAccelerationWithAvatar: true,
|
||||
renderStates: teleportRenderStates
|
||||
renderStates: teleportRenderStates,
|
||||
maxDistance: 8.0
|
||||
});
|
||||
|
||||
this.cleanup = function() {
|
||||
|
@ -216,16 +201,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
100);
|
||||
|
||||
this.enterTeleport = function() {
|
||||
if (coolInTimeout !== null) {
|
||||
Script.clearTimeout(coolInTimeout);
|
||||
}
|
||||
|
||||
this.state = TELEPORTER_STATES.COOL_IN;
|
||||
coolInTimeout = Script.setTimeout(function() {
|
||||
if (_this.state === TELEPORTER_STATES.COOL_IN) {
|
||||
_this.state = TELEPORTER_STATES.TARGETTING;
|
||||
}
|
||||
}, COOL_IN_DURATION);
|
||||
this.state = TELEPORTER_STATES.TARGETTING;
|
||||
};
|
||||
|
||||
this.isReady = function(controllerData, deltaTime) {
|
||||
|
@ -287,11 +263,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
} else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) {
|
||||
this.setTeleportState(mode, "", "cancel");
|
||||
} else if (teleportLocationType === TARGET.SURFACE) {
|
||||
if (this.state === TELEPORTER_STATES.COOL_IN) {
|
||||
this.setTeleportState(mode, "cancel", "");
|
||||
} else {
|
||||
this.setTeleportState(mode, "teleport", "");
|
||||
}
|
||||
this.setTeleportState(mode, "teleport", "");
|
||||
} else if (teleportLocationType === TARGET.SEAT) {
|
||||
this.setTeleportState(mode, "", "seat");
|
||||
}
|
||||
|
@ -304,7 +276,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
return makeRunningValues(true, [], []);
|
||||
}
|
||||
|
||||
if (target === TARGET.NONE || target === TARGET.INVALID || this.state === TELEPORTER_STATES.COOL_IN) {
|
||||
if (target === TARGET.NONE || target === TARGET.INVALID) {
|
||||
// Do nothing
|
||||
} else if (target === TARGET.SEAT) {
|
||||
Entities.callEntityMethod(result.objectID, 'sit');
|
||||
|
|
|
@ -44,7 +44,7 @@ TOUCH_CONTROLLER_CONFIGURATION_LEFT = {
|
|||
controllers: [
|
||||
{
|
||||
modelURL: BASE_URL + "touch_l_body.fbx",
|
||||
jointIndex: MyAvatar.getJointIndex("_CONTROLLER_LEFTHAND"),
|
||||
jointIndex: MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"),
|
||||
naturalPosition: { x: 0.01648625358939171, y: -0.03551870584487915, z: -0.018527675420045853 },
|
||||
dimensions: { x: 0.11053799837827682, y: 0.0995776429772377, z: 0.10139888525009155 },
|
||||
rotation: leftBaseRotation,
|
||||
|
@ -209,7 +209,7 @@ TOUCH_CONTROLLER_CONFIGURATION_RIGHT = {
|
|||
controllers: [
|
||||
{
|
||||
modelURL: BASE_URL + "touch_r_body.fbx",
|
||||
jointIndex: MyAvatar.getJointIndex("_CONTROLLER_RIGHTHAND"),
|
||||
jointIndex: MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"),
|
||||
naturalPosition: { x: -0.016486231237649918, y: -0.03551865369081497, z: -0.018527653068304062 },
|
||||
dimensions: { x: 0.11053784191608429, y: 0.09957750141620636, z: 0.10139875113964081 },
|
||||
rotation: rightBaseRotation,
|
||||
|
|
|
@ -2038,10 +2038,16 @@ var PropertiesTool = function (opts) {
|
|||
};
|
||||
|
||||
that.setVisible(false);
|
||||
|
||||
function emitScriptEvent(data) {
|
||||
var dataString = JSON.stringify(data);
|
||||
webView.emitScriptEvent(dataString);
|
||||
createToolsWindow.emitScriptEvent(dataString);
|
||||
}
|
||||
|
||||
function updateScriptStatus(info) {
|
||||
info.type = "server_script_status";
|
||||
webView.emitScriptEvent(JSON.stringify(info));
|
||||
emitScriptEvent(info);
|
||||
}
|
||||
|
||||
function resetScriptStatus() {
|
||||
|
@ -2094,8 +2100,7 @@ var PropertiesTool = function (opts) {
|
|||
}
|
||||
data.selections = selections;
|
||||
|
||||
webView.emitScriptEvent(JSON.stringify(data));
|
||||
createToolsWindow.emitScriptEvent(JSON.stringify(data));
|
||||
emitScriptEvent(data);
|
||||
}
|
||||
selectionManager.addEventListener(updateSelections);
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ var lastEntityID = null;
|
|||
|
||||
var MATERIAL_PREFIX_STRING = "mat::";
|
||||
|
||||
var PENDING_SCRIPT_STATUS = "[ Fetching status ]";
|
||||
|
||||
function debugPrint(message) {
|
||||
EventBridge.emitWebEvent(
|
||||
JSON.stringify({
|
||||
|
@ -980,7 +982,7 @@ function loaded() {
|
|||
elCollideOtherAvatar.checked = false;
|
||||
|
||||
elGrabbable.checked = false;
|
||||
elWantsTrigger.checked = false;
|
||||
elTriggerable.checked = false;
|
||||
elIgnoreIK.checked = false;
|
||||
|
||||
elCloneable.checked = false;
|
||||
|
@ -1671,7 +1673,7 @@ function loaded() {
|
|||
elServerScripts.addEventListener('change', createEmitTextPropertyUpdateFunction('serverScripts'));
|
||||
elServerScripts.addEventListener('change', function() {
|
||||
// invalidate the current status (so that same-same updates can still be observed visually)
|
||||
elServerScriptStatus.innerText = '[' + elServerScriptStatus.innerText + ']';
|
||||
elServerScriptStatus.innerText = PENDING_SCRIPT_STATUS;
|
||||
});
|
||||
|
||||
elClearUserData.addEventListener("click", function() {
|
||||
|
@ -2145,7 +2147,7 @@ function loaded() {
|
|||
});
|
||||
elReloadServerScriptsButton.addEventListener("click", function() {
|
||||
// invalidate the current status (so that same-same updates can still be observed visually)
|
||||
elServerScriptStatus.innerText = '[' + elServerScriptStatus.innerText + ']';
|
||||
elServerScriptStatus.innerText = PENDING_SCRIPT_STATUS;
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "action",
|
||||
action: "reloadServerScripts"
|
||||
|
|
|
@ -39,8 +39,6 @@ var TABLET_NATURAL_DIMENSIONS = {x: 32.083, y: 48.553, z: 2.269};
|
|||
var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "images/button-close.png";
|
||||
// var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png";
|
||||
// var TABLET_MODEL_PATH = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx";
|
||||
var LOCAL_BEZEL_HIGHLIGHT = Script.resourcesPath() + "images/buttonBezel_highlight.png";
|
||||
var LOCAL_NORMAL_BEZEL = Script.resourcesPath() + "images/buttonBezel.png";
|
||||
|
||||
var LOCAL_TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-button-small-bezel.fbx";
|
||||
var HIGH_PRIORITY = 1;
|
||||
|
@ -87,8 +85,7 @@ cleanUpOldMaterialEntities = function() {
|
|||
for (var entityID in avatarEntityData) {
|
||||
var entityName = Entities.getEntityProperties(entityID, ["name"]).name;
|
||||
|
||||
if (entityName === TABLET_MATERIAL_ENTITY_NAME && entityID !== HMD.homeButtonHighlightMaterialID &&
|
||||
entityID !== HMD.homeButtonUnhighlightMaterialID) {
|
||||
if (entityName === TABLET_MATERIAL_ENTITY_NAME) {
|
||||
Entities.deleteEntity(entityID);
|
||||
}
|
||||
}
|
||||
|
@ -194,45 +191,21 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
|||
parentJointIndex: -1
|
||||
});
|
||||
|
||||
this.homeButtonUnhighlightMaterial = Entities.addEntity({
|
||||
type: "Material",
|
||||
name: TABLET_MATERIAL_ENTITY_NAME,
|
||||
materialURL: "materialData",
|
||||
localPosition: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
priority: HIGH_PRIORITY,
|
||||
materialData: JSON.stringify({
|
||||
materials: {
|
||||
albedoMap: LOCAL_NORMAL_BEZEL
|
||||
}
|
||||
|
||||
}),
|
||||
userData: JSON.stringify({
|
||||
"grabbableKey": {"grabbable": false}
|
||||
}),
|
||||
visible: false,
|
||||
parentMaterialName: SUBMESH,
|
||||
parentID: this.tabletEntityID
|
||||
}, true);
|
||||
|
||||
this.homeButtonHighlightMaterial = Entities.addEntity({
|
||||
type: "Material",
|
||||
name: TABLET_MATERIAL_ENTITY_NAME,
|
||||
materialURL: "materialData",
|
||||
localPosition: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
priority: LOW_PRIORITY,
|
||||
visible: false,
|
||||
materialData: JSON.stringify({
|
||||
materials: {
|
||||
emissiveMap: LOCAL_BEZEL_HIGHLIGHT
|
||||
}
|
||||
|
||||
}),
|
||||
userData: JSON.stringify({
|
||||
"grabbableKey": {"grabbable": false}
|
||||
}),
|
||||
parentMaterialName: SUBMESH,
|
||||
parentID: this.tabletEntityID
|
||||
}, true);
|
||||
this.homeButtonHighlightID = Overlays.addOverlay("circle3d", {
|
||||
name: "homeButtonHighlight",
|
||||
localPosition: { x: -HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET },
|
||||
localRotation: { x: 0, y: 1, z: 0, w: 0},
|
||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim },
|
||||
color: {red: 255, green: 255, blue: 255},
|
||||
solid: true,
|
||||
innerRadius: 0.9,
|
||||
ignoreIntersection: true,
|
||||
alpha: 0.0,
|
||||
visible: visible,
|
||||
drawInFront: false,
|
||||
parentID: this.tabletEntityID,
|
||||
parentJointIndex: -1
|
||||
});
|
||||
|
||||
this.receive = function (channel, senderID, senderUUID, localOnly) {
|
||||
if (_this.homeButtonID === senderID) {
|
||||
|
@ -387,8 +360,7 @@ WebTablet.prototype.destroy = function () {
|
|||
Overlays.deleteOverlay(this.webOverlayID);
|
||||
Overlays.deleteOverlay(this.tabletEntityID);
|
||||
Overlays.deleteOverlay(this.homeButtonID);
|
||||
Entities.deleteEntity(this.homeButtonUnhighlightMaterial);
|
||||
Entities.deleteEntity(this.homeButtonHighlightMaterial);
|
||||
Overlays.deleteOverlay(this.homeButtonHighlightID);
|
||||
HMD.displayModeChanged.disconnect(this.myOnHmdChanged);
|
||||
|
||||
Controller.mousePressEvent.disconnect(this.myMousePressEvent);
|
||||
|
@ -482,22 +454,19 @@ WebTablet.prototype.calculateWorldAttitudeRelativeToCamera = function (windowPos
|
|||
|
||||
WebTablet.prototype.onHoverEnterOverlay = function (overlayID, pointerEvent) {
|
||||
if (overlayID === this.homeButtonID) {
|
||||
Entities.editEntity(this.homeButtonUnhighlightMaterial, {priority: LOW_PRIORITY});
|
||||
Entities.editEntity(this.homeButtonHighlightMaterial, {priority: HIGH_PRIORITY});
|
||||
Overlays.editOverlay(this.homeButtonHighlightID, { alpha: 1.0 });
|
||||
}
|
||||
};
|
||||
|
||||
WebTablet.prototype.onHoverOverOverlay = function (overlayID, pointerEvent) {
|
||||
if (overlayID !== this.homeButtonID) {
|
||||
Entities.editEntity(this.homeButtonUnhighlightMaterial, {priority: HIGH_PRIORITY});
|
||||
Entities.editEntity(this.homeButtonHighlightMaterial, {priority: LOW_PRIORITY});
|
||||
Overlays.editOverlay(this.homeButtonHighlightID, { alpha: 0.0 });
|
||||
}
|
||||
};
|
||||
|
||||
WebTablet.prototype.onHoverLeaveOverlay = function (overlayID, pointerEvent) {
|
||||
if (overlayID === this.homeButtonID) {
|
||||
Entities.editEntity(this.homeButtonUnhighlightMaterial, {priority: HIGH_PRIORITY});
|
||||
Entities.editEntity(this.homeButtonHighlightMaterial, {priority: LOW_PRIORITY});
|
||||
Overlays.editOverlay(this.homeButtonHighlightID, { alpha: 0.0 });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -627,6 +596,21 @@ WebTablet.prototype.scheduleMouseMoveProcessor = function() {
|
|||
}
|
||||
};
|
||||
|
||||
WebTablet.prototype.handleMouseButtonHover = function(x, y) {
|
||||
var pickRay = Camera.computePickRay(x, y);
|
||||
var entityPickResults;
|
||||
var homebuttonHovered = false;
|
||||
entityPickResults = Overlays.findRayIntersection(pickRay, true, [this.tabletEntityID]);
|
||||
if (entityPickResults.intersects && (entityPickResults.entityID === this.tabletEntityID ||
|
||||
entityPickResults.overlayID === this.tabletEntityID)) {
|
||||
var overlayPickResults = Overlays.findRayIntersection(pickRay, true, [this.homeButtonID], []);
|
||||
if (overlayPickResults.intersects && overlayPickResults.overlayID === this.homeButtonID) {
|
||||
homebuttonHovered = true;
|
||||
}
|
||||
}
|
||||
Overlays.editOverlay(this.homeButtonHighlightID, { alpha: homebuttonHovered ? 1.0 : 0.0 });
|
||||
};
|
||||
|
||||
WebTablet.prototype.mouseMoveEvent = function (event) {
|
||||
if (this.dragging) {
|
||||
this.currentMouse = {
|
||||
|
@ -634,6 +618,8 @@ WebTablet.prototype.mouseMoveEvent = function (event) {
|
|||
y: event.y
|
||||
};
|
||||
this.scheduleMouseMoveProcessor();
|
||||
} else {
|
||||
this.handleHomeButtonHover(event.x, event.y);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -660,6 +646,8 @@ WebTablet.prototype.mouseMoveProcessor = function () {
|
|||
});
|
||||
}
|
||||
this.scheduleMouseMoveProcessor();
|
||||
} else {
|
||||
this.handleHomeButtonHover(this.currentMouse.x, this.currentMouse.y);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -38,30 +38,34 @@ getGrabPointSphereOffset = function(handController, ignoreSensorToWorldScale) {
|
|||
getControllerWorldLocation = function (handController, doOffset) {
|
||||
var orientation;
|
||||
var position;
|
||||
var pose = Controller.getPoseValue(handController);
|
||||
var valid = pose.valid;
|
||||
var controllerJointIndex;
|
||||
if (pose.valid) {
|
||||
if (handController === Controller.Standard.RightHand) {
|
||||
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND");
|
||||
} else {
|
||||
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
|
||||
}
|
||||
orientation = Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(controllerJointIndex));
|
||||
position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)));
|
||||
var valid = false;
|
||||
|
||||
if (handController >= 0) {
|
||||
var pose = Controller.getPoseValue(handController);
|
||||
valid = pose.valid;
|
||||
var controllerJointIndex;
|
||||
if (pose.valid) {
|
||||
if (handController === Controller.Standard.RightHand) {
|
||||
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND");
|
||||
} else {
|
||||
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
|
||||
}
|
||||
orientation = Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(controllerJointIndex));
|
||||
position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)));
|
||||
|
||||
// add to the real position so the grab-point is out in front of the hand, a bit
|
||||
if (doOffset) {
|
||||
var offset = getGrabPointSphereOffset(handController);
|
||||
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, offset));
|
||||
}
|
||||
// add to the real position so the grab-point is out in front of the hand, a bit
|
||||
if (doOffset) {
|
||||
var offset = getGrabPointSphereOffset(handController);
|
||||
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, offset));
|
||||
}
|
||||
|
||||
} else if (!HMD.isHandControllerAvailable()) {
|
||||
// NOTE: keep this offset in sync with scripts/system/controllers/handControllerPointer.js:493
|
||||
var VERTICAL_HEAD_LASER_OFFSET = 0.1 * MyAvatar.sensorToWorldScale;
|
||||
position = Vec3.sum(Camera.position, Vec3.multiplyQbyV(Camera.orientation, {x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0}));
|
||||
orientation = Quat.multiply(Camera.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));
|
||||
valid = true;
|
||||
} else if (!HMD.isHandControllerAvailable()) {
|
||||
// NOTE: keep this offset in sync with scripts/system/controllers/handControllerPointer.js:493
|
||||
var VERTICAL_HEAD_LASER_OFFSET = 0.1 * MyAvatar.sensorToWorldScale;
|
||||
position = Vec3.sum(Camera.position, Vec3.multiplyQbyV(Camera.orientation, {x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0}));
|
||||
orientation = Quat.multiply(Camera.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {position: position,
|
||||
|
|
|
@ -111,11 +111,6 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
|||
return value !== undefined ? value : "";
|
||||
}
|
||||
|
||||
function filterEntity(entityID) {
|
||||
return ((entityID === HMD.homeButtonHighlightMaterialID) ||
|
||||
(entityID === HMD.homeButtonUnhighlightMaterialID));
|
||||
}
|
||||
|
||||
that.sendUpdate = function() {
|
||||
var entities = [];
|
||||
|
||||
|
@ -126,10 +121,6 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
|||
ids = Entities.findEntities(MyAvatar.position, searchRadius);
|
||||
}
|
||||
|
||||
ids = ids.filter(function(id) {
|
||||
return !filterEntity(id);
|
||||
});
|
||||
|
||||
var cameraPosition = Camera.position;
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
var id = ids[i];
|
||||
|
|
|
@ -260,8 +260,8 @@ SelectionManager = (function() {
|
|||
|
||||
// Re-apply actions from the original entity
|
||||
var actionIDs = Entities.getActionIDs(properties.id);
|
||||
for (var i = 0; i < actionIDs.length; ++i) {
|
||||
var actionID = actionIDs[i];
|
||||
for (var j = 0; j < actionIDs.length; ++j) {
|
||||
var actionID = actionIDs[j];
|
||||
var actionArguments = Entities.getActionArguments(properties.id, actionID);
|
||||
if (actionArguments) {
|
||||
var type = actionArguments.type;
|
||||
|
@ -494,6 +494,7 @@ SelectionDisplay = (function() {
|
|||
that.replaceCollisionsAfterStretch = false;
|
||||
|
||||
var handlePropertiesTranslateArrowCones = {
|
||||
alpha: 1,
|
||||
shape: "Cone",
|
||||
solid: true,
|
||||
visible: false,
|
||||
|
@ -501,6 +502,7 @@ SelectionDisplay = (function() {
|
|||
drawInFront: true
|
||||
};
|
||||
var handlePropertiesTranslateArrowCylinders = {
|
||||
alpha: 1,
|
||||
shape: "Cylinder",
|
||||
solid: true,
|
||||
visible: false,
|
||||
|
@ -577,6 +579,7 @@ SelectionDisplay = (function() {
|
|||
});
|
||||
|
||||
var handlePropertiesStretchSpheres = {
|
||||
alpha: 1,
|
||||
shape: "Sphere",
|
||||
solid: true,
|
||||
visible: false,
|
||||
|
@ -606,6 +609,7 @@ SelectionDisplay = (function() {
|
|||
Overlays.editOverlay(handleStretchZPanel, { color: COLOR_BLUE });
|
||||
|
||||
var handlePropertiesScaleCubes = {
|
||||
alpha: 1,
|
||||
size: 0.025,
|
||||
color: COLOR_SCALE_CUBE,
|
||||
solid: true,
|
||||
|
@ -624,6 +628,7 @@ SelectionDisplay = (function() {
|
|||
var handleScaleRTFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, y, z)
|
||||
|
||||
var handlePropertiesScaleEdge = {
|
||||
alpha: 1,
|
||||
color: COLOR_SCALE_EDGE,
|
||||
visible: false,
|
||||
ignoreRayIntersection: true,
|
||||
|
@ -644,6 +649,7 @@ SelectionDisplay = (function() {
|
|||
var handleScaleFLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge);
|
||||
|
||||
var handleCloner = Overlays.addOverlay("cube", {
|
||||
alpha: 1,
|
||||
size: 0.05,
|
||||
color: COLOR_GREEN,
|
||||
solid: true,
|
||||
|
|
|
@ -370,7 +370,7 @@ getTabletWidthFromSettings = function () {
|
|||
|
||||
resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride) {
|
||||
|
||||
if (!HMD.tabletID || !HMD.tabletScreenID || !HMD.homeButtonID) {
|
||||
if (!HMD.tabletID || !HMD.tabletScreenID || !HMD.homeButtonID || !HMD.homeButtonHighlightID) {
|
||||
return;
|
||||
}
|
||||
var sensorScaleFactor = sensorToWorldScaleOverride || MyAvatar.sensorToWorldScale;
|
||||
|
@ -422,6 +422,12 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride)
|
|||
localRotation: { x: 0, y: 1, z: 0, w: 0 },
|
||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||
});
|
||||
|
||||
Overlays.editOverlay(HMD.homeButtonHighlightID, {
|
||||
localPosition: { x: -HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET },
|
||||
localRotation: { x: 0, y: 1, z: 0, w: 0 },
|
||||
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim }
|
||||
});
|
||||
};
|
||||
|
||||
getMainTabletIDs = function () {
|
||||
|
|
|
@ -114,6 +114,7 @@ var selectionDisplay = null; // for gridTool.js to ignore
|
|||
|
||||
Overlays.editOverlay(HMD.tabletID, { isVisibleInSecondaryCamera : visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.homeButtonID, { isVisibleInSecondaryCamera : visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.homeButtonHighlightID, { isVisibleInSecondaryCamera : visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.tabletScreenID, { isVisibleInSecondaryCamera : visibleInSecondaryCam });
|
||||
}
|
||||
|
||||
|
|
|
@ -112,8 +112,7 @@
|
|||
HMD.tabletID = UIWebTablet.tabletEntityID;
|
||||
HMD.homeButtonID = UIWebTablet.homeButtonID;
|
||||
HMD.tabletScreenID = UIWebTablet.webOverlayID;
|
||||
HMD.homeButtonHighlightMaterialID = UIWebTablet.homeButtonHighlightMaterial;
|
||||
HMD.homeButtonUnhighlightMaterialID = UIWebTablet.homeButtonUnhighlightMaterial;
|
||||
HMD.homeButtonHighlightID = UIWebTablet.homeButtonHighlightID;
|
||||
HMD.displayModeChanged.connect(onHmdChanged);
|
||||
MyAvatar.sensorToWorldScaleChanged.connect(onSensorToWorldScaleChanged);
|
||||
|
||||
|
@ -139,6 +138,7 @@
|
|||
tabletProperties.visible = true;
|
||||
Overlays.editOverlay(HMD.tabletID, tabletProperties);
|
||||
Overlays.editOverlay(HMD.homeButtonID, { visible: true });
|
||||
Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: true });
|
||||
Overlays.editOverlay(HMD.tabletScreenID, { visible: true });
|
||||
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 });
|
||||
updateTabletWidthFromSettings(true);
|
||||
|
@ -159,6 +159,7 @@
|
|||
|
||||
Overlays.editOverlay(HMD.tabletID, { visible: false });
|
||||
Overlays.editOverlay(HMD.homeButtonID, { visible: false });
|
||||
Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: false });
|
||||
Overlays.editOverlay(HMD.tabletScreenID, { visible: false });
|
||||
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 1 });
|
||||
}
|
||||
|
@ -179,6 +180,7 @@
|
|||
UIWebTablet = null;
|
||||
HMD.tabletID = null;
|
||||
HMD.homeButtonID = null;
|
||||
HMD.homeButtonHighlightID = null;
|
||||
HMD.tabletScreenID = null;
|
||||
} else if (debugTablet) {
|
||||
print("TABLET closeTabletUI, UIWebTablet is null");
|
||||
|
@ -331,9 +333,8 @@
|
|||
Overlays.deleteOverlay(tabletID);
|
||||
HMD.tabletID = null;
|
||||
HMD.homeButtonID = null;
|
||||
HMD.homeButtonHighlightID = null;
|
||||
HMD.tabletScreenID = null;
|
||||
HMD.homeButtonHighlightMaterialID = null;
|
||||
HMD.homeButtonUnhighlightMaterialID = null;
|
||||
});
|
||||
Script.setTimeout(cleanupMaterialEntities, 100);
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
Loading…
Reference in a new issue