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

This commit is contained in:
Dante Ruiz 2018-02-14 15:15:46 -08:00
commit 8a95920c31
14 changed files with 168 additions and 109 deletions

View file

@ -88,8 +88,8 @@
] ]
}, },
{ "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.W", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_FORWARD" },
{ "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.S", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_BACKWARD" },
{ "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
{ "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" }, { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
{ "from": "Keyboard.Left", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.Left", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_LEFT" },

View file

@ -202,8 +202,4 @@ TreeView {
} }
onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index) onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index)
onClicked: {
selectionModel.setCurrentIndex(index, ItemSelectionModel.ClearAndSelect);
}
} }

View file

@ -37,7 +37,7 @@ Windows.ScrollingWindow {
property var assetProxyModel: Assets.proxyModel; property var assetProxyModel: Assets.proxyModel;
property var assetMappingsModel: Assets.mappingModel; property var assetMappingsModel: Assets.mappingModel;
property var currentDirectory; property var currentDirectory;
property var selectedItems: treeView.selection.selectedIndexes.length; property var selectedItemCount: treeView.selection.selectedIndexes.length;
Settings { Settings {
category: "Overlay.AssetServer" category: "Overlay.AssetServer"
@ -75,17 +75,17 @@ Windows.ScrollingWindow {
}); });
} }
function doDeleteFile(path) { function doDeleteFile(paths) {
console.log("Deleting " + path); console.log("Deleting " + paths);
Assets.deleteMappings(path, function(err) { Assets.deleteMappings(paths, function(err) {
if (err) { if (err) {
console.log("Asset browser - error deleting path: ", path, err); console.log("Asset browser - error deleting paths: ", paths, err);
box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err); box = errorMessageBox("There was an error deleting:\n" + paths + "\n" + err);
box.selected.connect(reload); box.selected.connect(reload);
} else { } else {
console.log("Asset browser - finished deleting path: ", path); console.log("Asset browser - finished deleting paths: ", paths);
reload(); reload();
} }
}); });
@ -145,7 +145,7 @@ Windows.ScrollingWindow {
function canAddToWorld(path) { function canAddToWorld(path) {
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i]; var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i];
if (selectedItems > 1) { if (selectedItemCount > 1) {
return false; return false;
} }
@ -155,7 +155,7 @@ Windows.ScrollingWindow {
} }
function canRename() { function canRename() {
if (treeView.selection.hasSelection && selectedItems == 1) { if (treeView.selection.hasSelection && selectedItemCount == 1) {
return true; return true;
} else { } else {
return false; return false;
@ -344,29 +344,28 @@ Windows.ScrollingWindow {
}); });
} }
function deleteFile(index) { function deleteFile(index) {
var path = []; var paths = [];
if (!index) { if (!index) {
for (var i = 0; i < selectedItems; i++) { for (var i = 0; i < selectedItemCount; ++i) {
treeView.selection.setCurrentIndex(treeView.selection.selectedIndexes[i], 0x100); index = treeView.selection.selectedIndexes[i];
index = treeView.selection.currentIndex; paths[i] = assetProxyModel.data(index, 0x100);
path[i] = assetProxyModel.data(index, 0x100);
} }
} }
if (!path) { if (!paths) {
return; return;
} }
var modalMessage = ""; var modalMessage = "";
var items = selectedItems.toString(); var items = selectedItemCount.toString();
var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101);
var typeString = isFolder ? 'folder' : 'file'; var typeString = isFolder ? 'folder' : 'file';
if (selectedItems > 1) { if (selectedItemCount > 1) {
modalMessage = "You are about to delete " + items + " items \nDo you want to continue?"; modalMessage = "You are about to delete " + items + " items \nDo you want to continue?";
} else { } else {
modalMessage = "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"; modalMessage = "You are about to delete the following " + typeString + ":\n" + paths + "\nDo you want to continue?";
} }
var object = desktop.messageBox({ var object = desktop.messageBox({
@ -378,7 +377,7 @@ Windows.ScrollingWindow {
}); });
object.selected.connect(function(button) { object.selected.connect(function(button) {
if (button === OriginalDialogs.StandardButton.Yes) { if (button === OriginalDialogs.StandardButton.Yes) {
doDeleteFile(path); doDeleteFile(paths);
} }
}); });
} }
@ -705,7 +704,7 @@ Windows.ScrollingWindow {
} }
} }
} }
} }// End_OF( itemLoader )
Rectangle { Rectangle {
id: treeLabelToolTip id: treeLabelToolTip
@ -742,50 +741,59 @@ Windows.ScrollingWindow {
showTimer.stop(); showTimer.stop();
treeLabelToolTip.visible = false; treeLabelToolTip.visible = false;
} }
} }// End_OF( treeLabelToolTip )
MouseArea { MouseArea {
propagateComposedEvents: true propagateComposedEvents: true
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
onClicked: { onClicked: {
if (!HMD.active) { // Popup only displays properly on desktop if (treeView.selection.hasSelection && !HMD.active) { // Popup only displays properly on desktop
var index = treeView.indexAt(mouse.x, mouse.y); // Only display the popup if the click triggered within
treeView.selection.setCurrentIndex(index, 0x0002); // the selection.
contextMenu.currentIndex = index; var clickedIndex = treeView.indexAt(mouse.x, mouse.y);
contextMenu.popup(); var displayContextMenu = false;
for ( var i = 0; i < selectedItemCount; ++i) {
var currentSelectedIndex = treeView.selection.selectedIndexes[i];
if (clickedIndex === currentSelectedIndex) {
contextMenu.popup();
break;
}
}
} }
} }
} }
Menu { Menu {
id: contextMenu id: contextMenu
title: "Edit" title: "Edit"
property var url: "" property var url: ""
property var currentIndex: null
MenuItem { MenuItem {
text: "Copy URL" text: "Copy URL"
enabled: (selectedItemCount == 1)
onTriggered: { onTriggered: {
copyURLToClipboard(contextMenu.currentIndex); copyURLToClipboard(treeView.selection.currentIndex);
} }
} }
MenuItem { MenuItem {
text: "Rename" text: "Rename"
enabled: (selectedItemCount == 1)
onTriggered: { onTriggered: {
renameFile(contextMenu.currentIndex); renameFile(treeView.selection.currentIndex);
} }
} }
MenuItem { MenuItem {
text: "Delete" text: "Delete"
enabled: (selectedItemCount > 0)
onTriggered: { onTriggered: {
deleteFile(contextMenu.currentIndex); deleteFile();
} }
} }
} }// End_OF( contextMenu )
} }// End_OF( treeView )
Row { Row {
id: infoRow id: infoRow
@ -798,8 +806,8 @@ Windows.ScrollingWindow {
function makeText() { function makeText() {
var numPendingBakes = assetMappingsModel.numPendingBakes; var numPendingBakes = assetMappingsModel.numPendingBakes;
if (selectedItems > 1 || numPendingBakes === 0) { if (selectedItemCount > 1 || numPendingBakes === 0) {
return selectedItems + " items selected"; return selectedItemCount + " items selected";
} else { } else {
return numPendingBakes + " bakes pending" return numPendingBakes + " bakes pending"
} }
@ -896,7 +904,7 @@ Windows.ScrollingWindow {
"Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors."); "Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors.");
} }
} }
} }// End_OF( infoRow )
HifiControls.ContentSection { HifiControls.ContentSection {
id: uploadSection id: uploadSection
@ -956,7 +964,7 @@ Windows.ScrollingWindow {
} }
} }
} }
} }// End_OF( uploadSection )
} }
} }

