mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 16:50:43 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into messaging
This commit is contained in:
commit
9c4286b6ca
18 changed files with 604 additions and 97 deletions
13
BUILD.md
13
BUILD.md
|
@ -1,7 +1,7 @@
|
|||
###Dependencies
|
||||
|
||||
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.12.2
|
||||
* [Qt](http://www.qt.io/download-open-source) ~> 5.4.1
|
||||
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 3.3.2
|
||||
* [Qt](http://www.qt.io/download-open-source) ~> 5.5.1
|
||||
* [OpenSSL](https://www.openssl.org/community/binaries.html) ~> 1.0.1m
|
||||
* IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
|
@ -42,12 +42,12 @@ Hifi uses CMake to generate build files and project files for your platform.
|
|||
####Qt
|
||||
In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation.
|
||||
|
||||
For example, a Qt5 5.4.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
For example, a Qt5 5.5.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
|
||||
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.4.1/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.4.1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.5.1/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.5.1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||
|
||||
####Generating build files
|
||||
|
@ -64,7 +64,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E
|
|||
|
||||
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
||||
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.4.1/lib/cmake
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.5.1/lib/cmake
|
||||
|
||||
####Finding Dependencies
|
||||
|
||||
|
@ -83,4 +83,3 @@ In the examples below the variable $NAME would be replaced by the name of the de
|
|||
####Devices
|
||||
|
||||
You can support external input/output devices such as Leap Motion, MIDI, and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
|
||||
|
|
13
BUILD_OSX.md
13
BUILD_OSX.md
|
@ -3,20 +3,15 @@ Please read the [general build guide](BUILD.md) for information on dependencies
|
|||
###Homebrew
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all High Fidelity dependencies very simple.
|
||||
|
||||
brew tap highfidelity/homebrew-formulas
|
||||
brew install cmake openssl
|
||||
brew install highfidelity/formulas/qt5
|
||||
brew link qt5 --force
|
||||
brew install cmake openssl qt5
|
||||
|
||||
We have a [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) that you can use/tap to install some of the dependencies. In the code block above qt5 is installed from a formula in this repository.
|
||||
|
||||
*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.4.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.*
|
||||
We no longer require install of qt5 via our [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas). Versions of Qt that are 5.5.x and above provide a mechanism to disable the wireless scanning we previously had a custom patch for.
|
||||
|
||||
###Qt
|
||||
|
||||
Assuming you've installed Qt 5 using the homebrew instructions above, you'll need to set QT_CMAKE_PREFIX_PATH so CMake can find your installation of Qt. For Qt 5.4.1 installed via homebrew, set QT_CMAKE_PREFIX_PATH as follows.
|
||||
Assuming you've installed Qt 5 using the homebrew instructions above, you'll need to set QT_CMAKE_PREFIX_PATH so CMake can find your installation of Qt. For Qt 5.5.1 installed via homebrew, set QT_CMAKE_PREFIX_PATH as follows.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.4.1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.5.1/lib/cmake
|
||||
|
||||
###Xcode
|
||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||
|
|
|
@ -29,12 +29,12 @@ NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit
|
|||
|
||||
* [Download the online installer](http://qt-project.org/downloads)
|
||||
* When it asks you to select components, ONLY select the following:
|
||||
* Qt > Qt 5.4.1 > **msvc2013 32-bit OpenGL**
|
||||
* Qt > Qt 5.5.1 > **msvc2013 32-bit**
|
||||
|
||||
* [Download the offline installer](http://download.qt.io/official_releases/qt/5.4/5.4.1/qt-opensource-windows-x86-msvc2013_opengl-5.4.1.exe)
|
||||
* [Download the offline installer](http://download.qt.io/official_releases/qt/5.5/5.5.1/qt-opensource-windows-x86-msvc2013-5.5.1.exe)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.4.1\msvc2013_opengl\lib\cmake` directory.
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.5.1\msvc2013\lib\cmake` directory.
|
||||
* You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New
|
||||
|
||||
###External Libraries
|
||||
|
|
|
@ -38,11 +38,11 @@ var SHOW = 4;
|
|||
var HIDE = 5;
|
||||
var LOAD = 6;
|
||||
|
||||
Avatar.setPlayFromCurrentLocation(playFromCurrentLocation);
|
||||
Avatar.setPlayerUseDisplayName(useDisplayName);
|
||||
Avatar.setPlayerUseAttachments(useAttachments);
|
||||
Avatar.setPlayerUseHeadModel(false);
|
||||
Avatar.setPlayerUseSkeletonModel(useAvatarModel);
|
||||
Recording.setPlayFromCurrentLocation(playFromCurrentLocation);
|
||||
Recording.setPlayerUseDisplayName(useDisplayName);
|
||||
Recording.setPlayerUseAttachments(useAttachments);
|
||||
Recording.setPlayerUseHeadModel(false);
|
||||
Recording.setPlayerUseSkeletonModel(useAvatarModel);
|
||||
|
||||
function setupEntityViewer() {
|
||||
var entityViewerOffset = 10;
|
||||
|
@ -96,25 +96,25 @@ function update(event) {
|
|||
if (!Agent.isAvatar) {
|
||||
Agent.isAvatar = true;
|
||||
}
|
||||
if (!Avatar.isPlaying()) {
|
||||
Avatar.startPlaying();
|
||||
if (!Recording.isPlaying()) {
|
||||
Recording.startPlaying();
|
||||
}
|
||||
Avatar.setPlayerLoop(false);
|
||||
Recording.setPlayerLoop(false);
|
||||
break;
|
||||
case PLAY_LOOP:
|
||||
print("Play loop");
|
||||
if (!Agent.isAvatar) {
|
||||
Agent.isAvatar = true;
|
||||
}
|
||||
if (!Avatar.isPlaying()) {
|
||||
Avatar.startPlaying();
|
||||
if (!Recording.isPlaying()) {
|
||||
Recording.startPlaying();
|
||||
}
|
||||
Avatar.setPlayerLoop(true);
|
||||
Recording.setPlayerLoop(true);
|
||||
break;
|
||||
case STOP:
|
||||
print("Stop");
|
||||
if (Avatar.isPlaying()) {
|
||||
Avatar.stopPlaying();
|
||||
if (Recording.isPlaying()) {
|
||||
Recording.stopPlaying();
|
||||
}
|
||||
break;
|
||||
case SHOW:
|
||||
|
@ -125,15 +125,15 @@ function update(event) {
|
|||
break;
|
||||
case HIDE:
|
||||
print("Hide");
|
||||
if (Avatar.isPlaying()) {
|
||||
Avatar.stopPlaying();
|
||||
if (Recording.isPlaying()) {
|
||||
Recording.stopPlaying();
|
||||
}
|
||||
Agent.isAvatar = false;
|
||||
break;
|
||||
case LOAD:
|
||||
print("Load");
|
||||
if(clip_url !== null) {
|
||||
Avatar.loadRecording(clip_url);
|
||||
Recording.loadRecording(clip_url);
|
||||
}
|
||||
break;
|
||||
case DO_NOTHING:
|
||||
|
@ -143,8 +143,8 @@ function update(event) {
|
|||
break;
|
||||
}
|
||||
|
||||
if (Avatar.isPlaying()) {
|
||||
Avatar.play();
|
||||
if (Recording.isPlaying()) {
|
||||
Recording.play();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
91
examples/entityScripts/recordingEntityScript.js
Normal file
91
examples/entityScripts/recordingEntityScript.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// recordingEntityScript.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Alessandro Signa on 11/12/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
|
||||
// All the avatars in the area when the master presses the button will start/stop recording.
|
||||
//
|
||||
|
||||
// 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 insideRecorderArea = false;
|
||||
var enteredInTime = false;
|
||||
var isAvatarRecording = false;
|
||||
var _this;
|
||||
|
||||
function recordingEntity() {
|
||||
_this = this;
|
||||
return;
|
||||
}
|
||||
|
||||
recordingEntity.prototype = {
|
||||
update: function(){
|
||||
var userData = JSON.parse(Entities.getEntityProperties(_this.entityID, ["userData"]).userData);
|
||||
var isRecordingStarted = userData.recordingKey.isRecordingStarted;
|
||||
if(isRecordingStarted && !isAvatarRecording){
|
||||
_this.startRecording();
|
||||
}else if((!isRecordingStarted && isAvatarRecording) || (isAvatarRecording && !insideRecorderArea)){
|
||||
_this.stopRecording();
|
||||
}else if(!isRecordingStarted && insideRecorderArea && !enteredInTime){
|
||||
//if an avatar enters the zone while a recording is started he will be able to participate to the next group recording
|
||||
enteredInTime = true;
|
||||
}
|
||||
|
||||
},
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
Script.update.connect(_this.update);
|
||||
},
|
||||
enterEntity: function(entityID) {
|
||||
print("entering in the recording area");
|
||||
insideRecorderArea = true;
|
||||
var userData = JSON.parse(Entities.getEntityProperties(_this.entityID, ["userData"]).userData);
|
||||
var isRecordingStarted = userData.recordingKey.isRecordingStarted;
|
||||
if(!isRecordingStarted){
|
||||
//i'm in the recording area in time (before the event starts)
|
||||
enteredInTime = true;
|
||||
}
|
||||
},
|
||||
leaveEntity: function(entityID) {
|
||||
print("leaving the recording area");
|
||||
insideRecorderArea = false;
|
||||
enteredInTime = false;
|
||||
},
|
||||
|
||||
startRecording: function(entityID){
|
||||
if(enteredInTime && !isAvatarRecording){
|
||||
print("RECORDING STARTED");
|
||||
Recording.startRecording();
|
||||
isAvatarRecording = true;
|
||||
}
|
||||
},
|
||||
|
||||
stopRecording: function(entityID){
|
||||
if(isAvatarRecording){
|
||||
print("RECORDING ENDED");
|
||||
Recording.stopRecording();
|
||||
Recording.loadLastRecording();
|
||||
isAvatarRecording = false;
|
||||
recordingFile = Window.save("Save recording to file", "./groupRecording", "Recordings (*.hfr)");
|
||||
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
||||
Recording.saveRecording(recordingFile);
|
||||
}
|
||||
}
|
||||
},
|
||||
clean: function(entityID) {
|
||||
Script.update.disconnect(_this.update);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return new recordingEntity();
|
||||
});
|
116
examples/entityScripts/recordingMaster.js
Normal file
116
examples/entityScripts/recordingMaster.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
//
|
||||
// recordingMaster.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Alessandro Signa on 11/12/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Run this script to spawn a box (recorder) and drive the start/end of the recording for anyone who is inside the box
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
var PARAMS_SCRIPT_URL = Script.resolvePath('recordingEntityScript.js');
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
Script.include("../libraries/toolBars.js");
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
|
||||
|
||||
var rotation = Quat.safeEulerAngles(Camera.getOrientation());
|
||||
rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(rotation)));
|
||||
|
||||
var TOOL_ICON_URL = HIFI_PUBLIC_BUCKET + "images/tools/";
|
||||
var ALPHA_ON = 1.0;
|
||||
var ALPHA_OFF = 0.7;
|
||||
var COLOR_TOOL_BAR = { red: 0, green: 0, blue: 0 };
|
||||
|
||||
var toolBar = null;
|
||||
var recordIcon;
|
||||
|
||||
|
||||
|
||||
var isRecording = false;
|
||||
|
||||
var recordAreaEntity = Entities.addEntity({
|
||||
name: 'recorderEntity',
|
||||
dimensions: {
|
||||
x: 2,
|
||||
y: 1,
|
||||
z: 2
|
||||
},
|
||||
type: 'Box',
|
||||
position: center,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
visible: true,
|
||||
ignoreForCollisions: true,
|
||||
script: PARAMS_SCRIPT_URL,
|
||||
|
||||
userData: JSON.stringify({
|
||||
recordingKey: {
|
||||
isRecordingStarted: false
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
setupToolBar();
|
||||
|
||||
function setupToolBar() {
|
||||
if (toolBar != null) {
|
||||
print("Multiple calls to setupToolBar()");
|
||||
return;
|
||||
}
|
||||
Tool.IMAGE_HEIGHT /= 2;
|
||||
Tool.IMAGE_WIDTH /= 2;
|
||||
|
||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); //put the button in the up-left corner
|
||||
|
||||
toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF);
|
||||
|
||||
recordIcon = toolBar.addTool({
|
||||
imageURL: TOOL_ICON_URL + "recording-record.svg",
|
||||
subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
x: 0, y: 0,
|
||||
width: Tool.IMAGE_WIDTH,
|
||||
height: Tool.IMAGE_HEIGHT,
|
||||
alpha: Recording.isPlaying() ? ALPHA_OFF : ALPHA_ON,
|
||||
visible: true
|
||||
}, true, isRecording);
|
||||
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
if (recordIcon === toolBar.clicked(clickedOverlay, false)) {
|
||||
if (!isRecording) {
|
||||
print("I'm the master. I want to start recording");
|
||||
isRecording = true;
|
||||
setEntityCustomData("recordingKey", recordAreaEntity, {isRecordingStarted: true});
|
||||
|
||||
} else {
|
||||
print("I want to stop recording");
|
||||
isRecording = false;
|
||||
setEntityCustomData("recordingKey", recordAreaEntity, {isRecordingStarted: false});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function cleanup() {
|
||||
toolBar.cleanup();
|
||||
Entities.callEntityMethod(recordAreaEntity, 'clean'); //have to call this before deleting to avoid the JSON warnings
|
||||
Entities.deleteEntity(recordAreaEntity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
90
examples/entityScripts/synchronizerEntityScript.js
Normal file
90
examples/entityScripts/synchronizerEntityScript.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// synchronizerEntityScript.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Alessandro Signa on 11/12/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
|
||||
// This script shows how to create a synchronized event between avatars trhough an entity.
|
||||
// It works using the entity's userData: the master change its value and every client checks it every frame
|
||||
// This entity prints a message when the event starts and when it ends.
|
||||
// The client running synchronizerMaster.js is the event master and it decides when the event starts/ends by pressing a button.
|
||||
// All the avatars in the area when the master presses the button will receive a message.
|
||||
//
|
||||
|
||||
// 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 insideArea = false;
|
||||
var isJoiningTheEvent = false;
|
||||
var _this;
|
||||
|
||||
|
||||
|
||||
function ParamsEntity() {
|
||||
_this = this;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ParamsEntity.prototype = {
|
||||
update: function(){
|
||||
var userData = JSON.parse(Entities.getEntityProperties(_this.entityID, ["userData"]).userData);
|
||||
var valueToCheck = userData.myKey.valueToCheck;
|
||||
if(valueToCheck && !isJoiningTheEvent){
|
||||
_this.sendMessage();
|
||||
}else if((!valueToCheck && isJoiningTheEvent) || (isJoiningTheEvent && !insideArea)){
|
||||
_this.stopMessage();
|
||||
}
|
||||
},
|
||||
preload: function(entityID) {
|
||||
print('entity loaded')
|
||||
this.entityID = entityID;
|
||||
Script.update.connect(_this.update);
|
||||
},
|
||||
enterEntity: function(entityID) {
|
||||
print("enterEntity("+entityID+")");
|
||||
var userData = JSON.parse(Entities.getEntityProperties(_this.entityID, ["userData"]).userData);
|
||||
var valueToCheck = userData.myKey.valueToCheck;
|
||||
if(!valueToCheck){
|
||||
//i'm in the area in time (before the event starts)
|
||||
insideArea = true;
|
||||
}
|
||||
change(entityID);
|
||||
},
|
||||
leaveEntity: function(entityID) {
|
||||
print("leaveEntity("+entityID+")");
|
||||
Entities.editEntity(entityID, { color: { red: 255, green: 190, blue: 20} });
|
||||
insideArea = false;
|
||||
},
|
||||
|
||||
sendMessage: function(myID){
|
||||
if(insideArea && !isJoiningTheEvent){
|
||||
print("The event started");
|
||||
isJoiningTheEvent = true;
|
||||
}
|
||||
},
|
||||
|
||||
stopMessage: function(myID){
|
||||
if(isJoiningTheEvent){
|
||||
print("The event ended");
|
||||
isJoiningTheEvent = false;
|
||||
}
|
||||
},
|
||||
clean: function(entityID) {
|
||||
Script.update.disconnect(_this.update);
|
||||
}
|
||||
}
|
||||
|
||||
function change(entityID) {
|
||||
Entities.editEntity(entityID, { color: { red: 255, green: 100, blue: 220} });
|
||||
}
|
||||
|
||||
|
||||
return new ParamsEntity();
|
||||
});
|
117
examples/entityScripts/synchronizerMaster.js
Normal file
117
examples/entityScripts/synchronizerMaster.js
Normal file
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// synchronizerMaster.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Alessandro Signa on 11/12/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Run this script to spawn a box (synchronizer) and drive the start/end of the event for anyone who is inside the box
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
var PARAMS_SCRIPT_URL = Script.resolvePath('synchronizerEntityScript.js');
|
||||
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
Script.include("../libraries/toolBars.js");
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
|
||||
|
||||
var rotation = Quat.safeEulerAngles(Camera.getOrientation());
|
||||
rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(rotation)));
|
||||
|
||||
var TOOL_ICON_URL = HIFI_PUBLIC_BUCKET + "images/tools/";
|
||||
var ALPHA_ON = 1.0;
|
||||
var ALPHA_OFF = 0.7;
|
||||
var COLOR_TOOL_BAR = { red: 0, green: 0, blue: 0 };
|
||||
|
||||
var toolBar = null;
|
||||
var recordIcon;
|
||||
|
||||
|
||||
|
||||
var isHappening = false;
|
||||
|
||||
var testEntity = Entities.addEntity({
|
||||
name: 'paramsTestEntity',
|
||||
dimensions: {
|
||||
x: 2,
|
||||
y: 1,
|
||||
z: 2
|
||||
},
|
||||
type: 'Box',
|
||||
position: center,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
visible: true,
|
||||
ignoreForCollisions: true,
|
||||
script: PARAMS_SCRIPT_URL,
|
||||
|
||||
userData: JSON.stringify({
|
||||
myKey: {
|
||||
valueToCheck: false
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
setupToolBar();
|
||||
|
||||
function setupToolBar() {
|
||||
if (toolBar != null) {
|
||||
print("Multiple calls to setupToolBar()");
|
||||
return;
|
||||
}
|
||||
Tool.IMAGE_HEIGHT /= 2;
|
||||
Tool.IMAGE_WIDTH /= 2;
|
||||
|
||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); //put the button in the up-left corner
|
||||
|
||||
toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF);
|
||||
|
||||
recordIcon = toolBar.addTool({
|
||||
imageURL: TOOL_ICON_URL + "recording-record.svg",
|
||||
subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
x: 0, y: 0,
|
||||
width: Tool.IMAGE_WIDTH,
|
||||
height: Tool.IMAGE_HEIGHT,
|
||||
alpha: MyAvatar.isPlaying() ? ALPHA_OFF : ALPHA_ON,
|
||||
visible: true
|
||||
}, true, isHappening);
|
||||
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
if (recordIcon === toolBar.clicked(clickedOverlay, false)) {
|
||||
if (!isHappening) {
|
||||
print("I'm the event master. I want the event starts");
|
||||
isHappening = true;
|
||||
setEntityCustomData("myKey", testEntity, {valueToCheck: true});
|
||||
|
||||
} else {
|
||||
print("I want the event stops");
|
||||
isHappening = false;
|
||||
setEntityCustomData("myKey", testEntity, {valueToCheck: false});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function cleanup() {
|
||||
toolBar.cleanup();
|
||||
Entities.callEntityMethod(testEntity, 'clean'); //have to call this before deleting to avoid the JSON warnings
|
||||
Entities.deleteEntity(testEntity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
|
@ -379,6 +379,13 @@ void MyAvatar::updateHMDFollowVelocity() {
|
|||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
void MyAvatar::updateSensorToWorldMatrix() {
|
||||
|
||||
#ifdef DEBUG_RENDERING
|
||||
// draw marker about avatar's position
|
||||
const glm::vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
DebugDraw::getInstance().addMyAvatarMarker("pos", glm::quat(), glm::vec3(), red);
|
||||
#endif
|
||||
|
||||
// update the sensor mat so that the body position will end up in the desired
|
||||
// position when driven from the head.
|
||||
glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition());
|
||||
|
@ -1859,6 +1866,7 @@ glm::quat MyAvatar::getWorldBodyOrientation() const {
|
|||
return glm::quat_cast(_sensorToWorldMatrix * _bodySensorMatrix);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// derive avatar body position and orientation from the current HMD Sensor location.
|
||||
// results are in sensor space
|
||||
glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
|
||||
|
@ -1876,6 +1884,66 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
|
|||
}
|
||||
return glm::mat4();
|
||||
}
|
||||
#else
|
||||
// old school meat hook style
|
||||
glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
|
||||
|
||||
// HMD is in sensor space.
|
||||
const glm::vec3 hmdPosition = getHMDSensorPosition();
|
||||
const glm::quat hmdOrientation = getHMDSensorOrientation();
|
||||
const glm::quat hmdOrientationYawOnly = cancelOutRollAndPitch(hmdOrientation);
|
||||
|
||||
/*
|
||||
const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 1.6f, 0.0f);
|
||||
const glm::vec3 DEFAULT_LEFT_EYE_POS(0.3f, 1.6f, 0.0f);
|
||||
const glm::vec3 DEFAULT_NECK_POS(0.0f, 1.5f, 0.0f);
|
||||
const glm::vec3 DEFAULT_HIPS_POS(0.0f, 1.0f, 0.0f);
|
||||
*/
|
||||
|
||||
// 2 meter tall dude
|
||||
const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 1.9f, 0.0f);
|
||||
const glm::vec3 DEFAULT_LEFT_EYE_POS(0.3f, 1.9f, 0.0f);
|
||||
const glm::vec3 DEFAULT_NECK_POS(0.0f, 1.70f, 0.0f);
|
||||
const glm::vec3 DEFAULT_HIPS_POS(0.0f, 1.05f, 0.0f);
|
||||
|
||||
vec3 localEyes, localNeck;
|
||||
if (!_debugDrawSkeleton) {
|
||||
const glm::quat rotY180 = glm::angleAxis((float)PI, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
localEyes = rotY180 * (((DEFAULT_RIGHT_EYE_POS + DEFAULT_LEFT_EYE_POS) / 2.0f) - DEFAULT_HIPS_POS);
|
||||
localNeck = rotY180 * (DEFAULT_NECK_POS - DEFAULT_HIPS_POS);
|
||||
} else {
|
||||
// TODO: At the moment MyAvatar does not have access to the rig, which has the skeleton, which has the bind poses.
|
||||
// for now use the _debugDrawSkeleton, which is initialized with the same FBX model as the rig.
|
||||
|
||||
// TODO: cache these indices.
|
||||
int rightEyeIndex = _debugDrawSkeleton->nameToJointIndex("RightEye");
|
||||
int leftEyeIndex = _debugDrawSkeleton->nameToJointIndex("LeftEye");
|
||||
int neckIndex = _debugDrawSkeleton->nameToJointIndex("Neck");
|
||||
int hipsIndex = _debugDrawSkeleton->nameToJointIndex("Hips");
|
||||
|
||||
glm::vec3 absRightEyePos = rightEyeIndex != -1 ? _debugDrawSkeleton->getAbsoluteBindPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS;
|
||||
glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? _debugDrawSkeleton->getAbsoluteBindPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS;
|
||||
glm::vec3 absNeckPos = neckIndex != -1 ? _debugDrawSkeleton->getAbsoluteBindPose(neckIndex).trans : DEFAULT_NECK_POS;
|
||||
glm::vec3 absHipsPos = neckIndex != -1 ? _debugDrawSkeleton->getAbsoluteBindPose(hipsIndex).trans : DEFAULT_HIPS_POS;
|
||||
|
||||
const glm::quat rotY180 = glm::angleAxis((float)PI, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
localEyes = rotY180 * (((absRightEyePos + absLeftEyePos) / 2.0f) - absHipsPos);
|
||||
localNeck = rotY180 * (absNeckPos - absHipsPos);
|
||||
}
|
||||
|
||||
// apply simplistic head/neck model
|
||||
// figure out where the avatar body should be by applying offsets from the avatar's neck & head joints.
|
||||
|
||||
// eyeToNeck offset is relative full HMD orientation.
|
||||
// while neckToRoot offset is only relative to HMDs yaw.
|
||||
glm::vec3 eyeToNeck = hmdOrientation * (localNeck - localEyes);
|
||||
glm::vec3 neckToRoot = hmdOrientationYawOnly * -localNeck;
|
||||
glm::vec3 bodyPos = hmdPosition + eyeToNeck + neckToRoot;
|
||||
|
||||
// avatar facing is determined solely by hmd orientation.
|
||||
return createMatFromQuatAndPos(hmdOrientationYawOnly, bodyPos);
|
||||
}
|
||||
#endif
|
||||
|
||||
glm::vec3 MyAvatar::getPositionForAudio() {
|
||||
switch (_audioListenerMode) {
|
||||
|
|
|
@ -56,11 +56,11 @@ bool RecordingScriptingInterface::isPaused() {
|
|||
}
|
||||
|
||||
float RecordingScriptingInterface::playerElapsed() {
|
||||
return (float)_player->position() / MSECS_PER_SECOND;
|
||||
return _player->position();
|
||||
}
|
||||
|
||||
float RecordingScriptingInterface::playerLength() {
|
||||
return _player->length() / MSECS_PER_SECOND;
|
||||
return _player->length();
|
||||
}
|
||||
|
||||
void RecordingScriptingInterface::loadRecording(const QString& filename) {
|
||||
|
@ -103,7 +103,7 @@ void RecordingScriptingInterface::setPlayerAudioOffset(float audioOffset) {
|
|||
}
|
||||
|
||||
void RecordingScriptingInterface::setPlayerTime(float time) {
|
||||
_player->seek(time * MSECS_PER_SECOND);
|
||||
_player->seek(time);
|
||||
}
|
||||
|
||||
void RecordingScriptingInterface::setPlayFromCurrentLocation(bool playFromCurrentLocation) {
|
||||
|
|
|
@ -79,7 +79,7 @@ const QString& AnimSkeleton::getJointName(int jointIndex) const {
|
|||
}
|
||||
|
||||
AnimPose AnimSkeleton::getAbsolutePose(int jointIndex, const AnimPoseVec& poses) const {
|
||||
if (jointIndex < 0) {
|
||||
if (jointIndex < 0 || jointIndex >= (int)poses.size() || jointIndex >= (int)_joints.size()) {
|
||||
return AnimPose::identity;
|
||||
} else {
|
||||
return getAbsolutePose(_joints[jointIndex].parentIndex, poses) * poses[jointIndex];
|
||||
|
|
|
@ -23,6 +23,19 @@
|
|||
#include "AnimSkeleton.h"
|
||||
#include "IKTarget.h"
|
||||
|
||||
/*
|
||||
const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 1.6f, 0.0f);
|
||||
const glm::vec3 DEFAULT_LEFT_EYE_POS(0.3f, 1.6f, 0.0f);
|
||||
const glm::vec3 DEFAULT_HEAD_POS(0.0f, 1.55f, 0.0f);
|
||||
const glm::vec3 DEFAULT_NECK_POS(0.0f, 1.5f, 0.0f);
|
||||
*/
|
||||
|
||||
// 2 meter tall dude
|
||||
const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 1.9f, 0.0f);
|
||||
const glm::vec3 DEFAULT_LEFT_EYE_POS(0.3f, 1.9f, 0.0f);
|
||||
const glm::vec3 DEFAULT_HEAD_POS(0.0f, 1.75f, 0.0f);
|
||||
const glm::vec3 DEFAULT_NECK_POS(0.0f, 1.70f, 0.0f);
|
||||
|
||||
void insertSorted(QList<AnimationHandlePointer>& handles, const AnimationHandlePointer& handle) {
|
||||
for (QList<AnimationHandlePointer>::iterator it = handles.begin(); it != handles.end(); it++) {
|
||||
if (handle->getPriority() > (*it)->getPriority()) {
|
||||
|
@ -410,17 +423,19 @@ void Rig::calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds,
|
|||
void Rig::computeEyesInRootFrame(const AnimPoseVec& poses) {
|
||||
// TODO: use cached eye/hips indices for these calculations
|
||||
int numPoses = poses.size();
|
||||
int rightEyeIndex = _animSkeleton->nameToJointIndex(QString("RightEye"));
|
||||
int leftEyeIndex = _animSkeleton->nameToJointIndex(QString("LeftEye"));
|
||||
if (numPoses > rightEyeIndex && numPoses > leftEyeIndex
|
||||
&& rightEyeIndex > 0 && leftEyeIndex > 0) {
|
||||
int hipsIndex = _animSkeleton->nameToJointIndex(QString("Hips"));
|
||||
int headIndex = _animSkeleton->nameToJointIndex(QString("Head"));
|
||||
if (hipsIndex >= 0 && headIndex > 0) {
|
||||
int hipsIndex = _animSkeleton->nameToJointIndex(QString("Hips"));
|
||||
int headIndex = _animSkeleton->nameToJointIndex(QString("Head"));
|
||||
if (hipsIndex > 0 && headIndex > 0) {
|
||||
int rightEyeIndex = _animSkeleton->nameToJointIndex(QString("RightEye"));
|
||||
int leftEyeIndex = _animSkeleton->nameToJointIndex(QString("LeftEye"));
|
||||
if (numPoses > rightEyeIndex && numPoses > leftEyeIndex && rightEyeIndex > 0 && leftEyeIndex > 0) {
|
||||
glm::vec3 rightEye = _animSkeleton->getAbsolutePose(rightEyeIndex, poses).trans;
|
||||
glm::vec3 leftEye = _animSkeleton->getAbsolutePose(leftEyeIndex, poses).trans;
|
||||
glm::vec3 hips = _animSkeleton->getAbsolutePose(hipsIndex, poses).trans;
|
||||
_eyesInRootFrame = 0.5f * (rightEye + leftEye) - hips;
|
||||
} else {
|
||||
glm::vec3 hips = _animSkeleton->getAbsolutePose(hipsIndex, poses).trans;
|
||||
_eyesInRootFrame = 0.5f * (DEFAULT_RIGHT_EYE_POS + DEFAULT_LEFT_EYE_POS) - hips;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1172,11 +1187,6 @@ static void computeHeadNeckAnimVars(AnimSkeleton::ConstPointer skeleton, const A
|
|||
int headIndex = skeleton->nameToJointIndex("Head");
|
||||
int neckIndex = skeleton->nameToJointIndex("Neck");
|
||||
|
||||
const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 1.6f, 0.0f);
|
||||
const glm::vec3 DEFAULT_LEFT_EYE_POS(0.3f, 1.6f, 0.0f);
|
||||
const glm::vec3 DEFAULT_HEAD_POS(0.0f, 1.55f, 0.0f);
|
||||
const glm::vec3 DEFAULT_NECK_POS(0.0f, 1.5f, 0.0f);
|
||||
|
||||
// Use absolute bindPose positions just in case the relBindPose have rotations we don't expect.
|
||||
glm::vec3 absRightEyePos = rightEyeIndex != -1 ? skeleton->getAbsoluteBindPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS;
|
||||
glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? skeleton->getAbsoluteBindPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS;
|
||||
|
|
|
@ -662,7 +662,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
|
|||
// move head forward
|
||||
_particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles;
|
||||
} else {
|
||||
float age = 1.0f - _particleLifetimes[i] / _lifespan; // 0.0 .. 1.0
|
||||
float age = _particleLifetimes[i] / _lifespan; // 0.0 .. 1.0
|
||||
updateRadius(i, age);
|
||||
updateColor(i, age);
|
||||
updateAlpha(i, age);
|
||||
|
|
|
@ -299,14 +299,17 @@ qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiS
|
|||
|
||||
qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode) {
|
||||
Q_ASSERT(!packet->isPartOfMessage());
|
||||
if (!destinationNode.getActiveSocket()) {
|
||||
auto activeSocket = destinationNode.getActiveSocket();
|
||||
|
||||
if (activeSocket) {
|
||||
emit dataSent(destinationNode.getType(), packet->getDataSize());
|
||||
destinationNode.recordBytesSent(packet->getDataSize());
|
||||
|
||||
return sendPacket(std::move(packet), *activeSocket, destinationNode.getConnectionSecret());
|
||||
} else {
|
||||
qDebug() << "LimitedNodeList::sendPacket called without active socket for node" << destinationNode << "- not sending";
|
||||
return 0;
|
||||
}
|
||||
|
||||
emit dataSent(destinationNode.getType(), packet->getDataSize());
|
||||
destinationNode.recordBytesSent(packet->getDataSize());
|
||||
|
||||
return sendPacket(std::move(packet), *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret());
|
||||
}
|
||||
|
||||
qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const HifiSockAddr& sockAddr,
|
||||
|
@ -327,21 +330,25 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const HifiS
|
|||
|
||||
qint64 LimitedNodeList::sendPacketList(NLPacketList& packetList, const Node& destinationNode) {
|
||||
auto activeSocket = destinationNode.getActiveSocket();
|
||||
if (!activeSocket) {
|
||||
|
||||
if (activeSocket) {
|
||||
qint64 bytesSent = 0;
|
||||
auto connectionSecret = destinationNode.getConnectionSecret();
|
||||
|
||||
// close the last packet in the list
|
||||
packetList.closeCurrentPacket();
|
||||
|
||||
while (!packetList._packets.empty()) {
|
||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), *activeSocket, connectionSecret);
|
||||
}
|
||||
|
||||
emit dataSent(destinationNode.getType(), bytesSent);
|
||||
return bytesSent;
|
||||
} else {
|
||||
qDebug() << "LimitedNodeList::sendPacketList called without active socket for node" << destinationNode
|
||||
<< " - not sending.";
|
||||
return 0;
|
||||
}
|
||||
qint64 bytesSent = 0;
|
||||
auto connectionSecret = destinationNode.getConnectionSecret();
|
||||
|
||||
// close the last packet in the list
|
||||
packetList.closeCurrentPacket();
|
||||
|
||||
while (!packetList._packets.empty()) {
|
||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), *activeSocket, connectionSecret);
|
||||
}
|
||||
|
||||
emit dataSent(destinationNode.getType(), bytesSent);
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
qint64 LimitedNodeList::sendPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr,
|
||||
|
@ -372,23 +379,35 @@ qint64 LimitedNodeList::sendPacketList(std::unique_ptr<NLPacketList> packetList,
|
|||
}
|
||||
|
||||
qint64 LimitedNodeList::sendPacketList(std::unique_ptr<NLPacketList> packetList, const Node& destinationNode) {
|
||||
// close the last packet in the list
|
||||
packetList->closeCurrentPacket();
|
||||
auto activeSocket = destinationNode.getActiveSocket();
|
||||
if (activeSocket) {
|
||||
// close the last packet in the list
|
||||
packetList->closeCurrentPacket();
|
||||
|
||||
for (std::unique_ptr<udt::Packet>& packet : packetList->_packets) {
|
||||
NLPacket* nlPacket = static_cast<NLPacket*>(packet.get());
|
||||
collectPacketStats(*nlPacket);
|
||||
fillPacketHeader(*nlPacket, destinationNode.getConnectionSecret());
|
||||
for (std::unique_ptr<udt::Packet>& packet : packetList->_packets) {
|
||||
NLPacket* nlPacket = static_cast<NLPacket*>(packet.get());
|
||||
collectPacketStats(*nlPacket);
|
||||
fillPacketHeader(*nlPacket, destinationNode.getConnectionSecret());
|
||||
}
|
||||
|
||||
return _nodeSocket.writePacketList(std::move(packetList), *activeSocket);
|
||||
} else {
|
||||
qCDebug(networking) << "LimitedNodeList::sendPacketList called without active socket for node. Not sending.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _nodeSocket.writePacketList(std::move(packetList), *destinationNode.getActiveSocket());
|
||||
}
|
||||
|
||||
qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode,
|
||||
const HifiSockAddr& overridenSockAddr) {
|
||||
if (overridenSockAddr.isNull() && !destinationNode.getActiveSocket()) {
|
||||
qCDebug(networking) << "LimitedNodeList::sendPacket called without active socket for node. Not sending.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// use the node's active socket as the destination socket if there is no overriden socket address
|
||||
auto& destinationSockAddr = (overridenSockAddr.isNull()) ? *destinationNode.getActiveSocket()
|
||||
: overridenSockAddr;
|
||||
|
||||
return sendPacket(std::move(packet), destinationSockAddr, destinationNode.getConnectionSecret());
|
||||
}
|
||||
|
||||
|
|
|
@ -113,6 +113,10 @@ void NetworkPeer::setActiveSocket(HifiSockAddr* discoveredSocket) {
|
|||
|
||||
// we're now considered connected to this peer - reset the number of connection attemps
|
||||
resetConnectionAttempts();
|
||||
|
||||
if (_activeSocket) {
|
||||
emit socketActivated(*_activeSocket);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkPeer::activateLocalSocket() {
|
||||
|
|
|
@ -83,6 +83,7 @@ public slots:
|
|||
void stopPingTimer();
|
||||
signals:
|
||||
void pingTimerTimeout();
|
||||
void socketActivated(const HifiSockAddr& sockAddr);
|
||||
protected:
|
||||
void setActiveSocket(HifiSockAddr* discoveredSocket);
|
||||
|
||||
|
|
|
@ -167,10 +167,7 @@ void OculusLegacyDisplayPlugin::activate() {
|
|||
}
|
||||
});
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
ovrBool result =
|
||||
#endif
|
||||
ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
|
||||
ovrBool result = ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
|
||||
Q_ASSERT(result);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue