Merge branch 'feat/create/interactive-window' into feat/create/native-windows

# Conflicts:
#	scripts/system/libraries/entityList.js
#	scripts/system/particle_explorer/particleExplorerTool.js
This commit is contained in:
Thijs Wenker 2018-07-03 18:47:38 +02:00
commit c583c07d9c
75 changed files with 612 additions and 360 deletions

View file

@ -64,6 +64,7 @@ Agent::Agent(ReceivedMessage& message) :
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender); DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
DependencyManager::set<ResourceManager>(); DependencyManager::set<ResourceManager>();
DependencyManager::set<PluginManager>();
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>(); DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
@ -833,6 +834,8 @@ void Agent::aboutToFinish() {
DependencyManager::get<ResourceManager>()->cleanup(); DependencyManager::get<ResourceManager>()->cleanup();
DependencyManager::destroy<PluginManager>();
// cleanup the AudioInjectorManager (and any still running injectors) // cleanup the AudioInjectorManager (and any still running injectors)
DependencyManager::destroy<AudioInjectorManager>(); DependencyManager::destroy<AudioInjectorManager>();

View file

@ -65,7 +65,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
// hash the available codecs (on the mixer) // hash the available codecs (on the mixer)
_availableCodecs.clear(); // Make sure struct is clean _availableCodecs.clear(); // Make sure struct is clean
auto codecPlugins = PluginManager::getInstance()->getCodecPlugins(); auto pluginManager = DependencyManager::set<PluginManager>();
auto codecPlugins = pluginManager->getCodecPlugins();
std::for_each(codecPlugins.cbegin(), codecPlugins.cend(), std::for_each(codecPlugins.cbegin(), codecPlugins.cend(),
[&](const CodecPluginPointer& codec) { [&](const CodecPluginPointer& codec) {
_availableCodecs[codec->getName()] = codec; _availableCodecs[codec->getName()] = codec;
@ -106,6 +107,10 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled);
} }
void AudioMixer::aboutToFinish() {
DependencyManager::destroy<PluginManager>();
}
void AudioMixer::queueAudioPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node) { void AudioMixer::queueAudioPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node) {
if (message->getType() == PacketType::SilentAudioFrame) { if (message->getType() == PacketType::SilentAudioFrame) {
_numSilentPackets++; _numSilentPackets++;

View file

@ -58,6 +58,9 @@ public:
to.getPublicSocket() != from.getPublicSocket() && to.getPublicSocket() != from.getPublicSocket() &&
to.getLocalSocket() != from.getLocalSocket(); to.getLocalSocket() != from.getLocalSocket();
} }
virtual void aboutToFinish() override;
public slots: public slots:
void run() override; void run() override;
void sendStatsPacket() override; void sendStatsPacket() override;

View file

@ -58,6 +58,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender); DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
DependencyManager::set<ResourceManager>(); DependencyManager::set<ResourceManager>();
DependencyManager::set<PluginManager>();
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>(); DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
@ -572,6 +573,8 @@ void EntityScriptServer::aboutToFinish() {
DependencyManager::get<ResourceManager>()->cleanup(); DependencyManager::get<ResourceManager>()->cleanup();
DependencyManager::destroy<PluginManager>();
// cleanup the AudioInjectorManager (and any still running injectors) // cleanup the AudioInjectorManager (and any still running injectors)
DependencyManager::destroy<AudioInjectorManager>(); DependencyManager::destroy<AudioInjectorManager>();
DependencyManager::destroy<ScriptEngines>(); DependencyManager::destroy<ScriptEngines>();

View file

@ -22,7 +22,7 @@ macro(optional_win_executable_signing)
# setup a post build command to sign the executable # setup a post build command to sign the executable
add_custom_command( add_custom_command(
TARGET ${TARGET_NAME} POST_BUILD TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${SIGNTOOL_EXECUTABLE} sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 ${EXECUTABLE_PATH} COMMAND ${SIGNTOOL_EXECUTABLE} sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 ${EXECUTABLE_PATH}
) )
else () else ()
message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.") message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.")

View file

@ -130,7 +130,7 @@
; The Inner invocation has written an uninstaller binary for us. ; The Inner invocation has written an uninstaller binary for us.
; We need to sign it if it's a production or PR build. ; We need to sign it if it's a production or PR build.
!if @PRODUCTION_BUILD@ == 1 !if @PRODUCTION_BUILD@ == 1
!system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0 !system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0
!endif !endif
; Good. Now we can carry on writing the real installer. ; Good. Now we can carry on writing the real installer.

View file

@ -28,6 +28,8 @@ Windows.Window {
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
destroyOnCloseButton: false; destroyOnCloseButton: false;
signal selfDestruct();
property var flags: 0; property var flags: 0;
property var source; property var source;
@ -67,8 +69,14 @@ Windows.Window {
x = interactiveWindowPosition.x; x = interactiveWindowPosition.x;
y = interactiveWindowPosition.y; y = interactiveWindowPosition.y;
} else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) { } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {
nativeWindow.x = interactiveWindowPosition.x; if (interactiveWindowPosition.x === 0 && interactiveWindowPosition.y === 0) {
nativeWindow.y = interactiveWindowPosition.y; // default position for native window in center of main application window
nativeWindow.x = Math.floor(Window.x + (Window.innerWidth / 2) - (interactiveWindowSize.width / 2));
nativeWindow.y = Math.floor(Window.y + (Window.innerHeight / 2) - (interactiveWindowSize.height / 2));
} else {
nativeWindow.x = interactiveWindowPosition.x;
nativeWindow.y = interactiveWindowPosition.y;
}
} }
} }
@ -83,7 +91,6 @@ Windows.Window {
} }
function setupPresentationMode() { function setupPresentationMode() {
console.warn(presentationMode);
if (presentationMode === Desktop.PresentationMode.VIRTUAL) { if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
if (nativeWindow) { if (nativeWindow) {
nativeWindow.setVisible(false); nativeWindow.setVisible(false);
@ -104,7 +111,6 @@ Windows.Window {
} }
Component.onCompleted: { Component.onCompleted: {
x = interactiveWindowPosition.x; x = interactiveWindowPosition.x;
y = interactiveWindowPosition.y; y = interactiveWindowPosition.y;
width = interactiveWindowSize.width; width = interactiveWindowSize.width;
@ -161,6 +167,11 @@ Windows.Window {
} }
}); });
nativeWindow.closing.connect(function(closeEvent) {
closeEvent.accepted = false;
windowClosed();
});
// finally set the initial window mode: // finally set the initial window mode:
setupPresentationMode(); setupPresentationMode();
@ -243,10 +254,10 @@ Windows.Window {
onWindowClosed: { onWindowClosed: {
// set invisible on close, to make it not re-appear unintended after switching PresentationMode // set invisible on close, to make it not re-appear unintended after switching PresentationMode
interactiveWindowVisible = false; interactiveWindowVisible = false;
}
onWindowDestroyed: { if ((flags & Desktop.CLOSE_BUTTON_HIDES) !== Desktop.CLOSE_BUTTON_HIDES) {
console.warn("destroyed"); selfDestruct();
}
} }
Item { Item {

View file

@ -135,6 +135,8 @@ Item {
placeholderText: qsTr("Password") placeholderText: qsTr("Password")
echoMode: TextInput.Password echoMode: TextInput.Password
Keys.onReturnPressed: linkAccountBody.login()
} }
} }

View file

@ -177,6 +177,8 @@ Item {
root.text = ""; root.text = "";
root.isPassword = true; root.isPassword = true;
} }
Keys.onReturnPressed: linkAccountBody.login()
} }
CheckBox { CheckBox {

View file

@ -164,6 +164,8 @@ Item {
root.text = ""; root.text = "";
root.isPassword = focus root.isPassword = focus
} }
Keys.onReturnPressed: signupBody.signup()
} }
Row { Row {

View file

@ -56,8 +56,8 @@ Preference {
id: slider id: slider
value: preference.value value: preference.value
width: 100 width: 100
minimumValue: MyAvatar.getDomainMinScale() minimumValue: preference.min
maximumValue: MyAvatar.getDomainMaxScale() maximumValue: preference.max
stepSize: preference.step stepSize: preference.step
onValueChanged: { onValueChanged: {
spinner.realValue = value spinner.realValue = value
@ -74,8 +74,8 @@ Preference {
id: spinner id: spinner
decimals: preference.decimals decimals: preference.decimals
realValue: preference.value realValue: preference.value
minimumValue: MyAvatar.getDomainMinScale() minimumValue: preference.min
maximumValue: MyAvatar.getDomainMaxScale() maximumValue: preference.max
width: 100 width: 100
onValueChanged: { onValueChanged: {
slider.value = realValue; slider.value = realValue;

View file

@ -129,12 +129,10 @@ Rectangle {
id: stereoMic id: stereoMic
spacing: muteMic.spacing; spacing: muteMic.spacing;
text: qsTr("Enable stereo input"); text: qsTr("Enable stereo input");
checked: AudioScriptingInterface.isStereoInput(); checked: AudioScriptingInterface.isStereoInput;
onClicked: { onClicked: {
var success = AudioScriptingInterface.setStereoInput(checked); AudioScriptingInterface.isStereoInput = checked;
if (!success) { checked = Qt.binding(function() { return AudioScriptingInterface.isStereoInput; }); // restore binding
checked = !checked;
}
} }
} }
} }

View file

@ -92,9 +92,9 @@ Rectangle {
onBuyResult: { onBuyResult: {
if (result.status !== 'success') { if (result.status !== 'success') {
failureErrorText.text = result.message; failureErrorText.text = result.data.message;
root.activeView = "checkoutFailure"; root.activeView = "checkoutFailure";
UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message); UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.data.message);
} else { } else {
root.certificateId = result.data.certificate_id; root.certificateId = result.data.certificate_id;
root.itemHref = result.data.download_url; root.itemHref = result.data.download_url;

View file

@ -17,7 +17,7 @@ PreferencesDialog {
id: root id: root
objectName: "GeneralPreferencesDialog" objectName: "GeneralPreferencesDialog"
title: "General Settings" title: "General Settings"
showCategories: ["User Interface", "HMD", "Snapshots", "Privacy"] showCategories: ["User Interface", "Mouse Sensitivity", "HMD", "Snapshots", "Privacy"]
property var settings: Settings { property var settings: Settings {
category: root.objectName category: root.objectName
property alias x: root.x property alias x: root.x

View file

@ -32,6 +32,6 @@ StackView {
TabletPreferencesDialog { TabletPreferencesDialog {
id: root id: root
objectName: "TabletGeneralPreferences" objectName: "TabletGeneralPreferences"
showCategories: ["User Interface", "HMD", "Snapshots", "Privacy"] showCategories: ["User Interface", "Mouse Sensitivity", "HMD", "Snapshots", "Privacy"]
} }
} }

View file

@ -270,9 +270,6 @@ public:
} }
_renderContext->doneCurrent(); _renderContext->doneCurrent();
// Deleting the object with automatically shutdown the thread
connect(qApp, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater);
// Transfer to a new thread // Transfer to a new thread
moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) { moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) {
hifi::qt::addBlockingForbiddenThread("Render", renderThread); hifi::qt::addBlockingForbiddenThread("Render", renderThread);
@ -815,6 +812,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
} }
// Tell the plugin manager about our statically linked plugins // Tell the plugin manager about our statically linked plugins
DependencyManager::set<PluginManager>();
auto pluginManager = PluginManager::getInstance(); auto pluginManager = PluginManager::getInstance();
pluginManager->setInputPluginProvider([] { return getInputPlugins(); }); pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
pluginManager->setDisplayPluginProvider([] { return getDisplayPlugins(); }); pluginManager->setDisplayPluginProvider([] { return getDisplayPlugins(); });
@ -1379,6 +1377,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
initializeRenderEngine(); initializeRenderEngine();
qCDebug(interfaceapp, "Initialized Render Engine."); qCDebug(interfaceapp, "Initialized Render Engine.");
// Overlays need to exist before we set the ContextOverlayInterface dependency
_overlays.init(); // do this before scripts load
DependencyManager::set<ContextOverlayInterface>();
// Initialize the user interface and menu system // Initialize the user interface and menu system
// Needs to happen AFTER the render engine initialization to access its configuration // Needs to happen AFTER the render engine initialization to access its configuration
initializeUi(); initializeUi();
@ -1515,10 +1517,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// allow you to move an entity around in your hand // allow you to move an entity around in your hand
_entityEditSender.setPacketsPerSecond(3000); // super high!! _entityEditSender.setPacketsPerSecond(3000); // super high!!
// Overlays need to exist before we set the ContextOverlayInterface dependency
_overlays.init(); // do this before scripts load
DependencyManager::set<ContextOverlayInterface>();
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
updateHeartbeat(); updateHeartbeat();
@ -2556,25 +2554,28 @@ Application::~Application() {
_octreeProcessor.terminate(); _octreeProcessor.terminate();
_entityEditSender.terminate(); _entityEditSender.terminate();
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
steamClient->shutdown();
}
DependencyManager::destroy<PluginManager>();
DependencyManager::destroy<CompositorHelper>(); // must be destroyed before the FramebufferCache
DependencyManager::destroy<AvatarManager>(); DependencyManager::destroy<AvatarManager>();
DependencyManager::destroy<AnimationCache>(); DependencyManager::destroy<AnimationCache>();
DependencyManager::destroy<FramebufferCache>(); DependencyManager::destroy<FramebufferCache>();
DependencyManager::destroy<TextureCache>(); DependencyManager::destroy<TextureCache>();
DependencyManager::destroy<ModelCache>(); DependencyManager::destroy<ModelCache>();
DependencyManager::destroy<GeometryCache>();
DependencyManager::destroy<ScriptCache>(); DependencyManager::destroy<ScriptCache>();
DependencyManager::destroy<SoundCache>(); DependencyManager::destroy<SoundCache>();
DependencyManager::destroy<OctreeStatsProvider>(); DependencyManager::destroy<OctreeStatsProvider>();
DependencyManager::destroy<GeometryCache>();
DependencyManager::get<ResourceManager>()->cleanup(); DependencyManager::get<ResourceManager>()->cleanup();
// remove the NodeList from the DependencyManager // remove the NodeList from the DependencyManager
DependencyManager::destroy<NodeList>(); DependencyManager::destroy<NodeList>();
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
steamClient->shutdown();
}
#if 0 #if 0
ConnexionClient::getInstance().destroy(); ConnexionClient::getInstance().destroy();
#endif #endif
@ -2594,6 +2595,8 @@ Application::~Application() {
// Can't log to file passed this point, FileLogger about to be deleted // Can't log to file passed this point, FileLogger about to be deleted
qInstallMessageHandler(LogHandler::verboseMessageHandler); qInstallMessageHandler(LogHandler::verboseMessageHandler);
_renderEventHandler->deleteLater();
} }
void Application::initializeGL() { void Application::initializeGL() {
@ -2720,7 +2723,7 @@ void Application::initializeDisplayPlugins() {
setDisplayPlugin(defaultDisplayPlugin); setDisplayPlugin(defaultDisplayPlugin);
// Now set the desired plugin if it's not the same as the default plugin // Now set the desired plugin if it's not the same as the default plugin
if (targetDisplayPlugin != defaultDisplayPlugin) { if (!targetDisplayPlugin && (targetDisplayPlugin != defaultDisplayPlugin)) {
setDisplayPlugin(targetDisplayPlugin); setDisplayPlugin(targetDisplayPlugin);
} }
@ -2894,6 +2897,7 @@ void Application::initializeUi() {
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();
connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] { connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] {
if (isHMDMode()) { if (isHMDMode()) {
auto compositorHelper = DependencyManager::get<CompositorHelper>(); // don't capture outer smartpointer
showCursor(compositorHelper->getAllowMouseCapture() ? showCursor(compositorHelper->getAllowMouseCapture() ?
Cursor::Manager::lookupIcon(_preferredCursor.get()) : Cursor::Manager::lookupIcon(_preferredCursor.get()) :
Cursor::Icon::SYSTEM); Cursor::Icon::SYSTEM);

View file

@ -139,7 +139,10 @@ void Application::paintGL() {
frame->frameIndex = _renderFrameCount; frame->frameIndex = _renderFrameCount;
frame->framebuffer = finalFramebuffer; frame->framebuffer = finalFramebuffer;
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) { frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer); auto frameBufferCache = DependencyManager::get<FramebufferCache>();
if (frameBufferCache) {
frameBufferCache->releaseFramebuffer(framebuffer);
}
}; };
// deliver final scene rendering commands to the display plugin // deliver final scene rendering commands to the display plugin
{ {

View file

@ -36,13 +36,13 @@
#include <SettingHandle.h> #include <SettingHandle.h>
#include <UsersScriptingInterface.h> #include <UsersScriptingInterface.h>
#include <UUID.h> #include <UUID.h>
#include <avatars-renderer/OtherAvatar.h>
#include <shared/ConicalViewFrustum.h> #include <shared/ConicalViewFrustum.h>
#include "Application.h" #include "Application.h"
#include "InterfaceLogging.h" #include "InterfaceLogging.h"
#include "Menu.h" #include "Menu.h"
#include "MyAvatar.h" #include "MyAvatar.h"
#include "OtherAvatar.h"
#include "SceneScriptingInterface.h" #include "SceneScriptingInterface.h"
// 50 times per second - target is 45hz, but this helps account for any small deviations // 50 times per second - target is 45hz, but this helps account for any small deviations
@ -192,6 +192,15 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
while (!sortedAvatars.empty()) { while (!sortedAvatars.empty()) {
const SortableAvatar& sortData = sortedAvatars.top(); const SortableAvatar& sortData = sortedAvatars.top();
const auto avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar()); const auto avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar());
const auto otherAvatar = std::static_pointer_cast<OtherAvatar>(sortData.getAvatar());
// if the geometry is loaded then turn off the orb
if (avatar->getSkeletonModel()->isLoaded()) {
// remove the orb if it is there
otherAvatar->removeOrb();
} else {
otherAvatar->updateOrbPosition();
}
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID()); bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
if (ignoring) { if (ignoring) {

View file

@ -1098,7 +1098,6 @@ void MyAvatar::saveData() {
settings.setValue("displayName", _displayName); settings.setValue("displayName", _displayName);
settings.setValue("collisionSoundURL", _collisionSoundURL); settings.setValue("collisionSoundURL", _collisionSoundURL);
settings.setValue("useSnapTurn", _useSnapTurn); settings.setValue("useSnapTurn", _useSnapTurn);
settings.setValue("clearOverlayWhenMoving", _clearOverlayWhenMoving);
settings.setValue("userHeight", getUserHeight()); settings.setValue("userHeight", getUserHeight());
settings.setValue("enabledFlying", getFlyingEnabled()); settings.setValue("enabledFlying", getFlyingEnabled());
@ -1254,7 +1253,6 @@ void MyAvatar::loadData() {
setDisplayName(settings.value("displayName").toString()); setDisplayName(settings.value("displayName").toString());
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString()); setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool()); setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool());
setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower()); setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower());
setUserHeight(settings.value("userHeight", DEFAULT_AVATAR_HEIGHT).toDouble()); setUserHeight(settings.value("userHeight", DEFAULT_AVATAR_HEIGHT).toDouble());
settings.endGroup(); settings.endGroup();

View file

@ -250,7 +250,7 @@ public:
Q_ENUM(DriveKeys) Q_ENUM(DriveKeys)
explicit MyAvatar(QThread* thread); explicit MyAvatar(QThread* thread);
~MyAvatar(); virtual ~MyAvatar();
void instantiableAvatar() override {}; void instantiableAvatar() override {};
void registerMetaTypes(ScriptEnginePointer engine); void registerMetaTypes(ScriptEnginePointer engine);
@ -469,16 +469,6 @@ public:
* @param {boolean} on * @param {boolean} on
*/ */
Q_INVOKABLE void setSnapTurn(bool on) { _useSnapTurn = on; } Q_INVOKABLE void setSnapTurn(bool on) { _useSnapTurn = on; }
/**jsdoc
* @function MyAvatar.getClearOverlayWhenMoving
* @returns {boolean}
*/
Q_INVOKABLE bool getClearOverlayWhenMoving() const { return _clearOverlayWhenMoving; }
/**jsdoc
* @function MyAvatar.setClearOverlayWhenMoving
* @param {boolean} on
*/
Q_INVOKABLE void setClearOverlayWhenMoving(bool on) { _clearOverlayWhenMoving = on; }
/**jsdoc /**jsdoc
@ -1496,7 +1486,6 @@ private:
ThreadSafeValueCache<QUrl> _prefOverrideAnimGraphUrl; ThreadSafeValueCache<QUrl> _prefOverrideAnimGraphUrl;
QUrl _fstAnimGraphOverrideUrl; QUrl _fstAnimGraphOverrideUrl;
bool _useSnapTurn { true }; bool _useSnapTurn { true };
bool _clearOverlayWhenMoving { true };
QString _dominantHand { DOMINANT_RIGHT_HAND }; QString _dominantHand { DOMINANT_RIGHT_HAND };
const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // degrees const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // degrees

View file

@ -0,0 +1,60 @@
//
// Created by Bradley Austin Davis on 2017/04/27
// Copyright 2013-2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OtherAvatar.h"
#include "Application.h"
OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
// give the pointer to our head to inherited _headData variable from AvatarData
_headData = new Head(this);
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr);
_skeletonModel->setLoadingPriority(OTHERAVATAR_LOADING_PRIORITY);
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
// add the purple orb
createOrb();
}
OtherAvatar::~OtherAvatar() {
removeOrb();
}
void OtherAvatar::removeOrb() {
if (qApp->getOverlays().isAddedOverlay(_otherAvatarOrbMeshPlaceholderID)) {
qApp->getOverlays().deleteOverlay(_otherAvatarOrbMeshPlaceholderID);
}
}
void OtherAvatar::updateOrbPosition() {
if (_otherAvatarOrbMeshPlaceholder != nullptr) {
_otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition());
}
}
void OtherAvatar::createOrb() {
if (_otherAvatarOrbMeshPlaceholderID == UNKNOWN_OVERLAY_ID ||
!qApp->getOverlays().isAddedOverlay(_otherAvatarOrbMeshPlaceholderID)) {
_otherAvatarOrbMeshPlaceholder = std::make_shared<Sphere3DOverlay>();
_otherAvatarOrbMeshPlaceholder->setAlpha(1.0f);
_otherAvatarOrbMeshPlaceholder->setColor({ 0xFF, 0x00, 0xFF });
_otherAvatarOrbMeshPlaceholder->setIsSolid(false);
_otherAvatarOrbMeshPlaceholder->setPulseMin(0.5);
_otherAvatarOrbMeshPlaceholder->setPulseMax(1.0);
_otherAvatarOrbMeshPlaceholder->setColorPulse(1.0);
_otherAvatarOrbMeshPlaceholder->setIgnoreRayIntersection(true);
_otherAvatarOrbMeshPlaceholder->setDrawInFront(false);
_otherAvatarOrbMeshPlaceholderID = qApp->getOverlays().addOverlay(_otherAvatarOrbMeshPlaceholder);
// Position focus
_otherAvatarOrbMeshPlaceholder->setWorldOrientation(glm::quat(0.0f, 0.0f, 0.0f, 1.0));
_otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition());
_otherAvatarOrbMeshPlaceholder->setDimensions(glm::vec3(0.5f, 0.5f, 0.5f));
_otherAvatarOrbMeshPlaceholder->setVisible(true);
}
}

View file

@ -0,0 +1,32 @@
//
// Created by Bradley Austin Davis on 2017/04/27
// Copyright 2013-2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_OtherAvatar_h
#define hifi_OtherAvatar_h
#include <avatars-renderer/Avatar.h>
#include "ui/overlays/Overlays.h"
#include "ui/overlays/Sphere3DOverlay.h"
#include "InterfaceLogging.h"
class OtherAvatar : public Avatar {
public:
explicit OtherAvatar(QThread* thread);
virtual ~OtherAvatar();
virtual void instantiableAvatar() override { };
virtual void createOrb() override;
void updateOrbPosition();
void removeOrb();
protected:
std::shared_ptr<Sphere3DOverlay> _otherAvatarOrbMeshPlaceholder { nullptr };
OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID };
};
#endif // hifi_OtherAvatar_h

View file

@ -35,5 +35,8 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVar
} }
void SettingsScriptingInterface::setValue(const QString& setting, const QVariant& value) { void SettingsScriptingInterface::setValue(const QString& setting, const QVariant& value) {
Setting::Handle<QVariant>(setting).set(value); // Make a deep-copy of the string.
// Dangling pointers can occur with QStrings that are implicitly shared from a QScriptEngine.
QString deepCopy = QString::fromUtf16(setting.utf16());
Setting::Handle<QVariant>(deepCopy).set(value);
} }

View file

@ -88,38 +88,24 @@ void OverlayConductor::update(float dt) {
_hmdMode = false; _hmdMode = false;
} }
bool isAtRest = updateAvatarIsAtRest();
bool isMoving = !isAtRest;
bool shouldRecenter = false; bool shouldRecenter = false;
if (_flags & SuppressedByMove) { if (_suppressedByHead) {
if (!isMoving) { if (updateAvatarIsAtRest()) {
_flags &= ~SuppressedByMove; _suppressedByHead = false;
shouldRecenter = true;
}
} else {
if (myAvatar->getClearOverlayWhenMoving() && isMoving) {
_flags |= SuppressedByMove;
}
}
if (_flags & SuppressedByHead) {
if (isAtRest) {
_flags &= ~SuppressedByHead;
shouldRecenter = true; shouldRecenter = true;
} }
} else { } else {
if (_hmdMode && headOutsideOverlay()) { if (_hmdMode && headOutsideOverlay()) {
_flags |= SuppressedByHead; _suppressedByHead = true;
} }
} }
bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && (0 == (_flags & SuppressMask)); bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && !_suppressedByHead;
if (targetVisible != currentVisible) { if (targetVisible != currentVisible) {
offscreenUi->setPinned(!targetVisible); offscreenUi->setPinned(!targetVisible);
} }
if (shouldRecenter && !_flags) { if (shouldRecenter && !_suppressedByHead) {
centerUI(); centerUI();
} }
} }

View file

@ -25,13 +25,7 @@ private:
bool headOutsideOverlay() const; bool headOutsideOverlay() const;
bool updateAvatarIsAtRest(); bool updateAvatarIsAtRest();
enum SupressionFlags { bool _suppressedByHead { false };
SuppressedByMove = 0x01,
SuppressedByHead = 0x02,
SuppressMask = 0x03,
};
uint8_t _flags { SuppressedByMove };
bool _hmdMode { false }; bool _hmdMode { false };
// used by updateAvatarIsAtRest // used by updateAvatarIsAtRest

View file

@ -161,12 +161,6 @@ void setupPreferences() {
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter)); preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter));
} }
{
auto getter = [=]()->bool { return myAvatar->getClearOverlayWhenMoving(); };
auto setter = [=](bool value) { myAvatar->setClearOverlayWhenMoving(value); };
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Clear overlays when moving", getter, setter));
}
static const QString VIEW_CATEGORY{ "View" }; static const QString VIEW_CATEGORY{ "View" };
{ {
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); }; auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
@ -233,6 +227,8 @@ void setupPreferences() {
auto getter = [=]()->float { return myAvatar->getTargetScale(); }; auto getter = [=]()->float { return myAvatar->getTargetScale(); };
auto setter = [=](float value) { myAvatar->setTargetScale(value); }; auto setter = [=](float value) { myAvatar->setTargetScale(value); };
auto preference = new SpinnerSliderPreference(AVATAR_TUNING, "Avatar Scale", getter, setter); auto preference = new SpinnerSliderPreference(AVATAR_TUNING, "Avatar Scale", getter, setter);
preference->setMin(0.25);
preference->setMax(4);
preference->setStep(0.05f); preference->setStep(0.05f);
preference->setDecimals(2); preference->setDecimals(2);
preferences->addPreference(preference); preferences->addPreference(preference);
@ -309,17 +305,21 @@ void setupPreferences() {
{ {
auto getter = [=]()->float { return myAvatar->getPitchSpeed(); }; auto getter = [=]()->float { return myAvatar->getPitchSpeed(); };
auto setter = [=](float value) { myAvatar->setPitchSpeed(value); }; auto setter = [=](float value) { myAvatar->setPitchSpeed(value); };
auto preference = new SpinnerPreference(AVATAR_CAMERA, "Pitch speed (degrees/second)", getter, setter); auto preference = new SpinnerSliderPreference(AVATAR_CAMERA, "Y input:", getter, setter);
preference->setMin(1.0f); preference->setMin(1.0f);
preference->setMax(360.0f); preference->setMax(360.0f);
preference->setStep(1);
preference->setDecimals(1);
preferences->addPreference(preference); preferences->addPreference(preference);
} }
{ {
auto getter = [=]()->float { return myAvatar->getYawSpeed(); }; auto getter = [=]()->float { return myAvatar->getYawSpeed(); };
auto setter = [=](float value) { myAvatar->setYawSpeed(value); }; auto setter = [=](float value) { myAvatar->setYawSpeed(value); };
auto preference = new SpinnerPreference(AVATAR_CAMERA, "Yaw speed (degrees/second)", getter, setter); auto preference = new SpinnerSliderPreference(AVATAR_CAMERA, "X input:", getter, setter);
preference->setMin(1.0f); preference->setMin(1.0f);
preference->setMax(360.0f); preference->setMax(360.0f);
preference->setStep(1);
preference->setDecimals(1);
preferences->addPreference(preference); preferences->addPreference(preference);
} }

View file

@ -1426,6 +1426,8 @@ bool AudioClient::setIsStereoInput(bool isStereoInput) {
// restart the input device // restart the input device
switchInputToAudioDevice(_inputDeviceInfo); switchInputToAudioDevice(_inputDeviceInfo);
emit isStereoInputChanged(_isStereoInput);
} }
return stereoInputChanged; return stereoInputChanged;
@ -1463,6 +1465,8 @@ void AudioClient::outputFormatChanged() {
} }
bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest) { bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest) {
Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
qCDebug(audioclient) << __FUNCTION__ << "inputDeviceInfo: [" << inputDeviceInfo.deviceName() << "]"; qCDebug(audioclient) << __FUNCTION__ << "inputDeviceInfo: [" << inputDeviceInfo.deviceName() << "]";
bool supportedFormat = false; bool supportedFormat = false;
@ -1663,6 +1667,8 @@ void AudioClient::outputNotify() {
} }
bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) { bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) {
Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
qCDebug(audioclient) << "AudioClient::switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]"; qCDebug(audioclient) << "AudioClient::switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]";
bool supportedFormat = false; bool supportedFormat = false;
@ -2021,7 +2027,7 @@ void AudioClient::setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 sca
void AudioClient::startThread() { void AudioClient::startThread() {
moveToNewNamedThread(this, "Audio Thread", [this] { start(); }); moveToNewNamedThread(this, "Audio Thread", [this] { start(); }, QThread::TimeCriticalPriority);
} }
void AudioClient::setInputVolume(float volume, bool emitSignal) { void AudioClient::setInputVolume(float volume, bool emitSignal) {

View file

@ -44,6 +44,9 @@ public slots:
virtual bool setIsStereoInput(bool stereo) = 0; virtual bool setIsStereoInput(bool stereo) = 0;
virtual bool isStereoInput() = 0; virtual bool isStereoInput() = 0;
signals:
void isStereoInputChanged(bool isStereo);
}; };
Q_DECLARE_METATYPE(AbstractAudioInterface*) Q_DECLARE_METATYPE(AbstractAudioInterface*)

View file

@ -1338,6 +1338,9 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
} }
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
if (!isMyAvatar()) {
createOrb();
}
AvatarData::setSkeletonModelURL(skeletonModelURL); AvatarData::setSkeletonModelURL(skeletonModelURL);
if (QThread::currentThread() == thread()) { if (QThread::currentThread() == thread()) {
_skeletonModel->setURL(_skeletonModelURL); _skeletonModel->setURL(_skeletonModelURL);

View file

@ -23,7 +23,6 @@
#include <graphics-scripting/Forward.h> #include <graphics-scripting/Forward.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include "Head.h" #include "Head.h"
#include "SkeletonModel.h" #include "SkeletonModel.h"
#include "Rig.h" #include "Rig.h"
@ -41,7 +40,6 @@ static const float SCALING_RATIO = .05f;
extern const float CHAT_MESSAGE_SCALE; extern const float CHAT_MESSAGE_SCALE;
extern const float CHAT_MESSAGE_HEIGHT; extern const float CHAT_MESSAGE_HEIGHT;
enum ScreenTintLayer { enum ScreenTintLayer {
SCREEN_TINT_BEFORE_LANDSCAPE = 0, SCREEN_TINT_BEFORE_LANDSCAPE = 0,
SCREEN_TINT_BEFORE_AVATARS, SCREEN_TINT_BEFORE_AVATARS,
@ -69,7 +67,7 @@ public:
static void setShowNamesAboveHeads(bool show); static void setShowNamesAboveHeads(bool show);
explicit Avatar(QThread* thread); explicit Avatar(QThread* thread);
~Avatar(); virtual ~Avatar();
virtual void instantiableAvatar() = 0; virtual void instantiableAvatar() = 0;
@ -109,6 +107,7 @@ public:
float getLODDistance() const; float getLODDistance() const;
virtual bool isMyAvatar() const override { return false; } virtual bool isMyAvatar() const override { return false; }
virtual void createOrb() { }
virtual QVector<glm::quat> getJointRotations() const override; virtual QVector<glm::quat> getJointRotations() const override;
using AvatarData::getJointRotation; using AvatarData::getJointRotation;
@ -167,8 +166,8 @@ public:
virtual int parseDataFromBuffer(const QByteArray& buffer) override; virtual int parseDataFromBuffer(const QByteArray& buffer) override;
static void renderJointConnectingCone( gpu::Batch& batch, glm::vec3 position1, glm::vec3 position2, static void renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, glm::vec3 position2,
float radius1, float radius2, const glm::vec4& color); float radius1, float radius2, const glm::vec4& color);
virtual void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { } virtual void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { }
@ -235,7 +234,7 @@ public:
/// Scales a world space position vector relative to the avatar position and scale /// Scales a world space position vector relative to the avatar position and scale
/// \param vector position to be scaled. Will store the result /// \param vector position to be scaled. Will store the result
void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; void scaleVectorRelativeToPosition(glm::vec3& positionToScale) const;
void slamPosition(const glm::vec3& position); void slamPosition(const glm::vec3& position);
virtual void updateAttitude(const glm::quat& orientation) override; virtual void updateAttitude(const glm::quat& orientation) override;
@ -254,7 +253,6 @@ public:
void setPositionViaScript(const glm::vec3& position) override; void setPositionViaScript(const glm::vec3& position) override;
void setOrientationViaScript(const glm::quat& orientation) override; void setOrientationViaScript(const glm::quat& orientation) override;
/**jsdoc /**jsdoc
* @function MyAvatar.getParentID * @function MyAvatar.getParentID
* @returns {Uuid} * @returns {Uuid}
@ -283,7 +281,6 @@ public:
// This calls through to the SpatiallyNestable versions, but is here to expose these to JavaScript. // This calls through to the SpatiallyNestable versions, but is here to expose these to JavaScript.
Q_INVOKABLE virtual void setParentJointIndex(quint16 parentJointIndex) override; Q_INVOKABLE virtual void setParentJointIndex(quint16 parentJointIndex) override;
/**jsdoc /**jsdoc
* Returns an array of joints, where each joint is an object containing name, index, and parentIndex fields. * Returns an array of joints, where each joint is an object containing name, index, and parentIndex fields.
* @function MyAvatar.getSkeleton * @function MyAvatar.getSkeleton
@ -349,7 +346,6 @@ public:
// not all subclasses of AvatarData have access to this data. // not all subclasses of AvatarData have access to this data.
virtual bool canMeasureEyeHeight() const override { return true; } virtual bool canMeasureEyeHeight() const override { return true; }
virtual float getModelScale() const { return _modelScale; } virtual float getModelScale() const { return _modelScale; }
virtual void setModelScale(float scale) { _modelScale = scale; } virtual void setModelScale(float scale) { _modelScale = scale; }
virtual glm::vec3 scaleForChildren() const override { return glm::vec3(getModelScale()); } virtual glm::vec3 scaleForChildren() const override { return glm::vec3(getModelScale()); }

View file

@ -1,19 +0,0 @@
//
// Created by Bradley Austin Davis on 2017/04/27
// Copyright 2013-2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OtherAvatar.h"
OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
// give the pointer to our head to inherited _headData variable from AvatarData
_headData = new Head(this);
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr);
_skeletonModel->setLoadingPriority(OTHERAVATAR_LOADING_PRIORITY);
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
}

View file

@ -1,20 +0,0 @@
//
// Created by Bradley Austin Davis on 2017/04/27
// Copyright 2013-2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_OtherAvatar_h
#define hifi_OtherAvatar_h
#include "Avatar.h"
class OtherAvatar : public Avatar {
public:
explicit OtherAvatar(QThread* thread);
virtual void instantiableAvatar() override {};
};
#endif // hifi_OtherAvatar_h

View file

@ -1269,6 +1269,8 @@ bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& poin
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID)); EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
if (!entity) { if (!entity) {
qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID;
// There is no entity
return false;
} }
EntityTypes::EntityType entityType = entity->getType(); EntityTypes::EntityType entityType = entity->getType();

View file

@ -2521,6 +2521,13 @@ bool EntityTree::readFromMap(QVariantMap& map) {
} }
} }
// Zero out the spread values that were fixed in version ParticleEntityFix so they behave the same as before
if (contentVersion < (int)EntityVersion::ParticleEntityFix) {
properties.setRadiusSpread(0.0f);
properties.setAlphaSpread(0.0f);
properties.setColorSpread({0, 0, 0});
}
EntityItemPointer entity = addEntity(entityItemID, properties); EntityItemPointer entity = addEntity(entityItemID, properties);
if (!entity) { if (!entity) {
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();

View file

@ -203,10 +203,11 @@ void GLBackend::releaseResourceTexture(uint32_t slot) {
} }
void GLBackend::resetResourceStage() { void GLBackend::resetResourceStage() {
for (uint32_t i = 0; i < _resource._buffers.size(); i++) { uint32_t i;
for (i = 0; i < _resource._buffers.size(); i++) {
releaseResourceBuffer(i); releaseResourceBuffer(i);
} }
for (uint32_t i = 0; i < _resource._textures.size(); i++) { for (i = 0; i < _resource._textures.size(); i++) {
releaseResourceTexture(i); releaseResourceTexture(i);
} }
} }

View file

@ -59,7 +59,11 @@ const size_t GLVariableAllocationSupport::MAX_BUFFER_SIZE = MAX_TRANSFER_SIZE;
GLenum GLTexture::getGLTextureType(const Texture& texture) { GLenum GLTexture::getGLTextureType(const Texture& texture) {
switch (texture.getType()) { switch (texture.getType()) {
case Texture::TEX_2D: case Texture::TEX_2D:
return GL_TEXTURE_2D; if (!texture.isArray()) {
return GL_TEXTURE_2D;
} else {
return GL_TEXTURE_2D_ARRAY;
}
break; break;
case Texture::TEX_CUBE: case Texture::TEX_CUBE:
@ -77,6 +81,7 @@ GLenum GLTexture::getGLTextureType(const Texture& texture) {
uint8_t GLTexture::getFaceCount(GLenum target) { uint8_t GLTexture::getFaceCount(GLenum target) {
switch (target) { switch (target) {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
case GL_TEXTURE_2D_ARRAY:
return TEXTURE_2D_NUM_FACES; return TEXTURE_2D_NUM_FACES;
case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP:
return TEXTURE_CUBE_NUM_FACES; return TEXTURE_CUBE_NUM_FACES;
@ -86,17 +91,22 @@ uint8_t GLTexture::getFaceCount(GLenum target) {
} }
} }
const std::vector<GLenum>& GLTexture::getFaceTargets(GLenum target) { const std::vector<GLenum>& GLTexture::getFaceTargets(GLenum target) {
static std::vector<GLenum> cubeFaceTargets { static const std::vector<GLenum> cubeFaceTargets {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
}; };
static std::vector<GLenum> faceTargets { static const std::vector<GLenum> faceTargets {
GL_TEXTURE_2D GL_TEXTURE_2D
}; };
static const std::vector<GLenum> arrayFaceTargets{
GL_TEXTURE_2D_ARRAY
};
switch (target) { switch (target) {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
return faceTargets; return faceTargets;
case GL_TEXTURE_2D_ARRAY:
return arrayFaceTargets;
case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP:
return cubeFaceTargets; return cubeFaceTargets;
default: default:

View file

@ -64,7 +64,12 @@ public:
} }
if (gltexture) { if (gltexture) {
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); if (gltexture->_target == GL_TEXTURE_2D) {
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0);
} else {
glFramebufferTextureLayer(GL_FRAMEBUFFER, colorAttachments[unit], gltexture->_texture, 0,
b._subresource);
}
_colorBuffers.push_back(colorAttachments[unit]); _colorBuffers.push_back(colorAttachments[unit]);
} else { } else {
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, 0, 0);
@ -91,7 +96,12 @@ public:
} }
if (gltexture) { if (gltexture) {
glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); if (gltexture->_target == GL_TEXTURE_2D) {
glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0);
} else {
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachement, gltexture->_texture, 0,
_gpuObject.getDepthStencilBufferSubresource());
}
} else { } else {
glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, 0, 0);
} }

View file

@ -182,7 +182,7 @@ void GL41Texture::syncSampler() const {
glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, fm.magFilter);
if (sampler.doComparison()) { if (sampler.doComparison()) {
glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(_target, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); glTexParameteri(_target, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
} else { } else {
glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
@ -197,7 +197,7 @@ void GL41Texture::syncSampler() const {
glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY, sampler.getMaxAnisotropy());
} }
using GL41FixedAllocationTexture = GL41Backend::GL41FixedAllocationTexture; using GL41FixedAllocationTexture = GL41Backend::GL41FixedAllocationTexture;
@ -215,12 +215,19 @@ GL41FixedAllocationTexture::~GL41FixedAllocationTexture() {
void GL41FixedAllocationTexture::allocateStorage() const { void GL41FixedAllocationTexture::allocateStorage() const {
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
const auto numMips = _gpuObject.getNumMips(); const auto numMips = _gpuObject.getNumMips();
const auto numSlices = _gpuObject.getNumSlices();
// glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); // glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
for (GLint level = 0; level < numMips; level++) { for (GLint level = 0; level < numMips; level++) {
Vec3u dimensions = _gpuObject.evalMipDimensions(level); Vec3u dimensions = _gpuObject.evalMipDimensions(level);
for (GLenum target : getFaceTargets(_target)) { for (GLenum target : getFaceTargets(_target)) {
glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, nullptr); if (!_gpuObject.isArray()) {
glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format,
texelFormat.type, nullptr);
} else {
glTexImage3D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, numSlices, 0,
texelFormat.format, texelFormat.type, nullptr);
}
} }
} }

View file

@ -60,7 +60,11 @@ public:
} }
if (gltexture) { if (gltexture) {
glNamedFramebufferTexture(_id, colorAttachments[unit], gltexture->_texture, 0); if (gltexture->_target == GL_TEXTURE_2D) {
glNamedFramebufferTexture(_id, colorAttachments[unit], gltexture->_texture, 0);
} else {
glNamedFramebufferTextureLayer(_id, colorAttachments[unit], gltexture->_texture, 0, b._subresource);
}
_colorBuffers.push_back(colorAttachments[unit]); _colorBuffers.push_back(colorAttachments[unit]);
} else { } else {
glNamedFramebufferTexture(_id, colorAttachments[unit], 0, 0); glNamedFramebufferTexture(_id, colorAttachments[unit], 0, 0);
@ -87,14 +91,18 @@ public:
} }
if (gltexture) { if (gltexture) {
glNamedFramebufferTexture(_id, attachement, gltexture->_texture, 0); if (gltexture->_target == GL_TEXTURE_2D) {
glNamedFramebufferTexture(_id, attachement, gltexture->_texture, 0);
} else {
glNamedFramebufferTextureLayer(_id, attachement, gltexture->_texture, 0,
_gpuObject.getDepthStencilBufferSubresource());
}
} else { } else {
glNamedFramebufferTexture(_id, attachement, 0, 0); glNamedFramebufferTexture(_id, attachement, 0, 0);
} }
_depthStamp = _gpuObject.getDepthStamp(); _depthStamp = _gpuObject.getDepthStamp();
} }
// Last but not least, define where we draw // Last but not least, define where we draw
if (!_colorBuffers.empty()) { if (!_colorBuffers.empty()) {
glNamedFramebufferDrawBuffers(_id, (GLsizei)_colorBuffers.size(), _colorBuffers.data()); glNamedFramebufferDrawBuffers(_id, (GLsizei)_colorBuffers.size(), _colorBuffers.data());

View file

@ -152,7 +152,7 @@ public:
glSamplerParameteri(result, GL_TEXTURE_MIN_FILTER, fm.minFilter); glSamplerParameteri(result, GL_TEXTURE_MIN_FILTER, fm.minFilter);
glSamplerParameteri(result, GL_TEXTURE_MAG_FILTER, fm.magFilter); glSamplerParameteri(result, GL_TEXTURE_MAG_FILTER, fm.magFilter);
if (sampler.doComparison()) { if (sampler.doComparison()) {
glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glSamplerParameteri(result, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); glSamplerParameteri(result, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
} else { } else {
glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_NONE); glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_NONE);
@ -341,7 +341,7 @@ void GL45Texture::syncSampler() const {
glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter);
if (sampler.doComparison()) { if (sampler.doComparison()) {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
} else { } else {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE);
@ -374,8 +374,13 @@ void GL45FixedAllocationTexture::allocateStorage() const {
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
const auto dimensions = _gpuObject.getDimensions(); const auto dimensions = _gpuObject.getDimensions();
const auto mips = _gpuObject.getNumMips(); const auto mips = _gpuObject.getNumMips();
const auto numSlices = _gpuObject.getNumSlices();
glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); if (!_gpuObject.isArray()) {
glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
} else {
glTextureStorage3D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y, numSlices);
}
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, mips - 1); glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, mips - 1);

View file

@ -64,7 +64,12 @@ public:
} }
if (gltexture) { if (gltexture) {
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); if (gltexture->_target == GL_TEXTURE_2D) {
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0);
} else {
glFramebufferTextureLayer(GL_FRAMEBUFFER, colorAttachments[unit], gltexture->_texture, 0,
b._subresource);
}
_colorBuffers.push_back(colorAttachments[unit]); _colorBuffers.push_back(colorAttachments[unit]);
} else { } else {
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, 0, 0);
@ -91,7 +96,12 @@ public:
} }
if (gltexture) { if (gltexture) {
glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); if (gltexture->_target == GL_TEXTURE_2D) {
glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0);
} else {
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachement, gltexture->_texture, 0,
_gpuObject.getDepthStencilBufferSubresource());
}
} else { } else {
glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, 0, 0);
} }

View file

@ -268,16 +268,27 @@ GLsizei getCompressedImageSize(int width, int height, GLenum internalFormat) {
void GLESFixedAllocationTexture::allocateStorage() const { void GLESFixedAllocationTexture::allocateStorage() const {
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
const auto numMips = _gpuObject.getNumMips(); const auto numMips = _gpuObject.getNumMips();
const auto numSlices = _gpuObject.getNumSlices();
// glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); // glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
for (GLint level = 0; level < numMips; level++) { for (GLint level = 0; level < numMips; level++) {
Vec3u dimensions = _gpuObject.evalMipDimensions(level); Vec3u dimensions = _gpuObject.evalMipDimensions(level);
for (GLenum target : getFaceTargets(_target)) { for (GLenum target : getFaceTargets(_target)) {
if (texelFormat.isCompressed()) { if (texelFormat.isCompressed()) {
glCompressedTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, auto size = getCompressedImageSize(dimensions.x, dimensions.y, texelFormat.internalFormat);
getCompressedImageSize(dimensions.x, dimensions.y, texelFormat.internalFormat), nullptr); if (!_gpuObject.isArray()) {
glCompressedTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, size, nullptr);
} else {
glCompressedTexImage3D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, numSlices, 0, size * numSlices, nullptr);
}
} else { } else {
glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, nullptr); if (!_gpuObject.isArray()) {
glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format,
texelFormat.type, nullptr);
} else {
glTexImage3D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, numSlices, 0,
texelFormat.format, texelFormat.type, nullptr);
}
} }
} }
} }

View file

@ -21,10 +21,7 @@ Frame::~Frame() {
framebuffer.reset(); framebuffer.reset();
} }
assert(bufferUpdates.empty()); bufferUpdates.clear();
if (!bufferUpdates.empty()) {
qFatal("Buffer sync error... frame destroyed without buffer updates being applied");
}
} }
void Frame::finish() { void Frame::finish() {

View file

@ -184,6 +184,10 @@ TexturePointer Texture::createRenderBuffer(const Element& texelFormat, uint16 wi
return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler); return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
} }
TexturePointer Texture::createRenderBufferArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, numSlices, numMips, sampler);
}
TexturePointer Texture::create1D(const Element& texelFormat, uint16 width, uint16 numMips, const Sampler& sampler) { TexturePointer Texture::create1D(const Element& texelFormat, uint16 width, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_1D, texelFormat, width, 1, 1, 1, 0, numMips, sampler); return create(TextureUsageType::RESOURCE, TEX_1D, texelFormat, width, 1, 1, 1, 0, numMips, sampler);
} }
@ -192,6 +196,10 @@ TexturePointer Texture::create2D(const Element& texelFormat, uint16 width, uint1
return create(TextureUsageType::RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler); return create(TextureUsageType::RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
} }
TexturePointer Texture::create2DArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, numSlices, numMips, sampler);
}
TexturePointer Texture::createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) { TexturePointer Texture::createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler); return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
} }

View file

@ -374,9 +374,11 @@ public:
static const uint16 SINGLE_MIP = 1; static const uint16 SINGLE_MIP = 1;
static TexturePointer create1D(const Element& texelFormat, uint16 width, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer create1D(const Element& texelFormat, uint16 width, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static TexturePointer create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static TexturePointer create2DArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static TexturePointer create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static TexturePointer createCube(const Element& texelFormat, uint16 width, uint16 numMips = 1, const Sampler& sampler = Sampler()); static TexturePointer createCube(const Element& texelFormat, uint16 width, uint16 numMips = 1, const Sampler& sampler = Sampler());
static TexturePointer createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static TexturePointer createRenderBufferArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static TexturePointer createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); static TexturePointer createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static TexturePointer createExternal(const ExternalRecycler& recycler, const Sampler& sampler = Sampler()); static TexturePointer createExternal(const ExternalRecycler& recycler, const Sampler& sampler = Sampler());

View file

@ -515,7 +515,7 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) {
header.getPixelHeight(), header.getPixelHeight(),
header.getPixelDepth(), header.getPixelDepth(),
1, // num Samples 1, // num Samples
header.getNumberOfSlices(), header.isArray() ? header.getNumberOfSlices() : 0,
header.getNumberOfLevels(), header.getNumberOfLevels(),
samplerDesc); samplerDesc);
texture->setUsage(gpuktxKeyValue._usage); texture->setUsage(gpuktxKeyValue._usage);

View file

@ -163,6 +163,7 @@ namespace ktx {
uint32_t getPixelDepth() const { return (pixelDepth ? pixelDepth : 1); } uint32_t getPixelDepth() const { return (pixelDepth ? pixelDepth : 1); }
uint32_t getNumberOfSlices() const { return (numberOfArrayElements ? numberOfArrayElements : 1); } uint32_t getNumberOfSlices() const { return (numberOfArrayElements ? numberOfArrayElements : 1); }
uint32_t getNumberOfLevels() const { return (numberOfMipmapLevels ? numberOfMipmapLevels : 1); } uint32_t getNumberOfLevels() const { return (numberOfMipmapLevels ? numberOfMipmapLevels : 1); }
bool isArray() const { return numberOfArrayElements > 0; }
bool isCompressed() const { return glFormat == COMPRESSED_FORMAT; } bool isCompressed() const { return glFormat == COMPRESSED_FORMAT; }
uint32_t evalMaxDimension() const; uint32_t evalMaxDimension() const;

View file

@ -39,8 +39,13 @@ ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(at
} }
ResourceManager::~ResourceManager() { ResourceManager::~ResourceManager() {
_thread.terminate(); if (_thread.isRunning()) {
_thread.wait(); _thread.quit();
static const auto MAX_RESOURCE_MANAGER_THREAD_QUITTING_TIME = MSECS_PER_SECOND / 2;
if (!_thread.wait(MAX_RESOURCE_MANAGER_THREAD_QUITTING_TIME)) {
_thread.terminate();
}
}
} }
void ResourceManager::setUrlPrefixOverride(const QString& prefix, const QString& replacement) { void ResourceManager::setUrlPrefixOverride(const QString& prefix, const QString& replacement) {

View file

@ -239,7 +239,7 @@ void Connection::sync() {
sendACK(); sendACK();
} }
if (_lossList.getLength() > 0) { if (_congestionControl->shouldNAK() && _lossList.getLength() > 0) {
// check if we need to re-transmit a loss list // check if we need to re-transmit a loss list
// we do this if it has been longer than the current nakInterval since we last sent // we do this if it has been longer than the current nakInterval since we last sent
auto now = p_high_resolution_clock::now(); auto now = p_high_resolution_clock::now();
@ -271,10 +271,13 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) {
SequenceNumber nextACKNumber = nextACK(); SequenceNumber nextACKNumber = nextACK();
Q_ASSERT_X(nextACKNumber >= _lastSentACK, "Connection::sendACK", "Sending lower ACK, something is wrong"); Q_ASSERT_X(nextACKNumber >= _lastSentACK, "Connection::sendACK", "Sending lower ACK, something is wrong");
if (nextACKNumber == _lastSentACK) { // if our congestion control doesn't want to send an ACK for every packet received
// We already sent this ACK, but check if we should re-send it. // check if we already sent this ACK
if (nextACKNumber < _lastReceivedAcknowledgedACK) { if (_congestionControl->_ackInterval > 1 && nextACKNumber == _lastSentACK) {
// if we use ACK2s, check if the receiving side already confirmed receipt of this ACK
if (_congestionControl->shouldACK2() && nextACKNumber < _lastReceivedAcknowledgedACK) {
// we already got an ACK2 for this ACK we would be sending, don't bother // we already got an ACK2 for this ACK we would be sending, don't bother
return; return;
} }
@ -287,11 +290,11 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) {
} }
} }
// we have received new packets since the last sent ACK // we have received new packets since the last sent ACK
// or our congestion control dictates that we always send ACKs
// update the last sent ACK // update the last sent ACK
_lastSentACK = nextACKNumber; _lastSentACK = nextACKNumber;
_ackPacket->reset(); // We need to reset it every time. _ackPacket->reset(); // We need to reset it every time.
// pack in the ACK sub-sequence number // pack in the ACK sub-sequence number
@ -448,20 +451,22 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in
// mark our last receive time as now (to push the potential expiry farther) // mark our last receive time as now (to push the potential expiry farther)
_lastReceiveTime = p_high_resolution_clock::now(); _lastReceiveTime = p_high_resolution_clock::now();
// check if this is a packet pair we should estimate bandwidth from, or just a regular packet if (_congestionControl->shouldProbe()) {
if (((uint32_t) sequenceNumber & 0xF) == 0) { // check if this is a packet pair we should estimate bandwidth from, or just a regular packet
_receiveWindow.onProbePair1Arrival(); if (((uint32_t) sequenceNumber & 0xF) == 0) {
} else if (((uint32_t) sequenceNumber & 0xF) == 1) { _receiveWindow.onProbePair1Arrival();
// only use this packet for bandwidth estimation if we didn't just receive a control packet in its place } else if (((uint32_t) sequenceNumber & 0xF) == 1) {
if (!_receivedControlProbeTail) { // only use this packet for bandwidth estimation if we didn't just receive a control packet in its place
_receiveWindow.onProbePair2Arrival(); if (!_receivedControlProbeTail) {
} else { _receiveWindow.onProbePair2Arrival();
// reset our control probe tail marker so the next probe that comes with data can be used } else {
_receivedControlProbeTail = false; // reset our control probe tail marker so the next probe that comes with data can be used
_receivedControlProbeTail = false;
}
} }
} }
_receiveWindow.onPacketArrival(); _receiveWindow.onPacketArrival();
// If this is not the next sequence number, report loss // If this is not the next sequence number, report loss

View file

@ -40,9 +40,8 @@ void PluginManager::setInputPluginSettingsPersister(const InputPluginSettingsPer
_inputSettingsPersister = persister; _inputSettingsPersister = persister;
} }
PluginManager* PluginManager::getInstance() { PluginManagerPointer PluginManager::getInstance() {
static PluginManager _manager; return DependencyManager::get<PluginManager>();
return &_manager;
} }
QString getPluginNameFromMetaData(QJsonObject object) { QString getPluginNameFromMetaData(QJsonObject object) {
@ -136,9 +135,6 @@ const LoaderList& getLoadedPlugins() {
return loadedPlugins; return loadedPlugins;
} }
PluginManager::PluginManager() {
}
const CodecPluginList& PluginManager::getCodecPlugins() { const CodecPluginList& PluginManager::getCodecPlugins() {
static CodecPluginList codecPlugins; static CodecPluginList codecPlugins;
static std::once_flag once; static std::once_flag once;

View file

@ -9,12 +9,19 @@
#include <QObject> #include <QObject>
#include <DependencyManager.h>
#include "Forward.h" #include "Forward.h"
class PluginManager : public QObject {
class PluginManager;
using PluginManagerPointer = QSharedPointer<PluginManager>;
class PluginManager : public QObject, public Dependency {
SINGLETON_DEPENDENCY
public: public:
static PluginManager* getInstance(); static PluginManagerPointer getInstance();
PluginManager();
const DisplayPluginList& getDisplayPlugins(); const DisplayPluginList& getDisplayPlugins();
const InputPluginList& getInputPlugins(); const InputPluginList& getInputPlugins();
@ -39,6 +46,8 @@ public:
void setInputPluginSettingsPersister(const InputPluginSettingsPersister& persister); void setInputPluginSettingsPersister(const InputPluginSettingsPersister& persister);
private: private:
PluginManager() = default;
DisplayPluginProvider _displayPluginProvider { []()->DisplayPluginList { return {}; } }; DisplayPluginProvider _displayPluginProvider { []()->DisplayPluginList { return {}; } };
InputPluginProvider _inputPluginProvider { []()->InputPluginList { return {}; } }; InputPluginProvider _inputPluginProvider { []()->InputPluginList { return {}; } };
CodecPluginProvider _codecPluginProvider { []()->CodecPluginList { return {}; } }; CodecPluginProvider _codecPluginProvider { []()->CodecPluginList { return {}; } };

View file

@ -66,7 +66,7 @@ OffscreenSurface::OffscreenSurface()
} }
OffscreenSurface::~OffscreenSurface() { OffscreenSurface::~OffscreenSurface() {
delete _sharedObject; _sharedObject->deleteLater();
} }
bool OffscreenSurface::fetchTexture(TextureAndFence& textureAndFence) { bool OffscreenSurface::fetchTexture(TextureAndFence& textureAndFence) {

View file

@ -60,7 +60,8 @@ enum TextureSlot {
enum ParamSlot { enum ParamSlot {
CameraCorrection = 0, CameraCorrection = 0,
DeferredFrameTransform, DeferredFrameTransform,
ShadowTransform ShadowTransform,
DebugParametersBuffer
}; };
static const std::string DEFAULT_ALBEDO_SHADER { static const std::string DEFAULT_ALBEDO_SHADER {
@ -139,12 +140,11 @@ static const std::string DEFAULT_LIGHTING_SHADER {
" }" " }"
}; };
static const std::string DEFAULT_SHADOW_SHADER{ static const std::string DEFAULT_SHADOW_DEPTH_SHADER{
"uniform sampler2DShadow shadowMap;"
"vec4 getFragmentColor() {" "vec4 getFragmentColor() {"
" for (int i = 255; i >= 0; --i) {" " for (int i = 255; i >= 0; --i) {"
" float depth = i / 255.0;" " float depth = i / 255.0;"
" if (texture(shadowMap, vec3(uv, depth)) > 0.5) {" " if (texture(shadowMaps, vec4(uv, parameters._shadowCascadeIndex, depth)) > 0.5) {"
" return vec4(vec3(depth), 1.0);" " return vec4(vec3(depth), 1.0);"
" }" " }"
" }" " }"
@ -323,7 +323,7 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust
case ShadowCascade1Mode: case ShadowCascade1Mode:
case ShadowCascade2Mode: case ShadowCascade2Mode:
case ShadowCascade3Mode: case ShadowCascade3Mode:
return DEFAULT_SHADOW_SHADER; return DEFAULT_SHADOW_DEPTH_SHADER;
case ShadowCascadeIndicesMode: case ShadowCascadeIndicesMode:
return DEFAULT_SHADOW_CASCADE_SHADER; return DEFAULT_SHADOW_CASCADE_SHADER;
case LinearDepthMode: case LinearDepthMode:
@ -396,6 +396,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str
slotBindings.insert(gpu::Shader::Binding("cameraCorrectionBuffer", CameraCorrection)); slotBindings.insert(gpu::Shader::Binding("cameraCorrectionBuffer", CameraCorrection));
slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", DeferredFrameTransform)); slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", DeferredFrameTransform));
slotBindings.insert(gpu::Shader::Binding("shadowTransformBuffer", ShadowTransform)); slotBindings.insert(gpu::Shader::Binding("shadowTransformBuffer", ShadowTransform));
slotBindings.insert(gpu::Shader::Binding("parametersBuffer", DebugParametersBuffer));
slotBindings.insert(gpu::Shader::Binding("albedoMap", Albedo)); slotBindings.insert(gpu::Shader::Binding("albedoMap", Albedo));
slotBindings.insert(gpu::Shader::Binding("normalMap", Normal)); slotBindings.insert(gpu::Shader::Binding("normalMap", Normal));
@ -403,7 +404,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str
slotBindings.insert(gpu::Shader::Binding("depthMap", Depth)); slotBindings.insert(gpu::Shader::Binding("depthMap", Depth));
slotBindings.insert(gpu::Shader::Binding("obscuranceMap", AmbientOcclusion)); slotBindings.insert(gpu::Shader::Binding("obscuranceMap", AmbientOcclusion));
slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting));
slotBindings.insert(gpu::Shader::Binding("shadowMap", Shadow)); slotBindings.insert(gpu::Shader::Binding("shadowMaps", Shadow));
slotBindings.insert(gpu::Shader::Binding("linearDepthMap", LinearDepth)); slotBindings.insert(gpu::Shader::Binding("linearDepthMap", LinearDepth));
slotBindings.insert(gpu::Shader::Binding("halfLinearDepthMap", HalfLinearDepth)); slotBindings.insert(gpu::Shader::Binding("halfLinearDepthMap", HalfLinearDepth));
slotBindings.insert(gpu::Shader::Binding("halfNormalMap", HalfNormal)); slotBindings.insert(gpu::Shader::Binding("halfNormalMap", HalfNormal));
@ -432,8 +433,11 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str
} }
void DebugDeferredBuffer::configure(const Config& config) { void DebugDeferredBuffer::configure(const Config& config) {
auto& parameters = _parameters.edit();
_mode = (Mode)config.mode; _mode = (Mode)config.mode;
_size = config.size; _size = config.size;
parameters._shadowCascadeIndex = glm::clamp(_mode - Mode::ShadowCascade0Mode, 0, (int)SHADOW_CASCADE_MAX_COUNT - 1);
} }
void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const Inputs& inputs) { void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
@ -483,14 +487,15 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
batch.setResourceTexture(Velocity, velocityFramebuffer->getVelocityTexture()); batch.setResourceTexture(Velocity, velocityFramebuffer->getVelocityTexture());
} }
batch.setUniformBuffer(DebugParametersBuffer, _parameters);
auto lightStage = renderContext->_scene->getStage<LightStage>(); auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage); assert(lightStage);
assert(lightStage->getNumLights() > 0); assert(lightStage->getNumLights() > 0);
auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow();
const auto& globalShadow = lightAndShadow.second; const auto& globalShadow = lightAndShadow.second;
if (globalShadow) { if (globalShadow) {
const auto cascadeIndex = glm::clamp(_mode - Mode::ShadowCascade0Mode, 0, (int)globalShadow->getCascadeCount() - 1); batch.setResourceTexture(Shadow, globalShadow->map);
batch.setResourceTexture(Shadow, globalShadow->getCascade(cascadeIndex).map);
batch.setUniformBuffer(ShadowTransform, globalShadow->getBuffer()); batch.setUniformBuffer(ShadowTransform, globalShadow->getBuffer());
batch.setUniformBuffer(DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
} }

View file

@ -30,7 +30,7 @@ public:
DebugDeferredBufferConfig() : render::Job::Config(false) {} DebugDeferredBufferConfig() : render::Job::Config(false) {}
void setMode(int newMode); void setMode(int newMode);
int mode{ 0 }; int mode{ 0 };
glm::vec4 size{ 0.0f, -1.0f, 1.0f, 1.0f }; glm::vec4 size{ 0.0f, -1.0f, 1.0f, 1.0f };
signals: signals:
@ -39,20 +39,26 @@ signals:
class DebugDeferredBuffer { class DebugDeferredBuffer {
public: public:
using Inputs = render::VaryingSet6<DeferredFramebufferPointer, LinearDepthFramebufferPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer, VelocityFramebufferPointer, DeferredFrameTransformPointer>; using Inputs = render::VaryingSet6<DeferredFramebufferPointer,
LinearDepthFramebufferPointer,
SurfaceGeometryFramebufferPointer,
AmbientOcclusionFramebufferPointer,
VelocityFramebufferPointer,
DeferredFrameTransformPointer>;
using Config = DebugDeferredBufferConfig; using Config = DebugDeferredBufferConfig;
using JobModel = render::Job::ModelI<DebugDeferredBuffer, Inputs, Config>; using JobModel = render::Job::ModelI<DebugDeferredBuffer, Inputs, Config>;
DebugDeferredBuffer(); DebugDeferredBuffer();
~DebugDeferredBuffer(); ~DebugDeferredBuffer();
void configure(const Config& config); void configure(const Config& config);
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
protected: protected:
friend class DebugDeferredBufferConfig; friend class DebugDeferredBufferConfig;
enum Mode : uint8_t { enum Mode : uint8_t
{
// Use Mode suffix to avoid collisions // Use Mode suffix to avoid collisions
Off = 0, Off = 0,
DepthMode, DepthMode,
@ -83,7 +89,7 @@ protected:
AmbientOcclusionMode, AmbientOcclusionMode,
AmbientOcclusionBlurredMode, AmbientOcclusionBlurredMode,
VelocityMode, VelocityMode,
CustomMode, // Needs to stay last CustomMode, // Needs to stay last
NumModes, NumModes,
}; };
@ -92,20 +98,25 @@ private:
Mode _mode{ Off }; Mode _mode{ Off };
glm::vec4 _size; glm::vec4 _size;
#include "debug_deferred_buffer_shared.slh"
using ParametersBuffer = gpu::StructBuffer<DebugParameters>;
struct CustomPipeline { struct CustomPipeline {
gpu::PipelinePointer pipeline; gpu::PipelinePointer pipeline;
mutable QFileInfo info; mutable QFileInfo info;
}; };
using StandardPipelines = std::array<gpu::PipelinePointer, NumModes>; using StandardPipelines = std::array<gpu::PipelinePointer, NumModes>;
using CustomPipelines = std::unordered_map<std::string, CustomPipeline>; using CustomPipelines = std::unordered_map<std::string, CustomPipeline>;
bool pipelineNeedsUpdate(Mode mode, std::string customFile = std::string()) const; bool pipelineNeedsUpdate(Mode mode, std::string customFile = std::string()) const;
const gpu::PipelinePointer& getPipeline(Mode mode, std::string customFile = std::string()); const gpu::PipelinePointer& getPipeline(Mode mode, std::string customFile = std::string());
std::string getShaderSourceCode(Mode mode, std::string customFile = std::string()); std::string getShaderSourceCode(Mode mode, std::string customFile = std::string());
ParametersBuffer _parameters;
StandardPipelines _pipelines; StandardPipelines _pipelines;
CustomPipelines _customPipelines; CustomPipelines _customPipelines;
int _geometryId { 0 }; int _geometryId{ 0 };
}; };
#endif // hifi_DebugDeferredBuffer_h #endif // hifi_DebugDeferredBuffer_h

View file

@ -68,7 +68,7 @@ enum DeferredShader_MapSlot {
SCATTERING_SPECULAR_UNIT = 9, SCATTERING_SPECULAR_UNIT = 9,
SKYBOX_MAP_UNIT = render::ShapePipeline::Slot::LIGHT_AMBIENT_MAP, // unit = 10 SKYBOX_MAP_UNIT = render::ShapePipeline::Slot::LIGHT_AMBIENT_MAP, // unit = 10
SHADOW_MAP_UNIT = 11, SHADOW_MAP_UNIT = 11,
nextAvailableUnit = SHADOW_MAP_UNIT + SHADOW_CASCADE_MAX_COUNT nextAvailableUnit = SHADOW_MAP_UNIT
}; };
enum DeferredShader_BufferSlot { enum DeferredShader_BufferSlot {
DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT = 0, DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT = 0,
@ -534,9 +534,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
// Bind the shadow buffers // Bind the shadow buffers
if (globalShadow) { if (globalShadow) {
for (unsigned int i = 0; i < globalShadow->getCascadeCount(); i++) { batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow->map);
batch.setResourceTexture(SHADOW_MAP_UNIT+i, globalShadow->getCascade(i).map);
}
} }
auto program = deferredLightingEffect->_directionalSkyboxLight; auto program = deferredLightingEffect->_directionalSkyboxLight;

View file

@ -74,8 +74,6 @@ LightStage::Shadow::Cascade::Cascade() :
_frustum{ std::make_shared<ViewFrustum>() }, _frustum{ std::make_shared<ViewFrustum>() },
_minDistance{ 0.0f }, _minDistance{ 0.0f },
_maxDistance{ 20.0f } { _maxDistance{ 20.0f } {
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
map = framebuffer->getDepthStencilBuffer();
} }
const glm::mat4& LightStage::Shadow::Cascade::getView() const { const glm::mat4& LightStage::Shadow::Cascade::getView() const {
@ -127,8 +125,29 @@ LightStage::Shadow::Shadow(graphics::LightPointer light, float maxDistance, unsi
Schema schema; Schema schema;
schema.cascadeCount = cascadeCount; schema.cascadeCount = cascadeCount;
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema); _schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
// Create shadow cascade texture array
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); // Depth32 texel format
map = gpu::TexturePointer(gpu::Texture::createRenderBufferArray(depthFormat, MAP_SIZE, MAP_SIZE, cascadeCount));
gpu::Sampler::Desc samplerDesc;
samplerDesc._borderColor = glm::vec4(1.0f);
samplerDesc._wrapModeU = gpu::Sampler::WRAP_BORDER;
samplerDesc._wrapModeV = gpu::Sampler::WRAP_BORDER;
samplerDesc._filter = gpu::Sampler::FILTER_MIN_MAG_LINEAR;
samplerDesc._comparisonFunc = gpu::LESS;
map->setSampler(gpu::Sampler(samplerDesc));
_cascades.resize(cascadeCount); _cascades.resize(cascadeCount);
for (uint cascadeIndex=0; cascadeIndex < cascadeCount; cascadeIndex++) {
auto& cascade = _cascades[cascadeIndex];
std::string name = "Shadowmap Cascade ";
name += '0' + cascadeIndex;
cascade.framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name));
cascade.framebuffer->setDepthBuffer(map, depthFormat, cascadeIndex);
}
setMaxDistance(maxDistance); setMaxDistance(maxDistance);
} }

View file

@ -53,7 +53,6 @@ public:
Cascade(); Cascade();
gpu::FramebufferPointer framebuffer; gpu::FramebufferPointer framebuffer;
gpu::TexturePointer map;
const std::shared_ptr<ViewFrustum>& getFrustum() const { return _frustum; } const std::shared_ptr<ViewFrustum>& getFrustum() const { return _frustum; }
@ -93,6 +92,8 @@ public:
const graphics::LightPointer& getLight() const { return _light; } const graphics::LightPointer& getLight() const { return _light; }
gpu::TexturePointer map;
protected: protected:
#include "Shadows_shared.slh" #include "Shadows_shared.slh"

View file

@ -60,7 +60,7 @@ void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs&
if (_opaquePass) { if (_opaquePass) {
gpu::doInBatch("DrawOverlay3D::run::clear", args->_context, [&](gpu::Batch& batch){ gpu::doInBatch("DrawOverlay3D::run::clear", args->_context, [&](gpu::Batch& batch){
batch.enableStereo(false); batch.enableStereo(false);
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTHSTENCIL, glm::vec4(), 1.f, 0, false); batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, false);
}); });
} }

View file

@ -227,7 +227,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
} }
const auto setupOutput = task.addJob<RenderShadowSetup>("ShadowSetup"); const auto setupOutput = task.addJob<RenderShadowSetup>("ShadowSetup");
const auto queryResolution = setupOutput.getN<RenderShadowSetup::Outputs>(2); const auto queryResolution = setupOutput.getN<RenderShadowSetup::Outputs>(1);
// Fetch and cull the items from the scene // Fetch and cull the items from the scene
static const auto shadowCasterReceiverFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask); static const auto shadowCasterReceiverFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask);
@ -248,10 +248,12 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
const auto sortedShapes = task.addJob<DepthSortShapes>("DepthSortShadow", sortedPipelines, true); const auto sortedShapes = task.addJob<DepthSortShapes>("DepthSortShadow", sortedPipelines, true);
render::Varying cascadeFrustums[SHADOW_CASCADE_MAX_COUNT] = { render::Varying cascadeFrustums[SHADOW_CASCADE_MAX_COUNT] = {
ViewFrustumPointer(), ViewFrustumPointer()
ViewFrustumPointer(), #if SHADOW_CASCADE_MAX_COUNT>1
,ViewFrustumPointer(),
ViewFrustumPointer(), ViewFrustumPointer(),
ViewFrustumPointer() ViewFrustumPointer()
#endif
}; };
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
@ -293,13 +295,15 @@ RenderShadowSetup::RenderShadowSetup() :
void RenderShadowSetup::configure(const Config& configuration) { void RenderShadowSetup::configure(const Config& configuration) {
setConstantBias(0, configuration.constantBias0); setConstantBias(0, configuration.constantBias0);
setConstantBias(1, configuration.constantBias1);
setConstantBias(2, configuration.constantBias2);
setConstantBias(3, configuration.constantBias3);
setSlopeBias(0, configuration.slopeBias0); setSlopeBias(0, configuration.slopeBias0);
#if SHADOW_CASCADE_MAX_COUNT>1
setConstantBias(1, configuration.constantBias1);
setSlopeBias(1, configuration.slopeBias1); setSlopeBias(1, configuration.slopeBias1);
setConstantBias(2, configuration.constantBias2);
setSlopeBias(2, configuration.slopeBias2); setSlopeBias(2, configuration.slopeBias2);
setConstantBias(3, configuration.constantBias3);
setSlopeBias(3, configuration.slopeBias3); setSlopeBias(3, configuration.slopeBias3);
#endif
} }
void RenderShadowSetup::setConstantBias(int cascadeIndex, float value) { void RenderShadowSetup::setConstantBias(int cascadeIndex, float value) {

View file

@ -17,11 +17,11 @@
#define SHADOW_SCREEN_SPACE_DITHER 1 #define SHADOW_SCREEN_SPACE_DITHER 1
// the shadow texture // the shadow texture
uniform sampler2DShadow shadowMaps[SHADOW_CASCADE_MAX_COUNT]; uniform sampler2DArrayShadow shadowMaps;
// Sample the shadowMap with PCF (built-in) // Sample the shadowMap with PCF (built-in)
float fetchShadow(int cascadeIndex, vec3 shadowTexcoord) { float fetchShadow(int cascadeIndex, vec3 shadowTexcoord) {
return texture(shadowMaps[cascadeIndex], shadowTexcoord); return texture(shadowMaps, vec4(shadowTexcoord.xy, cascadeIndex, shadowTexcoord.z));
} }
vec2 PCFkernel[4] = vec2[4]( vec2 PCFkernel[4] = vec2[4](

View file

@ -23,11 +23,18 @@ uniform sampler2D occlusionMap;
uniform sampler2D occlusionBlurredMap; uniform sampler2D occlusionBlurredMap;
uniform sampler2D scatteringMap; uniform sampler2D scatteringMap;
uniform sampler2D velocityMap; uniform sampler2D velocityMap;
uniform sampler2DArrayShadow shadowMaps;
<@include ShadowCore.slh@> <@include ShadowCore.slh@>
<$declareDeferredCurvature()$> <$declareDeferredCurvature()$>
<@include debug_deferred_buffer_shared.slh@>
layout(std140) uniform parametersBuffer {
DebugParameters parameters;
};
float curvatureAO(float k) { float curvatureAO(float k) {
return 1.0f - (0.0022f * k * k) + (0.0776f * k) + 0.7369f; return 1.0f - (0.0022f * k * k) + (0.0776f * k) + 0.7369f;
} }

View file

@ -0,0 +1,17 @@
// glsl / C++ compatible source as interface for FadeEffect
#ifdef __cplusplus
# define INT32 glm::int32
#else
# define INT32 int
#endif
struct DebugParameters
{
INT32 _shadowCascadeIndex;
};
// <@if 1@>
// Trigger Scribe include
// <@endif@> <!def that !>
//

View file

@ -370,10 +370,13 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
const auto& inShapes = inputs.get0(); const auto& inShapes = inputs.get0();
const auto& cullFilter = inputs.get1(); const auto& cullFilter = inputs.get1();
const auto& boundsFilter = inputs.get2(); const auto& boundsFilter = inputs.get2();
const auto& antiFrustum = inputs.get3(); ViewFrustumPointer antiFrustum;
auto& outShapes = outputs.edit0(); auto& outShapes = outputs.edit0();
auto& outBounds = outputs.edit1(); auto& outBounds = outputs.edit1();
if (!inputs[3].isNull()) {
antiFrustum = inputs.get3();
}
outShapes.clear(); outShapes.clear();
outBounds = AABox(); outBounds = AABox();

View file

@ -23,6 +23,21 @@ void registerAudioMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue); qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue);
} }
void AudioScriptingInterface::setLocalAudioInterface(AbstractAudioInterface* audioInterface) {
if (_localAudioInterface) {
disconnect(_localAudioInterface, &AbstractAudioInterface::isStereoInputChanged,
this, &AudioScriptingInterface::isStereoInputChanged);
}
_localAudioInterface = audioInterface;
if (_localAudioInterface) {
connect(_localAudioInterface, &AbstractAudioInterface::isStereoInputChanged,
this, &AudioScriptingInterface::isStereoInputChanged);
}
}
ScriptAudioInjector* AudioScriptingInterface::playSystemSound(SharedSoundPointer sound, const QVector3D& position) { ScriptAudioInjector* AudioScriptingInterface::playSystemSound(SharedSoundPointer sound, const QVector3D& position) {
AudioInjectorOptions options; AudioInjectorOptions options;
options.position = glm::vec3(position.x(), position.y(), position.z()); options.position = glm::vec3(position.x(), position.y(), position.z());
@ -61,11 +76,10 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(SharedSoundPointer sound
} }
bool AudioScriptingInterface::setStereoInput(bool stereo) { bool AudioScriptingInterface::setStereoInput(bool stereo) {
bool stereoInputChanged = false;
if (_localAudioInterface) { if (_localAudioInterface) {
stereoInputChanged = _localAudioInterface->setIsStereoInput(stereo); QMetaObject::invokeMethod(_localAudioInterface, "setIsStereoInput", Q_ARG(bool, stereo));
} }
return stereoInputChanged; return true;
} }
bool AudioScriptingInterface::isStereoInput() { bool AudioScriptingInterface::isStereoInput() {

View file

@ -23,9 +23,11 @@ class AudioScriptingInterface : public QObject, public Dependency {
Q_OBJECT Q_OBJECT
SINGLETON_DEPENDENCY SINGLETON_DEPENDENCY
Q_PROPERTY(bool isStereoInput READ isStereoInput WRITE setStereoInput NOTIFY isStereoInputChanged)
public: public:
virtual ~AudioScriptingInterface() {} virtual ~AudioScriptingInterface() {}
void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } void setLocalAudioInterface(AbstractAudioInterface* audioInterface);
protected: protected:
AudioScriptingInterface() {} AudioScriptingInterface() {}
@ -52,7 +54,7 @@ protected:
/**jsdoc /**jsdoc
* @function Audio.setStereoInput * @function Audio.setStereoInput
* @param {boolean} stereo * @param {boolean} stereo
* @returns {boolean} * @returns {boolean}
*/ */
Q_INVOKABLE bool setStereoInput(bool stereo); Q_INVOKABLE bool setStereoInput(bool stereo);
@ -114,6 +116,13 @@ signals:
*/ */
void inputReceived(const QByteArray& inputSamples); void inputReceived(const QByteArray& inputSamples);
/**jsdoc
* @function Audio.isStereoInputChanged
* @param {boolean} isStereo
* @returns {Signal}
*/
void isStereoInputChanged(bool isStereo);
private: private:
AbstractAudioInterface* _localAudioInterface { nullptr }; AbstractAudioInterface* _localAudioInterface { nullptr };
}; };

View file

@ -1639,22 +1639,24 @@ QVariantMap ScriptEngine::fetchModuleSource(const QString& modulePath, const boo
loader->start(MAX_RETRIES); loader->start(MAX_RETRIES);
if (!loader->isFinished()) { if (!loader->isFinished()) {
QTimer monitor; // This lambda can get called AFTER this local scope has completed.
QEventLoop loop; // This is why we pass smart ptrs to the lambda instead of references to local variables.
QObject::connect(loader, &BatchLoader::finished, this, [&monitor, &loop]{ auto monitor = std::make_shared<QTimer>();
monitor.stop(); auto loop = std::make_shared<QEventLoop>();
loop.quit(); QObject::connect(loader, &BatchLoader::finished, this, [monitor, loop] {
monitor->stop();
loop->quit();
}); });
// this helps detect the case where stop() is invoked during the download // this helps detect the case where stop() is invoked during the download
// but not seen in time to abort processing in onload()... // but not seen in time to abort processing in onload()...
connect(&monitor, &QTimer::timeout, this, [this, &loop]{ connect(monitor.get(), &QTimer::timeout, this, [this, loop] {
if (isStopping()) { if (isStopping()) {
loop.exit(-1); loop->exit(-1);
} }
}); });
monitor.start(500); monitor->start(500);
loop.exec(); loop->exec();
} }
loader->deleteLater(); loader->deleteLater();
return req; return req;

View file

@ -84,7 +84,8 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
connect(object, SIGNAL(interactiveWindowVisibleChanged()), this, SIGNAL(visibleChanged()), Qt::QueuedConnection); connect(object, SIGNAL(interactiveWindowVisibleChanged()), this, SIGNAL(visibleChanged()), Qt::QueuedConnection);
connect(object, SIGNAL(presentationModeChanged()), this, SIGNAL(presentationModeChanged()), Qt::QueuedConnection); connect(object, SIGNAL(presentationModeChanged()), this, SIGNAL(presentationModeChanged()), Qt::QueuedConnection);
connect(object, SIGNAL(titleChanged()), this, SIGNAL(titleChanged()), Qt::QueuedConnection); connect(object, SIGNAL(titleChanged()), this, SIGNAL(titleChanged()), Qt::QueuedConnection);
connect(object, SIGNAL(windowClosed()), this, SIGNAL(closed()), Qt::QueuedConnection);
connect(object, SIGNAL(selfDestruct()), this, SLOT(close()), Qt::QueuedConnection);
QUrl sourceURL{ sourceUrl }; QUrl sourceURL{ sourceUrl };
// If the passed URL doesn't correspond to a known scheme, assume it's a local file path // If the passed URL doesn't correspond to a known scheme, assume it's a local file path
@ -182,7 +183,6 @@ bool InteractiveWindow::isVisible() const {
return result; return result;
} }
// The tool window itself has special logic based on whether any tabs are enabled
if (_qmlWindow.isNull()) { if (_qmlWindow.isNull()) {
return false; return false;
} }

View file

@ -47,46 +47,19 @@ using namespace InteractiveWindowEnums;
* @hifi-interface * @hifi-interface
* @hifi-client-en * @hifi-client-en
* *
* @property {string} mode * @property {string} title
* @property {Vec2} position
* @property {Vec2} size
* @property {boolean} visible
* @property {Desktop.PresentationMode} presentationMode
*
*/ */
class InteractiveWindow : public QObject { class InteractiveWindow : public QObject {
Q_OBJECT Q_OBJECT
/**jsdoc
* title of the window
*
* @name InteractiveWindow#title
* @type string
* @default "InteractiveWindow"
*/
Q_PROPERTY(QString title READ getTitle WRITE setTitle) Q_PROPERTY(QString title READ getTitle WRITE setTitle)
/**jsdoc
* window position on current desktop
*
* @name InteractiveWindow#position
* @type Vec2
*/
Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition) Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition)
/**jsdoc
* window size
*
* @name InteractiveWindow#size
* @type Vec2
*/
Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize) Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize)
/**jsdoc
* visibility of the window
*
* @name InteractiveWindow#visible
* @type boolean
* @default true
* @example
* // Toggle window visiblity;
* interactiveWindow.visible = !interactiveWindow.visible;
*/
Q_PROPERTY(bool visible READ isVisible WRITE setVisible) Q_PROPERTY(bool visible READ isVisible WRITE setVisible)
Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode) Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode)

View file

@ -44,6 +44,11 @@ void Space::processResets(const Transaction::Resets& transactions) {
for (auto& reset : transactions) { for (auto& reset : transactions) {
// Access the true item // Access the true item
auto proxyID = std::get<0>(reset); auto proxyID = std::get<0>(reset);
// Guard against proxyID being past the end of the list.
if (proxyID < 0 || proxyID >= (int32_t)_proxies.size() || proxyID >= (int32_t)_owners.size()) {
continue;
}
auto& item = _proxies[proxyID]; auto& item = _proxies[proxyID];
// Reset the item with a new payload // Reset the item with a new payload

View file

@ -2421,7 +2421,6 @@ function selectParticleEntity(entityID) {
particleExplorerTool.createWebView(); particleExplorerTool.createWebView();
particleExplorerTool.setActiveParticleEntity(entityID); particleExplorerTool.setActiveParticleEntity(entityID);
particleExplorerTool.setActiveParticleProperties(properties);
// Switch to particle explorer // Switch to particle explorer
var selectTabMethod = { method: 'selectTab', params: { id: 'particle' } }; var selectTabMethod = { method: 'selectTab', params: { id: 'particle' } };

View file

@ -101,6 +101,7 @@ function onWebEventReceived(event) {
// If user provides input during a sit, the avatar animation state should be restored // If user provides input during a sit, the avatar animation state should be restored
Controller.keyPressEvent.connect(restoreAnimation); Controller.keyPressEvent.connect(restoreAnimation);
Controller.enableMapping(eventMappingName);
MyAvatar.overrideAnimation(ANIMATIONS[emoteName].url, FPS, false, 0, frameCount); MyAvatar.overrideAnimation(ANIMATIONS[emoteName].url, FPS, false, 0, frameCount);
} else { } else {
@ -132,6 +133,7 @@ function restoreAnimation() {
// Make sure the input is disconnected after animations are restored so it doesn't affect any emotes other than sit // Make sure the input is disconnected after animations are restored so it doesn't affect any emotes other than sit
Controller.keyPressEvent.disconnect(restoreAnimation); Controller.keyPressEvent.disconnect(restoreAnimation);
Controller.disableMapping(eventMappingName);
} }
// Note peek() so as to not interfere with other mappings. // Note peek() so as to not interfere with other mappings.
@ -151,7 +153,7 @@ eventMapping.from(Controller.Standard.RS).peek().to(restoreAnimation);
eventMapping.from(Controller.Standard.RightGrip).peek().to(restoreAnimation); eventMapping.from(Controller.Standard.RightGrip).peek().to(restoreAnimation);
eventMapping.from(Controller.Standard.Back).peek().to(restoreAnimation); eventMapping.from(Controller.Standard.Back).peek().to(restoreAnimation);
eventMapping.from(Controller.Standard.Start).peek().to(restoreAnimation); eventMapping.from(Controller.Standard.Start).peek().to(restoreAnimation);
Controller.enableMapping(eventMappingName);
button.clicked.connect(onClicked); button.clicked.connect(onClicked);
tablet.screenChanged.connect(onScreenChanged); tablet.screenChanged.connect(onScreenChanged);

View file

@ -134,12 +134,17 @@ EntityListTool = function() {
url: url, url: url,
locked: properties.locked, locked: properties.locked,
visible: properties.visible, visible: properties.visible,
verticesCount: valueIfDefined(properties.renderInfo.verticesCount), verticesCount: (properties.renderInfo !== undefined ?
texturesCount: valueIfDefined(properties.renderInfo.texturesCount), valueIfDefined(properties.renderInfo.verticesCount) : ""),
texturesSize: valueIfDefined(properties.renderInfo.texturesSize), texturesCount: (properties.renderInfo !== undefined ?
hasTransparent: valueIfDefined(properties.renderInfo.hasTransparent), valueIfDefined(properties.renderInfo.texturesCount) : ""),
texturesSize: (properties.renderInfo !== undefined ?
valueIfDefined(properties.renderInfo.texturesSize) : ""),
hasTransparent: (properties.renderInfo !== undefined ?
valueIfDefined(properties.renderInfo.hasTransparent) : ""),
isBaked: properties.type === "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false, isBaked: properties.type === "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false,
drawCalls: valueIfDefined(properties.renderInfo.drawCalls), drawCalls: (properties.renderInfo !== undefined ?
valueIfDefined(properties.renderInfo.drawCalls) : ""),
hasScript: properties.script !== "" hasScript: properties.script !== ""
}); });
} }

View file

@ -61,12 +61,18 @@ function HifiEntityUI(parent) {
this.parent = parent; this.parent = parent;
var self = this; var self = this;
this.sendPackage = {};
this.settingsUpdateLock = false; this.settingsUpdateLock = false;
this.webBridgeSync = _.debounce(function (id, val) { this.webBridgeSync = function(id, val) {
if (self.EventBridge && !self.settingsUpdateLock) { if (!this.settingsUpdateLock) {
var sendPackage = {}; this.sendPackage[id] = val;
sendPackage[id] = val; this.webBridgeSyncDebounce();
self.submitChanges(sendPackage); }
};
this.webBridgeSyncDebounce = _.debounce(function () {
if (self.EventBridge) {
self.submitChanges(self.sendPackage);
self.sendPackage = {};
} }
}, DEBOUNCE_TIMEOUT); }, DEBOUNCE_TIMEOUT);
} }
@ -159,7 +165,6 @@ HifiEntityUI.prototype = {
var self = this; var self = this;
var fields = document.getElementsByTagName("input"); var fields = document.getElementsByTagName("input");
self.settingsUpdateLock = true;
if (!currentProperties.locked) { if (!currentProperties.locked) {
for (var i = 0; i < fields.length; i++) { for (var i = 0; i < fields.length; i++) {
fields[i].removeAttribute("disabled"); fields[i].removeAttribute("disabled");
@ -179,7 +184,7 @@ HifiEntityUI.prototype = {
for (var e in keys) { for (var e in keys) {
if (keys.hasOwnProperty(e)) { if (keys.hasOwnProperty(e)) {
var value = keys[e]; var value = keys[e];
var property = currentProperties[value]; var property = currentProperties[value];
var field = self.builtRows[value]; var field = self.builtRows[value];
if (field) { if (field) {
@ -235,10 +240,6 @@ HifiEntityUI.prototype = {
} }
} }
} }
// Now unlocking settings Update lock for sending messages on callbacks.
setTimeout(function () {
self.settingsUpdateLock = false;
}, DEBOUNCE_TIMEOUT * 2.5);
}, },
connect: function (EventBridge) { connect: function (EventBridge) {
this.EventBridge = EventBridge; this.EventBridge = EventBridge;
@ -253,28 +254,9 @@ HifiEntityUI.prototype = {
data = JSON.parse(data); data = JSON.parse(data);
if (data.messageType === 'particle_settings') { if (data.messageType === 'particle_settings') {
// Update settings self.settingsUpdateLock = true;
var currentProperties = data.currentProperties; self.fillFields(data.currentProperties);
// Update uninitialized variables self.settingsUpdateLock = false;
if (!currentProperties.alphaStart) {
currentProperties.alphaStart = currentProperties.alpha;
}
if (!currentProperties.alphaFinish) {
currentProperties.alphaFinish = currentProperties.alpha;
}
if (!currentProperties.radiusStart) {
currentProperties.radiusStart = currentProperties.particleRadius;
}
if (!currentProperties.radiusFinish) {
currentProperties.radiusFinish = currentProperties.particleRadius;
}
if (!currentProperties.colorStart || !currentProperties.colorStart.red) {
currentProperties.colorStart = currentProperties.color;
}
if (!currentProperties.colorFinish || !currentProperties.colorFinish.red) {
currentProperties.colorFinish = currentProperties.color;
}
self.fillFields(currentProperties);
// Do expected property match with structure; // Do expected property match with structure;
} else if (data.messageType === 'particle_close') { } else if (data.messageType === 'particle_close') {
self.disableFields(); self.disableFields();

View file

@ -17,7 +17,7 @@ var PARTICLE_EXPLORER_HTML_URL = Script.resolvePath('particleExplorer.html');
ParticleExplorerTool = function (createToolsWindow) { ParticleExplorerTool = function (createToolsWindow) {
var that = {}; var that = {};
that.activeParticleEntity = 0; that.activeParticleEntity = 0;
that.activeParticleProperties = {}; that.updatedActiveParticleProperties = {};
that.createWebView = function() { that.createWebView = function() {
that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system"); that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
@ -37,52 +37,93 @@ ParticleExplorerTool = function (createToolsWindow) {
return; return;
} }
that.activeParticleEntity = 0; that.activeParticleEntity = 0;
that.activeParticleProperties = {}; that.updatedActiveParticleProperties = {};
emitScriptEvent({ emitScriptEvent({
messageType: "particle_close" messageType: "particle_close"
}); });
}; };
function sendActiveParticleProperties() { function sendParticleProperties(properties) {
emitScriptEvent({ emitScriptEvent({
messageType: "particle_settings", messageType: "particle_settings",
currentProperties: that.activeParticleProperties currentProperties: properties
}); });
} }
function sendActiveParticleProperties() {
var properties = Entities.getEntityProperties(that.activeParticleEntity);
if (properties.emitOrientation) {
properties.emitOrientation = Quat.safeEulerAngles(properties.emitOrientation);
}
// Update uninitialized variables
if (isNaN(properties.alphaStart)) {
properties.alphaStart = properties.alpha;
}
if (isNaN(properties.alphaFinish)) {
properties.alphaFinish = properties.alpha;
}
if (isNaN(properties.radiusStart)) {
properties.radiusStart = properties.particleRadius;
}
if (isNaN(properties.radiusFinish)) {
properties.radiusFinish = properties.particleRadius;
}
if (isNaN(properties.colorStart.red)) {
properties.colorStart = properties.color;
}
if (isNaN(properties.colorFinish.red)) {
properties.colorFinish = properties.color;
}
sendParticleProperties(properties);
}
function sendUpdatedActiveParticleProperties() {
sendParticleProperties(that.updatedActiveParticleProperties);
that.updatedActiveParticleProperties = {};
}
that.webEventReceived = function(message) { that.webEventReceived = function(message) {
var data = JSON.parse(message); var data = JSON.parse(message);
if (data.messageType === "settings_update") { if (data.messageType === "settings_update") {
if (data.updatedSettings.emitOrientation) { var updatedSettings = data.updatedSettings;
data.updatedSettings.emitOrientation = Quat.fromVec3Degrees(data.updatedSettings.emitOrientation);
}
Entities.editEntity(that.activeParticleEntity, data.updatedSettings);
for (var key in data.updatedSettings) {
if (that.activeParticleProperties.hasOwnProperty(key)) {
that.activeParticleProperties[key] = data.updatedSettings[key];
}
}
var optionalProps = ["alphaStart", "alphaFinish", "radiusStart", "radiusFinish", "colorStart", "colorFinish"]; var optionalProps = ["alphaStart", "alphaFinish", "radiusStart", "radiusFinish", "colorStart", "colorFinish"];
var fallbackProps = ["alpha", "particleRadius", "color"]; var fallbackProps = ["alpha", "particleRadius", "color"];
var entityProps = Entities.getEntityProperties(that.activeParticleProperties, optionalProps); for (var i = 0; i < optionalProps.length; i++) {
var fallbackProp = fallbackProps[Math.floor(i / 2)];
var optionalValue = updatedSettings[optionalProps[i]];
var fallbackValue = updatedSettings[fallbackProp];
if (optionalValue && fallbackValue) {
delete updatedSettings[optionalProps[i]];
}
}
if (updatedSettings.emitOrientation) {
updatedSettings.emitOrientation = Quat.fromVec3Degrees(updatedSettings.emitOrientation);
}
Entities.editEntity(that.activeParticleEntity, updatedSettings);
var entityProps = Entities.getEntityProperties(that.activeParticleEntity, optionalProps);
var needsUpdate = false; var needsUpdate = false;
for (var i = 0; i < optionalProps.length; i++) { for (var i = 0; i < optionalProps.length; i++) {
var fallback = fallbackProps[Math.floor(i / 2)]; var fallbackProp = fallbackProps[Math.floor(i / 2)];
if (data.updatedSettings[fallback]) { var fallbackValue = updatedSettings[fallbackProp];
var prop = optionalProps[i]; if (fallbackValue) {
if (!that.activeParticleProperties[prop] || (fallback === "color" && !that.activeParticleProperties[prop].red)) { var optionalProp = optionalProps[i];
that.activeParticleProperties[prop] = entityProps[fallback]; if ((fallbackProp !== "color" && isNaN(entityProps[optionalProp])) || (fallbackProp === "color" && isNaN(entityProps[optionalProp].red))) {
that.updatedActiveParticleProperties[optionalProp] = fallbackValue;
needsUpdate = true; needsUpdate = true;
} }
} }
} }
if (needsUpdate) { if (needsUpdate) {
sendActiveParticleProperties(); sendUpdatedActiveParticleProperties();
} }
} else if (data.messageType === "page_loaded") { } else if (data.messageType === "page_loaded") {
sendActiveParticleProperties(); sendActiveParticleProperties();
} }
@ -90,12 +131,8 @@ ParticleExplorerTool = function (createToolsWindow) {
that.setActiveParticleEntity = function(id) { that.setActiveParticleEntity = function(id) {
that.activeParticleEntity = id; that.activeParticleEntity = id;
};
that.setActiveParticleProperties = function(properties) {
that.activeParticleProperties = properties;
sendActiveParticleProperties(); sendActiveParticleProperties();
}; };
return that; return that;
}; };

View file

@ -17,7 +17,6 @@ var SNAPSHOT_DELAY = 500; // 500ms
var FINISH_SOUND_DELAY = 350; var FINISH_SOUND_DELAY = 350;
var resetOverlays; var resetOverlays;
var reticleVisible; var reticleVisible;
var clearOverlayWhenMoving;
var buttonName = "SNAP"; var buttonName = "SNAP";
var buttonConnected = false; var buttonConnected = false;
@ -286,6 +285,7 @@ function printToPolaroid(image_url) {
var polaroid_url = image_url; var polaroid_url = image_url;
var model_pos = Vec3.sum(MyAvatar.position, Vec3.multiply(1.25, Quat.getForward(MyAvatar.orientation))); var model_pos = Vec3.sum(MyAvatar.position, Vec3.multiply(1.25, Quat.getForward(MyAvatar.orientation)));
model_pos.y += 0.2; // Print a bit closer to the head
var model_q1 = MyAvatar.orientation; var model_q1 = MyAvatar.orientation;
var model_q2 = Quat.angleAxis(90, Quat.getRight(model_q1)); var model_q2 = Quat.angleAxis(90, Quat.getRight(model_q1));
@ -295,11 +295,11 @@ function printToPolaroid(image_url) {
"type": 'Model', "type": 'Model',
"shapeType": 'box', "shapeType": 'box',
"name": "New Snapshot", "name": "Snapshot by " + MyAvatar.sessionDisplayName,
"description": "Printed from Snaps", "description": "Printed from SNAP app",
"modelURL": POLAROID_MODEL_URL, "modelURL": POLAROID_MODEL_URL,
"dimensions": { "x": 0.5667, "y": 0.0212, "z": 0.4176 }, "dimensions": { "x": 0.5667, "y": 0.042, "z": 0.4176 },
"position": model_pos, "position": model_pos,
"rotation": model_rot, "rotation": model_rot,
@ -307,9 +307,9 @@ function printToPolaroid(image_url) {
"density": 200, "density": 200,
"restitution": 0.15, "restitution": 0.15,
"gravity": { "x": 0, "y": -4.5, "z": 0 }, "gravity": { "x": 0, "y": -2.5, "z": 0 },
"velocity": { "x": 0, "y": 3.5, "z": 0 }, "velocity": { "x": 0, "y": 1.95, "z": 0 },
"angularVelocity": { "x": -1.0, "y": 0, "z": -1.3 }, "angularVelocity": { "x": -1.0, "y": 0, "z": -1.3 },
"dynamic": true, "dynamic": true,
@ -438,11 +438,6 @@ function takeSnapshot() {
isUploadingPrintableStill = true; isUploadingPrintableStill = true;
updatePrintPermissions(); updatePrintPermissions();
// Raising the desktop for the share dialog at end will interact badly with clearOverlayWhenMoving.
// Turn it off now, before we start futzing with things (and possibly moving).
clearOverlayWhenMoving = MyAvatar.getClearOverlayWhenMoving(); // Do not use Settings. MyAvatar keeps a separate copy.
MyAvatar.setClearOverlayWhenMoving(false);
// We will record snapshots based on the starting location. That could change, e.g., when recording a .gif. // We will record snapshots based on the starting location. That could change, e.g., when recording a .gif.
// Even the domainID could change (e.g., if the user falls into a teleporter while recording). // Even the domainID could change (e.g., if the user falls into a teleporter while recording).
href = location.href; href = location.href;
@ -544,9 +539,6 @@ function stillSnapshotTaken(pathStillSnapshot, notify) {
// last element in data array tells dialog whether we can share or not // last element in data array tells dialog whether we can share or not
Settings.setValue("previousStillSnapPath", pathStillSnapshot); Settings.setValue("previousStillSnapPath", pathStillSnapshot);
if (clearOverlayWhenMoving) {
MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog
}
HMD.openTablet(); HMD.openTablet();
isDomainOpen(domainID, function (canShare) { isDomainOpen(domainID, function (canShare) {
@ -590,9 +582,6 @@ function processingGifStarted(pathStillSnapshot) {
} }
Settings.setValue("previousStillSnapPath", pathStillSnapshot); Settings.setValue("previousStillSnapPath", pathStillSnapshot);
if (clearOverlayWhenMoving) {
MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog
}
HMD.openTablet(); HMD.openTablet();
isDomainOpen(domainID, function (canShare) { isDomainOpen(domainID, function (canShare) {