View file

@ -39,7 +39,7 @@ Rectangle {
property var assetProxyModel: Assets.proxyModel; property var assetProxyModel: Assets.proxyModel;
property var assetMappingsModel: Assets.mappingModel; property var assetMappingsModel: Assets.mappingModel;
property var currentDirectory; property var currentDirectory;
property var selectedItems: treeView.selection.selectedIndexes.length; property var selectedItemCount: treeView.selection.selectedIndexes.length;
Settings { Settings {
category: "Overlay.AssetServer" category: "Overlay.AssetServer"
@ -76,17 +76,17 @@ Rectangle {
}); });
} }
function doDeleteFile(path) { function doDeleteFile(paths) {
console.log("Deleting " + path); console.log("Deleting " + paths);
Assets.deleteMappings(path, function(err) { Assets.deleteMappings(paths, function(err) {
if (err) { if (err) {
console.log("Asset browser - error deleting path: ", path, err); console.log("Asset browser - error deleting paths: ", paths, err);
box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err); box = errorMessageBox("There was an error deleting:\n" + paths + "\n" + err);
box.selected.connect(reload); box.selected.connect(reload);
} else { } else {
console.log("Asset browser - finished deleting path: ", path); console.log("Asset browser - finished deleting paths: ", paths);
reload(); reload();
} }
}); });
@ -146,7 +146,7 @@ Rectangle {
function canAddToWorld(path) { function canAddToWorld(path) {
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i];
if (selectedItems > 1) { if (selectedItemCount > 1) {
return false; return false;
} }
@ -156,7 +156,7 @@ Rectangle {
} }
function canRename() { function canRename() {
if (treeView.selection.hasSelection && selectedItems == 1) { if (treeView.selection.hasSelection && selectedItemCount == 1) {
return true; return true;
} else { } else {
return false; return false;
@ -345,29 +345,28 @@ Rectangle {
}); });
} }
function deleteFile(index) { function deleteFile(index) {
var path = []; var paths = [];
if (!index) { if (!index) {
for (var i = 0; i < selectedItems; i++) { for (var i = 0; i < selectedItemCount; ++i) {
treeView.selection.setCurrentIndex(treeView.selection.selectedIndexes[i], 0x100); index = treeView.selection.selectedIndexes[i];
index = treeView.selection.currentIndex; paths[i] = assetProxyModel.data(index, 0x100);
path[i] = assetProxyModel.data(index, 0x100);
} }
} }
if (!path) { if (!paths) {
return; return;
} }
var modalMessage = ""; var modalMessage = "";
var items = selectedItems.toString(); var items = selectedItemCount.toString();
var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101);
var typeString = isFolder ? 'folder' : 'file'; var typeString = isFolder ? 'folder' : 'file';
if (selectedItems > 1) { if (selectedItemCount > 1) {
modalMessage = "You are about to delete " + items + " items \nDo you want to continue?"; modalMessage = "You are about to delete " + items + " items \nDo you want to continue?";
} else { } else {
modalMessage = "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"; modalMessage = "You are about to delete the following " + typeString + ":\n" + paths + "\nDo you want to continue?";
} }
var object = tabletRoot.messageBox({ var object = tabletRoot.messageBox({
@ -379,7 +378,7 @@ Rectangle {
}); });
object.selected.connect(function(button) { object.selected.connect(function(button) {
if (button === OriginalDialogs.StandardButton.Yes) { if (button === OriginalDialogs.StandardButton.Yes) {
doDeleteFile(path); doDeleteFile(paths);
} }
}); });
} }
@ -704,7 +703,7 @@ Rectangle {
} }
} }
} }
} }// End_OF( itemLoader )
Rectangle { Rectangle {
id: treeLabelToolTip id: treeLabelToolTip
@ -741,50 +740,59 @@ Rectangle {
showTimer.stop(); showTimer.stop();
treeLabelToolTip.visible = false; treeLabelToolTip.visible = false;
} }
} }// End_OF( treeLabelToolTip )
MouseArea { MouseArea {
propagateComposedEvents: true propagateComposedEvents: true
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
onClicked: { onClicked: {
if (!HMD.active) { // Popup only displays properly on desktop if (treeView.selection.hasSelection && !HMD.active) { // Popup only displays properly on desktop
var index = treeView.indexAt(mouse.x, mouse.y); // Only display the popup if the click triggered within
treeView.selection.setCurrentIndex(index, 0x0002); // the selection.
contextMenu.currentIndex = index; var clickedIndex = treeView.indexAt(mouse.x, mouse.y);
contextMenu.popup(); var displayContextMenu = false;
for ( var i = 0; i < selectedItemCount; ++i) {
var currentSelectedIndex = treeView.selection.selectedIndexes[i];
if (clickedIndex === currentSelectedIndex) {
contextMenu.popup();
break;
}
}
} }
} }
} }
Menu { Menu {
id: contextMenu id: contextMenu
title: "Edit" title: "Edit"
property var url: "" property var url: ""
property var currentIndex: null
MenuItem { MenuItem {
text: "Copy URL" text: "Copy URL"
enabled: (selectedItemCount == 1)
onTriggered: { onTriggered: {
copyURLToClipboard(contextMenu.currentIndex); copyURLToClipboard(treeView.selection.currentIndex);
} }
} }
MenuItem { MenuItem {
text: "Rename" text: "Rename"
enabled: (selectedItemCount == 1)
onTriggered: { onTriggered: {
renameFile(contextMenu.currentIndex); renameFile(treeView.selection.currentIndex);
} }
} }
MenuItem { MenuItem {
text: "Delete" text: "Delete"
enabled: (selectedItemCount > 0)
onTriggered: { onTriggered: {
deleteFile(contextMenu.currentIndex); deleteFile();
} }
} }
} }// End_OF( contextMenu )
} }// End_OF( treeView )
Row { Row {
id: infoRow id: infoRow
@ -797,8 +805,8 @@ Rectangle {
function makeText() { function makeText() {
var numPendingBakes = assetMappingsModel.numPendingBakes; var numPendingBakes = assetMappingsModel.numPendingBakes;
if (selectedItems > 1 || numPendingBakes === 0) { if (selectedItemCount > 1 || numPendingBakes === 0) {
return selectedItems + " items selected"; return selectedItemCount + " items selected";
} else { } else {
return numPendingBakes + " bakes pending" return numPendingBakes + " bakes pending"
} }
@ -895,7 +903,7 @@ Rectangle {
"Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors."); "Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors.");
} }
} }
} }// End_OF( infoRow )
HifiControls.TabletContentSection { HifiControls.TabletContentSection {
id: uploadSection id: uploadSection
@ -972,7 +980,7 @@ Rectangle {
} }
} }
} }
} }// End_OF( uploadSection )
} }
} }

