mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 08:22:30 +02:00
Merge master' into 'workload'
This commit is contained in:
commit
4329ea5240
66 changed files with 813 additions and 581 deletions
|
@ -14,12 +14,16 @@ package io.highfidelity.hifiinterface;
|
|||
import android.content.Intent;
|
||||
import android.content.res.AssetManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Vibrator;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.WindowManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.qtproject.qt5.android.QtLayout;
|
||||
import org.qtproject.qt5.android.QtSurface;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
|
||||
/*import com.google.vr.cardboard.DisplaySynchronizer;
|
||||
|
@ -31,6 +35,9 @@ import android.content.pm.ActivityInfo;
|
|||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class InterfaceActivity extends QtActivity {
|
||||
|
||||
|
@ -134,6 +141,7 @@ public class InterfaceActivity extends QtActivity {
|
|||
protected void onResume() {
|
||||
super.onResume();
|
||||
nativeEnterForeground();
|
||||
surfacesWorkaround();
|
||||
//gvrApi.resumeTracking();
|
||||
}
|
||||
|
||||
|
@ -158,6 +166,41 @@ public class InterfaceActivity extends QtActivity {
|
|||
Log.w("[VR]", "Portrait detected but not in VR mode. Should not happen");
|
||||
}
|
||||
}
|
||||
surfacesWorkaround();
|
||||
}
|
||||
|
||||
private void surfacesWorkaround() {
|
||||
FrameLayout fl = findViewById(android.R.id.content);
|
||||
if (fl.getChildCount() > 0) {
|
||||
QtLayout qtLayout = (QtLayout) fl.getChildAt(0);
|
||||
if (qtLayout.getChildCount() > 1) {
|
||||
QtSurface s1 = (QtSurface) qtLayout.getChildAt(0);
|
||||
QtSurface s2 = (QtSurface) qtLayout.getChildAt(1);
|
||||
Integer subLayer1 = 0;
|
||||
Integer subLayer2 = 0;
|
||||
try {
|
||||
String field;
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
field = "mSubLayer";
|
||||
} else {
|
||||
field = "mWindowType";
|
||||
}
|
||||
Field f = s1.getClass().getSuperclass().getDeclaredField(field);
|
||||
f.setAccessible(true);
|
||||
subLayer1 = (Integer) f.get(s1);
|
||||
subLayer2 = (Integer) f.get(s2);
|
||||
if (subLayer1 < subLayer2) {
|
||||
s1.setVisibility(View.VISIBLE);
|
||||
s2.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
s1.setVisibility(View.INVISIBLE);
|
||||
s2.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Log.e(TAG, "Workaround failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void openUrlInAndroidWebView(String urlString) {
|
||||
|
|
|
@ -8,48 +8,46 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AboutUtil.h"
|
||||
#include <QDate>
|
||||
#include <QLocale>
|
||||
|
||||
#include "AboutUtil.h"
|
||||
#include "BuildInfo.h"
|
||||
#include <ui/TabletScriptingInterface.h>
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
#include "BuildInfo.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
#include "Application.h"
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
AboutUtil::AboutUtil(QObject *parent) : QObject(parent) {
|
||||
QLocale locale_;
|
||||
m_DateConverted = QDate::fromString(BuildInfo::BUILD_TIME, "dd/MM/yyyy").
|
||||
toString(locale_.dateFormat(QLocale::ShortFormat));
|
||||
QLocale locale;
|
||||
_dateConverted = QDate::fromString(BuildInfo::BUILD_TIME, "dd/MM/yyyy").
|
||||
toString(locale.dateFormat(QLocale::ShortFormat));
|
||||
}
|
||||
|
||||
AboutUtil *AboutUtil::getInstance()
|
||||
{
|
||||
AboutUtil *AboutUtil::getInstance() {
|
||||
static AboutUtil instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
QString AboutUtil::buildDate() const
|
||||
{
|
||||
return m_DateConverted;
|
||||
QString AboutUtil::getBuildDate() const {
|
||||
return _dateConverted;
|
||||
}
|
||||
|
||||
QString AboutUtil::buildVersion() const
|
||||
{
|
||||
QString AboutUtil::getBuildVersion() const {
|
||||
return BuildInfo::VERSION;
|
||||
}
|
||||
|
||||
QString AboutUtil::qtVersion() const
|
||||
{
|
||||
QString AboutUtil::getQtVersion() const {
|
||||
return qVersion();
|
||||
}
|
||||
|
||||
void AboutUtil::openUrl(const QString& url) const {
|
||||
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||
auto tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
|
||||
|
|
|
@ -16,27 +16,24 @@
|
|||
#include <QObject>
|
||||
|
||||
class AboutUtil : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString buildDate READ buildDate CONSTANT)
|
||||
Q_PROPERTY(QString buildVersion READ buildVersion CONSTANT)
|
||||
Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT)
|
||||
|
||||
AboutUtil(QObject* parent = nullptr);
|
||||
Q_PROPERTY(QString buildDate READ getBuildDate CONSTANT)
|
||||
Q_PROPERTY(QString buildVersion READ getBuildVersion CONSTANT)
|
||||
Q_PROPERTY(QString qtVersion READ getQtVersion CONSTANT)
|
||||
public:
|
||||
static AboutUtil* getInstance();
|
||||
~AboutUtil() {}
|
||||
|
||||
QString buildDate() const;
|
||||
QString buildVersion() const;
|
||||
QString qtVersion() const;
|
||||
QString getBuildDate() const;
|
||||
QString getBuildVersion() const;
|
||||
QString getQtVersion() const;
|
||||
|
||||
public slots:
|
||||
void openUrl(const QString &url) const;
|
||||
private:
|
||||
|
||||
QString m_DateConverted;
|
||||
AboutUtil(QObject* parent = nullptr);
|
||||
QString _dateConverted;
|
||||
};
|
||||
|
||||
#endif // hifi_AboutUtil_h
|
||||
|
|
|
@ -334,7 +334,11 @@ static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" };
|
|||
static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
|
||||
#else
|
||||
static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4;
|
||||
#endif
|
||||
|
||||
// For processing on QThreadPool, we target a number of threads after reserving some
|
||||
// based on how many are being consumed by the application and the display plugin. However,
|
||||
|
@ -3648,7 +3652,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
_keysPressed.insert(event->key());
|
||||
|
||||
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface->isKeyCaptured(event)) {
|
||||
return;
|
||||
|
@ -3733,6 +3736,13 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_R:
|
||||
if (isMeta && !event->isAutoRepeat()) {
|
||||
DependencyManager::get<ScriptEngines>()->reloadAllScripts();
|
||||
DependencyManager::get<OffscreenUi>()->clearCache();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Asterisk:
|
||||
Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox);
|
||||
break;
|
||||
|
@ -7682,18 +7692,18 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa
|
|||
});
|
||||
}
|
||||
|
||||
void Application::takeSecondaryCameraSnapshot(const QString& filename) {
|
||||
postLambdaEvent([filename, this] {
|
||||
void Application::takeSecondaryCameraSnapshot(const bool& notify, const QString& filename) {
|
||||
postLambdaEvent([notify, filename, this] {
|
||||
QString snapshotPath = DependencyManager::get<Snapshot>()->saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename,
|
||||
TestScriptingInterface::getInstance()->getTestResultsLocation());
|
||||
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, true);
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, notify);
|
||||
});
|
||||
}
|
||||
|
||||
void Application::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) {
|
||||
postLambdaEvent([filename, cubemapOutputFormat, cameraPosition] {
|
||||
DependencyManager::get<Snapshot>()->save360Snapshot(cameraPosition, cubemapOutputFormat, filename);
|
||||
void Application::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) {
|
||||
postLambdaEvent([notify, filename, cubemapOutputFormat, cameraPosition] {
|
||||
DependencyManager::get<Snapshot>()->save360Snapshot(cameraPosition, cubemapOutputFormat, notify, filename);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -285,8 +285,11 @@ public:
|
|||
float getGameLoopRate() const { return _gameLoopCounter.rate(); }
|
||||
|
||||
void takeSnapshot(bool notify, bool includeAnimated = false, float aspectRatio = 0.0f, const QString& filename = QString());
|
||||
void takeSecondaryCameraSnapshot(const QString& filename = QString());
|
||||
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename = QString());
|
||||
void takeSecondaryCameraSnapshot(const bool& notify, const QString& filename = QString());
|
||||
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition,
|
||||
const bool& cubemapOutputFormat,
|
||||
const bool& notify,
|
||||
const QString& filename = QString());
|
||||
|
||||
void shareSnapshot(const QString& filename, const QUrl& href = QUrl(""));
|
||||
|
||||
|
|
|
@ -104,6 +104,9 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
|||
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
|
||||
|
||||
_myAvatar->update(deltaTime);
|
||||
render::Transaction transaction;
|
||||
_myAvatar->updateRenderItem(transaction);
|
||||
qApp->getMain3DScene()->enqueueTransaction(transaction);
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 dt = now - _lastSendAvatarDataTime;
|
||||
|
|
|
@ -1127,7 +1127,11 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
|
|||
}
|
||||
|
||||
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
|
||||
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
|
||||
return Avatar::setEnableMeshVisible(isEnabled);
|
||||
}
|
||||
|
||||
bool MyAvatar::getEnableMeshVisible() const {
|
||||
return Avatar::getEnableMeshVisible();
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
|
||||
|
@ -1479,7 +1483,10 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
_skeletonModelChangeCount++;
|
||||
int skeletonModelChangeCount = _skeletonModelChangeCount;
|
||||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
|
||||
_skeletonModel->setTagMask(render::hifi::TAG_NONE);
|
||||
_skeletonModel->setGroupCulled(true);
|
||||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
||||
|
||||
_headBoneSet.clear();
|
||||
_cauterizationNeedsUpdate = true;
|
||||
|
||||
|
@ -2054,14 +2061,12 @@ void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
|
|||
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
|
||||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
|
||||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
|
||||
uint8_t modelRenderTagBits = shouldDrawHead ? render::ItemKey::TAG_BITS_0 : render::ItemKey::TAG_BITS_NONE;
|
||||
modelRenderTagBits |= render::ItemKey::TAG_BITS_1;
|
||||
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene(),
|
||||
modelRenderTagBits, false);
|
||||
uint8_t modelRenderTagBits = shouldDrawHead ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_SECONDARY_VIEW;
|
||||
|
||||
uint8_t castShadowRenderTagBits = render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1;
|
||||
_attachmentModels[i]->setCanCastShadow(true, qApp->getMain3DScene(),
|
||||
castShadowRenderTagBits, false);
|
||||
_attachmentModels[i]->setTagMask(modelRenderTagBits);
|
||||
_attachmentModels[i]->setGroupCulled(false);
|
||||
_attachmentModels[i]->setCanCastShadow(true);
|
||||
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1159,7 +1159,7 @@ public slots:
|
|||
* @function MyAvatar.getEnableMeshVisible
|
||||
* @returns {boolean} <code>true</code> if your avatar's mesh is visible, otherwise <code>false</code>.
|
||||
*/
|
||||
bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); }
|
||||
bool getEnableMeshVisible() const override;
|
||||
|
||||
/**jsdoc
|
||||
* Set whether or not your avatar mesh is visible.
|
||||
|
@ -1171,7 +1171,7 @@ public slots:
|
|||
* MyAvatar.setEnableMeshVisible(true);
|
||||
* }, 10000);
|
||||
*/
|
||||
void setEnableMeshVisible(bool isEnabled);
|
||||
virtual void setEnableMeshVisible(bool isEnabled) override;
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.setEnableInverseKinematics
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <shared/FileUtils.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <MainWindow.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <StatTracker.h>
|
||||
#include <Trace.h>
|
||||
|
@ -186,3 +187,7 @@ void TestScriptingInterface::saveObject(QVariant variant, const QString& filenam
|
|||
file.write(jsonData);
|
||||
file.close();
|
||||
}
|
||||
|
||||
void TestScriptingInterface::showMaximized() {
|
||||
qApp->getWindow()->showMaximized();
|
||||
}
|
|
@ -27,70 +27,128 @@ public slots:
|
|||
|
||||
/**jsdoc
|
||||
* Exits the application
|
||||
* @function Test.quit
|
||||
*/
|
||||
void quit();
|
||||
|
||||
/**jsdoc
|
||||
* Waits for all texture transfers to be complete
|
||||
* @function Test.waitForTextureIdle
|
||||
*/
|
||||
void waitForTextureIdle();
|
||||
|
||||
/**jsdoc
|
||||
* Waits for all pending downloads to be complete
|
||||
* @function Test.waitForDownloadIdle
|
||||
*/
|
||||
void waitForDownloadIdle();
|
||||
|
||||
/**jsdoc
|
||||
* Waits for all file parsing operations to be complete
|
||||
* @function Test.waitForProcessingIdle
|
||||
*/
|
||||
void waitForProcessingIdle();
|
||||
|
||||
/**jsdoc
|
||||
* Waits for all pending downloads, parsing and texture transfers to be complete
|
||||
* @function Test.waitIdle
|
||||
*/
|
||||
void waitIdle();
|
||||
|
||||
/**jsdoc
|
||||
* Waits for establishment of connection to server
|
||||
* @function Test.waitForConnection
|
||||
* @param {int} maxWaitMs [default=10000] - Number of milliseconds to wait
|
||||
*/
|
||||
bool waitForConnection(qint64 maxWaitMs = 10000);
|
||||
|
||||
/**jsdoc
|
||||
* Waits a specific number of milliseconds
|
||||
* @function Test.wait
|
||||
* @param {int} milliseconds - Number of milliseconds to wait
|
||||
*/
|
||||
void wait(int milliseconds);
|
||||
|
||||
/**jsdoc
|
||||
* Waits for all pending downloads, parsing and texture transfers to be complete
|
||||
* @function Test.loadTestScene
|
||||
* @param {string} sceneFile - URL of scene to load
|
||||
*/
|
||||
bool loadTestScene(QString sceneFile);
|
||||
|
||||
/**jsdoc
|
||||
* Clears all caches
|
||||
* @function Test.clear
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**jsdoc
|
||||
* Start recording Chrome compatible tracing events
|
||||
* logRules can be used to specify a set of logging category rules to limit what gets captured
|
||||
* @function Test.startTracing
|
||||
* @param {string} logrules [defaultValue=""] - See implementation for explanation
|
||||
*/
|
||||
bool startTracing(QString logrules = "");
|
||||
|
||||
/**jsdoc
|
||||
* Stop recording Chrome compatible tracing events and serialize recorded events to a file
|
||||
* Using a filename with a .gz extension will automatically compress the output file
|
||||
* @function Test.stopTracing
|
||||
* @param {string} filename - Name of file to save to
|
||||
* @returns {bool} True if successful.
|
||||
*/
|
||||
bool stopTracing(QString filename);
|
||||
|
||||
/**jsdoc
|
||||
* Starts a specific trace event
|
||||
* @function Test.startTraceEvent
|
||||
* @param {string} name - Name of event
|
||||
*/
|
||||
void startTraceEvent(QString name);
|
||||
|
||||
/**jsdoc
|
||||
* Stop a specific name event
|
||||
* Using a filename with a .gz extension will automatically compress the output file
|
||||
* @function Test.endTraceEvent
|
||||
* @param {string} filename - Name of event
|
||||
*/
|
||||
void endTraceEvent(QString name);
|
||||
|
||||
/**jsdoc
|
||||
* Write detailed timing stats of next physics stepSimulation() to filename
|
||||
* @function Test.savePhysicsSimulationStats
|
||||
* @param {string} filename - Name of file to save to
|
||||
*/
|
||||
void savePhysicsSimulationStats(QString filename);
|
||||
|
||||
/**jsdoc
|
||||
* Profiles a specific function
|
||||
* @function Test.savePhysicsSimulationStats
|
||||
* @param {string} name - Name used to reference the function
|
||||
* @param {function} function - Function to profile
|
||||
*/
|
||||
Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
|
||||
|
||||
/**jsdoc
|
||||
* Clear all caches (menu command Reload Content)
|
||||
* @function Test.clearCaches
|
||||
*/
|
||||
void clearCaches();
|
||||
|
||||
/**jsdoc
|
||||
* Save a JSON object to a file in the test results location
|
||||
* @function Test.saveObject
|
||||
* @param {string} name - Name of the object
|
||||
* @param {string} filename - Name of file to save to
|
||||
*/
|
||||
void saveObject(QVariant v, const QString& filename);
|
||||
|
||||
/**jsdoc
|
||||
* Maximizes the window
|
||||
* @function Test.showMaximized
|
||||
*/
|
||||
void showMaximized();
|
||||
|
||||
private:
|
||||
bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition);
|
||||
QString _testResultsLocation;
|
||||
|
|
|
@ -446,12 +446,12 @@ void WindowScriptingInterface::takeSnapshot(bool notify, bool includeAnimated, f
|
|||
qApp->takeSnapshot(notify, includeAnimated, aspectRatio, filename);
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::takeSecondaryCameraSnapshot(const QString& filename) {
|
||||
qApp->takeSecondaryCameraSnapshot(filename);
|
||||
void WindowScriptingInterface::takeSecondaryCameraSnapshot(const bool& notify, const QString& filename) {
|
||||
qApp->takeSecondaryCameraSnapshot(notify, filename);
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) {
|
||||
qApp->takeSecondaryCamera360Snapshot(cameraPosition, cubemapOutputFormat, filename);
|
||||
void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) {
|
||||
qApp->takeSecondaryCamera360Snapshot(cameraPosition, cubemapOutputFormat, notify, filename);
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::shareSnapshot(const QString& path, const QUrl& href) {
|
||||
|
|
|
@ -362,27 +362,31 @@ public slots:
|
|||
* Takes a still snapshot of the current view from the secondary camera that can be set up through the {@link Render} API.
|
||||
* NOTE: to provide a non-default value - all previous parameters must be provided.
|
||||
* @function Window.takeSecondaryCameraSnapshot
|
||||
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
|
||||
* signal.
|
||||
* @param {string} [filename=""] - If this parameter is not given, the image will be saved as 'hifi-snap-by-<user name>-YYYY-MM-DD_HH-MM-SS'.
|
||||
* If this parameter is <code>""</code> then the image will be saved as ".jpg".
|
||||
* Otherwise, the image will be saved to this filename, with an appended ".jpg".
|
||||
*
|
||||
* var filename = QString();
|
||||
*/
|
||||
void takeSecondaryCameraSnapshot(const QString& filename = QString());
|
||||
void takeSecondaryCameraSnapshot(const bool& notify = true, const QString& filename = QString());
|
||||
|
||||
/**jsdoc
|
||||
* Takes a 360 snapshot given a position of the secondary camera (which does not need to have been previously set up).
|
||||
* @function Window.takeSecondaryCameraSnapshot
|
||||
* @function Window.takeSecondaryCamera360Snapshot
|
||||
* @param {vec3} [cameraPosition] - The (x, y, z) position of the camera for the 360 snapshot
|
||||
* @param {boolean} [cubemapOutputFormat=false] - If <code>true</code> then the snapshot is saved as a cube map image,
|
||||
* otherwise is saved as an equirectangular image.
|
||||
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
|
||||
* signal.
|
||||
* @param {string} [filename=""] - If this parameter is not given, the image will be saved as 'hifi-snap-by-<user name>-YYYY-MM-DD_HH-MM-SS'.
|
||||
* If this parameter is <code>""</code> then the image will be saved as ".jpg".
|
||||
* Otherwise, the image will be saved to this filename, with an appended ".jpg".
|
||||
*
|
||||
* var filename = QString();
|
||||
*/
|
||||
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat = false, const QString& filename = QString());
|
||||
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat = false, const bool& notify = true, const QString& filename = QString());
|
||||
|
||||
/**jsdoc
|
||||
* Emit a {@link Window.connectionAdded|connectionAdded} or a {@link Window.connectionError|connectionError} signal that
|
||||
|
|
|
@ -122,8 +122,9 @@ static const glm::quat CAMERA_ORIENTATION_LEFT(glm::quat(glm::radians(glm::vec3(
|
|||
static const glm::quat CAMERA_ORIENTATION_BACK(glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f))));
|
||||
static const glm::quat CAMERA_ORIENTATION_RIGHT(glm::quat(glm::radians(glm::vec3(0.0f, 270.0f, 0.0f))));
|
||||
static const glm::quat CAMERA_ORIENTATION_UP(glm::quat(glm::radians(glm::vec3(90.0f, 0.0f, 0.0f))));
|
||||
void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) {
|
||||
void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) {
|
||||
_snapshotFilename = filename;
|
||||
_notify360 = notify;
|
||||
_cubemapOutputFormat = cubemapOutputFormat;
|
||||
SecondaryCameraJobConfig* secondaryCameraRenderConfig = static_cast<SecondaryCameraJobConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera"));
|
||||
|
||||
|
@ -247,7 +248,8 @@ void Snapshot::convertToCubemap() {
|
|||
|
||||
painter.end();
|
||||
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename), true);
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename),
|
||||
_notify360);
|
||||
}
|
||||
|
||||
void Snapshot::convertToEquirectangular() {
|
||||
|
@ -327,7 +329,8 @@ void Snapshot::convertToEquirectangular() {
|
|||
}
|
||||
}
|
||||
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename), true);
|
||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename),
|
||||
_notify360);
|
||||
}
|
||||
|
||||
QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) {
|
||||
|
|
|
@ -50,7 +50,10 @@ class Snapshot : public QObject, public Dependency {
|
|||
public:
|
||||
Snapshot();
|
||||
QString saveSnapshot(QImage image, const QString& filename, const QString& pathname = QString());
|
||||
void save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename);
|
||||
void save360Snapshot(const glm::vec3& cameraPosition,
|
||||
const bool& cubemapOutputFormat,
|
||||
const bool& notify,
|
||||
const QString& filename);
|
||||
QTemporaryFile* saveTempSnapshot(QImage image);
|
||||
SnapshotMetaData* parseSnapshotData(QString snapshotPath);
|
||||
|
||||
|
@ -89,6 +92,7 @@ private:
|
|||
const QString& userSelectedFilename = QString(),
|
||||
const QString& userSelectedPathname = QString());
|
||||
QString _snapshotFilename;
|
||||
bool _notify360;
|
||||
bool _cubemapOutputFormat;
|
||||
QTimer _snapshotTimer;
|
||||
qint16 _snapshotIndex;
|
||||
|
|
|
@ -103,10 +103,9 @@ void ModelOverlay::update(float deltatime) {
|
|||
if (_visibleDirty) {
|
||||
_visibleDirty = false;
|
||||
// don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true
|
||||
_model->setVisibleInScene(getVisible(), scene,
|
||||
render::ItemKey::TAG_BITS_0 |
|
||||
(_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE),
|
||||
false);
|
||||
uint8_t modelRenderTagMask = (_isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW);
|
||||
_model->setTagMask(modelRenderTagMask, scene);
|
||||
_model->setVisibleInScene(getVisible(), scene);
|
||||
}
|
||||
if (_drawInFrontDirty) {
|
||||
_drawInFrontDirty = false;
|
||||
|
|
|
@ -132,7 +132,6 @@ private:
|
|||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay);
|
||||
template <> int payloadGetLayer(const Overlay::Pointer& overlay);
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
|
||||
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);
|
||||
|
|
|
@ -35,14 +35,18 @@ namespace render {
|
|||
auto builder = ItemKey::Builder().withTypeShape();
|
||||
if (overlay->is3D()) {
|
||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
|
||||
if (overlay3D->getDrawInFront() || overlay3D->getDrawHUDLayer()) {
|
||||
builder.withLayered();
|
||||
if (overlay3D->getDrawInFront()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_FRONT);
|
||||
} else if (overlay3D->getDrawHUDLayer()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_HUD);
|
||||
}
|
||||
|
||||
if (overlay->isTransparent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
} else {
|
||||
builder.withViewSpace();
|
||||
builder.withLayer(render::hifi::LAYER_2D);
|
||||
}
|
||||
|
||||
if (!overlay->getVisible()) {
|
||||
|
@ -50,30 +54,14 @@ namespace render {
|
|||
}
|
||||
|
||||
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
|
||||
uint32_t viewTaskBits = render::ItemKey::TAG_BITS_0 |
|
||||
(overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE);
|
||||
|
||||
builder.withTagBits(viewTaskBits);
|
||||
render::hifi::Tag viewTagBits = overlay->getIsVisibleInSecondaryCamera() ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
|
||||
builder.withTagBits(viewTagBits);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
||||
return overlay->getBounds();
|
||||
}
|
||||
template <> int payloadGetLayer(const Overlay::Pointer& overlay) {
|
||||
if (overlay->is3D()) {
|
||||
auto overlay3D = std::dynamic_pointer_cast<Base3DOverlay>(overlay);
|
||||
if (overlay3D->getDrawInFront()) {
|
||||
return Item::LAYER_3D_FRONT;
|
||||
} else if (overlay3D->getDrawHUDLayer()) {
|
||||
return Item::LAYER_3D_HUD;
|
||||
} else {
|
||||
return Item::LAYER_3D;
|
||||
}
|
||||
} else {
|
||||
return Item::LAYER_2D;
|
||||
}
|
||||
}
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
if (args) {
|
||||
overlay->render(args);
|
||||
|
@ -83,7 +71,6 @@ namespace render {
|
|||
return overlay->getShapeKey();
|
||||
}
|
||||
|
||||
|
||||
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems) {
|
||||
return overlay->fetchMetaSubItems(subItems);
|
||||
}
|
||||
|
|
|
@ -52,10 +52,15 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withMetaCullGroup();
|
||||
ItemKey::Builder keyBuilder = ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::hifi::TAG_ALL_VIEWS).withMetaCullGroup();
|
||||
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
||||
if (!avatarPtr->getEnableMeshVisible()) {
|
||||
keyBuilder.withInvisible();
|
||||
}
|
||||
return keyBuilder.build();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
|
||||
return static_pointer_cast<Avatar>(avatar)->getBounds();
|
||||
return static_pointer_cast<Avatar>(avatar)->getRenderBounds();
|
||||
}
|
||||
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
|
||||
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
||||
|
@ -164,6 +169,11 @@ AABox Avatar::getBounds() const {
|
|||
return _skeletonModel->getRenderableMeshBound();
|
||||
}
|
||||
|
||||
|
||||
AABox Avatar::getRenderBounds() const {
|
||||
return _renderBound;
|
||||
}
|
||||
|
||||
void Avatar::animateScaleChanges(float deltaTime) {
|
||||
|
||||
if (_isAnimatingScale) {
|
||||
|
@ -569,16 +579,26 @@ static TextRenderer3D* textRenderer(TextRendererType type) {
|
|||
|
||||
void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
auto avatarPayload = new render::Payload<AvatarData>(self);
|
||||
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
|
||||
|
||||
auto avatarPayloadPointer = std::shared_ptr<render::Payload<AvatarData>>(avatarPayload);
|
||||
if (_renderItemID == render::Item::INVALID_ITEM_ID) {
|
||||
_renderItemID = scene->allocateID();
|
||||
}
|
||||
// INitialize the _render bound as we are creating the avatar render item
|
||||
_renderBound = getBounds();
|
||||
transaction.resetItem(_renderItemID, avatarPayloadPointer);
|
||||
_skeletonModel->addToScene(scene, transaction);
|
||||
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||
_skeletonModel->setGroupCulled(true);
|
||||
_skeletonModel->setCanCastShadow(true);
|
||||
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
|
||||
processMaterials();
|
||||
for (auto& attachmentModel : _attachmentModels) {
|
||||
attachmentModel->addToScene(scene, transaction);
|
||||
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||
attachmentModel->setGroupCulled(false);
|
||||
attachmentModel->setCanCastShadow(true);
|
||||
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
}
|
||||
|
||||
_mustFadeIn = true;
|
||||
|
@ -637,7 +657,15 @@ void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointe
|
|||
|
||||
void Avatar::updateRenderItem(render::Transaction& transaction) {
|
||||
if (render::Item::isValidID(_renderItemID)) {
|
||||
transaction.updateItem<render::Payload<AvatarData>>(_renderItemID, [](render::Payload<AvatarData>& p) {});
|
||||
auto renderBound = getBounds();
|
||||
transaction.updateItem<AvatarData>(_renderItemID,
|
||||
[renderBound](AvatarData& avatar) {
|
||||
auto avatarPtr = dynamic_cast<Avatar*>(&avatar);
|
||||
if (avatarPtr) {
|
||||
avatarPtr->_renderBound = renderBound;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,6 +787,18 @@ void Avatar::render(RenderArgs* renderArgs) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Avatar::setEnableMeshVisible(bool isEnabled) {
|
||||
if (_isMeshVisible != isEnabled) {
|
||||
_isMeshVisible = isEnabled;
|
||||
_needMeshVisibleSwitch = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Avatar::getEnableMeshVisible() const {
|
||||
return _isMeshVisible;
|
||||
}
|
||||
|
||||
void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
||||
bool canTryFade{ false };
|
||||
|
||||
|
@ -770,6 +810,12 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
|||
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
|
||||
_skeletonModel->removeFromScene(scene, transaction);
|
||||
_skeletonModel->addToScene(scene, transaction);
|
||||
|
||||
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||
_skeletonModel->setGroupCulled(true);
|
||||
_skeletonModel->setCanCastShadow(true);
|
||||
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
|
||||
processMaterials();
|
||||
canTryFade = true;
|
||||
_isAnimatingScale = true;
|
||||
|
@ -778,9 +824,25 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
|||
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
|
||||
attachmentModel->removeFromScene(scene, transaction);
|
||||
attachmentModel->addToScene(scene, transaction);
|
||||
|
||||
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||
attachmentModel->setGroupCulled(false);
|
||||
attachmentModel->setCanCastShadow(true);
|
||||
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
}
|
||||
}
|
||||
|
||||
if (_needMeshVisibleSwitch) {
|
||||
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
for (auto attachmentModel : _attachmentModels) {
|
||||
if (attachmentModel->isRenderable()) {
|
||||
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
}
|
||||
}
|
||||
updateRenderItem(transaction);
|
||||
_needMeshVisibleSwitch = false;
|
||||
}
|
||||
|
||||
if (_mustFadeIn && canTryFade) {
|
||||
// Do it now to be sure all the sub items are ready and the fade is sent to them too
|
||||
fade(transaction, render::Transition::USER_ENTER_DOMAIN);
|
||||
|
|
|
@ -74,7 +74,6 @@ public:
|
|||
virtual void instantiableAvatar() = 0;
|
||||
|
||||
typedef render::Payload<AvatarData> Payload;
|
||||
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
|
||||
|
||||
void init();
|
||||
void updateAvatarEntities();
|
||||
|
@ -322,6 +321,7 @@ public:
|
|||
bool hasNewJointData() const { return _hasNewJointData; }
|
||||
|
||||
float getBoundingRadius() const;
|
||||
AABox getRenderBounds() const; // THis call is accessible from rendering thread only to report the bounding box of the avatar during the frame.
|
||||
|
||||
void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
||||
void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
||||
|
@ -356,6 +356,10 @@ public:
|
|||
|
||||
virtual void setAvatarEntityDataChanged(bool value) override;
|
||||
|
||||
// Show hide the model representation of the avatar
|
||||
virtual void setEnableMeshVisible(bool isEnabled);
|
||||
virtual bool getEnableMeshVisible() const;
|
||||
|
||||
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
|
||||
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
|
||||
|
||||
|
@ -532,6 +536,10 @@ protected:
|
|||
std::mutex _materialsLock;
|
||||
|
||||
void processMaterials();
|
||||
|
||||
AABox _renderBound;
|
||||
bool _isMeshVisible{ true };
|
||||
bool _needMeshVisibleSwitch{ true };
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
|
@ -35,7 +35,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
|||
_useDualQuaternionSkinning = true;
|
||||
|
||||
// Avatars all cast shadow
|
||||
_canCastShadow = true;
|
||||
setCanCastShadow(true);
|
||||
|
||||
assert(_owningAvatar);
|
||||
}
|
||||
|
|
|
@ -157,16 +157,20 @@ Item::Bound EntityRenderer::getBound() {
|
|||
return _bound;
|
||||
}
|
||||
|
||||
render::hifi::Tag EntityRenderer::getTagMask() const {
|
||||
return _isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
|
||||
}
|
||||
|
||||
ItemKey EntityRenderer::getKey() {
|
||||
if (isTransparent()) {
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask());
|
||||
}
|
||||
|
||||
// This allows shapes to cast shadows
|
||||
if (_canCastShadow) {
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).withShadowCaster();
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withShadowCaster();
|
||||
} else {
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,6 +384,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
|
|||
|
||||
_moving = entity->isMovingRelativeToParent();
|
||||
_visible = entity->getVisible();
|
||||
setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
|
||||
_canCastShadow = entity->getCanCastShadow();
|
||||
_cauterized = entity->getCauterized();
|
||||
_needsRenderUpdate = false;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "AbstractViewStateInterface.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
#include <graphics-scripting/Forward.h>
|
||||
#include <RenderHifi.h>
|
||||
|
||||
class EntityTreeRenderer;
|
||||
|
||||
|
@ -74,6 +75,7 @@ protected:
|
|||
virtual Item::Bound getBound() override;
|
||||
virtual void render(RenderArgs* args) override final;
|
||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override;
|
||||
virtual render::hifi::Tag getTagMask() const;
|
||||
|
||||
// Returns true if the item in question needs to have updateInScene called because of internal rendering state changes
|
||||
virtual bool needsRenderUpdate() const;
|
||||
|
@ -97,6 +99,8 @@ protected:
|
|||
bool isFading() const { return _isFading; }
|
||||
virtual bool isTransparent() const { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; }
|
||||
inline bool isValidRenderItem() const { return _renderItemID != Item::INVALID_ITEM_ID; }
|
||||
|
||||
virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; }
|
||||
|
||||
template <typename F, typename T>
|
||||
T withReadLockResult(const std::function<T()>& f) {
|
||||
|
@ -129,6 +133,7 @@ protected:
|
|||
bool _isFading{ _entitiesShouldFadeFunction() };
|
||||
bool _prevIsTransparent { false };
|
||||
bool _visible { false };
|
||||
bool _isVisibleInSecondaryCamera { false };
|
||||
bool _canCastShadow { false };
|
||||
bool _cauterized { false };
|
||||
bool _moving { false };
|
||||
|
|
|
@ -43,7 +43,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
|
|||
|
||||
ItemKey MaterialEntityRenderer::getKey() {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
builder.withTypeShape().withTagBits(getTagMask());
|
||||
|
||||
if (!_visible) {
|
||||
builder.withInvisible();
|
||||
|
|
|
@ -1060,9 +1060,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
|
|||
|
||||
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
|
||||
if (didVisualGeometryRequestSucceed) {
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask());
|
||||
} else {
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(getTagMask());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1070,6 +1070,13 @@ ItemKey ModelEntityRenderer::getKey() {
|
|||
return _itemKey;
|
||||
}
|
||||
|
||||
render::hifi::Tag ModelEntityRenderer::getTagMask() const {
|
||||
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
|
||||
return _cauterized ?
|
||||
(_isVisibleInSecondaryCamera ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE) :
|
||||
Parent::getTagMask(); // calculate which views to be shown in
|
||||
}
|
||||
|
||||
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
|
||||
if (_model) {
|
||||
auto metaSubItems = _subRenderItemIDs;
|
||||
|
@ -1329,6 +1336,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
emit DependencyManager::get<scriptable::ModelProviderFactory>()->
|
||||
modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model);
|
||||
}
|
||||
_didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
|
||||
});
|
||||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
|
||||
|
@ -1386,21 +1394,22 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
entity->updateModelBounds();
|
||||
entity->stopModelOverrideIfNoParent();
|
||||
|
||||
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
|
||||
uint32_t viewTaskBits = _cauterized ?
|
||||
render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero)
|
||||
render::ItemKey::TAG_BITS_ALL; // draw in all views
|
||||
|
||||
if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) {
|
||||
render::hifi::Tag tagMask = getTagMask();
|
||||
if (model->isVisible() != _visible) {
|
||||
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||
// the renderable item. As it stands now the model checks it's visible/invisible state
|
||||
// so most of the time we don't do anything in this function.
|
||||
model->setVisibleInScene(_visible, scene, viewTaskBits, false);
|
||||
model->setVisibleInScene(_visible, scene);
|
||||
}
|
||||
|
||||
if (model->getTagMask() != tagMask) {
|
||||
model->setTagMask(tagMask, scene);
|
||||
}
|
||||
|
||||
// TODO? early exit here when not visible?
|
||||
|
||||
if (model->canCastShadow() != _canCastShadow) {
|
||||
model->setCanCastShadow(_canCastShadow, scene, viewTaskBits, false);
|
||||
model->setCanCastShadow(_canCastShadow, scene);
|
||||
}
|
||||
|
||||
if (_needsCollisionGeometryUpdate) {
|
||||
|
@ -1473,6 +1482,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) {
|
||||
Parent::setIsVisibleInSecondaryCamera(value);
|
||||
setKey(_didLastVisualGeometryRequestSucceed);
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::flagForCollisionGeometryUpdate() {
|
||||
_needsCollisionGeometryUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
|
|
|
@ -164,6 +164,10 @@ protected:
|
|||
void flagForCollisionGeometryUpdate();
|
||||
void setCollisionMeshKey(const void* key);
|
||||
|
||||
render::hifi::Tag getTagMask() const override;
|
||||
|
||||
void setIsVisibleInSecondaryCamera(bool value) override;
|
||||
|
||||
private:
|
||||
void animate(const TypedEntityPointer& entity);
|
||||
void mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames);
|
||||
|
@ -202,6 +206,8 @@ private:
|
|||
|
||||
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
|
||||
|
||||
bool _didLastVisualGeometryRequestSucceed { false };
|
||||
|
||||
void processMaterials();
|
||||
};
|
||||
|
||||
|
|
|
@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
|
|||
|
||||
ItemKey ParticleEffectEntityRenderer::getKey() {
|
||||
if (_visible) {
|
||||
return ItemKey::Builder::transparentShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
return ItemKey::Builder::transparentShape().withTagBits(getTagMask());
|
||||
} else {
|
||||
return ItemKey::Builder().withInvisible().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
|
||||
return ItemKey::Builder().withInvisible().withTagBits(getTagMask()).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
|
|||
}
|
||||
|
||||
ItemKey PolyLineEntityRenderer::getKey() {
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask());
|
||||
}
|
||||
|
||||
ShapeKey PolyLineEntityRenderer::getShapeKey() {
|
||||
|
|
|
@ -169,7 +169,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); }
|
||||
virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(getTagMask()); }
|
||||
virtual ShapeKey getShapeKey() override;
|
||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
|
|
|
@ -139,7 +139,7 @@ bool ShapeEntityRenderer::isTransparent() const {
|
|||
|
||||
ItemKey ShapeEntityRenderer::getKey() {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
builder.withTypeShape().withTypeMeta().withTagBits(getTagMask());
|
||||
|
||||
withReadLock([&] {
|
||||
if (isTransparent()) {
|
||||
|
|
|
@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
|
||||
|
||||
ItemKey ZoneEntityRenderer::getKey() {
|
||||
return ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
|
||||
return ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).build();
|
||||
}
|
||||
|
||||
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||
|
|
|
@ -1429,6 +1429,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isVisibleInSecondaryCamera, setIsVisibleInSecondaryCamera);
|
||||
|
||||
// Certifiable Properties
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemName, setItemName);
|
||||
|
@ -2808,6 +2809,28 @@ void EntityItem::setVisible(bool value) {
|
|||
}
|
||||
}
|
||||
|
||||
bool EntityItem::isVisibleInSecondaryCamera() const {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
result = _isVisibleInSecondaryCamera;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setIsVisibleInSecondaryCamera(bool value) {
|
||||
bool changed = false;
|
||||
withWriteLock([&] {
|
||||
if (_isVisibleInSecondaryCamera != value) {
|
||||
changed = true;
|
||||
_isVisibleInSecondaryCamera = value;
|
||||
}
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityItem::getCanCastShadow() const {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
|
|
|
@ -277,6 +277,9 @@ public:
|
|||
bool getVisible() const;
|
||||
void setVisible(bool value);
|
||||
|
||||
bool isVisibleInSecondaryCamera() const;
|
||||
void setIsVisibleInSecondaryCamera(bool value);
|
||||
|
||||
bool getCanCastShadow() const;
|
||||
void setCanCastShadow(bool value);
|
||||
|
||||
|
@ -590,6 +593,7 @@ protected:
|
|||
glm::vec3 _registrationPoint { ENTITY_ITEM_DEFAULT_REGISTRATION_POINT };
|
||||
float _angularDamping { ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING };
|
||||
bool _visible { ENTITY_ITEM_DEFAULT_VISIBLE };
|
||||
bool _isVisibleInSecondaryCamera { ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA };
|
||||
bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW };
|
||||
bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS };
|
||||
uint16_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT };
|
||||
|
|
|
@ -368,6 +368,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_DATA, materialData);
|
||||
CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera);
|
||||
|
||||
// Certifiable Properties
|
||||
CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName);
|
||||
|
@ -490,6 +491,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities. Shadows are cast if inside a
|
||||
* {@link Entities.EntityType|Zone} entity with <code>castShadows</code> enabled in its
|
||||
* {@link Entities.EntityProperties-Zone|keyLight} property.
|
||||
* @property {boolean} isVisibleInSecondaryCamera=true - Whether or not the entity is rendered in the secondary camera. If <code>true</code> then the entity is rendered.
|
||||
*
|
||||
* @property {Vec3} position=0,0,0 - The position of the entity.
|
||||
* @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates.
|
||||
|
@ -1226,6 +1228,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera);
|
||||
|
||||
// Certifiable Properties
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_NAME, itemName);
|
||||
|
@ -1565,6 +1568,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, glmVec2, setMaterialMappingScale);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialData, QString, setMaterialData);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera);
|
||||
|
||||
// Certifiable Properties
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName);
|
||||
|
@ -1896,7 +1900,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_PROPERTY_TO_MAP(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLLISIONLESS, Collisionless, collisionless, bool);
|
||||
ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, ignoreForCollisions, unused); // legacy support
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLLISIONLESS, unused, ignoreForCollisions, unused); // legacy support
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLLISION_MASK, unused, collisionMask, unused);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COLLISION_MASK, unused, collidesWith, unused);
|
||||
ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, collisionsWillMove, unused); // legacy support
|
||||
|
@ -1944,6 +1948,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_DATA, MaterialData, materialData, QString);
|
||||
|
||||
ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool);
|
||||
|
||||
// Certifiable Properties
|
||||
ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString);
|
||||
|
@ -3041,6 +3047,8 @@ void EntityItemProperties::markAllChanged() {
|
|||
_cloneDynamicChanged = true;
|
||||
_cloneAvatarEntityChanged = true;
|
||||
_cloneOriginIDChanged = true;
|
||||
|
||||
_isVisibleInSecondaryCameraChanged = true;
|
||||
}
|
||||
|
||||
// The minimum bounding box for the entity.
|
||||
|
@ -3319,6 +3327,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (materialDataChanged()) {
|
||||
out += "materialData";
|
||||
}
|
||||
if (isVisibleInSecondaryCameraChanged()) {
|
||||
out += "isVisibleInSecondaryCamera";
|
||||
}
|
||||
|
||||
// Certifiable Properties
|
||||
if (itemNameChanged()) {
|
||||
|
|
|
@ -233,6 +233,8 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float, 0);
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_DATA, MaterialData, materialData, QString, "");
|
||||
|
||||
DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA);
|
||||
|
||||
// Certifiable Properties - related to Proof of Purchase certificates
|
||||
DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME);
|
||||
DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION);
|
||||
|
|
|
@ -46,6 +46,7 @@ const quint32 ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION = 0;
|
|||
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
|
||||
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
|
||||
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
|
||||
const bool ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA = true;
|
||||
const bool ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW { true };
|
||||
|
||||
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");
|
||||
|
|
|
@ -249,6 +249,8 @@ enum EntityPropertyList {
|
|||
PROP_MATERIAL_MAPPING_ROT,
|
||||
PROP_MATERIAL_DATA,
|
||||
|
||||
PROP_VISIBLE_IN_SECONDARY_CAMERA, // not sent over the wire, only used locally
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -1688,15 +1688,21 @@ QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
|
|||
if (!_entityTree) {
|
||||
return result;
|
||||
}
|
||||
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID);
|
||||
if (!entity) {
|
||||
qCDebug(entities) << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
|
||||
return result;
|
||||
}
|
||||
|
||||
_entityTree->withReadLock([&] {
|
||||
entity->forEachChild([&](SpatiallyNestablePointer child) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
if (!parentFinder) {
|
||||
return;
|
||||
}
|
||||
bool success;
|
||||
SpatiallyNestableWeakPointer parentWP = parentFinder->find(parentID, success);
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
SpatiallyNestablePointer parent = parentWP.lock();
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
parent->forEachChild([&](SpatiallyNestablePointer child) {
|
||||
result.push_back(child->getID());
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1226,12 +1226,11 @@ public slots:
|
|||
|
||||
|
||||
/**jsdoc
|
||||
* Get the IDs of entities, overlays, and avatars that are directly parented to an entity. To get all descendants of an
|
||||
* entity, recurse on the IDs returned by the function.
|
||||
* Get the IDs of entities, overlays, and avatars that are directly parented to an entity, overlay, or avatar model. Recurse on the IDs returned by the function to get all descendants of an entity, overlay, or avatar.
|
||||
* @function Entities.getChildrenIDs
|
||||
* @param {Uuid} parentID - The ID of the entity to get the children IDs of.
|
||||
* @param {Uuid} parentID - The ID of the entity, overlay, or avatar to get the children IDs of.
|
||||
* @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the <code>parentID</code>
|
||||
* entity. Does not include children's children, etc. The array is empty if no children can be found or
|
||||
* entity, overlay, or avatar. Does not include children's children, etc. The array is empty if no children can be found or
|
||||
* <code>parentID</code> cannot be found.
|
||||
* @example <caption>Report the children of an entity.</caption>
|
||||
* function createEntity(description, position, parent) {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QUrlQuery>
|
||||
#include <QtCore/QThreadPool>
|
||||
#include <QtNetwork/QHttpMultiPart>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <qthread.h>
|
||||
|
@ -743,6 +744,9 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI
|
|||
return;
|
||||
}
|
||||
|
||||
// Ensure openssl/Qt config is set up.
|
||||
QSslConfiguration::defaultConfiguration();
|
||||
|
||||
// make sure we don't already have an outbound keypair generation request
|
||||
if (!_isWaitingForKeypairResponse) {
|
||||
_isWaitingForKeypairResponse = true;
|
||||
|
@ -751,94 +755,75 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI
|
|||
qCDebug(networking) << "Clearing current private key in DataServerAccountInfo";
|
||||
_accountInfo.setPrivateKey(QByteArray());
|
||||
|
||||
// setup a new QThread to generate the keypair on, in case it takes a while
|
||||
QThread* generateThread = new QThread(this);
|
||||
generateThread->setObjectName("Account Manager Generator Thread");
|
||||
|
||||
// setup a keypair generator
|
||||
// Create a runnable keypair generated to create an RSA pair and exit.
|
||||
RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator;
|
||||
|
||||
if (!isUserKeypair) {
|
||||
keypairGenerator->setDomainID(domainID);
|
||||
_accountInfo.setDomainID(domainID);
|
||||
}
|
||||
|
||||
// start keypair generation when the thread starts
|
||||
connect(generateThread, &QThread::started, keypairGenerator, &RSAKeypairGenerator::generateKeypair);
|
||||
|
||||
// handle success or failure of keypair generation
|
||||
connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this, &AccountManager::processGeneratedKeypair);
|
||||
connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair,
|
||||
this, &AccountManager::handleKeypairGenerationError);
|
||||
|
||||
connect(keypairGenerator, &QObject::destroyed, generateThread, &QThread::quit);
|
||||
connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater);
|
||||
|
||||
keypairGenerator->moveToThread(generateThread);
|
||||
connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this,
|
||||
&AccountManager::processGeneratedKeypair);
|
||||
connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair, this,
|
||||
&AccountManager::handleKeypairGenerationError);
|
||||
|
||||
qCDebug(networking) << "Starting worker thread to generate 2048-bit RSA keypair.";
|
||||
generateThread->start();
|
||||
// Start on Qt's global thread pool.
|
||||
QThreadPool::globalInstance()->start(keypairGenerator);
|
||||
}
|
||||
}
|
||||
|
||||
void AccountManager::processGeneratedKeypair() {
|
||||
void AccountManager::processGeneratedKeypair(QByteArray publicKey, QByteArray privateKey) {
|
||||
|
||||
qCDebug(networking) << "Generated 2048-bit RSA keypair. Uploading public key now.";
|
||||
|
||||
RSAKeypairGenerator* keypairGenerator = qobject_cast<RSAKeypairGenerator*>(sender());
|
||||
// hold the private key to later set our metaverse API account info if upload succeeds
|
||||
_pendingPrivateKey = privateKey;
|
||||
|
||||
if (keypairGenerator) {
|
||||
// hold the private key to later set our metaverse API account info if upload succeeds
|
||||
_pendingPrivateKey = keypairGenerator->getPrivateKey();
|
||||
// upload the public key so data-web has an up-to-date key
|
||||
const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key";
|
||||
const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key";
|
||||
|
||||
// upload the public key so data-web has an up-to-date key
|
||||
const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key";
|
||||
const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key";
|
||||
|
||||
QString uploadPath;
|
||||
const auto& domainID = keypairGenerator->getDomainID();
|
||||
if (domainID.isNull()) {
|
||||
uploadPath = USER_PUBLIC_KEY_UPDATE_PATH;
|
||||
} else {
|
||||
uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID));
|
||||
}
|
||||
|
||||
// setup a multipart upload to send up the public key
|
||||
QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
QHttpPart publicKeyPart;
|
||||
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||
|
||||
publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant("form-data; name=\"public_key\"; filename=\"public_key\""));
|
||||
publicKeyPart.setBody(keypairGenerator->getPublicKey());
|
||||
requestMultiPart->append(publicKeyPart);
|
||||
|
||||
if (!domainID.isNull()) {
|
||||
const auto& key = getTemporaryDomainKey(domainID);
|
||||
QHttpPart apiKeyPart;
|
||||
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||
apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant("form-data; name=\"api_key\""));
|
||||
apiKeyPart.setBody(key.toUtf8());
|
||||
requestMultiPart->append(apiKeyPart);
|
||||
}
|
||||
|
||||
// setup callback parameters so we know once the keypair upload has succeeded or failed
|
||||
JSONCallbackParameters callbackParameters;
|
||||
callbackParameters.jsonCallbackReceiver = this;
|
||||
callbackParameters.jsonCallbackMethod = "publicKeyUploadSucceeded";
|
||||
callbackParameters.errorCallbackReceiver = this;
|
||||
callbackParameters.errorCallbackMethod = "publicKeyUploadFailed";
|
||||
|
||||
sendRequest(uploadPath, AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation,
|
||||
callbackParameters, QByteArray(), requestMultiPart);
|
||||
|
||||
keypairGenerator->deleteLater();
|
||||
QString uploadPath;
|
||||
const auto& domainID = _accountInfo.getDomainID();
|
||||
if (domainID.isNull()) {
|
||||
uploadPath = USER_PUBLIC_KEY_UPDATE_PATH;
|
||||
} else {
|
||||
qCWarning(networking) << "Expected processGeneratedKeypair to be called by a live RSAKeypairGenerator"
|
||||
<< "but the casted sender is NULL. Will not process generated keypair.";
|
||||
uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID));
|
||||
}
|
||||
|
||||
// setup a multipart upload to send up the public key
|
||||
QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
QHttpPart publicKeyPart;
|
||||
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||
|
||||
publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant("form-data; name=\"public_key\"; filename=\"public_key\""));
|
||||
publicKeyPart.setBody(publicKey);
|
||||
requestMultiPart->append(publicKeyPart);
|
||||
|
||||
// Currently broken? We don't have the temporary domain key.
|
||||
if (!domainID.isNull()) {
|
||||
const auto& key = getTemporaryDomainKey(domainID);
|
||||
QHttpPart apiKeyPart;
|
||||
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||
apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant("form-data; name=\"api_key\""));
|
||||
apiKeyPart.setBody(key.toUtf8());
|
||||
requestMultiPart->append(apiKeyPart);
|
||||
}
|
||||
|
||||
// setup callback parameters so we know once the keypair upload has succeeded or failed
|
||||
JSONCallbackParameters callbackParameters;
|
||||
callbackParameters.jsonCallbackReceiver = this;
|
||||
callbackParameters.jsonCallbackMethod = "publicKeyUploadSucceeded";
|
||||
callbackParameters.errorCallbackReceiver = this;
|
||||
callbackParameters.errorCallbackMethod = "publicKeyUploadFailed";
|
||||
|
||||
sendRequest(uploadPath, AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation,
|
||||
callbackParameters, QByteArray(), requestMultiPart);
|
||||
}
|
||||
|
||||
void AccountManager::publicKeyUploadSucceeded(QNetworkReply& reply) {
|
||||
|
@ -877,6 +862,4 @@ void AccountManager::handleKeypairGenerationError() {
|
|||
|
||||
// reset our waiting state for keypair response
|
||||
_isWaitingForKeypairResponse = false;
|
||||
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ signals:
|
|||
private slots:
|
||||
void processReply();
|
||||
void handleKeypairGenerationError();
|
||||
void processGeneratedKeypair();
|
||||
void processGeneratedKeypair(QByteArray publicKey, QByteArray privateKey);
|
||||
void publicKeyUploadSucceeded(QNetworkReply& reply);
|
||||
void publicKeyUploadFailed(QNetworkReply& reply);
|
||||
void generateNewKeypair(bool isUserKeypair = true, const QUuid& domainID = QUuid());
|
||||
|
|
|
@ -25,7 +25,10 @@
|
|||
RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RSAKeypairGenerator::run() {
|
||||
generateKeypair();
|
||||
}
|
||||
|
||||
void RSAKeypairGenerator::generateKeypair() {
|
||||
|
@ -92,5 +95,5 @@ void RSAKeypairGenerator::generateKeypair() {
|
|||
OPENSSL_free(publicKeyDER);
|
||||
OPENSSL_free(privateKeyDER);
|
||||
|
||||
emit generatedKeypair();
|
||||
emit generatedKeypair(_publicKey, _privateKey);
|
||||
}
|
||||
|
|
|
@ -13,25 +13,20 @@
|
|||
#define hifi_RSAKeypairGenerator_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QRunnable>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
class RSAKeypairGenerator : public QObject {
|
||||
class RSAKeypairGenerator : public QObject, public QRunnable {
|
||||
Q_OBJECT
|
||||
public:
|
||||
RSAKeypairGenerator(QObject* parent = 0);
|
||||
RSAKeypairGenerator(QObject* parent = nullptr);
|
||||
|
||||
void setDomainID(const QUuid& domainID) { _domainID = domainID; }
|
||||
const QUuid& getDomainID() const { return _domainID; }
|
||||
|
||||
const QByteArray& getPublicKey() const { return _publicKey; }
|
||||
const QByteArray& getPrivateKey() const { return _privateKey; }
|
||||
|
||||
public slots:
|
||||
virtual void run() override;
|
||||
void generateKeypair();
|
||||
|
||||
signals:
|
||||
void errorGeneratingKeypair();
|
||||
void generatedKeypair();
|
||||
void generatedKeypair(QByteArray publicKey, QByteArray privateKey);
|
||||
|
||||
private:
|
||||
QUuid _domainID;
|
||||
|
|
|
@ -159,6 +159,13 @@ void ObjectDynamic::removeFromSimulation(EntitySimulationPointer simulation) con
|
|||
simulation->removeDynamic(myID);
|
||||
}
|
||||
|
||||
void ObjectDynamic::setOwnerEntity(const EntityItemPointer ownerEntity) {
|
||||
if (!ownerEntity) {
|
||||
activateBody();
|
||||
}
|
||||
_ownerEntity = ownerEntity;
|
||||
}
|
||||
|
||||
EntityItemPointer ObjectDynamic::getEntityByID(EntityItemID entityID) const {
|
||||
EntityItemPointer ownerEntity;
|
||||
withReadLock([&]{
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
|
||||
virtual void removeFromSimulation(EntitySimulationPointer simulation) const override;
|
||||
virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; }
|
||||
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) override { _ownerEntity = ownerEntity; }
|
||||
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) override;
|
||||
|
||||
virtual void invalidate() {};
|
||||
|
||||
|
|
|
@ -215,10 +215,7 @@ void CauterizedModel::updateRenderItems() {
|
|||
modelTransform.setRotation(self->getRotation());
|
||||
|
||||
bool isWireframe = self->isWireframe();
|
||||
bool isVisible = self->isVisible();
|
||||
bool canCastShadow = self->canCastShadow();
|
||||
bool isLayeredInFront = self->isLayeredInFront();
|
||||
bool isLayeredInHUD = self->isLayeredInHUD();
|
||||
auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
|
||||
bool enableCauterization = self->getEnableCauterization();
|
||||
|
||||
render::Transaction transaction;
|
||||
|
@ -234,7 +231,7 @@ void CauterizedModel::updateRenderItems() {
|
|||
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
|
||||
|
||||
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
|
||||
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization](CauterizedMeshPartPayload& data) {
|
||||
isWireframe, renderItemKeyGlobalFlags, enableCauterization](CauterizedMeshPartPayload& data) {
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions,
|
||||
cauterizedMeshState.clusterDualQuaternions);
|
||||
|
@ -276,8 +273,7 @@ void CauterizedModel::updateRenderItems() {
|
|||
data.updateTransformForCauterizedMesh(renderTransform);
|
||||
|
||||
data.setEnableCauterization(enableCauterization);
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -79,28 +79,10 @@ void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) {
|
|||
_drawMaterials.remove(material);
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) {
|
||||
ItemKey::Builder builder;
|
||||
void MeshPartPayload::updateKey(const render::ItemKey& key) {
|
||||
ItemKey::Builder builder(key);
|
||||
builder.withTypeShape();
|
||||
|
||||
if (!isVisible) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
builder.withTagBits(tagBits);
|
||||
|
||||
if (isLayered) {
|
||||
builder.withLayered();
|
||||
}
|
||||
|
||||
if (canCastShadow) {
|
||||
builder.withShadowCaster();
|
||||
}
|
||||
|
||||
if (isGroupCulled) {
|
||||
builder.withSubMetaCulled();
|
||||
}
|
||||
|
||||
if (topMaterialExists()) {
|
||||
auto matKey = _drawMaterials.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
|
@ -200,12 +182,6 @@ template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointe
|
|||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
template <> int payloadGetLayer(const ModelMeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getLayer();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
|
@ -332,28 +308,10 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
|
|||
}
|
||||
|
||||
// Note that this method is called for models but not for shapes
|
||||
void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) {
|
||||
ItemKey::Builder builder;
|
||||
void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
|
||||
ItemKey::Builder builder(key);
|
||||
builder.withTypeShape();
|
||||
|
||||
if (!isVisible) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
builder.withTagBits(tagBits);
|
||||
|
||||
if (isLayered) {
|
||||
builder.withLayered();
|
||||
}
|
||||
|
||||
if (canCastShadow) {
|
||||
builder.withShadowCaster();
|
||||
}
|
||||
|
||||
if (isGroupCulled) {
|
||||
builder.withSubMetaCulled();
|
||||
}
|
||||
|
||||
if (_isBlendShaped || _isSkinned) {
|
||||
builder.withDeformed();
|
||||
}
|
||||
|
@ -368,20 +326,6 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCas
|
|||
_itemKey = builder.build();
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) {
|
||||
if (isLayeredInFront) {
|
||||
_layer = Item::LAYER_3D_FRONT;
|
||||
} else if (isLayeredInHUD) {
|
||||
_layer = Item::LAYER_3D_HUD;
|
||||
} else {
|
||||
_layer = Item::LAYER_3D;
|
||||
}
|
||||
}
|
||||
|
||||
int ModelMeshPartPayload::getLayer() const {
|
||||
return _layer;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning) {
|
||||
if (invalidateShapeKey) {
|
||||
_shapeKey = ShapeKey::Builder::invalid();
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
typedef render::Payload<MeshPartPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
virtual void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false);
|
||||
virtual void updateKey(const render::ItemKey& key);
|
||||
|
||||
virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
|
||||
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
|
||||
void notifyLocationChanged() override;
|
||||
|
||||
void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false) override;
|
||||
void updateKey(const render::ItemKey& key) override;
|
||||
|
||||
// matrix palette skinning
|
||||
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices);
|
||||
|
@ -105,11 +105,9 @@ public:
|
|||
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
|
||||
|
||||
// Render Item interface
|
||||
int getLayer() const;
|
||||
render::ShapeKey getShapeKey() const override; // shape interface
|
||||
void render(RenderArgs* args) override;
|
||||
|
||||
void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
|
||||
void setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning);
|
||||
|
||||
// ModelMeshPartPayload functions to perform render
|
||||
|
@ -139,13 +137,11 @@ private:
|
|||
|
||||
gpu::BufferPointer _blendedVertexBuffer;
|
||||
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
|
||||
int _layer { render::Item::LAYER_3D };
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> int payloadGetLayer(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
|
|
@ -103,11 +103,10 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) :
|
|||
_snapModelToRegistrationPoint(false),
|
||||
_snappedToRegistrationPoint(false),
|
||||
_url(HTTP_INVALID_COM),
|
||||
_isVisible(true),
|
||||
_canCastShadow(false),
|
||||
_blendNumber(0),
|
||||
_appliedBlendNumber(0),
|
||||
_isWireframe(false)
|
||||
_isWireframe(false),
|
||||
_renderItemKeyGlobalFlags(render::ItemKey::Builder().withVisible().withTagBits(render::hifi::TAG_ALL_VIEWS).build())
|
||||
{
|
||||
// we may have been created in the network thread, but we live in the main thread
|
||||
if (_viewState) {
|
||||
|
@ -268,12 +267,7 @@ void Model::updateRenderItems() {
|
|||
modelTransform.setScale(glm::vec3(1.0f));
|
||||
|
||||
bool isWireframe = self->isWireframe();
|
||||
bool isVisible = self->isVisible();
|
||||
bool canCastShadow = self->canCastShadow();
|
||||
uint8_t viewTagBits = self->getViewTagBits();
|
||||
bool isLayeredInFront = self->isLayeredInFront();
|
||||
bool isLayeredInHUD = self->isLayeredInHUD();
|
||||
bool isGroupCulled = self->isGroupCulled();
|
||||
auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
|
||||
|
||||
render::Transaction transaction;
|
||||
for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
|
||||
|
@ -287,9 +281,7 @@ void Model::updateRenderItems() {
|
|||
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
|
||||
invalidatePayloadShapeKey, isWireframe, isVisible,
|
||||
canCastShadow, viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
invalidatePayloadShapeKey, isWireframe, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) {
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions);
|
||||
} else {
|
||||
|
@ -313,8 +305,7 @@ void Model::updateRenderItems() {
|
|||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning);
|
||||
});
|
||||
}
|
||||
|
@ -322,8 +313,9 @@ void Model::updateRenderItems() {
|
|||
Transform collisionMeshOffset;
|
||||
collisionMeshOffset.setIdentity();
|
||||
foreach(auto itemID, self->_collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<MeshPartPayload>(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) {
|
||||
transaction.updateItem<MeshPartPayload>(itemID, [renderItemKeyGlobalFlags, modelTransform, collisionMeshOffset](MeshPartPayload& data) {
|
||||
// update the model transform for this render item.
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.updateTransform(modelTransform, collisionMeshOffset);
|
||||
});
|
||||
}
|
||||
|
@ -773,110 +765,100 @@ void Model::calculateTriangleSets(const FBXGeometry& geometry) {
|
|||
}
|
||||
}
|
||||
|
||||
void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) {
|
||||
if (_isVisible != isVisible || _viewTagBits != viewTagBits || _isGroupCulled != isGroupCulled) {
|
||||
_isVisible = isVisible;
|
||||
_viewTagBits = viewTagBits;
|
||||
_isGroupCulled = isGroupCulled;
|
||||
void Model::updateRenderItemsKey(const render::ScenePointer& scene) {
|
||||
if (!scene) {
|
||||
_needsFixupInScene = true;
|
||||
return;
|
||||
}
|
||||
auto renderItemsKey = _renderItemKeyGlobalFlags;
|
||||
render::Transaction transaction;
|
||||
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
|
||||
data.updateKey(renderItemsKey);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
|
||||
data.updateKey(renderItemsKey);
|
||||
});
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
bool isLayeredInFront = _isLayeredInFront;
|
||||
bool isLayeredInHUD = _isLayeredInHUD;
|
||||
bool canCastShadow = _canCastShadow;
|
||||
render::Transaction transaction;
|
||||
foreach (auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
|
||||
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
|
||||
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
|
||||
});
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
void Model::setVisibleInScene(bool visible, const render::ScenePointer& scene) {
|
||||
if (Model::isVisible() != visible) {
|
||||
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
|
||||
_renderItemKeyGlobalFlags = (visible ? keyBuilder.withVisible() : keyBuilder.withInvisible());
|
||||
updateRenderItemsKey(scene);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) {
|
||||
if (_canCastShadow != canCastShadow) {
|
||||
_canCastShadow = canCastShadow;
|
||||
bool Model::isVisible() const {
|
||||
return _renderItemKeyGlobalFlags.isVisible();
|
||||
}
|
||||
|
||||
bool isVisible = _isVisible;
|
||||
bool isLayeredInFront = _isLayeredInFront;
|
||||
bool isLayeredInHUD = _isLayeredInHUD;
|
||||
|
||||
render::Transaction transaction;
|
||||
foreach (auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item,
|
||||
[isVisible, viewTagBits, canCastShadow, isLayeredInFront, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, viewTagBits, canCastShadow, isLayeredInFront || isLayeredInHUD, isGroupCulled);
|
||||
});
|
||||
}
|
||||
|
||||
scene->enqueueTransaction(transaction);
|
||||
void Model::setCanCastShadow(bool castShadow, const render::ScenePointer& scene) {
|
||||
if (Model::canCastShadow() != castShadow) {
|
||||
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
|
||||
_renderItemKeyGlobalFlags = (castShadow ? keyBuilder.withShadowCaster() : keyBuilder.withoutShadowCaster());
|
||||
updateRenderItemsKey(scene);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) {
|
||||
if (_isLayeredInFront != isLayeredInFront) {
|
||||
_isLayeredInFront = isLayeredInFront;
|
||||
bool Model::canCastShadow() const {
|
||||
return _renderItemKeyGlobalFlags.isShadowCaster();
|
||||
}
|
||||
|
||||
bool isVisible = _isVisible;
|
||||
bool canCastShadow = _canCastShadow;
|
||||
uint8_t viewTagBits = _viewTagBits;
|
||||
bool isLayeredInHUD = _isLayeredInHUD;
|
||||
bool isGroupCulled = _isGroupCulled;
|
||||
|
||||
render::Transaction transaction;
|
||||
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
|
||||
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
|
||||
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
});
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
void Model::setLayeredInFront(bool layeredInFront, const render::ScenePointer& scene) {
|
||||
if (Model::isLayeredInFront() != layeredInFront) {
|
||||
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
|
||||
_renderItemKeyGlobalFlags = (layeredInFront ? keyBuilder.withLayer(render::hifi::LAYER_3D_FRONT) : keyBuilder.withoutLayer());
|
||||
updateRenderItemsKey(scene);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene) {
|
||||
if (_isLayeredInHUD != isLayeredInHUD) {
|
||||
_isLayeredInHUD = isLayeredInHUD;
|
||||
bool Model::isLayeredInFront() const {
|
||||
return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_FRONT);
|
||||
}
|
||||
|
||||
bool isVisible = _isVisible;
|
||||
bool canCastShadow = _canCastShadow;
|
||||
uint8_t viewTagBits = _viewTagBits;
|
||||
bool isLayeredInFront = _isLayeredInFront;
|
||||
bool isGroupCulled = _isGroupCulled;
|
||||
|
||||
render::Transaction transaction;
|
||||
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
|
||||
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
|
||||
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
});
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
void Model::setLayeredInHUD(bool layeredInHUD, const render::ScenePointer& scene) {
|
||||
if (Model::isLayeredInHUD() != layeredInHUD) {
|
||||
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
|
||||
_renderItemKeyGlobalFlags = (layeredInHUD ? keyBuilder.withLayer(render::hifi::LAYER_3D_HUD) : keyBuilder.withoutLayer());
|
||||
updateRenderItemsKey(scene);
|
||||
}
|
||||
}
|
||||
|
||||
bool Model::isLayeredInHUD() const {
|
||||
return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_HUD);
|
||||
}
|
||||
|
||||
void Model::setTagMask(uint8_t mask, const render::ScenePointer& scene) {
|
||||
if (Model::getTagMask() != mask) {
|
||||
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
|
||||
_renderItemKeyGlobalFlags = keyBuilder.withTagBits(mask);
|
||||
updateRenderItemsKey(scene);
|
||||
}
|
||||
}
|
||||
render::hifi::Tag Model::getTagMask() const {
|
||||
return (render::hifi::Tag) _renderItemKeyGlobalFlags.getTagBits();
|
||||
}
|
||||
|
||||
void Model::setGroupCulled(bool groupCulled, const render::ScenePointer& scene) {
|
||||
if (Model::isGroupCulled() != groupCulled) {
|
||||
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
|
||||
_renderItemKeyGlobalFlags = (groupCulled ? keyBuilder.withSubMetaCulled() : keyBuilder.withoutSubMetaCulled());
|
||||
updateRenderItemsKey(scene);
|
||||
}
|
||||
}
|
||||
bool Model::isGroupCulled() const {
|
||||
return _renderItemKeyGlobalFlags.isSubMetaCulled();
|
||||
}
|
||||
|
||||
const render::ItemKey Model::getRenderItemKeyGlobalFlags() const {
|
||||
return _renderItemKeyGlobalFlags;
|
||||
}
|
||||
|
||||
bool Model::addToScene(const render::ScenePointer& scene,
|
||||
render::Transaction& transaction,
|
||||
render::Item::Status::Getters& statusGetters) {
|
||||
|
@ -1676,20 +1658,16 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par
|
|||
for (auto shapeID : shapeIDs) {
|
||||
if (shapeID < _modelMeshRenderItemIDs.size()) {
|
||||
auto itemID = _modelMeshRenderItemIDs[shapeID];
|
||||
bool visible = isVisible();
|
||||
uint8_t viewTagBits = getViewTagBits();
|
||||
bool layeredInFront = isLayeredInFront();
|
||||
bool layeredInHUD = isLayeredInHUD();
|
||||
bool canCastShadow = _canCastShadow;
|
||||
auto renderItemsKey = _renderItemKeyGlobalFlags;
|
||||
bool wireframe = isWireframe();
|
||||
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
|
||||
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow,
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
|
||||
invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
|
||||
data.addMaterial(material);
|
||||
// if the material changed, we might need to update our item key or shape key
|
||||
data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits);
|
||||
data.updateKey(renderItemsKey);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning);
|
||||
});
|
||||
}
|
||||
|
@ -1704,19 +1682,16 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string
|
|||
if (shapeID < _modelMeshRenderItemIDs.size()) {
|
||||
auto itemID = _modelMeshRenderItemIDs[shapeID];
|
||||
bool visible = isVisible();
|
||||
uint8_t viewTagBits = getViewTagBits();
|
||||
bool layeredInFront = isLayeredInFront();
|
||||
bool layeredInHUD = isLayeredInHUD();
|
||||
bool canCastShadow = _canCastShadow;
|
||||
auto renderItemsKey = _renderItemKeyGlobalFlags;
|
||||
bool wireframe = isWireframe();
|
||||
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
|
||||
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow,
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, renderItemsKey,
|
||||
invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
|
||||
data.removeMaterial(material);
|
||||
// if the material changed, we might need to update our item key or shape key
|
||||
data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits);
|
||||
data.updateKey(renderItemsKey);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <TriangleSet.h>
|
||||
#include <DualQuaternion.h>
|
||||
|
||||
#include "RenderHifi.h"
|
||||
#include "GeometryCache.h"
|
||||
#include "TextureCache.h"
|
||||
#include "Rig.h"
|
||||
|
@ -87,13 +88,27 @@ public:
|
|||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
// new Scene/Engine rendering support
|
||||
void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled);
|
||||
void setVisibleInScene(bool isVisible, const render::ScenePointer& scene = nullptr);
|
||||
bool isVisible() const;
|
||||
|
||||
bool canCastShadow() const { return _canCastShadow; }
|
||||
void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled);
|
||||
render::hifi::Tag getTagMask() const;
|
||||
void setTagMask(uint8_t mask, const render::ScenePointer& scene = nullptr);
|
||||
|
||||
bool isGroupCulled() const;
|
||||
void setGroupCulled(bool isGroupCulled, const render::ScenePointer& scene = nullptr);
|
||||
|
||||
bool canCastShadow() const;
|
||||
void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene = nullptr);
|
||||
|
||||
void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene = nullptr);
|
||||
void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene = nullptr);
|
||||
|
||||
bool isLayeredInFront() const;
|
||||
bool isLayeredInHUD() const;
|
||||
|
||||
// Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model.
|
||||
const render::ItemKey getRenderItemKeyGlobalFlags() const;
|
||||
|
||||
void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene);
|
||||
void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene);
|
||||
bool needsFixupInScene() const;
|
||||
|
||||
bool needsReload() const { return _needsReload; }
|
||||
|
@ -108,13 +123,7 @@ public:
|
|||
void removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction);
|
||||
bool isRenderable() const;
|
||||
|
||||
bool isVisible() const { return _isVisible; }
|
||||
uint8_t getViewTagBits() const { return _viewTagBits; }
|
||||
|
||||
bool isLayeredInFront() const { return _isLayeredInFront; }
|
||||
bool isLayeredInHUD() const { return _isLayeredInHUD; }
|
||||
|
||||
bool isGroupCulled() const { return _isGroupCulled; }
|
||||
void updateRenderItemsKey(const render::ScenePointer& scene);
|
||||
|
||||
virtual void updateRenderItems();
|
||||
void setRenderItemsNeedUpdate();
|
||||
|
@ -404,10 +413,6 @@ protected:
|
|||
QVector<float> _blendshapeCoefficients;
|
||||
|
||||
QUrl _url;
|
||||
bool _isVisible;
|
||||
uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL };
|
||||
|
||||
bool _canCastShadow;
|
||||
|
||||
gpu::Buffers _blendedVertexBuffers;
|
||||
|
||||
|
@ -471,10 +476,16 @@ protected:
|
|||
int _renderInfoDrawCalls { 0 };
|
||||
int _renderInfoHasTransparent { false };
|
||||
|
||||
bool _isLayeredInFront { false };
|
||||
bool _isLayeredInHUD { false };
|
||||
|
||||
bool _isGroupCulled{ false };
|
||||
// This Render ItemKey Global Flags capture the Model wide global set of flags that should be communicated to all the render items representing the Model.
|
||||
// The flags concerned are:
|
||||
// - isVisible: if true the Model is visible globally in the scene, regardless of the other flags in the item keys (tags or layer or shadow caster).
|
||||
// - TagBits: the view mask defined through the TagBits telling in which view the Model is rendered if visible.
|
||||
// - Layer: In which Layer this Model lives.
|
||||
// - CastShadow: if true and visible and rendered in the view, the Model cast shadows if in a Light volume casting shadows.
|
||||
// - CullGroup: if true, the render items representing the parts of the Model are culled by a single Meta render item that knows about them, they are not culled individually.
|
||||
// For this to work, a Meta RI must exists and knows about the RIs of this Model.
|
||||
//
|
||||
render::ItemKey _renderItemKeyGlobalFlags;
|
||||
|
||||
bool shouldInvalidatePayloadShapeKey(int meshIndex);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <render/DrawSceneOctree.h>
|
||||
#include <render/BlurTask.h>
|
||||
|
||||
#include "RenderHifi.h"
|
||||
#include "RenderCommonTask.h"
|
||||
#include "LightingModel.h"
|
||||
#include "StencilMaskPass.h"
|
||||
|
@ -200,8 +201,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
const auto overlaysInFrontRangeTimer = task.addJob<BeginGPURangeTimer>("BeginOverlaysInFrontRangeTimer", "BeginOverlaysInFrontRangeTimer");
|
||||
|
||||
// Layered Overlays
|
||||
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT);
|
||||
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT);
|
||||
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, render::hifi::LAYER_3D_FRONT);
|
||||
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, render::hifi::LAYER_3D_FRONT);
|
||||
const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0);
|
||||
const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0);
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <render/FilterTask.h>
|
||||
|
||||
#include "RenderHifi.h"
|
||||
#include "StencilMaskPass.h"
|
||||
#include "ZoneRenderer.h"
|
||||
#include "FadeEffect.h"
|
||||
|
@ -79,8 +80,8 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
|
|||
task.addJob<PrepareStencil>("PrepareStencil", framebuffer);
|
||||
|
||||
// Layered Overlays
|
||||
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT);
|
||||
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT);
|
||||
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, render::hifi::LAYER_3D_FRONT);
|
||||
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, render::hifi::LAYER_3D_FRONT);
|
||||
const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0);
|
||||
const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0);
|
||||
|
||||
|
|
43
libraries/render-utils/src/RenderHifi.h
Normal file
43
libraries/render-utils/src/RenderHifi.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// RenderHifi.h
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Sam Gateau on 5/30/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_RenderHifi_h
|
||||
#define hifi_RenderHifi_h
|
||||
|
||||
#include <render/Item.h>
|
||||
|
||||
|
||||
|
||||
// In the library render-utils we are specializing the generic components of the render library to create the custom hifi render engine
|
||||
// Objects and types serving this goal are define in the namespace render.hifi
|
||||
// TODO: extend the namespace to all the classes where it make sense in render-utils
|
||||
namespace render {
|
||||
namespace hifi {
|
||||
|
||||
// Tag is the alias names of render::ItemKey::Tag combinations used in the Hifi Render Engine
|
||||
enum Tag : uint8_t {
|
||||
TAG_NONE = render::ItemKey::TAG_BITS_NONE, // No Tags at all
|
||||
TAG_MAIN_VIEW = render::ItemKey::TAG_BITS_0, // Main view
|
||||
TAG_SECONDARY_VIEW = render::ItemKey::TAG_BITS_1, // Secondary View
|
||||
TAG_ALL_VIEWS = TAG_MAIN_VIEW | TAG_SECONDARY_VIEW, // All views
|
||||
};
|
||||
|
||||
// Layer is the alias names of the render::ItemKey::Layer used in the Hifi Render Engine
|
||||
enum Layer : uint8_t {
|
||||
LAYER_3D = render::ItemKey::LAYER_DEFAULT,
|
||||
LAYER_3D_FRONT = render::ItemKey::LAYER_1,
|
||||
LAYER_3D_HUD = render::ItemKey::LAYER_2,
|
||||
LAYER_2D = render::ItemKey::LAYER_3,
|
||||
LAYER_BACKGROUND = render::ItemKey::LAYER_BACKGROUND,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // hifi_RenderHifi_h
|
|
@ -368,9 +368,9 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
|
|||
RenderArgs* args = renderContext->args;
|
||||
|
||||
const auto& inShapes = inputs.get0();
|
||||
const auto& cullFilter = inputs.get1();
|
||||
const auto& boundsFilter = inputs.get2();
|
||||
const auto& antiFrustum = inputs.get3();
|
||||
const auto& cullFilter = inputs.get1();
|
||||
const auto& boundsFilter = inputs.get2();
|
||||
const auto& antiFrustum = inputs.get3();
|
||||
auto& outShapes = outputs.edit0();
|
||||
auto& outBounds = outputs.edit1();
|
||||
|
||||
|
@ -380,7 +380,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
|
|||
if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) {
|
||||
auto& details = args->_details.edit(_detailType);
|
||||
Test test(_cullFunctor, args, details, antiFrustum);
|
||||
auto scene = args->_scene;
|
||||
auto scene = args->_scene;
|
||||
|
||||
for (auto& inItems : inShapes) {
|
||||
auto key = inItems.first;
|
||||
|
@ -395,26 +395,26 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
|
|||
if (antiFrustum == nullptr) {
|
||||
for (auto& item : inItems.second) {
|
||||
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) {
|
||||
const auto shapeKey = scene->getItem(item.id).getKey();
|
||||
if (cullFilter.test(shapeKey)) {
|
||||
outItems->second.emplace_back(item);
|
||||
}
|
||||
if (boundsFilter.test(shapeKey)) {
|
||||
outBounds += item.bound;
|
||||
}
|
||||
const auto shapeKey = scene->getItem(item.id).getKey();
|
||||
if (cullFilter.test(shapeKey)) {
|
||||
outItems->second.emplace_back(item);
|
||||
}
|
||||
if (boundsFilter.test(shapeKey)) {
|
||||
outBounds += item.bound;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto& item : inItems.second) {
|
||||
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) {
|
||||
const auto shapeKey = scene->getItem(item.id).getKey();
|
||||
if (cullFilter.test(shapeKey)) {
|
||||
outItems->second.emplace_back(item);
|
||||
}
|
||||
if (boundsFilter.test(shapeKey)) {
|
||||
outBounds += item.bound;
|
||||
}
|
||||
}
|
||||
const auto shapeKey = scene->getItem(item.id).getKey();
|
||||
if (cullFilter.test(shapeKey)) {
|
||||
outItems->second.emplace_back(item);
|
||||
}
|
||||
if (boundsFilter.test(shapeKey)) {
|
||||
outBounds += item.bound;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
details._rendered += (int)outItems->second.size();
|
||||
|
@ -487,6 +487,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
if (filter.test(item.getKey())) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
outItems.emplace_back(itemBound);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,25 +29,9 @@ const float Item::Status::Value::CYAN = 180.0f;
|
|||
const float Item::Status::Value::BLUE = 240.0f;
|
||||
const float Item::Status::Value::MAGENTA = 300.0f;
|
||||
|
||||
const int Item::LAYER_2D = 0;
|
||||
const int Item::LAYER_3D = 1;
|
||||
const int Item::LAYER_3D_FRONT = 2;
|
||||
const int Item::LAYER_3D_HUD = 3;
|
||||
|
||||
const uint8_t ItemKey::TAG_BITS_ALL { 0xFF };
|
||||
const uint8_t ItemKey::TAG_BITS_NONE { 0x00 };
|
||||
const uint8_t ItemKey::TAG_BITS_0 { 0x01 };
|
||||
const uint8_t ItemKey::TAG_BITS_1 { 0x02 };
|
||||
const uint8_t ItemKey::TAG_BITS_2 { 0x04 };
|
||||
const uint8_t ItemKey::TAG_BITS_3 { 0x08 };
|
||||
const uint8_t ItemKey::TAG_BITS_4 { 0x10 };
|
||||
const uint8_t ItemKey::TAG_BITS_5 { 0x20 };
|
||||
const uint8_t ItemKey::TAG_BITS_6 { 0x40 };
|
||||
const uint8_t ItemKey::TAG_BITS_7 { 0x80 };
|
||||
|
||||
const uint32_t ItemKey::KEY_TAG_BITS_MASK = ((uint32_t) ItemKey::TAG_BITS_ALL) << FIRST_TAG_BIT;
|
||||
|
||||
|
||||
const uint32_t ItemKey::KEY_LAYER_BITS_MASK = ((uint32_t)ItemKey::LAYER_BITS_ALL) << FIRST_LAYER_BIT;
|
||||
|
||||
void Item::Status::Value::setScale(float scale) {
|
||||
_scale = (std::numeric_limits<unsigned short>::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f));
|
||||
|
|
|
@ -52,23 +52,45 @@ public:
|
|||
TAG_6,
|
||||
TAG_7,
|
||||
|
||||
NUM_TAGS
|
||||
NUM_TAGS,
|
||||
|
||||
// Tag bits are derived from the Tag enum
|
||||
TAG_BITS_ALL = 0xFF,
|
||||
TAG_BITS_NONE = 0x00,
|
||||
TAG_BITS_0 = 0x01,
|
||||
TAG_BITS_1 = 0x02,
|
||||
TAG_BITS_2 = 0x04,
|
||||
TAG_BITS_3 = 0x08,
|
||||
TAG_BITS_4 = 0x10,
|
||||
TAG_BITS_5 = 0x20,
|
||||
TAG_BITS_6 = 0x40,
|
||||
TAG_BITS_7 = 0x80,
|
||||
};
|
||||
|
||||
// Items are organized in layers, an item belongs to one of the 8 Layers available.
|
||||
// By default an item is in the 'LAYER_DEFAULT' meaning that it is NOT layered.
|
||||
// THere is NO ordering relationship between layers.
|
||||
enum Layer : uint8_t {
|
||||
LAYER_DEFAULT = 0, // layer 0 aka Default is a 'NOT' layer, items are not considered layered, this is the default value
|
||||
LAYER_1,
|
||||
LAYER_2,
|
||||
LAYER_3,
|
||||
LAYER_4,
|
||||
LAYER_5,
|
||||
LAYER_6,
|
||||
LAYER_BACKGROUND, // Last Layer is the background by convention
|
||||
|
||||
NUM_LAYERS,
|
||||
|
||||
// Layer bits are derived from the Layer enum, the number of bits needed to represent integer 0 to NUM_LAYERS
|
||||
NUM_LAYER_BITS = 3,
|
||||
LAYER_BITS_ALL = 0x07,
|
||||
};
|
||||
// Tag bits are derived from the Tag enum
|
||||
const static uint8_t TAG_BITS_ALL;
|
||||
const static uint8_t TAG_BITS_NONE;
|
||||
const static uint8_t TAG_BITS_0;
|
||||
const static uint8_t TAG_BITS_1;
|
||||
const static uint8_t TAG_BITS_2;
|
||||
const static uint8_t TAG_BITS_3;
|
||||
const static uint8_t TAG_BITS_4;
|
||||
const static uint8_t TAG_BITS_5;
|
||||
const static uint8_t TAG_BITS_6;
|
||||
const static uint8_t TAG_BITS_7;
|
||||
|
||||
enum FlagBit : uint32_t {
|
||||
TYPE_SHAPE = 0, // Item is a Shape
|
||||
TYPE_LIGHT, // Item is a Light
|
||||
TYPE_SHAPE = 0, // Item is a Shape: Implements the Shape Interface that draw a Geometry rendered with a Material
|
||||
TYPE_LIGHT, // Item is a Light: Implements the Light Interface that
|
||||
TYPE_CAMERA, // Item is a Camera: Implements the Camera Interface
|
||||
TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items
|
||||
|
||||
TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work...
|
||||
|
@ -77,13 +99,15 @@ public:
|
|||
DEFORMED, // Deformed within bound, not solid
|
||||
INVISIBLE, // Visible or not in the scene?
|
||||
SHADOW_CASTER, // Item cast shadows
|
||||
LAYERED, // Item belongs to one of the layers different from the default layer
|
||||
META_CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the view
|
||||
SUB_META_CULLED, // As a sub item of a meta render item set as cull group, need to be set to my culling to the meta render it
|
||||
|
||||
FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against
|
||||
LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS,
|
||||
|
||||
FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer
|
||||
LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS,
|
||||
|
||||
__SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells)
|
||||
|
||||
NUM_FLAGS, // Not a valid flag
|
||||
|
@ -96,6 +120,12 @@ public:
|
|||
return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT);
|
||||
}
|
||||
|
||||
// All the bits touching layer bits sets to true
|
||||
const static uint32_t KEY_LAYER_BITS_MASK;
|
||||
static uint32_t evalLayerBitsWithKeyBits(uint8_t layer, const uint32_t keyBits) {
|
||||
return (keyBits & ~KEY_LAYER_BITS_MASK) | (((uint32_t)layer & LAYER_BITS_ALL) << FIRST_LAYER_BIT);
|
||||
}
|
||||
|
||||
// The key is the Flags
|
||||
Flags _flags;
|
||||
|
||||
|
@ -124,19 +154,24 @@ public:
|
|||
Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
|
||||
Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); }
|
||||
Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
|
||||
Builder& withLayered() { _flags.set(LAYERED); return (*this); }
|
||||
Builder& withoutShadowCaster() { _flags.reset(SHADOW_CASTER); return (*this); }
|
||||
Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); }
|
||||
Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); }
|
||||
Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); }
|
||||
Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); }
|
||||
|
||||
Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); }
|
||||
// Set ALL the tags in one call using the Tag bits
|
||||
Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); }
|
||||
|
||||
Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong()); return (*this); }
|
||||
Builder& withoutLayer() { return withLayer(LAYER_DEFAULT); }
|
||||
|
||||
// Convenient standard keys that we will keep on using all over the place
|
||||
static Builder opaqueShape() { return Builder().withTypeShape(); }
|
||||
static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); }
|
||||
static Builder light() { return Builder().withTypeLight(); }
|
||||
static Builder background() { return Builder().withViewSpace().withLayered(); }
|
||||
static Builder background() { return Builder().withViewSpace().withLayer(LAYER_BACKGROUND); }
|
||||
};
|
||||
ItemKey(const Builder& builder) : ItemKey(builder._flags) {}
|
||||
|
||||
|
@ -161,9 +196,6 @@ public:
|
|||
|
||||
bool isShadowCaster() const { return _flags[SHADOW_CASTER]; }
|
||||
|
||||
bool isLayered() const { return _flags[LAYERED]; }
|
||||
bool isSpatial() const { return !isLayered(); }
|
||||
|
||||
bool isMetaCullGroup() const { return _flags[META_CULL_GROUP]; }
|
||||
void setMetaCullGroup(bool cullGroup) { (cullGroup ? _flags.set(META_CULL_GROUP) : _flags.reset(META_CULL_GROUP)); }
|
||||
|
||||
|
@ -173,6 +205,11 @@ public:
|
|||
bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; }
|
||||
uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); }
|
||||
|
||||
uint8_t getLayer() const { return ((_flags.to_ulong() & KEY_LAYER_BITS_MASK) >> FIRST_LAYER_BIT); }
|
||||
bool isLayer(uint8_t layer) const { return getLayer() == layer; }
|
||||
bool isLayered() const { return getLayer() != LAYER_DEFAULT; }
|
||||
bool isSpatial() const { return !isLayered(); }
|
||||
|
||||
// Probably not public, flags used by the scene
|
||||
bool isSmall() const { return _flags[__SMALLER]; }
|
||||
void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); }
|
||||
|
@ -230,9 +267,6 @@ public:
|
|||
Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
|
||||
Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
|
||||
|
||||
Builder& withoutLayered() { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); }
|
||||
Builder& withLayered() { _value.set(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); }
|
||||
|
||||
Builder& withoutMetaCullGroup() { _value.reset(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); }
|
||||
Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); }
|
||||
|
||||
|
@ -244,6 +278,9 @@ public:
|
|||
// Set ALL the tags in one call using the Tag bits and the Tag bits touched
|
||||
Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); }
|
||||
|
||||
Builder& withoutLayered() { _value = ItemKey::evalLayerBitsWithKeyBits(ItemKey::LAYER_DEFAULT, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); }
|
||||
Builder& withLayer(uint8_t layer) { _value = ItemKey::evalLayerBitsWithKeyBits(layer, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); }
|
||||
|
||||
Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); }
|
||||
|
||||
// Convenient standard keys that we will keep on using all over the place
|
||||
|
@ -252,9 +289,7 @@ public:
|
|||
static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); }
|
||||
static Builder light() { return Builder().withTypeLight(); }
|
||||
static Builder meta() { return Builder().withTypeMeta(); }
|
||||
static Builder background() { return Builder().withViewSpace().withLayered(); }
|
||||
static Builder opaqueShapeLayered() { return Builder().withTypeShape().withOpaque().withWorldSpace().withLayered(); }
|
||||
static Builder transparentShapeLayered() { return Builder().withTypeShape().withTransparent().withWorldSpace().withLayered(); }
|
||||
static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); }
|
||||
static Builder nothing() { return Builder().withNothing(); }
|
||||
};
|
||||
|
||||
|
@ -377,7 +412,6 @@ public:
|
|||
public:
|
||||
virtual const ItemKey getKey() const = 0;
|
||||
virtual const Bound getBound() const = 0;
|
||||
virtual int getLayer() const = 0;
|
||||
virtual void render(RenderArgs* args) = 0;
|
||||
|
||||
virtual const ShapeKey getShapeKey() const = 0;
|
||||
|
@ -422,13 +456,8 @@ public:
|
|||
// Get the bound of the item expressed in world space (or eye space depending on the key.isWorldSpace())
|
||||
const Bound getBound() const { return _payload->getBound(); }
|
||||
|
||||
// Get the layer where the item belongs.
|
||||
int getLayer() const { return _payload->getLayer(); }
|
||||
|
||||
static const int LAYER_2D;
|
||||
static const int LAYER_3D;
|
||||
static const int LAYER_3D_FRONT;
|
||||
static const int LAYER_3D_HUD;
|
||||
// Get the layer where the item belongs, simply reflecting the key.
|
||||
int getLayer() const { return _key.getLayer(); }
|
||||
|
||||
// Render call for the item
|
||||
void render(RenderArgs* args) const { _payload->render(args); }
|
||||
|
@ -478,7 +507,6 @@ inline QDebug operator<<(QDebug debug, const Item& item) {
|
|||
// Item shared interface supported by the payload
|
||||
template <class T> const ItemKey payloadGetKey(const std::shared_ptr<T>& payloadData) { return ItemKey(); }
|
||||
template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData) { return Item::Bound(); }
|
||||
template <class T> int payloadGetLayer(const std::shared_ptr<T>& payloadData) { return 0; }
|
||||
template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
|
||||
|
||||
// Shape type interface
|
||||
|
@ -505,7 +533,6 @@ public:
|
|||
// Payload general interface
|
||||
virtual const ItemKey getKey() const override { return payloadGetKey<T>(_data); }
|
||||
virtual const Item::Bound getBound() const override { return payloadGetBound<T>(_data); }
|
||||
virtual int getLayer() const override { return payloadGetLayer<T>(_data); }
|
||||
|
||||
virtual void render(RenderArgs* args) override { payloadRender<T>(_data, args); }
|
||||
|
||||
|
|
|
@ -48,6 +48,6 @@ bool blockingInvokeMethod(
|
|||
} }
|
||||
|
||||
#define BLOCKING_INVOKE_METHOD(obj, member, ...) \
|
||||
hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__)
|
||||
::hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
|||
"system/makeUserConnection.js",
|
||||
"system/tablet-goto.js",
|
||||
"system/marketplaces/marketplaces.js",
|
||||
"system/notifications.js",
|
||||
"system/commerce/wallet.js",
|
||||
"system/edit.js",
|
||||
"system/dialTone.js",
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
var isDisabled = false;
|
||||
|
||||
var previousFlyingState = MyAvatar.getFlyingEnabled();
|
||||
var previousDrivingState = MyAvatar.useAdvancedMovementControls;
|
||||
var previousDrivingState = false;
|
||||
|
||||
function rotate180() {
|
||||
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.angleAxis(180, {
|
||||
|
@ -100,7 +100,7 @@
|
|||
Controller.enableMapping(DRIVING_MAPPING_NAME);
|
||||
}
|
||||
|
||||
if (MyAvatar.getFyingEnabled()) {
|
||||
if (MyAvatar.getFlyingEnabled()) {
|
||||
Controller.disableMapping(FLYING_MAPPING_NAME);
|
||||
} else {
|
||||
Controller.enableMapping(FLYING_MAPPING_NAME);
|
||||
|
@ -171,25 +171,4 @@
|
|||
Messages.subscribe(HIFI_ADVANCED_MOVEMENT_DISABLER_CHANNEL);
|
||||
Messages.messageReceived.connect(handleMessage);
|
||||
|
||||
function initializeControls() {
|
||||
if(HMD.active) {
|
||||
if (Controller.Hardware.Vive !== undefined || Controller.Hardware.OculusTouch !== undefined) {
|
||||
if (MyAvatar.useAdvancedMovementControls) {
|
||||
Controller.disableMapping(DRIVING_MAPPING_NAME);
|
||||
} else {
|
||||
Controller.enableMapping(DRIVING_MAPPING_NAME);
|
||||
}
|
||||
|
||||
if (MyAvatar.getFlyingEnabled()) {
|
||||
Controller.disableMapping(FLYING_MAPPING_NAME);
|
||||
} else {
|
||||
Controller.enableMapping(FLYING_MAPPING_NAME);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
initializeControls();
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -79,11 +79,7 @@
|
|||
var frame = 0;
|
||||
var ctrlIsPressed = false;
|
||||
var ready = true;
|
||||
var MENU_NAME = 'Tools > Notifications';
|
||||
var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds";
|
||||
var NOTIFICATION_MENU_ITEM_POST = " Notifications";
|
||||
var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds";
|
||||
var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_";
|
||||
var NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications";
|
||||
|
||||
var NotificationType = {
|
||||
|
@ -401,11 +397,6 @@
|
|||
alpha: backgroundAlpha
|
||||
};
|
||||
|
||||
if (Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) &&
|
||||
Menu.isOptionChecked(NotificationType.getMenuString(notificationType))) {
|
||||
randomSounds.playRandom();
|
||||
}
|
||||
|
||||
return notify(noticeProperties, buttonProperties, height, imageProperties);
|
||||
}
|
||||
|
||||
|
@ -618,30 +609,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var type;
|
||||
Menu.addMenu(MENU_NAME);
|
||||
var checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING);
|
||||
checked = checked === '' ? true : checked;
|
||||
Menu.addMenuItem({
|
||||
menuName: MENU_NAME,
|
||||
menuItemName: PLAY_NOTIFICATION_SOUNDS_MENU_ITEM,
|
||||
isCheckable: true,
|
||||
isChecked: Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING)
|
||||
});
|
||||
Menu.addSeparator(MENU_NAME, "Play sounds for:");
|
||||
for (type in NotificationType.properties) {
|
||||
checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + (parseInt(type, 10) + 1));
|
||||
checked = checked === '' ? true : checked;
|
||||
Menu.addMenuItem({
|
||||
menuName: MENU_NAME,
|
||||
menuItemName: NotificationType.properties[type].text + NOTIFICATION_MENU_ITEM_POST,
|
||||
isCheckable: true,
|
||||
isChecked: checked
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// When our script shuts down, we should clean up all of our overlays
|
||||
function scriptEnding() {
|
||||
var notificationIndex;
|
||||
|
@ -649,27 +616,14 @@
|
|||
Overlays.deleteOverlay(notifications[notificationIndex]);
|
||||
Overlays.deleteOverlay(buttons[notificationIndex]);
|
||||
}
|
||||
Menu.removeMenu(MENU_NAME);
|
||||
Messages.unsubscribe(NOTIFICATIONS_MESSAGE_CHANNEL);
|
||||
}
|
||||
|
||||
function menuItemEvent(menuItem) {
|
||||
if (menuItem === PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) {
|
||||
Settings.setValue(PLAY_NOTIFICATION_SOUNDS_SETTING, Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM));
|
||||
return;
|
||||
}
|
||||
var notificationType = NotificationType.getTypeFromMenuItem(menuItem);
|
||||
if (notificationType !== notificationType.UNKNOWN) {
|
||||
Settings.setValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + notificationType, Menu.isOptionChecked(menuItem));
|
||||
}
|
||||
}
|
||||
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
Window.domainConnectionRefused.connect(onDomainConnectionRefused);
|
||||
Window.stillSnapshotTaken.connect(onSnapshotTaken);
|
||||
Window.snapshot360Taken.connect(onSnapshotTaken);
|
||||
|
@ -684,7 +638,4 @@
|
|||
|
||||
Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL);
|
||||
Messages.messageReceived.connect(onMessageReceived);
|
||||
|
||||
setup();
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -47,7 +47,6 @@ void RotationConstraintTests::testElbowConstraint() {
|
|||
glm::quat inputRotation = referenceRotation;
|
||||
glm::quat outputRotation = inputRotation;
|
||||
bool updated = elbow.apply(outputRotation);
|
||||
QVERIFY(updated == false);
|
||||
glm::quat expectedRotation = referenceRotation;
|
||||
QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON);
|
||||
}
|
||||
|
@ -62,7 +61,6 @@ void RotationConstraintTests::testElbowConstraint() {
|
|||
glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation;
|
||||
glm::quat outputRotation = inputRotation;
|
||||
bool updated = elbow.apply(outputRotation);
|
||||
QVERIFY(updated == false);
|
||||
QCOMPARE_WITH_ABS_ERROR(inputRotation, outputRotation, EPSILON);
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +70,6 @@ void RotationConstraintTests::testElbowConstraint() {
|
|||
glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation;
|
||||
glm::quat outputRotation = inputRotation;
|
||||
bool updated = elbow.apply(outputRotation);
|
||||
QVERIFY(updated == true);
|
||||
glm::quat expectedRotation = glm::angleAxis(minAngle, hingeAxis) * referenceRotation;
|
||||
QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON);
|
||||
}
|
||||
|
@ -82,7 +79,6 @@ void RotationConstraintTests::testElbowConstraint() {
|
|||
glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation;
|
||||
glm::quat outputRotation = inputRotation;
|
||||
bool updated = elbow.apply(outputRotation);
|
||||
QVERIFY(updated == true);
|
||||
glm::quat expectedRotation = glm::angleAxis(maxAngle, hingeAxis) * referenceRotation;
|
||||
QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON);
|
||||
}
|
||||
|
@ -94,7 +90,6 @@ void RotationConstraintTests::testElbowConstraint() {
|
|||
glm::quat inputRotation = glm::angleAxis(someAngle, twistVector) * referenceRotation;
|
||||
glm::quat outputRotation = inputRotation;
|
||||
bool updated = elbow.apply(outputRotation);
|
||||
QVERIFY(updated == true);
|
||||
glm::quat expectedRotation = referenceRotation;
|
||||
QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
// Computes SSIM - see https://en.wikipedia.org/wiki/Structural_similarity
|
||||
// The value is computed for the luminance component and the average value is returned
|
||||
double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) const {
|
||||
// Make sure the image is 8 bits per colour
|
||||
QImage::Format format = expectedImage.format();
|
||||
if (format != QImage::Format::Format_ARGB32) {
|
||||
throw -1;
|
||||
}
|
||||
|
||||
const int L = 255; // (2^number of bits per pixel) - 1
|
||||
const double K1 { 0.01 };
|
||||
const double K2 { 0.03 };
|
||||
|
@ -54,8 +60,8 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co
|
|||
|
||||
// Collect pixels into linear arrays
|
||||
int i{ 0 };
|
||||
for (int xx = 0; xx < WIN_SIZE; ++xx) {
|
||||
for (int yy = 0; yy < WIN_SIZE; ++yy) {
|
||||
for (int xx = 0; xx < WIN_SIZE && x + xx < expectedImage.width(); ++xx) {
|
||||
for (int yy = 0; yy < WIN_SIZE && y + yy < expectedImage.height(); ++yy) {
|
||||
// Get pixels
|
||||
QRgb pixelP = expectedImage.pixel(QPoint(x + xx, y + yy));
|
||||
QRgb pixelQ = resultImage.pixel(QPoint(x + xx, y + yy));
|
||||
|
|
|
@ -63,7 +63,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar)
|
|||
|
||||
// Loop over both lists and compare each pair of images
|
||||
// Quit loop if user has aborted due to a failed test.
|
||||
const double THRESHOLD { 0.99 };
|
||||
const double THRESHOLD { 0.9995 };
|
||||
bool success{ true };
|
||||
bool keepOn{ true };
|
||||
for (int i = 0; keepOn && i < expectedImagesFullFilenames.length(); ++i) {
|
||||
|
@ -131,7 +131,9 @@ void Test::appendTestResultsToFile(const QString& testResultsFolderPath, TestFai
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
QString failureFolderPath { testResultsFolderPath + "/" + "Failure_" + QString::number(index) + "--" + testFailure._actualImageFilename.left(testFailure._actualImageFilename.length() - 4) };
|
||||
QString err = QString::number(testFailure._error).left(6);
|
||||
|
||||
QString failureFolderPath { testResultsFolderPath + "/" + err + "-Failure_" + QString::number(index) + "--" + testFailure._actualImageFilename.left(testFailure._actualImageFilename.length() - 4) };
|
||||
if (!QDir().mkdir(failureFolderPath)) {
|
||||
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath);
|
||||
exit(-1);
|
||||
|
@ -395,9 +397,9 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact
|
|||
const QString DATE_TIME_FORMAT("MMM d yyyy, h:mm");
|
||||
textStream << "// This is an automatically generated file, created by auto-tester on " << QDateTime::currentDateTime().toString(DATE_TIME_FORMAT) << endl << endl;
|
||||
|
||||
textStream << "user = \"" + GIT_HUB_USER + "/\"" << endl;
|
||||
textStream << "repository = \"" + GIT_HUB_REPOSITORY + "/\"" << endl;
|
||||
textStream << "branch = \"" + GIT_HUB_BRANCH + "/\"" << endl << endl;
|
||||
textStream << "user = \"" + GIT_HUB_USER + "/\";" << endl;
|
||||
textStream << "repository = \"" + GIT_HUB_REPOSITORY + "/\";" << endl;
|
||||
textStream << "branch = \"" + GIT_HUB_BRANCH + "/\";" << endl << endl;
|
||||
|
||||
textStream << "var autoTester = Script.require(\"https://github.com/" + GIT_HUB_USER + "/hifi_tests/blob/"
|
||||
+ GIT_HUB_BRANCH + "/tests/utils/autoTester.js?raw=true\");" << endl << endl;
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
//
|
||||
#include "AutoTester.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) {
|
||||
ui.setupUi(this);
|
||||
ui.checkBoxInteractiveMode->setChecked(true);
|
||||
|
@ -20,6 +25,11 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) {
|
|||
connect(ui.actionClose, &QAction::triggered, this, &AutoTester::on_closeButton_clicked);
|
||||
connect(ui.actionAbout, &QAction::triggered, this, &AutoTester::about);
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
ui.hideTaskbarButton->setVisible(false);
|
||||
ui.showTaskbarButton->setVisible(false);
|
||||
#endif
|
||||
|
||||
test = new Test();
|
||||
}
|
||||
|
||||
|
@ -56,6 +66,30 @@ void AutoTester::on_createTestsOutlineButton_clicked() {
|
|||
test->createTestsOutline();
|
||||
}
|
||||
|
||||
// To toggle between show and hide
|
||||
// if (uState & ABS_AUTOHIDE) on_showTaskbarButton_clicked();
|
||||
// else on_hideTaskbarButton_clicked();
|
||||
//
|
||||
void AutoTester::on_hideTaskbarButton_clicked() {
|
||||
#ifdef Q_OS_WIN
|
||||
APPBARDATA abd = { sizeof abd };
|
||||
UINT uState = (UINT)SHAppBarMessage(ABM_GETSTATE, &abd);
|
||||
LPARAM param = uState & ABS_ALWAYSONTOP;
|
||||
abd.lParam = ABS_AUTOHIDE | param;
|
||||
SHAppBarMessage(ABM_SETSTATE, &abd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AutoTester::on_showTaskbarButton_clicked() {
|
||||
#ifdef Q_OS_WIN
|
||||
APPBARDATA abd = { sizeof abd };
|
||||
UINT uState = (UINT)SHAppBarMessage(ABM_GETSTATE, &abd);
|
||||
LPARAM param = uState & ABS_ALWAYSONTOP;
|
||||
abd.lParam = param;
|
||||
SHAppBarMessage(ABM_SETSTATE, &abd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AutoTester::on_closeButton_clicked() {
|
||||
exit(0);
|
||||
}
|
||||
|
@ -95,7 +129,7 @@ void AutoTester::saveImage(int index) {
|
|||
pixmap.loadFromData(downloaders[index]->downloadedData());
|
||||
|
||||
QImage image = pixmap.toImage();
|
||||
image = image.convertToFormat(QImage::Format_RGB32);
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
QString fullPathname = _directoryName + "/" + _filenames[index];
|
||||
if (!image.save(fullPathname, 0, 100)) {
|
||||
|
|
|
@ -36,6 +36,10 @@ private slots:
|
|||
void on_createMDFileButton_clicked();
|
||||
void on_createAllMDFilesButton_clicked();
|
||||
void on_createTestsOutlineButton_clicked();
|
||||
|
||||
void on_hideTaskbarButton_clicked();
|
||||
void on_showTaskbarButton_clicked();
|
||||
|
||||
void on_closeButton_clicked();
|
||||
|
||||
void saveImage(int index);
|
||||
|
|
|
@ -147,6 +147,32 @@
|
|||
<string>Create Tests Outline</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="showTaskbarButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>490</x>
|
||||
<y>280</y>
|
||||
<width>91</width>
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Taskbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="hideTaskbarButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>490</x>
|
||||
<y>230</y>
|
||||
<width>91</width>
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Hide Taskbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
|
|
|
@ -83,7 +83,8 @@
|
|||
"position": cameraPosition,
|
||||
"shapeType": "simple-compound",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":true}}"
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":true}}",
|
||||
"isVisibleInSecondaryCamera": false
|
||||
}, true);
|
||||
spectatorCameraConfig.attachedEntityId = camera;
|
||||
updateOverlay();
|
||||
|
|
Loading…
Reference in a new issue