Merge branch 'master' of github.com:highfidelity/hifi into exportToTestRail1

This commit is contained in:
NissimHadar 2018-08-10 08:52:24 -07:00
commit 65f8cdd00a
77 changed files with 709 additions and 719 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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