View file

@ -2338,6 +2338,7 @@ void Application::initializeGL() {
qFatal("Unable to make offscreen context current"); qFatal("Unable to make offscreen context current");
} }
_offscreenContext->doneCurrent(); _offscreenContext->doneCurrent();
_offscreenContext->setThreadContext();
_renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); _renderEventHandler = new RenderEventHandler(_glWidget->qglContext());
// The UI can't be created until the primary OpenGL // The UI can't be created until the primary OpenGL

View file

@ -27,6 +27,7 @@
#include <gl/GLWidget.h> #include <gl/GLWidget.h>
#include <gl/GLEscrow.h> #include <gl/GLEscrow.h>
#include <gl/Context.h> #include <gl/Context.h>
#include <gl/OffscreenGLCanvas.h>
#include <gpu/Texture.h> #include <gpu/Texture.h>
#include <gpu/StandardShaderLib.h> #include <gpu/StandardShaderLib.h>
@ -130,14 +131,14 @@ public:
CHECK_GL_ERROR(); CHECK_GL_ERROR();
_context->doneCurrent(); _context->doneCurrent();
while (!_shutdown) { while (!_shutdown) {
if (_pendingMainThreadOperation) { if (_pendingOtherThreadOperation) {
PROFILE_RANGE(render, "MainThreadOp") PROFILE_RANGE(render, "MainThreadOp")
{ {
Lock lock(_mutex); Lock lock(_mutex);
_context->doneCurrent(); _context->doneCurrent();
// Move the context to the main thread // Move the context to the main thread
_context->moveToThread(qApp->thread()); _context->moveToThread(_targetOperationThread);
_pendingMainThreadOperation = false; _pendingOtherThreadOperation = false;
// Release the main thread to do it's action // Release the main thread to do it's action
_condition.notify_one(); _condition.notify_one();
} }
@ -146,7 +147,7 @@ public:
{ {
// Main thread does it's thing while we wait on the lock to release // Main thread does it's thing while we wait on the lock to release
Lock lock(_mutex); Lock lock(_mutex);
_condition.wait(lock, [&] { return _finishedMainThreadOperation; }); _condition.wait(lock, [&] { return _finishedOtherThreadOperation; });
} }
} }
@ -214,23 +215,25 @@ public:
_condition.notify_one(); _condition.notify_one();
} }
void withMainThreadContext(std::function<void()> f) { void withOtherThreadContext(std::function<void()> f) {
// Signal to the thread that there is work to be done on the main thread // Signal to the thread that there is work to be done on the main thread
Lock lock(_mutex); Lock lock(_mutex);
_pendingMainThreadOperation = true; _targetOperationThread = QThread::currentThread();
_finishedMainThreadOperation = false; _pendingOtherThreadOperation = true;
_condition.wait(lock, [&] { return !_pendingMainThreadOperation; }); _finishedOtherThreadOperation = false;
_condition.wait(lock, [&] { return !_pendingOtherThreadOperation; });
_context->makeCurrent(); _context->makeCurrent();
f(); f();
_context->doneCurrent(); _context->doneCurrent();
_targetOperationThread = nullptr;
// Move the context back to the presentation thread // Move the context back to the presentation thread
_context->moveToThread(this); _context->moveToThread(this);
// restore control of the context to the presentation thread and signal // restore control of the context to the presentation thread and signal
// the end of the operation // the end of the operation
_finishedMainThreadOperation = true; _finishedOtherThreadOperation = true;
lock.unlock(); lock.unlock();
_condition.notify_one(); _condition.notify_one();
} }
@ -244,9 +247,11 @@ private:
Mutex _mutex; Mutex _mutex;
// Used to allow the main thread to perform context operations // Used to allow the main thread to perform context operations
Condition _condition; Condition _condition;
bool _pendingMainThreadOperation { false };
bool _finishedMainThreadOperation { false };
QThread* _mainThread { nullptr }; QThread* _targetOperationThread { nullptr };
bool _pendingOtherThreadOperation { false };
bool _finishedOtherThreadOperation { false };
std::queue<OpenGLDisplayPlugin*> _newPluginQueue; std::queue<OpenGLDisplayPlugin*> _newPluginQueue;
gl::Context* _context { nullptr }; gl::Context* _context { nullptr };
}; };
@ -744,10 +749,12 @@ void OpenGLDisplayPlugin::swapBuffers() {
context->swapBuffers(); context->swapBuffers();
} }
void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const { void OpenGLDisplayPlugin::withOtherThreadContext(std::function<void()> f) const {
static auto presentThread = DependencyManager::get<PresentThread>(); static auto presentThread = DependencyManager::get<PresentThread>();
presentThread->withMainThreadContext(f); presentThread->withOtherThreadContext(f);
_container->makeRenderingContextCurrent(); if (!OffscreenGLCanvas::restoreThreadContext()) {
qWarning("Unable to restore original OpenGL context");
}
} }
bool OpenGLDisplayPlugin::setDisplayTexture(const QString& name) { bool OpenGLDisplayPlugin::setDisplayTexture(const QString& name) {
@ -784,7 +791,7 @@ QImage OpenGLDisplayPlugin::getScreenshot(float aspectRatio) const {
} }
auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend(); auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend();
QImage screenshot(bestSize.x, bestSize.y, QImage::Format_ARGB32); QImage screenshot(bestSize.x, bestSize.y, QImage::Format_ARGB32);
withMainThreadContext([&] { withOtherThreadContext([&] {
glBackend->downloadFramebuffer(_compositeFramebuffer, ivec4(corner, bestSize), screenshot); glBackend->downloadFramebuffer(_compositeFramebuffer, ivec4(corner, bestSize), screenshot);
}); });
return screenshot.mirrored(false, true); return screenshot.mirrored(false, true);
@ -797,7 +804,7 @@ QImage OpenGLDisplayPlugin::getSecondaryCameraScreenshot() const {
auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend(); auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend();
QImage screenshot(region.z, region.w, QImage::Format_ARGB32); QImage screenshot(region.z, region.w, QImage::Format_ARGB32);
withMainThreadContext([&] { withOtherThreadContext([&] {
glBackend->downloadFramebuffer(secondaryCameraFramebuffer, region, screenshot); glBackend->downloadFramebuffer(secondaryCameraFramebuffer, region, screenshot);
}); });
return screenshot.mirrored(false, true); return screenshot.mirrored(false, true);
@ -886,7 +893,7 @@ void OpenGLDisplayPlugin::updateCompositeFramebuffer() {
void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer networkTexture, QOpenGLFramebufferObject* target, GLsync* fenceSync) { void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer networkTexture, QOpenGLFramebufferObject* target, GLsync* fenceSync) {
#if !defined(USE_GLES) #if !defined(USE_GLES)
auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend(); auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend();
withMainThreadContext([&] { withOtherThreadContext([&] {
GLuint sourceTexture = glBackend->getTextureID(networkTexture->getGPUTexture()); GLuint sourceTexture = glBackend->getTextureID(networkTexture->getGPUTexture());
GLuint targetTexture = target->texture(); GLuint targetTexture = target->texture();
GLuint fbo[2] {0, 0}; GLuint fbo[2] {0, 0};

View file

@ -119,7 +119,7 @@ protected:
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor); void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor);
virtual void updateFrameData(); virtual void updateFrameData();
void withMainThreadContext(std::function<void()> f) const; void withOtherThreadContext(std::function<void()> f) const;
void present(); void present();
virtual void swapBuffers(); virtual void swapBuffers();

View file

@ -985,6 +985,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
return; return;
} }
bool changed { false };
// relay any inbound joint changes from scripts/animation/network to the model/rig // relay any inbound joint changes from scripts/animation/network to the model/rig
_jointDataLock.withWriteLock([&] { _jointDataLock.withWriteLock([&] {
for (int index = 0; index < _localJointData.size(); ++index) { for (int index = 0; index < _localJointData.size(); ++index) {
@ -992,13 +993,21 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
if (jointData.rotationDirty) { if (jointData.rotationDirty) {
model->setJointRotation(index, true, jointData.joint.rotation, 1.0f); model->setJointRotation(index, true, jointData.joint.rotation, 1.0f);
jointData.rotationDirty = false; jointData.rotationDirty = false;
changed = true;
} }
if (jointData.translationDirty) { if (jointData.translationDirty) {
model->setJointTranslation(index, true, jointData.joint.translation, 1.0f); model->setJointTranslation(index, true, jointData.joint.translation, 1.0f);
jointData.translationDirty = false; jointData.translationDirty = false;
changed = true;
} }
} }
}); });
if (changed) {
forEachChild([&](SpatiallyNestablePointer object) {
object->locationChanged(false);
});
}
} }
using namespace render; using namespace render;

View file

@ -16,6 +16,7 @@
#include <QtCore/QProcessEnvironment> #include <QtCore/QProcessEnvironment>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QThread>
#include <QtGui/QOffscreenSurface> #include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLDebugLogger> #include <QtGui/QOpenGLDebugLogger>
@ -119,3 +120,29 @@ void OffscreenGLCanvas::moveToThreadWithContext(QThread* thread) {
moveToThread(thread); moveToThread(thread);
_context->moveToThread(thread); _context->moveToThread(thread);
} }
static const char* THREAD_CONTEXT_PROPERTY = "offscreenGlCanvas";
void OffscreenGLCanvas::setThreadContext() {
QThread::currentThread()->setProperty(THREAD_CONTEXT_PROPERTY, QVariant::fromValue<QObject*>(this));
}
bool OffscreenGLCanvas::restoreThreadContext() {
// Restore the rendering context for this thread
auto threadCanvasVariant = QThread::currentThread()->property(THREAD_CONTEXT_PROPERTY);
if (!threadCanvasVariant.isValid()) {
return false;
}
auto threadCanvasObject = qvariant_cast<QObject*>(threadCanvasVariant);
auto threadCanvas = static_cast<OffscreenGLCanvas*>(threadCanvasObject);
if (!threadCanvas) {
return false;
}
if (!threadCanvas->makeCurrent()) {
qFatal("Unable to restore Offscreen rendering context");
}
return true;
}

