mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 17:00:36 +02:00
Merge branch 'master' into vr-edit-a
This commit is contained in:
commit
2a654b3657
37 changed files with 846 additions and 146 deletions
|
@ -13,7 +13,7 @@ setup_memory_debugger()
|
|||
link_hifi_libraries(
|
||||
audio avatars octree gpu model fbx entities
|
||||
networking animation recording shared script-engine embedded-webserver
|
||||
physics plugins
|
||||
controllers physics plugins midi
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
Var STR_CONTAINS_VAR_3
|
||||
Var STR_CONTAINS_VAR_4
|
||||
Var STR_RETURN_VAR
|
||||
|
||||
|
||||
Function StrContains
|
||||
Exch $STR_NEEDLE
|
||||
Exch 1
|
||||
|
@ -343,22 +343,29 @@ SectionEnd
|
|||
;--------------------------------
|
||||
;Pages
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
|
||||
|
||||
!insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
|
||||
|
||||
Page custom InstallTypesPage ReadInstallTypes
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
|
||||
;Start Menu Folder Page Configuration
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
|
||||
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
|
||||
@CPACK_NSIS_PAGE_COMPONENTS@
|
||||
|
||||
|
||||
Page custom PostInstallOptionsPage ReadPostInstallOptions
|
||||
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
|
@ -442,6 +449,10 @@ Var CleanInstallCheckbox
|
|||
Var CurrentOffset
|
||||
Var OffsetUnits
|
||||
Var CopyFromProductionCheckbox
|
||||
Var ExpressInstallRadioButton
|
||||
Var CustomInstallRadioButton
|
||||
Var InstallTypeDialog
|
||||
Var Express
|
||||
|
||||
!macro SetPostInstallOption Checkbox OptionName Default
|
||||
; reads the value for the given post install option to the registry
|
||||
|
@ -459,6 +470,60 @@ Var CopyFromProductionCheckbox
|
|||
${EndIf}
|
||||
!macroend
|
||||
|
||||
Function InstallTypesPage
|
||||
!insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install"
|
||||
|
||||
nsDialogs::Create 1018
|
||||
Pop $InstallTypeDialog
|
||||
|
||||
${If} $InstallTypeDialog == error
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
StrCpy $CurrentOffset 0
|
||||
StrCpy $OffsetUnits u
|
||||
StrCpy $Express "0"
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${NSD_CreateRadioButton} 30% $CurrentOffset$OffsetUnits 100% 10u "Express Install (Recommended)"; $\nInstalls High Fidelity Interface and High Fidelity Sandbox"
|
||||
pop $ExpressInstallRadioButton
|
||||
${NSD_OnClick} $ExpressInstallRadioButton ChangeExpressLabel
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
||||
${NSD_CreateRadiobutton} 30% $CurrentOffset$OffsetUnits 100% 10u "Custom Install (Advanced)"
|
||||
pop $CustomInstallRadioButton
|
||||
${NSD_OnClick} $CustomInstallRadioButton ChangeCustomLabel
|
||||
${EndIf}
|
||||
|
||||
; Express Install selected by default
|
||||
${NSD_Check} $ExpressInstallRadioButton
|
||||
Call ChangeExpressLabel
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
Function ChangeExpressLabel
|
||||
Push $R1
|
||||
GetDlgItem $R1 $HWNDPARENT 1
|
||||
SendMessage $R1 ${WM_SETTEXT} 0 "STR:Install"
|
||||
Pop $R1
|
||||
FunctionEnd
|
||||
|
||||
Function ChangeCustomLabel
|
||||
Push $R1
|
||||
GetDlgItem $R1 $HWNDPARENT 1
|
||||
SendMessage $R1 ${WM_SETTEXT} 0 "STR:Next >"
|
||||
Pop $R1
|
||||
FunctionEnd
|
||||
|
||||
Function AbortFunction
|
||||
; Check if Express is set, if so, abort the post install options page
|
||||
Call HandleInstallTypes ; Sets Express if ExpressInstallRadioButton is checked and installs with defaults
|
||||
StrCmp $Express "1" 0 end
|
||||
Abort
|
||||
end:
|
||||
FunctionEnd
|
||||
|
||||
Function PostInstallOptionsPage
|
||||
!insertmacro MUI_HEADER_TEXT "Setup Options" ""
|
||||
|
||||
|
@ -549,9 +614,15 @@ Function PostInstallOptionsPage
|
|||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Copy settings and content from production install"
|
||||
Pop $CopyFromProductionCheckbox
|
||||
|
||||
${NSD_SetState} $CopyFromProductionCheckbox ${BST_CHECKED}
|
||||
${NSD_SetState} $CopyFromProductionCheckbox ${BST_UNCHECKED}
|
||||
${EndIf}
|
||||
|
||||
; Check if Express is set, if so, abort the post install options page
|
||||
Call HandleInstallTypes ; Sets Express if ExpressInstallRadioButton is checked and installs with defaults
|
||||
StrCmp $Express "1" 0 end
|
||||
Abort
|
||||
end:
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
|
@ -567,6 +638,16 @@ Var LaunchServerNowState
|
|||
Var LaunchClientNowState
|
||||
Var CopyFromProductionState
|
||||
Var CleanInstallState
|
||||
Var ExpressInstallState
|
||||
Var CustomInstallState
|
||||
|
||||
Function ReadInstallTypes
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
; check if the user asked for express/custom install
|
||||
${NSD_GetState} $ExpressInstallRadioButton $ExpressInstallState
|
||||
${NSD_GetState} $CustomInstallRadioButton $CustomInstallState
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function ReadPostInstallOptions
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
|
@ -603,6 +684,28 @@ Function ReadPostInstallOptions
|
|||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function HandleInstallTypes
|
||||
${If} $ExpressInstallState == ${BST_CHECKED}
|
||||
|
||||
StrCpy $Express "1"
|
||||
|
||||
; over ride custom checkboxes and select defaults
|
||||
${NSD_SetState} $DesktopClientCheckbox ${BST_CHECKED}
|
||||
${NSD_SetState} $ServerStartupCheckbox ${BST_CHECKED}
|
||||
${NSD_SetState} $LaunchServerNowCheckbox ${BST_CHECKED}
|
||||
${NSD_SetState} $LaunchClientNowCheckbox ${BST_CHECKED}
|
||||
|
||||
${If} @PR_BUILD@ == 1
|
||||
${NSD_SetState} $CopyFromProductionCheckbox ${BST_UNCHECKED}
|
||||
${EndIf}
|
||||
|
||||
; call ReadPostInstallOptions and HandlePostInstallOptions with defaults selected
|
||||
Call ReadPostInstallOptions
|
||||
Call HandlePostInstallOptions
|
||||
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function HandlePostInstallOptions
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
; check if the user asked for a desktop shortcut to High Fidelity
|
||||
|
@ -624,6 +727,7 @@ Function HandlePostInstallOptions
|
|||
!insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO
|
||||
${EndIf}
|
||||
|
||||
|
||||
; check if the user asked to have Sandbox launched every startup
|
||||
${If} $ServerStartupState == ${BST_CHECKED}
|
||||
; in case we added a shortcut in the global context, pull that now
|
||||
|
|
|
@ -195,7 +195,7 @@ link_hifi_libraries(
|
|||
shared octree ktx gpu gl gpu-gl procedural model render
|
||||
recording fbx networking model-networking entities avatars trackers
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer avatars-renderer ui auto-updater
|
||||
render-utils entities-renderer avatars-renderer ui auto-updater midi
|
||||
controllers plugins image trackers
|
||||
ui-plugins display-plugins input-plugins
|
||||
${NON_ANDROID_LIBRARIES}
|
||||
|
|
BIN
interface/resources/images/cursor-arrow.png
Normal file
BIN
interface/resources/images/cursor-arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
BIN
interface/resources/images/cursor-link.png
Normal file
BIN
interface/resources/images/cursor-link.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
interface/resources/images/cursor-none.png
Normal file
BIN
interface/resources/images/cursor-none.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 133 B |
BIN
interface/resources/images/cursor-reticle.png
Normal file
BIN
interface/resources/images/cursor-reticle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9 KiB |
|
@ -28,6 +28,7 @@ ScrollingWindow {
|
|||
minSize: Qt.vector2d(200, 300)
|
||||
|
||||
property int colorScheme: hifi.colorSchemes.dark
|
||||
property int selectionMode: SelectionMode.ExtendedSelection
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
|
@ -35,7 +36,8 @@ ScrollingWindow {
|
|||
property var assetProxyModel: Assets.proxyModel;
|
||||
property var assetMappingsModel: Assets.mappingModel;
|
||||
property var currentDirectory;
|
||||
|
||||
property var selectedItems: treeView.selection.selectedIndexes.length;
|
||||
|
||||
Settings {
|
||||
category: "Overlay.AssetServer"
|
||||
property alias x: root.x
|
||||
|
@ -48,7 +50,7 @@ ScrollingWindow {
|
|||
assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError);
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
function doDeleteFile(path) {
|
||||
console.log("Deleting " + path);
|
||||
|
||||
|
@ -118,11 +120,23 @@ ScrollingWindow {
|
|||
|
||||
function canAddToWorld(path) {
|
||||
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i];
|
||||
|
||||
if (selectedItems > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return supportedExtensions.reduce(function(total, current) {
|
||||
return total | new RegExp(current).test(path);
|
||||
}, false);
|
||||
}
|
||||
|
||||
function canRename() {
|
||||
if (treeView.selection.hasSelection && selectedItems == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
Assets.mappingModel.clear();
|
||||
|
@ -299,23 +313,37 @@ ScrollingWindow {
|
|||
});
|
||||
}
|
||||
function deleteFile(index) {
|
||||
var path = [];
|
||||
|
||||
if (!index) {
|
||||
index = treeView.selection.currentIndex;
|
||||
for (var i = 0; i < selectedItems; i++) {
|
||||
treeView.selection.setCurrentIndex(treeView.selection.selectedIndexes[i], 0x100);
|
||||
index = treeView.selection.currentIndex;
|
||||
path[i] = assetProxyModel.data(index, 0x100);
|
||||
}
|
||||
}
|
||||
var path = assetProxyModel.data(index, 0x100);
|
||||
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var modalMessage = "";
|
||||
var items = selectedItems.toString();
|
||||
var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101);
|
||||
var typeString = isFolder ? 'folder' : 'file';
|
||||
|
||||
|
||||
if (selectedItems > 1) {
|
||||
modalMessage = "You are about to delete " + items + " items \nDo you want to continue?";
|
||||
} else {
|
||||
modalMessage = "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?";
|
||||
}
|
||||
|
||||
var object = desktop.messageBox({
|
||||
icon: hifi.icons.question,
|
||||
buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No,
|
||||
defaultButton: OriginalDialogs.StandardButton.Yes,
|
||||
title: "Delete",
|
||||
text: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"
|
||||
text: modalMessage
|
||||
});
|
||||
object.selected.connect(function(button) {
|
||||
if (button === OriginalDialogs.StandardButton.Yes) {
|
||||
|
@ -455,20 +483,20 @@ ScrollingWindow {
|
|||
color: hifi.buttons.black
|
||||
colorScheme: root.colorScheme
|
||||
width: 120
|
||||
|
||||
|
||||
enabled: canAddToWorld(assetProxyModel.data(treeView.selection.currentIndex, 0x100))
|
||||
|
||||
|
||||
onClicked: root.addToWorld()
|
||||
}
|
||||
|
||||
|
||||
HifiControls.Button {
|
||||
text: "Rename"
|
||||
color: hifi.buttons.black
|
||||
colorScheme: root.colorScheme
|
||||
width: 80
|
||||
|
||||
|
||||
onClicked: root.renameFile()
|
||||
enabled: treeView.selection.hasSelection
|
||||
enabled: canRename()
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
|
@ -524,6 +552,7 @@ ScrollingWindow {
|
|||
treeModel: assetProxyModel
|
||||
canEdit: true
|
||||
colorScheme: root.colorScheme
|
||||
selectionMode: SelectionMode.ExtendedSelection
|
||||
|
||||
modifyEl: renameEl
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ Rectangle {
|
|||
property var assetProxyModel: Assets.proxyModel;
|
||||
property var assetMappingsModel: Assets.mappingModel;
|
||||
property var currentDirectory;
|
||||
property var selectedItems: treeView.selection.selectedIndexes.length;
|
||||
|
||||
Settings {
|
||||
category: "Overlay.AssetServer"
|
||||
|
@ -119,11 +120,23 @@ Rectangle {
|
|||
|
||||
function canAddToWorld(path) {
|
||||
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i];
|
||||
|
||||
if (selectedItems > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return supportedExtensions.reduce(function(total, current) {
|
||||
return total | new RegExp(current).test(path);
|
||||
}, false);
|
||||
}
|
||||
|
||||
function canRename() {
|
||||
if (treeView.selection.hasSelection && selectedItems == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
Assets.mappingModel.clear();
|
||||
|
@ -300,23 +313,37 @@ Rectangle {
|
|||
});
|
||||
}
|
||||
function deleteFile(index) {
|
||||
var path = [];
|
||||
|
||||
if (!index) {
|
||||
index = treeView.selection.currentIndex;
|
||||
for (var i = 0; i < selectedItems; i++) {
|
||||
treeView.selection.setCurrentIndex(treeView.selection.selectedIndexes[i], 0x100);
|
||||
index = treeView.selection.currentIndex;
|
||||
path[i] = assetProxyModel.data(index, 0x100);
|
||||
}
|
||||
}
|
||||
var path = assetProxyModel.data(index, 0x100);
|
||||
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
|
||||
var modalMessage = "";
|
||||
var items = selectedItems.toString();
|
||||
var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101);
|
||||
var typeString = isFolder ? 'folder' : 'file';
|
||||
|
||||
if (selectedItems > 1) {
|
||||
modalMessage = "You are about to delete " + items + " items \nDo you want to continue?";
|
||||
} else {
|
||||
modalMessage = "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?";
|
||||
}
|
||||
|
||||
var object = tabletRoot.messageBox({
|
||||
icon: hifi.icons.question,
|
||||
buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No,
|
||||
defaultButton: OriginalDialogs.StandardButton.Yes,
|
||||
title: "Delete",
|
||||
text: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"
|
||||
text: modalMessage
|
||||
});
|
||||
object.selected.connect(function(button) {
|
||||
if (button === OriginalDialogs.StandardButton.Yes) {
|
||||
|
@ -469,7 +496,7 @@ Rectangle {
|
|||
width: 80
|
||||
|
||||
onClicked: root.renameFile()
|
||||
enabled: treeView.selection.hasSelection
|
||||
enabled: canRename()
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
|
@ -525,6 +552,7 @@ Rectangle {
|
|||
treeModel: assetProxyModel
|
||||
canEdit: true
|
||||
colorScheme: root.colorScheme
|
||||
selectionMode: SelectionMode.ExtendedSelection
|
||||
|
||||
modifyEl: renameEl
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include <AssetClient.h>
|
||||
#include <AssetUpload.h>
|
||||
#include <AutoUpdater.h>
|
||||
#include <Midi.h>
|
||||
#include <AudioInjectorManager.h>
|
||||
#include <AvatarBookmarks.h>
|
||||
#include <CursorManager.h>
|
||||
|
@ -398,6 +399,10 @@ public:
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (message->message == WM_DEVICECHANGE) {
|
||||
Midi::USBchanged(); // re-scan the MIDI bus
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -567,6 +572,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<SceneScriptingInterface>();
|
||||
DependencyManager::set<OffscreenUi>();
|
||||
DependencyManager::set<AutoUpdater>();
|
||||
DependencyManager::set<Midi>();
|
||||
DependencyManager::set<PathUtils>();
|
||||
DependencyManager::set<InterfaceDynamicFactory>();
|
||||
DependencyManager::set<AudioInjectorManager>();
|
||||
|
@ -618,6 +624,7 @@ const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
|
|||
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
|
||||
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
|
||||
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false;
|
||||
const QString DEFAULT_CURSOR_NAME = "DEFAULT";
|
||||
|
||||
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runningMarkerExisted) :
|
||||
QApplication(argc, argv),
|
||||
|
@ -637,6 +644,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR),
|
||||
_preferAvatarFingerOverStylusSetting("preferAvatarFingerOverStylus", DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS),
|
||||
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
||||
_preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME),
|
||||
_scaleMirror(1.0f),
|
||||
_rotateMirror(0.0f),
|
||||
_raiseMirror(0.0f),
|
||||
|
@ -932,14 +940,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
||||
_glWidget->setFocus();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget
|
||||
#else
|
||||
// On windows and linux, hiding the top level cursor also means it's invisible when hovering over the
|
||||
// window menu, which is a pain, so only hide it for the GL surface
|
||||
auto cursorTarget = _glWidget;
|
||||
#endif
|
||||
cursorTarget->setCursor(Qt::BlankCursor);
|
||||
showCursor(Cursor::Manager::lookupIcon(_preferredCursor.get()));
|
||||
|
||||
// enable mouse tracking; otherwise, we only get drag events
|
||||
_glWidget->setMouseTracking(true);
|
||||
|
@ -1737,9 +1738,16 @@ void Application::checkChangeCursor() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::showCursor(const QCursor& cursor) {
|
||||
void Application::showCursor(const Cursor::Icon& cursor) {
|
||||
QMutexLocker locker(&_changeCursorLock);
|
||||
_desiredCursor = cursor;
|
||||
|
||||
auto managedCursor = Cursor::Manager::instance().getCursor();
|
||||
auto curIcon = managedCursor->getIcon();
|
||||
if (curIcon != cursor) {
|
||||
managedCursor->setIcon(cursor);
|
||||
curIcon = cursor;
|
||||
}
|
||||
_desiredCursor = cursor == Cursor::Icon::SYSTEM ? Qt::ArrowCursor : Qt::BlankCursor;
|
||||
_cursorNeedsChanging = true;
|
||||
}
|
||||
|
||||
|
@ -2160,9 +2168,11 @@ void Application::initializeUi() {
|
|||
_window->setMenuBar(new Menu());
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] {
|
||||
connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] {
|
||||
if (isHMDMode()) {
|
||||
showCursor(compositorHelper->getAllowMouseCapture() ? Qt::BlankCursor : Qt::ArrowCursor);
|
||||
showCursor(compositorHelper->getAllowMouseCapture() ?
|
||||
Cursor::Manager::lookupIcon(_preferredCursor.get()) :
|
||||
Cursor::Icon::SYSTEM);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2504,6 +2514,12 @@ void Application::setPreferAvatarFingerOverStylus(bool value) {
|
|||
_preferAvatarFingerOverStylusSetting.set(value);
|
||||
}
|
||||
|
||||
void Application::setPreferredCursor(const QString& cursorName) {
|
||||
qCDebug(interfaceapp) << "setPreferredCursor" << cursorName;
|
||||
_preferredCursor.set(cursorName.isEmpty() ? DEFAULT_CURSOR_NAME : cursorName);
|
||||
showCursor(Cursor::Manager::lookupIcon(_preferredCursor.get()));
|
||||
}
|
||||
|
||||
void Application::setSettingConstrainToolbarPosition(bool setting) {
|
||||
_constrainToolbarPosition.set(setting);
|
||||
DependencyManager::get<OffscreenUi>()->setConstrainToolbarToCenterX(setting);
|
||||
|
@ -3020,7 +3036,9 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_F: {
|
||||
_physicsEngine->dumpNextStats();
|
||||
if (isOption) {
|
||||
_physicsEngine->dumpNextStats();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3064,9 +3082,13 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
auto cursor = Cursor::Manager::instance().getCursor();
|
||||
auto curIcon = cursor->getIcon();
|
||||
if (curIcon == Cursor::Icon::DEFAULT) {
|
||||
cursor->setIcon(Cursor::Icon::LINK);
|
||||
showCursor(Cursor::Icon::RETICLE);
|
||||
} else if (curIcon == Cursor::Icon::RETICLE) {
|
||||
showCursor(Cursor::Icon::SYSTEM);
|
||||
} else if (curIcon == Cursor::Icon::SYSTEM) {
|
||||
showCursor(Cursor::Icon::LINK);
|
||||
} else {
|
||||
cursor->setIcon(Cursor::Icon::DEFAULT);
|
||||
showCursor(Cursor::Icon::DEFAULT);
|
||||
}
|
||||
} else {
|
||||
resetSensors(true);
|
||||
|
@ -4460,27 +4482,31 @@ void Application::cameraModeChanged() {
|
|||
|
||||
|
||||
void Application::cameraMenuChanged() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
auto menu = Menu::getInstance();
|
||||
if (menu->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
if (isHMDMode()) {
|
||||
menu->setIsOptionChecked(MenuOption::FullscreenMirror, false);
|
||||
menu->setIsOptionChecked(MenuOption::FirstPerson, true);
|
||||
} else if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
_myCamera.setMode(CAMERA_MODE_MIRROR);
|
||||
}
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) {
|
||||
} else if (menu->isOptionChecked(MenuOption::FirstPerson)) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) {
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||
getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN);
|
||||
}
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::ThirdPerson)) {
|
||||
} else if (menu->isOptionChecked(MenuOption::ThirdPerson)) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
||||
if (getMyAvatar()->getBoomLength() == MyAvatar::ZOOM_MIN) {
|
||||
getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT);
|
||||
}
|
||||
}
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode)) {
|
||||
} else if (menu->isOptionChecked(MenuOption::IndependentMode)) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
|
||||
_myCamera.setMode(CAMERA_MODE_INDEPENDENT);
|
||||
}
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::CameraEntityMode)) {
|
||||
} else if (menu->isOptionChecked(MenuOption::CameraEntityMode)) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_ENTITY) {
|
||||
_myCamera.setMode(CAMERA_MODE_ENTITY);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "BandwidthRecorder.h"
|
||||
#include "FancyCamera.h"
|
||||
#include "ConnectionMonitor.h"
|
||||
#include "CursorManager.h"
|
||||
#include "gpu/Context.h"
|
||||
#include "Menu.h"
|
||||
#include "octree/OctreePacketProcessor.h"
|
||||
|
@ -165,7 +166,7 @@ public:
|
|||
QSize getDeviceSize() const;
|
||||
bool hasFocus() const;
|
||||
|
||||
void showCursor(const QCursor& cursor);
|
||||
void showCursor(const Cursor::Icon& cursor);
|
||||
|
||||
bool isThrottleRendering() const;
|
||||
|
||||
|
@ -400,6 +401,9 @@ public slots:
|
|||
void loadDomainConnectionDialog();
|
||||
void showScriptLogs();
|
||||
|
||||
const QString getPreferredCursor() const { return _preferredCursor.get(); }
|
||||
void setPreferredCursor(const QString& cursor);
|
||||
|
||||
private slots:
|
||||
void showDesktop();
|
||||
void clearDomainOctreeDetails();
|
||||
|
@ -564,6 +568,7 @@ private:
|
|||
Setting::Handle<bool> _hmdTabletBecomesToolbarSetting;
|
||||
Setting::Handle<bool> _preferAvatarFingerOverStylusSetting;
|
||||
Setting::Handle<bool> _constrainToolbarPosition;
|
||||
Setting::Handle<QString> _preferredCursor;
|
||||
|
||||
float _scaleMirror;
|
||||
float _rotateMirror;
|
||||
|
@ -637,7 +642,7 @@ private:
|
|||
|
||||
void checkChangeCursor();
|
||||
mutable QMutex _changeCursorLock { QMutex::Recursive };
|
||||
QCursor _desiredCursor{ Qt::BlankCursor };
|
||||
Qt::CursorShape _desiredCursor{ Qt::BlankCursor };
|
||||
bool _cursorNeedsChanging { false };
|
||||
|
||||
QThread* _deadlockWatchdogThread;
|
||||
|
|
|
@ -222,19 +222,19 @@ Menu::Menu() {
|
|||
cameraModeGroup->setExclusive(true);
|
||||
|
||||
// View > First Person
|
||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||
MenuOption::FirstPerson, 0,
|
||||
true, qApp, SLOT(cameraMenuChanged())));
|
||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::FirstPerson, Qt::CTRL | Qt::Key_F,
|
||||
true, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
// View > Third Person
|
||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||
MenuOption::ThirdPerson, 0,
|
||||
false, qApp, SLOT(cameraMenuChanged())));
|
||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::ThirdPerson, Qt::CTRL | Qt::Key_G,
|
||||
false, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
// View > Mirror
|
||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||
MenuOption::FullscreenMirror, 0,
|
||||
false, qApp, SLOT(cameraMenuChanged())));
|
||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::FullscreenMirror, Qt::CTRL | Qt::Key_H,
|
||||
false, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
// View > Independent [advanced]
|
||||
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||
|
|
|
@ -613,7 +613,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
MovingEntitiesOperator moveOperator(entityTree);
|
||||
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||
// if the queryBox has changed, tell the entity-server
|
||||
if (object->computePuffedQueryAACube() && object->getNestableType() == NestableType::Entity) {
|
||||
if (object->getNestableType() == NestableType::Entity && object->checkAndMaybeUpdateQueryAACube()) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||
bool success;
|
||||
AACube newCube = entity->getQueryAACube(success);
|
||||
|
|
|
@ -106,6 +106,12 @@ void setupPreferences() {
|
|||
auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); };
|
||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Avatar Finger Over Stylus", getter, setter));
|
||||
}
|
||||
{
|
||||
static const QString RETICLE_ICON_NAME = { Cursor::Manager::getIconName(Cursor::Icon::RETICLE) };
|
||||
auto getter = []()->bool { return qApp->getPreferredCursor() == RETICLE_ICON_NAME; };
|
||||
auto setter = [](bool value) { qApp->setPreferredCursor(value ? RETICLE_ICON_NAME : QString()); };
|
||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter));
|
||||
}
|
||||
|
||||
// Snapshots
|
||||
static const QString SNAPSHOTS { "Snapshots" };
|
||||
|
|
|
@ -323,7 +323,7 @@ signals:
|
|||
private:
|
||||
void cleanupOverlaysToDelete();
|
||||
|
||||
mutable QMutex _mutex;
|
||||
mutable QMutex _mutex { QMutex::Recursive };
|
||||
QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
|
||||
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
|
||||
#if OVERLAY_PANELS
|
||||
|
|
|
@ -1355,8 +1355,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy);
|
||||
|
||||
AACube saveQueryAACube = _queryAACube;
|
||||
checkAndAdjustQueryAACube();
|
||||
if (saveQueryAACube != _queryAACube) {
|
||||
if (checkAndMaybeUpdateQueryAACube() && saveQueryAACube != _queryAACube) {
|
||||
somethingChanged = true;
|
||||
}
|
||||
|
||||
|
@ -1424,26 +1423,20 @@ void EntityItem::setDimensions(const glm::vec3& value) {
|
|||
///
|
||||
AACube EntityItem::getMaximumAACube(bool& success) const {
|
||||
if (_recalcMaxAACube) {
|
||||
// * we know that the position is the center of rotation
|
||||
glm::vec3 centerOfRotation = getPosition(success); // also where _registration point is
|
||||
if (success) {
|
||||
_recalcMaxAACube = false;
|
||||
// * we know that the registration point is the center of rotation
|
||||
// * we can calculate the length of the furthest extent from the registration point
|
||||
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec3 registrationPoint = (dimensions * _registrationPoint);
|
||||
glm::vec3 registrationRemainder = (dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
|
||||
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
|
||||
// we want to compute the furthestExtent that an entity can extend out from its "position"
|
||||
// to do this we compute the max of these two vec3s: registration and 1-registration
|
||||
// and then scale by dimensions
|
||||
glm::vec3 maxExtents = getDimensions() * glm::max(_registrationPoint, glm::vec3(1.0f) - _registrationPoint);
|
||||
|
||||
// * we know that if you rotate in any direction you would create a sphere
|
||||
// that has a radius of the length of furthest extent from registration point
|
||||
float radius = glm::length(furthestExtentFromRegistration);
|
||||
// there exists a sphere that contains maxExtents for all rotations
|
||||
float radius = glm::length(maxExtents);
|
||||
|
||||
// * we know that the minimum bounding cube of this maximum possible sphere is
|
||||
// (center - radius) to (center + radius)
|
||||
// put a cube around the sphere
|
||||
// TODO? replace _maxAACube with _boundingSphereRadius
|
||||
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
|
||||
|
||||
_maxAACube = AACube(minimumCorner, radius * 2.0f);
|
||||
}
|
||||
} else {
|
||||
|
@ -1635,6 +1628,8 @@ void EntityItem::updateDimensions(const glm::vec3& value) {
|
|||
if (getDimensions() != value) {
|
||||
setDimensions(value);
|
||||
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
||||
_queryAACubeSet = false;
|
||||
dimensionsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2157,12 +2157,17 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
return out;
|
||||
}
|
||||
|
||||
bool EntityItemProperties::parentDependentPropertyChanged() const {
|
||||
return localPositionChanged() || positionChanged() ||
|
||||
localRotationChanged() || rotationChanged() ||
|
||||
localVelocityChanged() || localAngularVelocityChanged();
|
||||
bool EntityItemProperties::transformChanged() const {
|
||||
return positionChanged() || rotationChanged() ||
|
||||
localPositionChanged() || localRotationChanged();
|
||||
}
|
||||
|
||||
bool EntityItemProperties::parentRelatedPropertyChanged() const {
|
||||
return parentDependentPropertyChanged() || parentIDChanged() || parentJointIndexChanged();
|
||||
return positionChanged() || rotationChanged() ||
|
||||
localPositionChanged() || localRotationChanged() ||
|
||||
parentIDChanged() || parentJointIndexChanged();
|
||||
}
|
||||
|
||||
bool EntityItemProperties::queryAACubeRelatedPropertyChanged() const {
|
||||
return parentRelatedPropertyChanged() || dimensionsChanged();
|
||||
}
|
||||
|
|
|
@ -86,8 +86,9 @@ public:
|
|||
|
||||
EntityPropertyFlags getChangedProperties() const;
|
||||
|
||||
bool parentDependentPropertyChanged() const; // was there a changed in a property that requires parent info to interpret?
|
||||
bool parentRelatedPropertyChanged() const; // parentDependentPropertyChanged or parentID or parentJointIndex
|
||||
bool transformChanged() const;
|
||||
bool parentRelatedPropertyChanged() const;
|
||||
bool queryAACubeRelatedPropertyChanged() const;
|
||||
|
||||
AABox getAABox() const;
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
|
|||
_entityTree->withWriteLock([&] {
|
||||
EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID);
|
||||
if (entity) {
|
||||
if (propertiesWithSimID.parentRelatedPropertyChanged()) {
|
||||
if (propertiesWithSimID.queryAACubeRelatedPropertyChanged()) {
|
||||
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
|
||||
bool success;
|
||||
AACube queryAACube = entity->getQueryAACube(success);
|
||||
|
@ -435,7 +435,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
entity->rememberHasSimulationOwnershipBid();
|
||||
}
|
||||
}
|
||||
if (properties.parentRelatedPropertyChanged() && entity->computePuffedQueryAACube()) {
|
||||
if (properties.queryAACubeRelatedPropertyChanged()) {
|
||||
properties.setQueryAACube(entity->getQueryAACube());
|
||||
}
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
|
@ -445,7 +445,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
// if they've changed.
|
||||
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
if (descendant->getNestableType() == NestableType::Entity) {
|
||||
if (descendant->computePuffedQueryAACube()) {
|
||||
if (descendant->checkAndMaybeUpdateQueryAACube()) {
|
||||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||
EntityItemProperties newQueryCubeProperties;
|
||||
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
|
|
|
@ -1675,6 +1675,7 @@ QVector<EntityItemID> EntityTree::sendEntities(EntityEditPacketSender* packetSen
|
|||
addToNeedsParentFixupList(entity);
|
||||
}
|
||||
entity->forceQueryAACubeUpdate();
|
||||
entity->checkAndMaybeUpdateQueryAACube();
|
||||
moveOperator.addEntityToMoveList(entity, entity->getQueryAACube());
|
||||
i++;
|
||||
} else {
|
||||
|
@ -1693,7 +1694,7 @@ QVector<EntityItemID> EntityTree::sendEntities(EntityEditPacketSender* packetSen
|
|||
EntityItemPointer entity = localTree->findEntityByEntityItemID(newID);
|
||||
if (entity) {
|
||||
// queue the packet to send to the server
|
||||
entity->computePuffedQueryAACube();
|
||||
entity->updateQueryAACube();
|
||||
EntityItemProperties properties = entity->getProperties();
|
||||
properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityAdd, localTree, newID, properties);
|
||||
|
|
|
@ -136,7 +136,7 @@ void SimpleEntitySimulation::sortEntitiesThatMoved() {
|
|||
SetOfEntities::iterator itemItr = _entitiesToSort.begin();
|
||||
while (itemItr != _entitiesToSort.end()) {
|
||||
EntityItemPointer entity = *itemItr;
|
||||
entity->computePuffedQueryAACube();
|
||||
entity->checkAndMaybeUpdateQueryAACube();
|
||||
++itemItr;
|
||||
}
|
||||
EntitySimulation::sortEntitiesThatMoved();
|
||||
|
|
3
libraries/midi/CMakeLists.txt
Normal file
3
libraries/midi/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
set(TARGET_NAME midi)
|
||||
setup_hifi_library(Network)
|
||||
link_hifi_libraries(shared networking)
|
275
libraries/midi/src/Midi.cpp
Normal file
275
libraries/midi/src/Midi.cpp
Normal file
|
@ -0,0 +1,275 @@
|
|||
//
|
||||
// Midi.cpp
|
||||
// libraries/midi/src
|
||||
//
|
||||
// Created by Burt Sloane
|
||||
// Copyright 2015 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 "Midi.h"
|
||||
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
#include "Windows.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
const int MIDI_BYTE_MASK = 0x0FF;
|
||||
const int MIDI_SHIFT_NOTE = 8;
|
||||
const int MIDI_SHIFT_VELOCITY = 16;
|
||||
#endif
|
||||
const int MIDI_STATUS_MASK = 0x0F0;
|
||||
const int MIDI_NOTE_OFF = 0x080;
|
||||
const int MIDI_NOTE_ON = 0x090;
|
||||
const int MIDI_CONTROL_CHANGE = 0x0b0;
|
||||
const int MIDI_CHANNEL_MODE_ALL_NOTES_OFF = 0x07b;
|
||||
|
||||
|
||||
static Midi* instance = NULL; // communicate this to non-class callbacks
|
||||
static bool thruModeEnabled = false;
|
||||
|
||||
std::vector<QString> Midi::midiinexclude;
|
||||
std::vector<QString> Midi::midioutexclude;
|
||||
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
|
||||
#pragma comment(lib, "Winmm.lib")
|
||||
|
||||
//
|
||||
std::vector<HMIDIIN> midihin;
|
||||
std::vector<HMIDIOUT> midihout;
|
||||
|
||||
|
||||
void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
|
||||
switch (wMsg) {
|
||||
case MIM_OPEN:
|
||||
// message not used
|
||||
break;
|
||||
case MIM_CLOSE:
|
||||
for (int i = 0; i < midihin.size(); i++) {
|
||||
if (midihin[i] == hMidiIn) {
|
||||
midihin[i] = NULL;
|
||||
instance->allNotesOff();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIM_DATA: {
|
||||
int status = MIDI_BYTE_MASK & dwParam1;
|
||||
int note = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE);
|
||||
int vel = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_VELOCITY);
|
||||
if (thruModeEnabled) {
|
||||
instance->sendNote(status, note, vel); // relay the note on to all other midi devices
|
||||
}
|
||||
instance->noteReceived(status, note, vel); // notify the javascript
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
|
||||
switch (wMsg) {
|
||||
case MOM_OPEN:
|
||||
// message not used
|
||||
break;
|
||||
case MOM_CLOSE:
|
||||
for (int i = 0; i < midihout.size(); i++) {
|
||||
if (midihout[i] == hmo) {
|
||||
midihout[i] = NULL;
|
||||
instance->allNotesOff();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Midi::sendNote(int status, int note, int vel) {
|
||||
for (int i = 0; i < midihout.size(); i++) {
|
||||
if (midihout[i] != NULL) {
|
||||
midiOutShortMsg(midihout[i], status + (note << MIDI_SHIFT_NOTE) + (vel << MIDI_SHIFT_VELOCITY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Midi::MidiSetup() {
|
||||
midihin.clear();
|
||||
midihout.clear();
|
||||
|
||||
MIDIINCAPS incaps;
|
||||
for (unsigned int i = 0; i < midiInGetNumDevs(); i++) {
|
||||
midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS));
|
||||
|
||||
bool found = false;
|
||||
for (int j = 0; j < midiinexclude.size(); j++) {
|
||||
if (midiinexclude[j].toStdString().compare(incaps.szPname) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) { // EXCLUDE AN INPUT BY NAME
|
||||
HMIDIIN tmphin;
|
||||
midiInOpen(&tmphin, i, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION);
|
||||
midiInStart(tmphin);
|
||||
midihin.push_back(tmphin);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MIDIOUTCAPS outcaps;
|
||||
for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) {
|
||||
midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS));
|
||||
|
||||
bool found = false;
|
||||
for (int j = 0; j < midioutexclude.size(); j++) {
|
||||
if (midioutexclude[j].toStdString().compare(outcaps.szPname) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) { // EXCLUDE AN OUTPUT BY NAME
|
||||
HMIDIOUT tmphout;
|
||||
midiOutOpen(&tmphout, i, (DWORD_PTR)MidiOutProc, NULL, CALLBACK_FUNCTION);
|
||||
midihout.push_back(tmphout);
|
||||
}
|
||||
}
|
||||
|
||||
allNotesOff();
|
||||
}
|
||||
|
||||
void Midi::MidiCleanup() {
|
||||
allNotesOff();
|
||||
|
||||
for (int i = 0; i < midihin.size(); i++) {
|
||||
if (midihin[i] != NULL) {
|
||||
midiInStop(midihin[i]);
|
||||
midiInClose(midihin[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < midihout.size(); i++) {
|
||||
if (midihout[i] != NULL) {
|
||||
midiOutClose(midihout[i]);
|
||||
}
|
||||
}
|
||||
midihin.clear();
|
||||
midihout.clear();
|
||||
}
|
||||
#else
|
||||
void Midi::sendNote(int status, int note, int vel) {
|
||||
}
|
||||
|
||||
void Midi::MidiSetup() {
|
||||
allNotesOff();
|
||||
}
|
||||
|
||||
void Midi::MidiCleanup() {
|
||||
allNotesOff();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Midi::noteReceived(int status, int note, int velocity) {
|
||||
if (((status & MIDI_STATUS_MASK) != MIDI_NOTE_OFF) &&
|
||||
((status & MIDI_STATUS_MASK) != MIDI_NOTE_ON)) {
|
||||
return; // NOTE: only sending note-on and note-off to Javascript
|
||||
}
|
||||
|
||||
QVariantMap eventData;
|
||||
eventData["status"] = status;
|
||||
eventData["note"] = note;
|
||||
eventData["velocity"] = velocity;
|
||||
emit midiNote(eventData);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Midi::Midi() {
|
||||
instance = this;
|
||||
#if defined Q_OS_WIN32
|
||||
midioutexclude.push_back("Microsoft GS Wavetable Synth"); // we don't want to hear this thing
|
||||
#endif
|
||||
MidiSetup();
|
||||
}
|
||||
|
||||
Midi::~Midi() {
|
||||
}
|
||||
|
||||
void Midi::playMidiNote(int status, int note, int velocity) {
|
||||
sendNote(status, note, velocity);
|
||||
}
|
||||
|
||||
void Midi::allNotesOff() {
|
||||
sendNote(MIDI_CONTROL_CHANGE, MIDI_CHANNEL_MODE_ALL_NOTES_OFF, 0); // all notes off
|
||||
}
|
||||
|
||||
void Midi::resetDevices() {
|
||||
MidiCleanup();
|
||||
MidiSetup();
|
||||
}
|
||||
|
||||
void Midi::USBchanged() {
|
||||
instance->MidiCleanup();
|
||||
instance->MidiSetup();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
QStringList Midi::listMidiDevices(bool output) {
|
||||
QStringList rv;
|
||||
#if defined Q_OS_WIN32
|
||||
if (output) {
|
||||
MIDIOUTCAPS outcaps;
|
||||
for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) {
|
||||
midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS));
|
||||
rv.append(outcaps.szPname);
|
||||
}
|
||||
} else {
|
||||
MIDIINCAPS incaps;
|
||||
for (unsigned int i = 0; i < midiInGetNumDevs(); i++) {
|
||||
midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS));
|
||||
rv.append(incaps.szPname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
void Midi::unblockMidiDevice(QString name, bool output) {
|
||||
if (output) {
|
||||
for (unsigned long i = 0; i < midioutexclude.size(); i++) {
|
||||
if (midioutexclude[i].toStdString().compare(name.toStdString()) == 0) {
|
||||
midioutexclude.erase(midioutexclude.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (unsigned long i = 0; i < midiinexclude.size(); i++) {
|
||||
if (midiinexclude[i].toStdString().compare(name.toStdString()) == 0) {
|
||||
midiinexclude.erase(midiinexclude.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Midi::blockMidiDevice(QString name, bool output) {
|
||||
unblockMidiDevice(name, output); // make sure it's only in there once
|
||||
if (output) {
|
||||
midioutexclude.push_back(name);
|
||||
} else {
|
||||
midiinexclude.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
void Midi::thruModeEnable(bool enable) {
|
||||
thruModeEnabled = enable;
|
||||
}
|
||||
|
72
libraries/midi/src/Midi.h
Normal file
72
libraries/midi/src/Midi.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// Midi.h
|
||||
// libraries/midi/src
|
||||
//
|
||||
// Created by Burt Sloane
|
||||
// Copyright 2015 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_Midi_h
|
||||
#define hifi_Midi_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class Midi : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void noteReceived(int status, int note, int velocity); // relay a note to Javascript
|
||||
void sendNote(int status, int note, int vel); // relay a note to MIDI outputs
|
||||
static void USBchanged();
|
||||
|
||||
private:
|
||||
static std::vector<QString> midiinexclude;
|
||||
static std::vector<QString> midioutexclude;
|
||||
|
||||
private:
|
||||
void MidiSetup();
|
||||
void MidiCleanup();
|
||||
|
||||
signals:
|
||||
void midiNote(QVariantMap eventData);
|
||||
|
||||
public slots:
|
||||
/// play a note on all connected devices
|
||||
/// @param {int} status: 0x80 is noteoff, 0x90 is noteon (if velocity=0, noteoff), etc
|
||||
/// @param {int} note: midi note number
|
||||
/// @param {int} velocity: note velocity (0 means noteoff)
|
||||
Q_INVOKABLE void playMidiNote(int status, int note, int velocity);
|
||||
|
||||
/// turn off all notes on all connected devices
|
||||
Q_INVOKABLE void allNotesOff();
|
||||
|
||||
/// clean up and re-discover attached devices
|
||||
Q_INVOKABLE void resetDevices();
|
||||
|
||||
/// ask for a list of inputs/outputs
|
||||
Q_INVOKABLE QStringList listMidiDevices(bool output);
|
||||
|
||||
/// block an input/output by name
|
||||
Q_INVOKABLE void blockMidiDevice(QString name, bool output);
|
||||
|
||||
/// unblock an input/output by name
|
||||
Q_INVOKABLE void unblockMidiDevice(QString name, bool output);
|
||||
|
||||
/// repeat all incoming notes to all outputs (default disabled)
|
||||
Q_INVOKABLE void thruModeEnable(bool enable);
|
||||
|
||||
public:
|
||||
Midi();
|
||||
virtual ~Midi();
|
||||
};
|
||||
|
||||
#endif // hifi_Midi_h
|
|
@ -484,11 +484,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (_entity->dynamicDataNeedsTransmit()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_entity->queryAABoxNeedsUpdate()) {
|
||||
if (_entity->dynamicDataNeedsTransmit() || _entity->queryAACubeNeedsUpdate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -577,9 +573,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
properties.setActionData(_serverActionData);
|
||||
}
|
||||
|
||||
if (properties.parentRelatedPropertyChanged() && _entity->computePuffedQueryAACube()) {
|
||||
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
|
||||
properties.setQueryAACube(_entity->getQueryAACube());
|
||||
if (properties.transformChanged()) {
|
||||
if (_entity->checkAndMaybeUpdateQueryAACube()) {
|
||||
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
|
||||
properties.setQueryAACube(_entity->getQueryAACube());
|
||||
}
|
||||
}
|
||||
|
||||
// set the LastEdited of the properties but NOT the entity itself
|
||||
|
@ -643,7 +641,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
_entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
if (descendant->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||
if (descendant->computePuffedQueryAACube()) {
|
||||
if (descendant->checkAndMaybeUpdateQueryAACube()) {
|
||||
EntityItemProperties newQueryCubeProperties;
|
||||
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
|
||||
|
|
|
@ -16,6 +16,6 @@ if (NOT ANDROID)
|
|||
|
||||
endif ()
|
||||
|
||||
link_hifi_libraries(shared networking octree gpu procedural model model-networking ktx recording avatars fbx entities controllers animation audio physics image)
|
||||
link_hifi_libraries(shared networking octree gpu procedural model model-networking ktx recording avatars fbx entities controllers animation audio physics image midi)
|
||||
# ui includes gl, but link_hifi_libraries does not use transitive includes, so gl must be explicit
|
||||
include_hifi_library_headers(gl)
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
|
||||
#include <Profile.h>
|
||||
|
||||
#include "../../midi/src/Midi.h" // FIXME why won't a simpler include work?
|
||||
#include "MIDIEvent.h"
|
||||
|
||||
const QString ScriptEngine::_SETTINGS_ENABLE_EXTENDED_EXCEPTIONS {
|
||||
|
@ -667,6 +668,8 @@ void ScriptEngine::init() {
|
|||
|
||||
registerGlobalObject("Audio", DependencyManager::get<AudioScriptingInterface>().data());
|
||||
|
||||
registerGlobalObject("Midi", DependencyManager::get<Midi>().data());
|
||||
|
||||
registerGlobalObject("Entities", entityScriptingInterface.data());
|
||||
registerGlobalObject("Quat", &_quatLibrary);
|
||||
registerGlobalObject("Vec3", &_vec3Library);
|
||||
|
|
|
@ -946,11 +946,35 @@ AACube SpatiallyNestable::getMaximumAACube(bool& success) const {
|
|||
return AACube(getPosition(success) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize);
|
||||
}
|
||||
|
||||
bool SpatiallyNestable::checkAndAdjustQueryAACube() {
|
||||
bool success;
|
||||
const float PARENTED_EXPANSION_FACTOR = 3.0f;
|
||||
|
||||
bool SpatiallyNestable::checkAndMaybeUpdateQueryAACube() {
|
||||
bool success = false;
|
||||
AACube maxAACube = getMaximumAACube(success);
|
||||
if (success && (!_queryAACubeSet || !_queryAACube.contains(maxAACube))) {
|
||||
setQueryAACube(maxAACube);
|
||||
if (success) {
|
||||
// maybe update _queryAACube
|
||||
if (!_queryAACubeSet || (_parentID.isNull() && _children.size() == 0) || !_queryAACube.contains(maxAACube)) {
|
||||
if (_parentJointIndex != INVALID_JOINT_INDEX || _children.size() > 0 ) {
|
||||
// make an expanded AACube centered on the object
|
||||
float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale();
|
||||
_queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale);
|
||||
} else {
|
||||
_queryAACube = maxAACube;
|
||||
}
|
||||
|
||||
getThisPointer()->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
bool childSuccess;
|
||||
AACube descendantAACube = descendant->getQueryAACube(childSuccess);
|
||||
if (childSuccess) {
|
||||
if (_queryAACube.contains(descendantAACube)) {
|
||||
return;
|
||||
}
|
||||
_queryAACube += descendantAACube.getMinimumPoint();
|
||||
_queryAACube += descendantAACube.getMaximumPoint();
|
||||
}
|
||||
});
|
||||
_queryAACubeSet = true;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
@ -961,46 +985,34 @@ void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) {
|
|||
return;
|
||||
}
|
||||
_queryAACube = queryAACube;
|
||||
if (queryAACube.getScale() > 0.0f) {
|
||||
_queryAACubeSet = true;
|
||||
}
|
||||
_queryAACubeSet = true;
|
||||
}
|
||||
|
||||
bool SpatiallyNestable::queryAABoxNeedsUpdate() const {
|
||||
bool success;
|
||||
AACube currentAACube = getMaximumAACube(success);
|
||||
if (!success) {
|
||||
qCDebug(shared) << "can't getMaximumAACube for" << getID();
|
||||
return false;
|
||||
bool SpatiallyNestable::queryAACubeNeedsUpdate() const {
|
||||
if (!_queryAACubeSet) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// make sure children are still in their boxes, also.
|
||||
bool childNeedsUpdate = false;
|
||||
getThisPointer()->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
if (!childNeedsUpdate && descendant->queryAABoxNeedsUpdate()) {
|
||||
if (!childNeedsUpdate && descendant->queryAACubeNeedsUpdate()) {
|
||||
childNeedsUpdate = true;
|
||||
}
|
||||
});
|
||||
if (childNeedsUpdate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_queryAACubeSet && _queryAACube.contains(currentAACube)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return childNeedsUpdate;
|
||||
}
|
||||
|
||||
bool SpatiallyNestable::computePuffedQueryAACube() {
|
||||
if (!queryAABoxNeedsUpdate()) {
|
||||
return false;
|
||||
}
|
||||
void SpatiallyNestable::updateQueryAACube() {
|
||||
bool success;
|
||||
AACube currentAACube = getMaximumAACube(success);
|
||||
// make an AACube with edges thrice as long and centered on the object
|
||||
_queryAACube = AACube(currentAACube.getCorner() - glm::vec3(currentAACube.getScale()), currentAACube.getScale() * 3.0f);
|
||||
_queryAACubeSet = true;
|
||||
AACube maxAACube = getMaximumAACube(success);
|
||||
if (_parentJointIndex != INVALID_JOINT_INDEX || _children.size() > 0 ) {
|
||||
// make an expanded AACube centered on the object
|
||||
float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale();
|
||||
_queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale);
|
||||
} else {
|
||||
_queryAACube = maxAACube;
|
||||
}
|
||||
|
||||
getThisPointer()->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
bool success;
|
||||
|
@ -1013,8 +1025,7 @@ bool SpatiallyNestable::computePuffedQueryAACube() {
|
|||
_queryAACube += descendantAACube.getMaximumPoint();
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
_queryAACubeSet = true;
|
||||
}
|
||||
|
||||
AACube SpatiallyNestable::getQueryAACube(bool& success) const {
|
||||
|
|
|
@ -102,11 +102,11 @@ public:
|
|||
virtual glm::vec3 getParentAngularVelocity(bool& success) const;
|
||||
|
||||
virtual AACube getMaximumAACube(bool& success) const;
|
||||
virtual bool checkAndAdjustQueryAACube();
|
||||
virtual bool computePuffedQueryAACube();
|
||||
bool checkAndMaybeUpdateQueryAACube();
|
||||
void updateQueryAACube();
|
||||
|
||||
virtual void setQueryAACube(const AACube& queryAACube);
|
||||
virtual bool queryAABoxNeedsUpdate() const;
|
||||
virtual bool queryAACubeNeedsUpdate() const;
|
||||
void forceQueryAACubeUpdate() { _queryAACubeSet = false; }
|
||||
virtual AACube getQueryAACube(bool& success) const;
|
||||
virtual AACube getQueryAACube() const;
|
||||
|
@ -197,7 +197,7 @@ protected:
|
|||
mutable QHash<QUuid, SpatiallyNestableWeakPointer> _children;
|
||||
|
||||
virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed
|
||||
virtual void dimensionsChanged() { } // called when a this object's dimensions have 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
|
||||
|
|
|
@ -31,12 +31,34 @@ namespace Cursor {
|
|||
}
|
||||
};
|
||||
|
||||
static QMap<uint16_t, QString> ICONS;
|
||||
QMap<uint16_t, QString> Manager::ICON_NAMES {
|
||||
{ Icon::SYSTEM, "SYSTEM", },
|
||||
{ Icon::DEFAULT, "DEFAULT", },
|
||||
{ Icon::LINK, "LINK", },
|
||||
{ Icon::ARROW, "ARROW", },
|
||||
{ Icon::RETICLE, "RETICLE", },
|
||||
};
|
||||
QMap<uint16_t, QString> Manager::ICONS;
|
||||
static uint16_t _customIconId = Icon::USER_BASE;
|
||||
|
||||
Manager::Manager() {
|
||||
ICONS[Icon::DEFAULT] = PathUtils::resourcesPath() + "images/arrow.png";
|
||||
ICONS[Icon::LINK] = PathUtils::resourcesPath() + "images/link.png";
|
||||
ICONS[Icon::SYSTEM] = PathUtils::resourcesPath() + "images/cursor-none.png";
|
||||
ICONS[Icon::DEFAULT] = PathUtils::resourcesPath() + "images/cursor-arrow.png";
|
||||
ICONS[Icon::LINK] = PathUtils::resourcesPath() + "images/cursor-link.png";
|
||||
ICONS[Icon::ARROW] = PathUtils::resourcesPath() + "images/cursor-arrow.png";
|
||||
ICONS[Icon::RETICLE] = PathUtils::resourcesPath() + "images/cursor-reticle.png";
|
||||
}
|
||||
|
||||
Icon Manager::lookupIcon(const QString& name) {
|
||||
for (const auto& kv : ICON_NAMES.toStdMap()) {
|
||||
if (kv.second == name) {
|
||||
return static_cast<Icon>(kv.first);
|
||||
}
|
||||
}
|
||||
return Icon::DEFAULT;
|
||||
}
|
||||
const QString& Manager::getIconName(const Icon& icon) {
|
||||
return ICON_NAMES.count(icon) ? ICON_NAMES[icon] : ICON_NAMES[Icon::DEFAULT];
|
||||
}
|
||||
|
||||
Manager& Manager::instance() {
|
||||
|
|
|
@ -18,16 +18,18 @@ namespace Cursor {
|
|||
};
|
||||
|
||||
enum Icon {
|
||||
SYSTEM,
|
||||
DEFAULT,
|
||||
LINK,
|
||||
GRAB,
|
||||
ARROW,
|
||||
RETICLE,
|
||||
|
||||
// Add new system cursors here
|
||||
|
||||
// User cursors will have ids over this value
|
||||
USER_BASE = 0xFF,
|
||||
};
|
||||
|
||||
class Instance {
|
||||
public:
|
||||
virtual Source getType() const = 0;
|
||||
|
@ -49,6 +51,11 @@ namespace Cursor {
|
|||
uint16_t registerIcon(const QString& path);
|
||||
QList<uint16_t> registeredIcons() const;
|
||||
const QString& getIconImage(uint16_t icon);
|
||||
|
||||
static QMap<uint16_t, QString> ICONS;
|
||||
static QMap<uint16_t, QString> ICON_NAMES;
|
||||
static Icon lookupIcon(const QString& name);
|
||||
static const QString& getIconName(const Icon& icon);
|
||||
private:
|
||||
float _scale{ 1.0f };
|
||||
};
|
||||
|
|
|
@ -825,7 +825,13 @@ TabletButtonProxy::~TabletButtonProxy() {
|
|||
|
||||
void TabletButtonProxy::setQmlButton(QQuickItem* qmlButton) {
|
||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||
if (_qmlButton) {
|
||||
QObject::disconnect(_qmlButton, &QQuickItem::destroyed, this, nullptr);
|
||||
}
|
||||
_qmlButton = qmlButton;
|
||||
if (_qmlButton) {
|
||||
QObject::connect(_qmlButton, &QQuickItem::destroyed, this, [this] { _qmlButton = nullptr; });
|
||||
}
|
||||
}
|
||||
|
||||
void TabletButtonProxy::setToolbarButtonProxy(QObject* toolbarButtonProxy) {
|
||||
|
|
|
@ -126,15 +126,17 @@ void OculusBaseDisplayPlugin::internalDeactivate() {
|
|||
}
|
||||
|
||||
bool OculusBaseDisplayPlugin::activateStandBySession() {
|
||||
_session = acquireOculusSession();
|
||||
if (!_session) {
|
||||
return false;
|
||||
_session = acquireOculusSession();
|
||||
}
|
||||
return true;
|
||||
return _session;
|
||||
}
|
||||
void OculusBaseDisplayPlugin::deactivateSession() {
|
||||
releaseOculusSession();
|
||||
_session = nullptr;
|
||||
// FIXME
|
||||
// Switching to Qt 5.9 exposed a race condition or similar issue that caused a crash when putting on an Rift
|
||||
// while already in VR mode. Commenting these out is a workaround.
|
||||
//releaseOculusSession();
|
||||
//_session = nullptr;
|
||||
}
|
||||
void OculusBaseDisplayPlugin::updatePresentPose() {
|
||||
//mat4 sensorResetMat;
|
||||
|
|
|
@ -13,7 +13,7 @@ if (APPLE)
|
|||
|
||||
set(TARGET_NAME oculusLegacy)
|
||||
setup_hifi_plugin()
|
||||
link_hifi_libraries(shared gl gpu gpu-gl plugins ui ui-plugins display-plugins input-plugins)
|
||||
link_hifi_libraries(shared gl gpu gpu-gl plugins ui ui-plugins display-plugins input-plugins midi)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
|
|
50
scripts/tutorials/createMidiSphere.js
Normal file
50
scripts/tutorials/createMidiSphere.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// Created by James B. Pollack @imgntn on April 18, 2016.
|
||||
// Adapted by Burt
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
//var SCRIPT_URL = "file:///e:/hifi/scripts/tutorials/entity_scripts/midiSphere.js";
|
||||
var SCRIPT_URL = "http://hifi-files.s3-website-us-west-2.amazonaws.com/midiSphere.js";
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(0.5, Quat.getForward(Camera.getOrientation())));
|
||||
|
||||
var BALL_GRAVITY = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
|
||||
var BALL_DIMENSIONS = {
|
||||
x: 0.4,
|
||||
y: 0.4,
|
||||
z: 0.4
|
||||
};
|
||||
|
||||
|
||||
var BALL_COLOR = {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var midiSphereProperties = {
|
||||
name: 'MIDI Sphere',
|
||||
shapeType: 'sphere',
|
||||
type: 'Sphere',
|
||||
script: SCRIPT_URL,
|
||||
color: BALL_COLOR,
|
||||
dimensions: BALL_DIMENSIONS,
|
||||
gravity: BALL_GRAVITY,
|
||||
dynamic: false,
|
||||
position: center,
|
||||
collisionless: false,
|
||||
ignoreForCollisions: true
|
||||
};
|
||||
|
||||
var midiSphere = Entities.addEntity(midiSphereProperties);
|
||||
|
||||
Script.stop();
|
52
scripts/tutorials/entity_scripts/midiSphere.js
Normal file
52
scripts/tutorials/entity_scripts/midiSphere.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
// midiSphere.js
|
||||
//
|
||||
// Script Type: Entity
|
||||
// Created by James B. Pollack @imgntn on 9/21/2015
|
||||
// Adapted by Burt
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This script listens to MIDI and makes the ball change color.
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
var _this;
|
||||
|
||||
function MidiSphere() {
|
||||
_this = this;
|
||||
this.clicked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
MidiSphere.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
Midi.midiNote.connect(function(eventData) {
|
||||
print("MidiSphere.noteReceived: "+JSON.stringify(eventData));
|
||||
Entities.editEntity(entityID, { color: { red: 2*eventData.note, green: 2*eventData.note, blue: 2*eventData.note} });
|
||||
});
|
||||
print("MidiSphere.preload");
|
||||
},
|
||||
unload: function(entityID) {
|
||||
print("MidiSphere.unload");
|
||||
},
|
||||
|
||||
clickDownOnEntity: function(entityID, mouseEvent) {
|
||||
print("MidiSphere.clickDownOnEntity");
|
||||
if (this.clicked) {
|
||||
Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} });
|
||||
this.clicked = false;
|
||||
Midi.playMidiNote(144, 64, 0);
|
||||
} else {
|
||||
Entities.editEntity(entityID, { color: { red: 255, green: 255, blue: 0} });
|
||||
this.clicked = true;
|
||||
Midi.playMidiNote(144, 64, 100);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// entity scripts should return a newly constructed object of our type
|
||||
return new MidiSphere();
|
||||
});
|
|
@ -12,8 +12,7 @@ setup_hifi_project(Quick Gui OpenGL)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl render model-networking networking render-utils entities entities-renderer animation audio avatars script-engine physics procedural)
|
||||
|
||||
link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl render model-networking networking render-utils entities entities-renderer animation audio avatars script-engine physics procedural midi)
|
||||
|
||||
package_libraries_for_deployment()
|
||||
|
||||
|
|
Loading…
Reference in a new issue