mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 01:04:06 +02:00
Merge branch 'master' into fix_menu_landscape
This commit is contained in:
commit
0333849aa8
23 changed files with 608 additions and 108 deletions
39
BUILD.md
39
BUILD.md
|
@ -1,28 +1,25 @@
|
|||
### Dependencies
|
||||
|
||||
* [cmake](https://cmake.org/download/) ~> 3.3.2
|
||||
* [Qt](https://www.qt.io/download-open-source) ~> 5.6.2
|
||||
* [OpenSSL](https://www.openssl.org/community/binaries.html)
|
||||
* IMPORTANT: Use the latest available version of OpenSSL to avoid security vulnerabilities.
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
- [cmake](https://cmake.org/download/): 3.9
|
||||
- [Qt](https://www.qt.io/download-open-source): 5.9.1
|
||||
- [OpenSSL](https://www.openssl.org/): Use the latest available version of OpenSSL to avoid security vulnerabilities.
|
||||
- [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
|
||||
#### CMake External Project Dependencies
|
||||
### CMake External Project Dependencies
|
||||
|
||||
* [boostconfig](https://github.com/boostorg/config) ~> 1.58
|
||||
* [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases) ~> 2.83
|
||||
* [GLEW](http://glew.sourceforge.net/)
|
||||
* [glm](https://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4
|
||||
* [gverb](https://github.com/highfidelity/gverb)
|
||||
* [Oculus SDK](https://developer.oculus.com/downloads/) ~> 0.6 (Win32) / 0.5 (Mac / Linux)
|
||||
* [oglplus](http://oglplus.org/) ~> 0.63
|
||||
* [OpenVR](https://github.com/ValveSoftware/openvr) ~> 0.91 (Win32 only)
|
||||
* [Polyvox](http://www.volumesoffun.com/) ~> 0.2.1
|
||||
* [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/) ~> 0.7.1
|
||||
* [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3
|
||||
* [soxr](https://sourceforge.net/p/soxr/wiki/Home/) ~> 0.1.1
|
||||
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
|
||||
* [Sixense](http://sixense.com/) ~> 071615
|
||||
* [zlib](http://www.zlib.net/) ~> 1.28 (Win32 only)
|
||||
These dependencies need not be installed manually. They are automatically downloaded on the platforms where they are required.
|
||||
- [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases): 2.83
|
||||
- [GLEW](http://glew.sourceforge.net/): 1.13
|
||||
- [glm](https://glm.g-truc.net/0.9.8/index.html): 0.9.8
|
||||
- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Win32) / 0.5 (Mac)
|
||||
- [OpenVR](https://github.com/ValveSoftware/openvr): 1.0.6 (Win32 only)
|
||||
- [Polyvox](http://www.volumesoffun.com/): 0.2.1
|
||||
- [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/): 0.7.3
|
||||
- [SDL2](https://www.libsdl.org/download-2.0.php): 2.0.3
|
||||
- [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/): 4.3
|
||||
- [Sixense](http://sixense.com/): 071615
|
||||
- [zlib](http://www.zlib.net/): 1.28 (Win32 only)
|
||||
- nVidia Texture Tools: 2.1
|
||||
|
||||
The above dependencies will be downloaded, built, linked and included automatically by CMake where we require them. The CMakeLists files that handle grabbing each of the following external dependencies can be found in the [cmake/externals folder](cmake/externals). The resulting downloads, source files and binaries will be placed in the `build/ext` folder in each of the subfolders for each external project.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>();
|
||||
|
@ -2116,7 +2122,6 @@ void Application::initializeUi() {
|
|||
surfaceContext->setContextProperty("AvatarManager", DependencyManager::get<AvatarManager>().data());
|
||||
surfaceContext->setContextProperty("UndoStack", &_undoStackScriptingInterface);
|
||||
surfaceContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
||||
surfaceContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
|
||||
surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
|
||||
|
|
|
@ -258,6 +258,7 @@ MyAvatar::~MyAvatar() {
|
|||
void MyAvatar::setDominantHand(const QString& hand) {
|
||||
if (hand == DOMINANT_LEFT_HAND || hand == DOMINANT_RIGHT_HAND) {
|
||||
_dominantHand = hand;
|
||||
emit dominantHandChanged(_dominantHand);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -615,6 +615,7 @@ signals:
|
|||
void wentAway();
|
||||
void wentActive();
|
||||
void skeletonChanged();
|
||||
void dominantHandChanged(const QString& hand);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -706,27 +706,27 @@ bool Overlays::isAddedOverlay(OverlayID id) {
|
|||
}
|
||||
|
||||
void Overlays::sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event) {
|
||||
emit mousePressOnOverlay(overlayID, event);
|
||||
QMetaObject::invokeMethod(this, "mousePressOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
void Overlays::sendMouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event) {
|
||||
emit mouseReleaseOnOverlay(overlayID, event);
|
||||
QMetaObject::invokeMethod(this, "mouseReleaseOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
void Overlays::sendMouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event) {
|
||||
emit mouseMoveOnOverlay(overlayID, event);
|
||||
QMetaObject::invokeMethod(this, "mouseMoveOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
void Overlays::sendHoverEnterOverlay(OverlayID id, PointerEvent event) {
|
||||
emit hoverEnterOverlay(id, event);
|
||||
QMetaObject::invokeMethod(this, "hoverEnterOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
void Overlays::sendHoverOverOverlay(OverlayID id, PointerEvent event) {
|
||||
emit hoverOverOverlay(id, event);
|
||||
QMetaObject::invokeMethod(this, "hoverOverOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
void Overlays::sendHoverLeaveOverlay(OverlayID id, PointerEvent event) {
|
||||
emit hoverLeaveOverlay(id, event);
|
||||
QMetaObject::invokeMethod(this, "hoverLeaveOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||
}
|
||||
|
||||
OverlayID Overlays::getKeyboardFocusOverlay() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -100,30 +100,14 @@ Web3DOverlay::~Web3DOverlay() {
|
|||
}
|
||||
|
||||
_webSurface->pause();
|
||||
_webSurface->disconnect(_connection);
|
||||
|
||||
QObject::disconnect(_mousePressConnection);
|
||||
_mousePressConnection = QMetaObject::Connection();
|
||||
QObject::disconnect(_mouseReleaseConnection);
|
||||
_mouseReleaseConnection = QMetaObject::Connection();
|
||||
QObject::disconnect(_mouseMoveConnection);
|
||||
_mouseMoveConnection = QMetaObject::Connection();
|
||||
QObject::disconnect(_hoverLeaveConnection);
|
||||
_hoverLeaveConnection = QMetaObject::Connection();
|
||||
|
||||
QObject::disconnect(_emitScriptEventConnection);
|
||||
_emitScriptEventConnection = QMetaObject::Connection();
|
||||
QObject::disconnect(_webEventReceivedConnection);
|
||||
_webEventReceivedConnection = QMetaObject::Connection();
|
||||
|
||||
// The lifetime of the QML surface MUST be managed by the main thread
|
||||
// Additionally, we MUST use local variables copied by value, rather than
|
||||
// member variables, since they would implicitly refer to a this that
|
||||
// is no longer valid
|
||||
auto webSurface = _webSurface;
|
||||
AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
|
||||
DependencyManager::get<OffscreenQmlSurfaceCache>()->release(QML, webSurface);
|
||||
});
|
||||
auto overlays = &(qApp->getOverlays());
|
||||
QObject::disconnect(overlays, &Overlays::mousePressOnOverlay, this, nullptr);
|
||||
QObject::disconnect(overlays, &Overlays::mouseReleaseOnOverlay, this, nullptr);
|
||||
QObject::disconnect(overlays, &Overlays::mouseMoveOnOverlay, this, nullptr);
|
||||
QObject::disconnect(overlays, &Overlays::hoverLeaveOverlay, this, nullptr);
|
||||
QObject::disconnect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
|
||||
QObject::disconnect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
|
||||
DependencyManager::get<OffscreenQmlSurfaceCache>()->release(QML, _webSurface);
|
||||
_webSurface.reset();
|
||||
}
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
@ -153,6 +137,9 @@ QString Web3DOverlay::pickURL() {
|
|||
|
||||
|
||||
void Web3DOverlay::loadSourceURL() {
|
||||
if (!_webSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl sourceUrl(_url);
|
||||
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
|
||||
|
@ -254,10 +241,11 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
}
|
||||
};
|
||||
|
||||
_mousePressConnection = connect(&(qApp->getOverlays()), &Overlays::mousePressOnOverlay, this, forwardPointerEvent, Qt::DirectConnection);
|
||||
_mouseReleaseConnection = connect(&(qApp->getOverlays()), &Overlays::mouseReleaseOnOverlay, this, forwardPointerEvent, Qt::DirectConnection);
|
||||
_mouseMoveConnection = connect(&(qApp->getOverlays()), &Overlays::mouseMoveOnOverlay, this, forwardPointerEvent, Qt::DirectConnection);
|
||||
_hoverLeaveConnection = connect(&(qApp->getOverlays()), &Overlays::hoverLeaveOverlay, this, [=](OverlayID overlayID, const PointerEvent& event) {
|
||||
auto overlays = &(qApp->getOverlays());
|
||||
QObject::connect(overlays, &Overlays::mousePressOnOverlay, this, forwardPointerEvent);
|
||||
QObject::connect(overlays, &Overlays::mouseReleaseOnOverlay, this, forwardPointerEvent);
|
||||
QObject::connect(overlays, &Overlays::mouseMoveOnOverlay, this, forwardPointerEvent);
|
||||
QObject::connect(overlays, &Overlays::hoverLeaveOverlay, this, [=](OverlayID overlayID, const PointerEvent& event) {
|
||||
auto self = weakSelf.lock();
|
||||
if (!self) {
|
||||
return;
|
||||
|
@ -267,10 +255,10 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
|
||||
forwardPointerEvent(overlayID, event);
|
||||
}
|
||||
}, Qt::DirectConnection);
|
||||
});
|
||||
|
||||
_emitScriptEventConnection = connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
|
||||
_webEventReceivedConnection = connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
|
||||
QObject::connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
|
||||
QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
|
||||
} else {
|
||||
if (_currentMaxFPS != _desiredMaxFPS) {
|
||||
setMaxFPS(_desiredMaxFPS);
|
||||
|
@ -440,11 +428,11 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
|
|||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
touchPoints.push_back(point);
|
||||
|
||||
QTouchEvent* touchEvent = new QTouchEvent(touchType, &_touchDevice, event.getKeyboardModifiers());
|
||||
touchEvent->setWindow(_webSurface->getWindow());
|
||||
touchEvent->setTarget(_webSurface->getRootItem());
|
||||
touchEvent->setTouchPoints(touchPoints);
|
||||
touchEvent->setTouchPointStates(touchPointState);
|
||||
QTouchEvent touchEvent(touchType, &_touchDevice, event.getKeyboardModifiers());
|
||||
touchEvent.setWindow(_webSurface->getWindow());
|
||||
touchEvent.setTarget(_webSurface->getRootItem());
|
||||
touchEvent.setTouchPoints(touchPoints);
|
||||
touchEvent.setTouchPointStates(touchPointState);
|
||||
|
||||
// Send mouse events to the Web surface so that HTML dialog elements work with mouse press and hover.
|
||||
// FIXME: Scroll bar dragging is a bit unstable in the tablet (content can jump up and down at times).
|
||||
|
@ -454,16 +442,16 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
|
|||
// receive mouse events
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
QMouseEvent* mouseEvent = new QMouseEvent(mouseType, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
|
||||
QMouseEvent mouseEvent(mouseType, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
|
||||
}
|
||||
#endif
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent);
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0)
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
QMouseEvent* mouseEvent = new QMouseEvent(mouseType, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
|
||||
QMouseEvent mouseEvent(mouseType, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -507,8 +495,8 @@ void Web3DOverlay::handlePointerEventAsMouse(const PointerEvent& event) {
|
|||
return;
|
||||
}
|
||||
|
||||
QMouseEvent* mouseEvent = new QMouseEvent(type, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
|
||||
QMouseEvent mouseEvent(type, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
|
||||
}
|
||||
|
||||
void Web3DOverlay::setProperties(const QVariantMap& properties) {
|
||||
|
@ -610,6 +598,9 @@ void Web3DOverlay::setScriptURL(const QString& scriptURL) {
|
|||
_scriptURL = scriptURL;
|
||||
if (_webSurface) {
|
||||
AbstractViewStateInterface::instance()->postLambdaEvent([this, scriptURL] {
|
||||
if (!_webSurface) {
|
||||
return;
|
||||
}
|
||||
_webSurface->getRootItem()->setProperty("scriptURL", scriptURL);
|
||||
});
|
||||
}
|
||||
|
@ -633,9 +624,5 @@ Web3DOverlay* Web3DOverlay::createClone() const {
|
|||
}
|
||||
|
||||
void Web3DOverlay::emitScriptEvent(const QVariant& message) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
} else {
|
||||
emit scriptEventReceived(message);
|
||||
}
|
||||
QMetaObject::invokeMethod(this, "scriptEventReceived", Q_ARG(QVariant, message));
|
||||
}
|
||||
|
|
|
@ -72,7 +72,6 @@ signals:
|
|||
private:
|
||||
InputMode _inputMode { Touch };
|
||||
QSharedPointer<OffscreenQmlSurface> _webSurface;
|
||||
QMetaObject::Connection _connection;
|
||||
gpu::TexturePointer _texture;
|
||||
QString _url;
|
||||
QString _scriptURL;
|
||||
|
@ -88,14 +87,6 @@ private:
|
|||
uint8_t _currentMaxFPS { 0 };
|
||||
|
||||
bool _mayNeedResize { false };
|
||||
|
||||
QMetaObject::Connection _mousePressConnection;
|
||||
QMetaObject::Connection _mouseReleaseConnection;
|
||||
QMetaObject::Connection _mouseMoveConnection;
|
||||
QMetaObject::Connection _hoverLeaveConnection;
|
||||
|
||||
QMetaObject::Connection _emitScriptEventConnection;
|
||||
QMetaObject::Connection _webEventReceivedConnection;
|
||||
};
|
||||
|
||||
#endif // hifi_Web3DOverlay_h
|
||||
|
|
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
|
|
@ -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);
|
||||
|
|
|
@ -329,6 +329,7 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) {
|
|||
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
|
||||
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
|
||||
rootContext->setContextProperty("HFTabletWebEngineProfile", new HFTabletWebEngineProfile(rootContext));
|
||||
rootContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
|
||||
}
|
||||
|
||||
QQmlEngine* acquireEngine(QQuickWindow* window) {
|
||||
|
|
|
@ -830,7 +830,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) {
|
||||
|
|
|
@ -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