View file

@ -32,6 +32,9 @@ public:
} }
QObject* getContextObject(); QObject* getContextObject();
void setThreadContext();
static bool restoreThreadContext();
private slots: private slots:
void onMessageLogged(const QOpenGLDebugMessage &debugMessage); void onMessageLogged(const QOpenGLDebugMessage &debugMessage);

View file

@ -54,11 +54,9 @@ void KeyboardMouseDevice::InputDevice::focusOutEvent() {
void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) { void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) {
auto input = _inputDevice->makeInput((Qt::Key) event->key()); auto input = _inputDevice->makeInput((Qt::Key) event->key());
if (!(event->modifiers() & Qt::KeyboardModifier::ControlModifier)) { auto result = _inputDevice->_buttonPressedMap.insert(input.getChannel());
auto result = _inputDevice->_buttonPressedMap.insert(input.getChannel()); if (result.second) {
if (result.second) { // key pressed again ? without catching the release event ?
// key pressed again ? without catching the release event ?
}
} }
} }
@ -237,6 +235,7 @@ controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInp
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString())); availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString())); availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Tab), QKeySequence(Qt::Key_Tab).toString())); availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Tab), QKeySequence(Qt::Key_Tab).toString()));
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Control), "Control"));
availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseButton")); availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseButton"));
availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseButton")); availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseButton"));

View file

@ -58,6 +58,7 @@ void RenderEventHandler::onInitalize() {
return; return;
} }
_canvas.setThreadContext();
if (!_canvas.makeCurrent()) { if (!_canvas.makeCurrent()) {
qFatal("Unable to make QML rendering context current on render thread"); qFatal("Unable to make QML rendering context current on render thread");
} }

View file

@ -207,6 +207,10 @@ public:
void dump(const QString& prefix = "") const; void dump(const QString& prefix = "") const;
virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed
virtual void dimensionsChanged() { _queryAACubeSet = false; } // called when a this object's dimensions have changed
virtual void parentDeleted() { } // called on children of a deleted parent
protected: protected:
const NestableType _nestableType; // EntityItem or an AvatarData const NestableType _nestableType; // EntityItem or an AvatarData
QUuid _id; QUuid _id;
@ -218,10 +222,6 @@ protected:
mutable ReadWriteLockable _childrenLock; mutable ReadWriteLockable _childrenLock;
mutable QHash<QUuid, SpatiallyNestableWeakPointer> _children; mutable QHash<QUuid, SpatiallyNestableWeakPointer> _children;
virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed
virtual void dimensionsChanged() { _queryAACubeSet = false; } // called when a this object's dimensions have changed
virtual void parentDeleted() { } // called on children of a deleted parent
// _queryAACube is used to decide where something lives in the octree // _queryAACube is used to decide where something lives in the octree
mutable AACube _queryAACube; mutable AACube _queryAACube;
mutable bool _queryAACubeSet { false }; mutable bool _queryAACubeSet { false };

View file

@ -485,7 +485,7 @@ bool OpenVrDisplayPlugin::internalActivate() {
if (_threadedSubmit) { if (_threadedSubmit) {
_submitThread = std::make_shared<OpenVrSubmitThread>(*this); _submitThread = std::make_shared<OpenVrSubmitThread>(*this);
if (!_submitCanvas) { if (!_submitCanvas) {
withMainThreadContext([&] { withOtherThreadContext([&] {
_submitCanvas = std::make_shared<gl::OffscreenContext>(); _submitCanvas = std::make_shared<gl::OffscreenContext>();
_submitCanvas->create(); _submitCanvas->create();
_submitCanvas->doneCurrent(); _submitCanvas->doneCurrent();