mirror of
https://github.com/lubosz/overte.git
synced 2025-04-13 21:06:32 +02:00
Merge branch 'correct-target-frame-rate' of https://github.com/howard-stearns/hifi into correct-target-frame-rate
This commit is contained in:
commit
5643a6a4c6
95 changed files with 2359 additions and 921 deletions
|
@ -221,3 +221,36 @@ if (HIFI_MEMORY_DEBUGGING)
|
|||
MESSAGE("-- Memory debugging is enabled")
|
||||
endif (UNIX)
|
||||
endif ()
|
||||
|
||||
include_application_version()
|
||||
|
||||
if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE)
|
||||
message(STATUS "+++++ Package for deployment will be generated on this build +++++")
|
||||
|
||||
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/full-stack-deployment)
|
||||
|
||||
set(ICONPATH_INTERFACE "$INSTDIR/${PATH_INSTALL_DATA}/interface.ico")
|
||||
set(ICONPATH_STACK_MANAGER "$INSTDIR/${PATH_INSTALL_DATA}/stack-manager.ico")
|
||||
string(REPLACE "/" "\\\\" ICONPATH_INTERFACE ${ICONPATH_INTERFACE})
|
||||
string(REPLACE "/" "\\\\" ICONPATH_STACK_MANAGER ${ICONPATH_STACK_MANAGER})
|
||||
|
||||
set(CPACK_PACKAGE_NAME "High Fidelity")
|
||||
set(CPACK_PACKAGE_VENDOR "High Fidelity, Inc")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "High Fidelity Interface and Stack")
|
||||
set(CPACK_PACKAGE_VERSION "${BUILD_SEQ}")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "${BUILD_SEQ}")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "0")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "0")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "High Fidelity-${BUILD_SEQ}")
|
||||
set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
||||
set(CPACK_PACKAGE_EXECUTABLES
|
||||
stack-manager "Stack Manager"
|
||||
interface "Interface"
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
install(DIRECTORY ${CMAKE_BINARY_DIR}/full-stack-deployment/ DESTINATION "./")
|
||||
endif (WIN32)
|
||||
|
||||
include(CPack)
|
||||
endif ()
|
||||
|
|
|
@ -11,3 +11,4 @@ link_hifi_libraries(
|
|||
|
||||
include_application_version()
|
||||
package_libraries_for_deployment()
|
||||
consolidate_stack_components()
|
|
@ -16,6 +16,7 @@
|
|||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include <AssetClient.h>
|
||||
#include <AvatarHashMap.h>
|
||||
#include <AudioInjectorManager.h>
|
||||
#include <AssetClient.h>
|
||||
|
@ -131,6 +132,7 @@ void Agent::run() {
|
|||
|
||||
// make sure we request our script once the agent connects to the domain
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, this, &Agent::requestScript);
|
||||
|
||||
ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent);
|
||||
|
@ -223,6 +225,7 @@ void Agent::executeScript() {
|
|||
// call model URL setters with empty URLs so our avatar, if user, will have the default models
|
||||
scriptedAvatar->setFaceModelURL(QUrl());
|
||||
scriptedAvatar->setSkeletonModelURL(QUrl());
|
||||
|
||||
// give this AvatarData object to the script engine
|
||||
_scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data());
|
||||
|
||||
|
|
|
@ -438,7 +438,6 @@ int AudioMixer::prepareMixForListeningNode(Node* node) {
|
|||
AudioMixerClientData* listenerNodeData = static_cast<AudioMixerClientData*>(node->getLinkedData());
|
||||
|
||||
// zero out the client mix for this node
|
||||
memset(_preMixSamples, 0, sizeof(_preMixSamples));
|
||||
memset(_mixSamples, 0, sizeof(_mixSamples));
|
||||
|
||||
// loop through all other nodes that have sufficient audio to mix
|
||||
|
@ -459,6 +458,9 @@ int AudioMixer::prepareMixForListeningNode(Node* node) {
|
|||
if (otherNodeStream->getType() == PositionalAudioStream::Microphone) {
|
||||
streamUUID = otherNode->getUUID();
|
||||
}
|
||||
|
||||
// clear out the pre-mix samples before filling it up with this source
|
||||
memset(_preMixSamples, 0, sizeof(_preMixSamples));
|
||||
|
||||
if (*otherNode != *node || otherNodeStream->shouldLoopbackForNode()) {
|
||||
streamsMixed += addStreamToMixForListeningNodeWithStream(listenerNodeData, streamUUID,
|
||||
|
|
27
cmake/macros/ConsolidateStackComponents.cmake
Normal file
27
cmake/macros/ConsolidateStackComponents.cmake
Normal file
|
@ -0,0 +1,27 @@
|
|||
macro(CONSOLIDATE_STACK_COMPONENTS)
|
||||
|
||||
if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE AND WIN32)
|
||||
|
||||
# Copy all the output for this target into the common deployment location
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory $<TARGET_FILE_DIR:${TARGET_NAME}> ${CMAKE_BINARY_DIR}/full-stack-deployment
|
||||
)
|
||||
|
||||
# Copy icon files for interface and stack manager
|
||||
if (TARGET_NAME STREQUAL "interface" OR TARGET_NAME STREQUAL "stack-manager")
|
||||
if (TARGET_NAME STREQUAL "interface")
|
||||
set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/icon/interface.ico")
|
||||
set (ICON_DESTINATION_NAME "interface.ico")
|
||||
elseif (TARGET_NAME STREQUAL "stack-manager")
|
||||
set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/assets/icon.ico")
|
||||
set (ICON_DESTINATION_NAME "stack-manager.ico")
|
||||
endif ()
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/full-stack-deployment/${ICON_DESTINATION_NAME}
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
endmacro()
|
|
@ -10,10 +10,15 @@
|
|||
#
|
||||
|
||||
macro(INCLUDE_APPLICATION_VERSION)
|
||||
#
|
||||
# We are relying on Jenkins defined environment variables to determine the origin of this build
|
||||
# and will only package if this is a PR or Release build
|
||||
if (DEFINED ENV{JOB_ID})
|
||||
set (DEPLOY_PACKAGE 1)
|
||||
set (BUILD_SEQ $ENV{JOB_ID})
|
||||
elseif (DEFINED ENV{ghprbPullId})
|
||||
set (BUILD_SEQ "PR: $ENV{ghprbPullId} - Commit: $ENV{ghprbActualCommit}")
|
||||
set (DEPLOY_PACKAGE 1)
|
||||
set (BUILD_SEQ "PR-$ENV{ghprbPullId}")
|
||||
else ()
|
||||
set(BUILD_SEQ "dev")
|
||||
endif ()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# CopyDllsBesideWindowsExecutable.cmake
|
||||
# PackageLibrariesForDeployment.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
|
@ -107,7 +107,7 @@ if (WIN32 AND NOT CYGWIN)
|
|||
select_library_configurations(SSL_EAY)
|
||||
|
||||
set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY})
|
||||
|
||||
|
||||
find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
|
||||
elseif (MINGW)
|
||||
|
@ -252,6 +252,15 @@ endif ()
|
|||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${OPENSSL_DLL_PATH})
|
||||
#
|
||||
# For some reason fixup misses the following DLL and only copies libeay32. There's gotta be a better way to handle this
|
||||
# but for now resorting to the following interm solution
|
||||
if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${OPENSSL_DLL_PATH}/ssleay32.dll ${CMAKE_BINARY_DIR}/full-stack-deployment/
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS)
|
||||
|
|
|
@ -53,4 +53,4 @@ else()
|
|||
endif()
|
||||
|
||||
file(GLOB RUNTIME_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}")
|
||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "${RUNTIME_PLUGINS}" "@FIXUP_LIBS@")
|
||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "${RUNTIME_PLUGINS}" "@FIXUP_LIBS@")
|
||||
|
|
|
@ -38,3 +38,4 @@ endif (UNIX)
|
|||
|
||||
include_application_version()
|
||||
package_libraries_for_deployment()
|
||||
consolidate_stack_components()
|
105
examples/baseball/assets.json
Normal file
105
examples/baseball/assets.json
Normal file
|
@ -0,0 +1,105 @@
|
|||
{
|
||||
"assets": {
|
||||
"crowd-boos.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-boos.wav",
|
||||
"atp_url": "atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/"
|
||||
},
|
||||
"crowd-cheers-organ.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-cheers-organ.wav",
|
||||
"atp_url": "atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/"
|
||||
},
|
||||
"crowd-medium.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-medium.wav",
|
||||
"atp_url": "atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/"
|
||||
},
|
||||
"baseball-hitting-bat-1.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav",
|
||||
"atp_url": "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: https://www.freesound.org/people/SocializedArtist45/"
|
||||
},
|
||||
"baseball-hitting-bat-set-1.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-1.wav",
|
||||
"atp_url": "atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/"
|
||||
},
|
||||
"baseball-hitting-bat-set-2.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-2.wav",
|
||||
"atp_url": "atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/"
|
||||
},
|
||||
"baseball-hitting-bat-set-3.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-3.wav",
|
||||
"atp_url": "atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/"
|
||||
},
|
||||
"baseball-hitting-bat-set-4.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav",
|
||||
"atp_url": "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/"
|
||||
},
|
||||
"chatter-loop.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/chatter-loop.wav",
|
||||
"atp_url": "atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/"
|
||||
},
|
||||
"zorba-organ.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/zorba-organ.wav",
|
||||
"atp_url": "atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/"
|
||||
},
|
||||
"charge-organ.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/charge-organ.wav",
|
||||
"atp_url": "atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/"
|
||||
},
|
||||
"ball-game.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/ball-game.wav",
|
||||
"atp_url": "atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/"
|
||||
},
|
||||
"clapping.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav",
|
||||
"atp_url": "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/"
|
||||
},
|
||||
"pop1.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop1.wav",
|
||||
"atp_url": "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav"
|
||||
},
|
||||
"pop2.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop2.wav",
|
||||
"atp_url": "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav"
|
||||
},
|
||||
"pop3.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop3.wav",
|
||||
"atp_url": "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav"
|
||||
},
|
||||
"pop4.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav",
|
||||
"atp_url": "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav"
|
||||
},
|
||||
"fire1.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire1.wav",
|
||||
"atp_url": "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav",
|
||||
"attribution": "CC BY 3.0 - Credir: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/"
|
||||
},
|
||||
"fire2.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire2.wav",
|
||||
"atp_url": "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/"
|
||||
},
|
||||
"fire3.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire3.wav",
|
||||
"atp_url": "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/"
|
||||
},
|
||||
"fire4.wav": {
|
||||
"s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire4.wav",
|
||||
"atp_url": "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav",
|
||||
"attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/"
|
||||
}
|
||||
}
|
||||
}
|
43
examples/baseball/baseballCrowd.js
Normal file
43
examples/baseball/baseballCrowd.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// baseballCrowd.js
|
||||
// examples/acScripts
|
||||
//
|
||||
// Created by Stephen Birarda on 10/20/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
var chatter = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav");
|
||||
var extras = [
|
||||
SoundCache.getSound("atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav"), // zorba
|
||||
SoundCache.getSound("atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav"), // charge
|
||||
SoundCache.getSound("atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav"), // take me out to the ball game
|
||||
SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping
|
||||
];
|
||||
|
||||
var CHATTER_VOLUME = 0.20
|
||||
var EXTRA_VOLUME = 0.25
|
||||
|
||||
function playChatter() {
|
||||
if (chatter.downloaded && !chatter.isPlaying) {
|
||||
Audio.playSound(chatter, { loop: true, volume: CHATTER_VOLUME });
|
||||
}
|
||||
}
|
||||
|
||||
chatter.ready.connect(playChatter);
|
||||
|
||||
var currentInjector = null;
|
||||
|
||||
function playRandomExtras() {
|
||||
if ((!currentInjector || !currentInjector.isPlaying) && (Math.random() < (1.0 / 1800.0))) {
|
||||
// play a random extra sound about every 30s
|
||||
currentInjector = Audio.playSound(
|
||||
extras[Math.floor(Math.random() * extras.length)],
|
||||
{ volume: EXTRA_VOLUME }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Script.update.connect(playRandomExtras);
|
43
examples/baseball/bat.js
Normal file
43
examples/baseball/bat.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// bat.js
|
||||
// examples/baseball/
|
||||
//
|
||||
// Created by Ryan Huffman on Nov 9, 2015
|
||||
// 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
|
||||
//
|
||||
|
||||
(function() {
|
||||
Script.include("pitching.js");
|
||||
|
||||
var pitchingMachine = null;
|
||||
|
||||
this.pitchAndHideAvatar = function() {
|
||||
if (!pitchingMachine) {
|
||||
pitchingMachine = getOrCreatePitchingMachine();
|
||||
Script.update.connect(function(dt) { pitchingMachine.update(dt); });
|
||||
}
|
||||
pitchingMachine.start();
|
||||
MyAvatar.shouldRenderLocally = false;
|
||||
};
|
||||
|
||||
this.startNearGrab = function() {
|
||||
// send the avatar to the baseball location so that they're ready to bat
|
||||
location = "/baseball"
|
||||
|
||||
this.pitchAndHideAvatar()
|
||||
};
|
||||
|
||||
this.continueNearGrab = function() {
|
||||
this.pitchAndHideAvatar()
|
||||
};
|
||||
|
||||
this.releaseGrab = function() {
|
||||
if (pitchingMachine) {
|
||||
pitchingMachine.stop();
|
||||
}
|
||||
MyAvatar.shouldRenderLocally = true;
|
||||
};
|
||||
});
|
76
examples/baseball/createBatButton.js
Normal file
76
examples/baseball/createBatButton.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// createBatButton.js
|
||||
// examples/baseball/moreBatsButton.js
|
||||
//
|
||||
// Created by Stephen Birarda on 10/28/2015.
|
||||
// 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
|
||||
//
|
||||
|
||||
(function(){
|
||||
this.clickReleaseOnEntity = function(entityID, mouseEvent) {
|
||||
if (!mouseEvent.isLeftButton) {
|
||||
return;
|
||||
}
|
||||
this.dropBats();
|
||||
};
|
||||
this.startNearTrigger = function() {
|
||||
this.dropBats();
|
||||
};
|
||||
this.startFarTrigger = function() {
|
||||
this.dropBats();
|
||||
};
|
||||
this.dropBats = function() {
|
||||
// if the bat box is near us, grab it's position
|
||||
var nearby = Entities.findEntities(this.position, 20);
|
||||
|
||||
nearby.forEach(function(id) {
|
||||
var properties = Entities.getEntityProperties(id, ["name", "position"]);
|
||||
if (properties.name && properties.name == "Bat Box") {
|
||||
boxPosition = properties.position;
|
||||
}
|
||||
});
|
||||
|
||||
var BAT_DROP_HEIGHT = 2.0;
|
||||
|
||||
var dropPosition;
|
||||
|
||||
if (!boxPosition) {
|
||||
// we got no bat box position, drop in front of the avatar instead
|
||||
} else {
|
||||
// drop the bat above the bat box
|
||||
dropPosition = Vec3.sum(boxPosition, { x: 0.0, y: BAT_DROP_HEIGHT, z: 0.0});
|
||||
}
|
||||
|
||||
var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx";
|
||||
var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj";
|
||||
var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js"
|
||||
|
||||
var batUserData = {
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
leftRelativePosition: { x: 0.9, y: 0.05, z: -0.05 },
|
||||
rightRelativePosition: { x: 0.9, y: 0.05, z: 0.05 },
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the fresh bat at the drop position
|
||||
var bat = Entities.addEntity({
|
||||
name: 'Bat',
|
||||
type: "Model",
|
||||
modelURL: BAT_MODEL,
|
||||
position: dropPosition,
|
||||
compoundShapeURL: BAT_COLLISION_HULL,
|
||||
collisionsWillMove: true,
|
||||
velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add
|
||||
gravity: { x: 0, y: -9.81, z: 0},
|
||||
rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0),
|
||||
script: SCRIPT_URL,
|
||||
userData: JSON.stringify(batUserData)
|
||||
});
|
||||
};
|
||||
});
|
138
examples/baseball/firework.js
Normal file
138
examples/baseball/firework.js
Normal file
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// firework.js
|
||||
// examples/baseball/
|
||||
//
|
||||
// Created by Ryan Huffman on Nov 9, 2015
|
||||
// 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
|
||||
//
|
||||
|
||||
Script.include("utils.js");
|
||||
|
||||
var emitters = [];
|
||||
|
||||
var smokeTrailSettings = {
|
||||
"name":"ParticlesTest Emitter",
|
||||
"type": "ParticleEffect",
|
||||
"color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235},
|
||||
"maxParticles":1000,
|
||||
"velocity": { x: 0, y: 18.0, z: 0 },
|
||||
"lifetime": 20,
|
||||
"lifespan":3,
|
||||
"emitRate":100,
|
||||
"emitSpeed":0.5,
|
||||
"speedSpread":0,
|
||||
"emitOrientation":{"x":0,"y":0,"z":0,"w":1},
|
||||
"emitDimensions":{"x":0,"y":0,"z":0},
|
||||
"emitRadiusStart":0.5,
|
||||
"polarStart":1,
|
||||
"polarFinish":1,
|
||||
"azimuthStart":0,
|
||||
"azimuthFinish":0,
|
||||
"emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0},
|
||||
"accelerationSpread":{"x":0,"y":0,"z":0},
|
||||
"particleRadius":0.03999999910593033,
|
||||
"radiusSpread":0,
|
||||
"radiusStart":0.13999999910593033,
|
||||
"radiusFinish":0.14,
|
||||
"colorSpread":{"red":0,"green":0,"blue":0},
|
||||
"colorStart":{"red":255,"green":255,"blue":255},
|
||||
"colorFinish":{"red":255,"green":255,"blue":255},
|
||||
"alpha":1,
|
||||
"alphaSpread":0,
|
||||
"alphaStart":0,
|
||||
"alphaFinish":1,
|
||||
"textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png"
|
||||
};
|
||||
|
||||
var fireworkSettings = {
|
||||
"name":"ParticlesTest Emitter",
|
||||
"type": "ParticleEffect",
|
||||
"color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235},
|
||||
"maxParticles":1000,
|
||||
"lifetime": 20,
|
||||
"lifespan":4,
|
||||
"emitRate":1000,
|
||||
"emitSpeed":1.5,
|
||||
"speedSpread":1.0,
|
||||
"emitOrientation":{"x":-0.2,"y":0,"z":0,"w":0.7000000000000001},
|
||||
"emitDimensions":{"x":0,"y":0,"z":0},
|
||||
"emitRadiusStart":0.5,
|
||||
"polarStart":1,
|
||||
"polarFinish":1.2,
|
||||
"azimuthStart":-Math.PI,
|
||||
"azimuthFinish":Math.PI,
|
||||
"emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0},
|
||||
"accelerationSpread":{"x":0,"y":0,"z":0},
|
||||
"particleRadius":0.03999999910593033,
|
||||
"radiusSpread":0,
|
||||
"radiusStart":0.13999999910593033,
|
||||
"radiusFinish":0.14,
|
||||
"colorSpread":{"red":0,"green":0,"blue":0},
|
||||
"colorStart":{"red":255,"green":255,"blue":255},
|
||||
"colorFinish":{"red":255,"green":255,"blue":255},
|
||||
"alpha":1,
|
||||
"alphaSpread":0,
|
||||
"alphaStart":0,
|
||||
"alphaFinish":1,
|
||||
"textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/spark_2.png",
|
||||
};
|
||||
|
||||
var popSounds = getSounds([
|
||||
"atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav",
|
||||
"atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav",
|
||||
"atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav",
|
||||
"atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav"
|
||||
]);
|
||||
|
||||
var launchSounds = getSounds([
|
||||
"atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav",
|
||||
"atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav",
|
||||
"atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav",
|
||||
"atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav"
|
||||
]);
|
||||
|
||||
function playRandomSound(sounds, options) {
|
||||
Audio.playSound(sounds[randomInt(sounds.length)], options);
|
||||
}
|
||||
|
||||
function shootFirework(position, color, options) {
|
||||
smokeTrailSettings.position = position;
|
||||
smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15);
|
||||
smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40);
|
||||
|
||||
playRandomSound(launchSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 });
|
||||
var smokeID = Entities.addEntity(smokeTrailSettings);
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(smokeID, { emitRate: 0 });
|
||||
var position = Entities.getEntityProperties(smokeID, ['position']).position;
|
||||
fireworkSettings.position = position;
|
||||
fireworkSettings.colorStart = color;
|
||||
fireworkSettings.colorFinish = color;
|
||||
var burstID = Entities.addEntity(fireworkSettings);
|
||||
playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 });
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(burstID, { emitRate: 0 });
|
||||
}, 500);
|
||||
Script.setTimeout(function() {
|
||||
Entities.deleteEntity(smokeID);
|
||||
Entities.deleteEntity(burstID);
|
||||
}, 10000);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
playFireworkShow = function(position, numberOfFireworks, duration) {
|
||||
for (var i = 0; i < numberOfFireworks; i++) {
|
||||
var randomOffset = randomVec3(-15, 15, -3, 3, -1, 1);
|
||||
var randomPosition = Vec3.sum(position, randomOffset);
|
||||
Script.setTimeout(function(position) {
|
||||
return function() {
|
||||
var color = randomColor(128, 255, 128, 255, 128, 255);
|
||||
shootFirework(position, color, fireworkSettings);
|
||||
}
|
||||
}(randomPosition), Math.random() * duration)
|
||||
}
|
||||
}
|
165
examples/baseball/line.js
Normal file
165
examples/baseball/line.js
Normal file
|
@ -0,0 +1,165 @@
|
|||
function info(message) {
|
||||
print("[INFO] " + message);
|
||||
}
|
||||
|
||||
function error(message) {
|
||||
print("[ERROR] " + message);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* PolyLine
|
||||
*****************************************************************************/
|
||||
var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 };
|
||||
var MAX_LINE_LENGTH = 40; // This must be 2 or greater;
|
||||
var PolyLine = function(position, color, defaultStrokeWidth) {
|
||||
//info("Creating polyline");
|
||||
//Vec3.print("New line at", position);
|
||||
this.position = position;
|
||||
this.color = color;
|
||||
this.defaultStrokeWidth = 0.10;
|
||||
this.points = [
|
||||
{ x: 0, y: 0, z: 0 },
|
||||
];
|
||||
this.strokeWidths = [
|
||||
this.defaultStrokeWidth,
|
||||
]
|
||||
this.normals = [
|
||||
{ x: 1, y: 0, z: 0 },
|
||||
]
|
||||
this.entityID = Entities.addEntity({
|
||||
type: "PolyLine",
|
||||
position: position,
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths,
|
||||
dimensions: LINE_DIMENSIONS,
|
||||
color: color,
|
||||
lifetime: 20,
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.enqueuePoint = function(position) {
|
||||
if (this.isFull()) {
|
||||
error("Hit max PolyLine size");
|
||||
return;
|
||||
}
|
||||
|
||||
//Vec3.print("pos", position);
|
||||
//info("Number of points: " + this.points.length);
|
||||
|
||||
position = Vec3.subtract(position, this.position);
|
||||
this.points.push(position);
|
||||
this.normals.push({ x: 1, y: 0, z: 0 });
|
||||
this.strokeWidths.push(this.defaultStrokeWidth);
|
||||
Entities.editEntity(this.entityID, {
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths,
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.dequeuePoint = function() {
|
||||
if (this.points.length == 0) {
|
||||
error("Hit min PolyLine size");
|
||||
return;
|
||||
}
|
||||
|
||||
this.points = this.points.slice(1);
|
||||
this.normals = this.normals.slice(1);
|
||||
this.strokeWidths = this.strokeWidths.slice(1);
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths,
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.getFirstPoint = function() {
|
||||
return Vec3.sum(this.position, this.points[0]);
|
||||
};
|
||||
|
||||
PolyLine.prototype.getLastPoint = function() {
|
||||
return Vec3.sum(this.position, this.points[this.points.length - 1]);
|
||||
};
|
||||
|
||||
PolyLine.prototype.getSize = function() {
|
||||
return this.points.length;
|
||||
}
|
||||
|
||||
PolyLine.prototype.isFull = function() {
|
||||
return this.points.length >= MAX_LINE_LENGTH;
|
||||
};
|
||||
|
||||
PolyLine.prototype.destroy = function() {
|
||||
Entities.deleteEntity(this.entityID);
|
||||
this.points = [];
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* InfiniteLine
|
||||
*****************************************************************************/
|
||||
InfiniteLine = function(position, color) {
|
||||
this.position = position;
|
||||
this.color = color;
|
||||
this.lines = [new PolyLine(position, color)];
|
||||
this.size = 0;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.enqueuePoint = function(position) {
|
||||
var currentLine;
|
||||
|
||||
if (this.lines.length == 0) {
|
||||
currentLine = new PolyLine(position, this.color);
|
||||
this.lines.push(currentLine);
|
||||
} else {
|
||||
currentLine = this.lines[this.lines.length - 1];
|
||||
}
|
||||
|
||||
if (currentLine.isFull()) {
|
||||
//info("Current line is full, creating new line");
|
||||
//Vec3.print("Last line is", currentLine.getLastPoint());
|
||||
//Vec3.print("New line is", position);
|
||||
var newLine = new PolyLine(currentLine.getLastPoint(), this.color);
|
||||
this.lines.push(newLine);
|
||||
currentLine = newLine;
|
||||
}
|
||||
|
||||
currentLine.enqueuePoint(position);
|
||||
|
||||
++this.size;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.dequeuePoint = function() {
|
||||
if (this.lines.length == 0) {
|
||||
error("Trying to dequeue from InfiniteLine when no points are left");
|
||||
return;
|
||||
}
|
||||
|
||||
var lastLine = this.lines[0];
|
||||
lastLine.dequeuePoint();
|
||||
|
||||
if (lastLine.getSize() <= 1) {
|
||||
this.lines = this.lines.slice(1);
|
||||
}
|
||||
|
||||
--this.size;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.getFirstPoint = function() {
|
||||
return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.getLastPoint = function() {
|
||||
return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.destroy = function() {
|
||||
for (var i = 0; i < this.lines.length; ++i) {
|
||||
this.lines[i].destroy();
|
||||
}
|
||||
|
||||
this.size = 0;
|
||||
};
|
554
examples/baseball/pitching.js
Normal file
554
examples/baseball/pitching.js
Normal file
|
@ -0,0 +1,554 @@
|
|||
//
|
||||
// pitching.js
|
||||
// examples/baseball/
|
||||
//
|
||||
// Created by Ryan Huffman on Nov 9, 2015
|
||||
// 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
|
||||
//
|
||||
|
||||
print("Loading pitching");
|
||||
|
||||
Script.include("../libraries/line.js");
|
||||
Script.include("firework.js");
|
||||
Script.include("utils.js");
|
||||
|
||||
var DISTANCE_BILLBOARD_NAME = "CurrentScore";
|
||||
var HIGH_SCORE_BILLBOARD_NAME = "HighScore";
|
||||
|
||||
var distanceBillboardEntityID = null;
|
||||
var highScoreBillboardEntityID = null;
|
||||
|
||||
function getDistanceBillboardEntityID() {
|
||||
if (distanceBillboardEntityID === null) {
|
||||
distanceBillboardEntityID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000);
|
||||
}
|
||||
return distanceBillboardEntityID;
|
||||
}
|
||||
function getHighScoreBillboardEntityID() {
|
||||
if (highScoreBillboardEntityID === null) {
|
||||
highScoreBillboardEntityID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000);
|
||||
}
|
||||
return highScoreBillboardEntityID;
|
||||
}
|
||||
|
||||
var METERS_TO_FEET = 3.28084;
|
||||
|
||||
var AUDIO = {
|
||||
crowdBoos: [
|
||||
SoundCache.getSound("atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav", false)
|
||||
],
|
||||
crowdCheers: [
|
||||
SoundCache.getSound("atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav", false),
|
||||
SoundCache.getSound("atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav", false),
|
||||
],
|
||||
batHit: [
|
||||
SoundCache.getSound("atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav", false),
|
||||
SoundCache.getSound("atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav", false),
|
||||
SoundCache.getSound("atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav", false),
|
||||
SoundCache.getSound("atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav", false),
|
||||
SoundCache.getSound("atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav", false),
|
||||
],
|
||||
strike: [
|
||||
SoundCache.getSound("atp:2a258076a85fffde4ba04b5ddc1de9034c7ae7d2af8c5d93d4fed0bcdef3472a.wav", false),
|
||||
SoundCache.getSound("atp:518363524af3ed9b9ae4ca2ceee61f01aecd37e266a51c5a5f5487efe2520fd5.wav", false),
|
||||
SoundCache.getSound("atp:d51d38b089574acbdfdf53ef733bfb3ab41d848fb8c0b6659c7790a785240009.wav", false),
|
||||
],
|
||||
foul: [
|
||||
SoundCache.getSound("atp:316fa18ff9eef457f670452b449a8dc5a41ccabd4e948781c50aaafaae63b0ab.wav", false),
|
||||
SoundCache.getSound("atp:c84d88352d38437edd7414b26dc74e567618712caeb59fec70822398b0c5a279.wav", false),
|
||||
]
|
||||
}
|
||||
|
||||
var PITCH_THUNK_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/ping_pong_gun/pong_sound.wav";
|
||||
var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false);
|
||||
updateBillboard("");
|
||||
|
||||
var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx";
|
||||
// This defines an offset to pitch a ball from with respect to the machine's position. The offset is a
|
||||
// percentage of the machine's dimensions. So, { x: 0.5, y: -1.0, z: 0.0 } would offset on 50% on the
|
||||
// machine's x axis, -100% on the y axis, and 0% on the z-axis. For the dimensions { x: 100, y: 100, z: 100 },
|
||||
// that would result in an offset of { x: 50, y: -100, z: 0 }. This makes it easy to calculate an offset if
|
||||
// the machine's dimensions change.
|
||||
var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = {
|
||||
x: 0.0,
|
||||
y: 0.25,
|
||||
z: -1.05,
|
||||
};
|
||||
var PITCHING_MACHINE_PROPERTIES = {
|
||||
name: "Pitching Machine",
|
||||
type: "Model",
|
||||
position: {
|
||||
x: -0.93,
|
||||
y: 0.8,
|
||||
z: -19.8
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
z: 0
|
||||
},
|
||||
gravity: {
|
||||
x: 0.0,
|
||||
y: -9.8,
|
||||
z: 0.0
|
||||
},
|
||||
registrationPoint: {
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
z: 0.5
|
||||
},
|
||||
rotation: Quat.fromPitchYawRollDegrees(0, 180, 0),
|
||||
modelURL: PITCHING_MACHINE_URL,
|
||||
dimensions: {
|
||||
x: 0.4,
|
||||
y: 0.61,
|
||||
z: 0.39
|
||||
},
|
||||
collisionsWillMove: false,
|
||||
shapeType: "Box"
|
||||
};
|
||||
PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions);
|
||||
var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z;
|
||||
|
||||
var PITCH_RATE = 5000;
|
||||
|
||||
getOrCreatePitchingMachine = function() {
|
||||
// Search for pitching machine
|
||||
var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000);
|
||||
var pitchingMachineID = null;
|
||||
|
||||
// Create if it doesn't exist
|
||||
if (entities.length == 0) {
|
||||
pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES);
|
||||
} else {
|
||||
pitchingMachineID = entities[0];
|
||||
}
|
||||
|
||||
// Wrap with PitchingMachine object and return
|
||||
return new PitchingMachine(pitchingMachineID);
|
||||
}
|
||||
|
||||
// The pitching machine wraps an entity ID and uses it's position & rotation to determin where to
|
||||
// pitch the ball from and in which direction, and uses the dimensions to determine the scale of them ball.
|
||||
function PitchingMachine(pitchingMachineID) {
|
||||
this.pitchingMachineID = pitchingMachineID;
|
||||
this.enabled = false;
|
||||
this.baseball = null;
|
||||
this.injector = null;
|
||||
}
|
||||
|
||||
PitchingMachine.prototype = {
|
||||
pitchBall: function() {
|
||||
cleanupTrail();
|
||||
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
print("Pitching ball");
|
||||
var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]);
|
||||
var pitchFromPositionBase = machineProperties.position;
|
||||
var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT);
|
||||
pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset);
|
||||
var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset);
|
||||
var pitchDirection = Quat.getFront(machineProperties.rotation);
|
||||
var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x;
|
||||
|
||||
var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED);
|
||||
var velocity = Vec3.multiply(speed, pitchDirection);
|
||||
|
||||
this.baseball = new Baseball(pitchFromPosition, velocity, ballScale);
|
||||
|
||||
if (!this.injector) {
|
||||
this.injector = Audio.playSound(pitchSound, {
|
||||
position: pitchFromPosition,
|
||||
volume: 1.0
|
||||
});
|
||||
} else {
|
||||
this.injector.restart();
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
if (this.enabled) {
|
||||
return;
|
||||
}
|
||||
print("Starting Pitching Machine");
|
||||
this.enabled = true;
|
||||
this.pitchBall();
|
||||
},
|
||||
stop: function() {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
print("Stopping Pitching Machine");
|
||||
this.enabled = false;
|
||||
},
|
||||
update: function(dt) {
|
||||
if (this.baseball) {
|
||||
this.baseball.update(dt);
|
||||
if (this.baseball.finished()) {
|
||||
this.baseball = null;
|
||||
var self = this;
|
||||
Script.setTimeout(function() { self.pitchBall(); }, 3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx";
|
||||
var BASEBALL_MIN_SPEED = 7.0;
|
||||
var BASEBALL_MAX_SPEED = 15.0;
|
||||
var BASEBALL_RADIUS = 0.07468;
|
||||
var BASEBALL_PROPERTIES = {
|
||||
name: "Baseball",
|
||||
type: "Model",
|
||||
modelURL: BASEBALL_MODEL_URL,
|
||||
shapeType: "Sphere",
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
dimensions: {
|
||||
x: BASEBALL_RADIUS,
|
||||
y: BASEBALL_RADIUS,
|
||||
z: BASEBALL_RADIUS
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
angularVelocity: {
|
||||
x: 17.0,
|
||||
y: 0,
|
||||
z: -8.0,
|
||||
|
||||
x: 0.0,
|
||||
y: 0,
|
||||
z: 0.0,
|
||||
},
|
||||
angularDamping: 0.0,
|
||||
damping: 0.0,
|
||||
restitution: 0.5,
|
||||
friction: 0.0,
|
||||
friction: 0.5,
|
||||
lifetime: 20,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}
|
||||
};
|
||||
var BASEBALL_STATE = {
|
||||
PITCHING: 0,
|
||||
HIT: 1,
|
||||
HIT_LANDED: 2,
|
||||
STRIKE: 3,
|
||||
FOUL: 4
|
||||
};
|
||||
|
||||
|
||||
|
||||
function vec3Mult(a, b) {
|
||||
return {
|
||||
x: a.x * b.x,
|
||||
y: a.y * b.y,
|
||||
z: a.z * b.z,
|
||||
};
|
||||
}
|
||||
|
||||
function map(value, min1, max1, min2, max2) {
|
||||
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
|
||||
}
|
||||
|
||||
function orientationOf(vector) {
|
||||
var RAD_TO_DEG = 180.0 / Math.PI;
|
||||
var Y_AXIS = { x: 0, y: 1, z: 0 };
|
||||
var X_AXIS = { x: 1, y: 0, z: 0 };
|
||||
var direction = Vec3.normalize(vector);
|
||||
|
||||
var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS);
|
||||
var pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS);
|
||||
|
||||
return Quat.multiply(yaw, pitch);
|
||||
}
|
||||
|
||||
var ACCELERATION_SPREAD = 0.35;
|
||||
|
||||
var TRAIL_COLOR = { red: 128, green: 255, blue: 89 };
|
||||
var TRAIL_LIFETIME = 20;
|
||||
|
||||
var trail = null;
|
||||
var trailInterval = null;
|
||||
function cleanupTrail() {
|
||||
if (trail) {
|
||||
Script.clearInterval(this.trailInterval);
|
||||
trailInterval = null;
|
||||
|
||||
trail.destroy();
|
||||
trail = null;
|
||||
}
|
||||
}
|
||||
|
||||
function setupTrail(entityID, position) {
|
||||
cleanupTrail();
|
||||
|
||||
var lastPosition = position;
|
||||
trail = new InfiniteLine(position, { red: 128, green: 255, blue: 89 }, 20);
|
||||
trailInterval = Script.setInterval(function() {
|
||||
var properties = Entities.getEntityProperties(entityID, ['position']);
|
||||
if (Vec3.distance(properties.position, lastPosition)) {
|
||||
var strokeWidth = Math.log(1 + trail.size) * 0.05;
|
||||
trail.enqueuePoint(properties.position, strokeWidth);
|
||||
lastPosition = properties.position;
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function Baseball(position, velocity, ballScale) {
|
||||
var self = this;
|
||||
|
||||
this.state = BASEBALL_STATE.PITCHING;
|
||||
|
||||
// Setup entity properties
|
||||
var properties = shallowCopy(BASEBALL_PROPERTIES);
|
||||
properties.position = position;
|
||||
properties.velocity = velocity;
|
||||
properties.dimensions = Vec3.multiply(ballScale, properties.dimensions);
|
||||
/*
|
||||
properties.gravity = {
|
||||
x: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD),
|
||||
y: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD),
|
||||
z: 0.0,
|
||||
};
|
||||
*/
|
||||
|
||||
// Create entity
|
||||
this.entityID = Entities.addEntity(properties);
|
||||
|
||||
this.timeSincePitched = 0;
|
||||
this.timeSinceHit = 0;
|
||||
this.hitBallAtPosition = null;
|
||||
this.distanceTravelled = 0;
|
||||
this.wasHighScore = false;
|
||||
this.landed = false;
|
||||
|
||||
// Listen for collision for the lifetime of the entity
|
||||
Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) {
|
||||
self.collisionCallback(entityA, entityB, collision);
|
||||
});
|
||||
if (Math.random() < 0.5) {
|
||||
for (var i = 0; i < 50; i++) {
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(entityID, {
|
||||
gravity: {
|
||||
x: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD),
|
||||
y: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD),
|
||||
z: 0.0,
|
||||
}
|
||||
})
|
||||
}, i * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the stadium billboard with the current distance or a text message and update the high score
|
||||
// if it has been beaten.
|
||||
function updateBillboard(distanceOrMessage) {
|
||||
var distanceBillboardEntityID = getDistanceBillboardEntityID();
|
||||
if (distanceBillboardEntityID) {
|
||||
Entities.editEntity(distanceBillboardEntityID, {
|
||||
text: distanceOrMessage
|
||||
});
|
||||
}
|
||||
|
||||
var highScoreBillboardEntityID = getHighScoreBillboardEntityID();
|
||||
// If a number was passed in, let's see if it is larger than the current high score
|
||||
// and update it if so.
|
||||
if (!isNaN(distanceOrMessage) && highScoreBillboardEntityID) {
|
||||
var properties = Entities.getEntityProperties(highScoreBillboardEntityID, ["text"]);
|
||||
var bestDistance = parseInt(properties.text);
|
||||
if (distanceOrMessage >= bestDistance) {
|
||||
Entities.editEntity(highScoreBillboardEntityID, {
|
||||
text: distanceOrMessage,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var FIREWORKS_SHOW_POSITION = { x: 0, y: 0, z: -78.0 };
|
||||
var FIREWORK_PER_X_FEET = 100;
|
||||
var MAX_FIREWORKS = 10;
|
||||
|
||||
Baseball.prototype = {
|
||||
finished: function() {
|
||||
return this.state == BASEBALL_STATE.FOUL
|
||||
|| this.state == BASEBALL_STATE.STRIKE
|
||||
|| this.state == BASEBALL_STATE.HIT_LANDED;
|
||||
},
|
||||
update: function(dt) {
|
||||
this.timeSincePitched += dt;
|
||||
if (this.state == BASEBALL_STATE.HIT) {
|
||||
this.timeSinceHit += dt;
|
||||
var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']);
|
||||
var speed = Vec3.length(myProperties.velocity);
|
||||
this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position) * METERS_TO_FEET;
|
||||
var wasHighScore = updateBillboard(Math.ceil(this.distanceTravelled));
|
||||
if (this.landed || this.timeSinceHit > 10 || speed < 1) {
|
||||
this.wasHighScore = wasHighScore;
|
||||
this.ballLanded();
|
||||
}
|
||||
} else if (this.state == BASEBALL_STATE.PITCHING) {
|
||||
if (this.timeSincePitched > 10) {
|
||||
print("TIMED OUT WHILE PITCHING");
|
||||
this.state = BASEBALL_STATE.STRIKE;
|
||||
}
|
||||
}
|
||||
},
|
||||
ballLanded: function() {
|
||||
this.state = BASEBALL_STATE.HIT_LANDED;
|
||||
var numberOfFireworks = Math.floor(this.distanceTravelled / FIREWORK_PER_X_FEET);
|
||||
if (numberOfFireworks > 0) {
|
||||
numberOfFireworks = Math.min(MAX_FIREWORKS, numberOfFireworks);
|
||||
playFireworkShow(FIREWORKS_SHOW_POSITION, numberOfFireworks, 2000);
|
||||
}
|
||||
print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land");
|
||||
print("Ball travelled " + this.distanceTravelled + " feet")
|
||||
},
|
||||
collisionCallback: function(entityA, entityB, collision) {
|
||||
var self = this;
|
||||
var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']);
|
||||
var myPosition = myProperties.position;
|
||||
var myVelocity = myProperties.velocity;
|
||||
|
||||
// Activate gravity
|
||||
Entities.editEntity(self.entityID, {
|
||||
gravity: { x: 0, y: -9.8, z: 0 }
|
||||
});
|
||||
|
||||
var name = Entities.getEntityProperties(entityB, ["name"]).name;
|
||||
if (name == "Bat") {
|
||||
if (this.state == BASEBALL_STATE.PITCHING) {
|
||||
print("HIT");
|
||||
|
||||
var FOUL_MIN_YAW = -135.0;
|
||||
var FOUL_MAX_YAW = 135.0;
|
||||
|
||||
var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI;
|
||||
var foul = yaw > FOUL_MIN_YAW && yaw < FOUL_MAX_YAW;
|
||||
|
||||
var speedMultiplier = 2;
|
||||
|
||||
if (foul && myVelocity.z > 0) {
|
||||
var TUNNELED_PITCH_RANGE = 15.0;
|
||||
var xzDist = Math.sqrt(myVelocity.x * myVelocity.x + myVelocity.z * myVelocity.z);
|
||||
var pitch = Math.atan2(myVelocity.y, xzDist) * 180 / Math.PI;
|
||||
print("Pitch: ", pitch);
|
||||
// If the pitch is going straight out the back and has a pitch in the range TUNNELED_PITCH_RANGE,
|
||||
// let's assume the ball tunneled through the bat and reverse its direction.
|
||||
if (Math.abs(pitch) < TUNNELED_PITCH_RANGE) {
|
||||
print("Reversing hit");
|
||||
myVelocity.x *= -1;
|
||||
myVelocity.y *= -1;
|
||||
myVelocity.z *= -1;
|
||||
|
||||
yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI;
|
||||
foul = yaw > FOUL_MIN_YAW && yaw < FOUL_MAX_YAW;
|
||||
|
||||
speedMultiplier = 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Update ball velocity
|
||||
Entities.editEntity(self.entityID, {
|
||||
velocity: Vec3.multiply(speedMultiplier, myVelocity)
|
||||
});
|
||||
|
||||
// Setup line update interval
|
||||
setupTrail(self.entityID, myPosition);
|
||||
|
||||
// Setup bat hit sound
|
||||
playRandomSound(AUDIO.batHit, {
|
||||
position: myPosition,
|
||||
volume: 2.0
|
||||
});
|
||||
|
||||
// Setup crowd reaction sound
|
||||
var speed = Vec3.length(myVelocity);
|
||||
Script.setTimeout(function() {
|
||||
playRandomSound((speed < 5.0) ? AUDIO.crowdBoos : AUDIO.crowdCheers, {
|
||||
position: { x: 0 ,y: 0, z: 0 },
|
||||
volume: 1.0
|
||||
});
|
||||
}, 500);
|
||||
|
||||
if (foul) {
|
||||
print("FOUL, yaw: ", yaw);
|
||||
updateBillboard("FOUL");
|
||||
this.state = BASEBALL_STATE.FOUL;
|
||||
playRandomSound(AUDIO.foul, {
|
||||
position: myPosition,
|
||||
volume: 2.0
|
||||
});
|
||||
} else {
|
||||
print("HIT ", yaw);
|
||||
this.state = BASEBALL_STATE.HIT;
|
||||
}
|
||||
}
|
||||
} else if (name == "stadium") {
|
||||
//entityCollisionWithGround(entityB, this.entityID, collision);
|
||||
this.landed = true;
|
||||
} else if (name == "backstop") {
|
||||
if (this.state == BASEBALL_STATE.PITCHING) {
|
||||
print("STRIKE");
|
||||
this.state = BASEBALL_STATE.STRIKE;
|
||||
updateBillboard("STRIKE");
|
||||
playRandomSound(AUDIO.strike, {
|
||||
position: myPosition,
|
||||
volume: 2.0
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function entityCollisionWithGround(ground, entity, collision) {
|
||||
var ZERO_VEC = { x: 0, y: 0, z: 0 };
|
||||
var dVelocityMagnitude = Vec3.length(collision.velocityChange);
|
||||
var position = Entities.getEntityProperties(entity, "position").position;
|
||||
var particleRadius = 0.3;
|
||||
var speed = map(dVelocityMagnitude, 0.05, 3, 0.02, 0.09);
|
||||
var displayTime = 400;
|
||||
var orientationChange = orientationOf(collision.velocityChange);
|
||||
|
||||
var dustEffect = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
name: "Dust-Puff",
|
||||
position: position,
|
||||
color: {red: 195, green: 170, blue: 185},
|
||||
lifespan: 3,
|
||||
lifetime: 2,//displayTime/1000 * 2, //So we can fade particle system out gracefully
|
||||
emitRate: 5,
|
||||
emitSpeed: speed,
|
||||
emitAcceleration: ZERO_VEC,
|
||||
accelerationSpread: ZERO_VEC,
|
||||
isEmitting: true,
|
||||
polarStart: Math.PI/2,
|
||||
polarFinish: Math.PI/2,
|
||||
emitOrientation: orientationChange,
|
||||
radiusSpread: 0.1,
|
||||
radiusStart: particleRadius,
|
||||
radiusFinish: particleRadius + particleRadius / 2,
|
||||
particleRadius: particleRadius,
|
||||
alpha: 0.45,
|
||||
alphaFinish: 0.001,
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Playa/Particles/Particle-Sprite-Gen.png"
|
||||
});
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
cleanupTrail();
|
||||
Entities.deleteEntity(pitchingMachineID);
|
||||
});
|
92
examples/baseball/utils.js
Normal file
92
examples/baseball/utils.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// utils.js
|
||||
// examples/baseball/
|
||||
//
|
||||
// Created by Ryan Huffman on Nov 9, 2015
|
||||
// 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
|
||||
//
|
||||
|
||||
randomInt = function(low, high) {
|
||||
return Math.floor(randomFloat(low, high));
|
||||
};
|
||||
|
||||
randomFloat = function(low, high) {
|
||||
if (high === undefined) {
|
||||
high = low;
|
||||
low = 0;
|
||||
}
|
||||
return low + Math.random() * (high - low);
|
||||
};
|
||||
|
||||
randomColor = function(redMin, redMax, greenMin, greenMax, blueMin, blueMax) {
|
||||
return {
|
||||
red: Math.ceil(randomFloat(redMin, redMax)),
|
||||
green: Math.ceil(randomFloat(greenMin, greenMax)),
|
||||
blue: Math.ceil(randomFloat(blueMin, blueMax)),
|
||||
}
|
||||
};
|
||||
|
||||
randomVec3 = function(xMin, xMax, yMin, yMax, zMin, zMax) {
|
||||
return {
|
||||
x: randomFloat(xMin, xMax),
|
||||
y: randomFloat(yMin, yMax),
|
||||
z: randomFloat(zMin, zMax),
|
||||
}
|
||||
};
|
||||
|
||||
getSounds = function(soundURLs) {
|
||||
var sounds = [];
|
||||
for (var i = 0; i < soundURLs.length; ++i) {
|
||||
sounds.push(SoundCache.getSound(soundURLs[i], false));
|
||||
}
|
||||
return sounds;
|
||||
};
|
||||
|
||||
playRandomSound = function(sounds, options) {
|
||||
if (options === undefined) {
|
||||
options = {
|
||||
volume: 1.0,
|
||||
position: MyAvatar.position,
|
||||
}
|
||||
}
|
||||
return Audio.playSound(sounds[randomInt(sounds.length)], options);
|
||||
}
|
||||
|
||||
shallowCopy = function(obj) {
|
||||
var copy = {}
|
||||
for (var key in obj) {
|
||||
copy[key] = obj[key];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
findEntity = function(properties, searchRadius) {
|
||||
var entities = findEntities(properties, searchRadius);
|
||||
return entities.length > 0 ? entities[0] : null;
|
||||
}
|
||||
|
||||
// Return all entities with properties `properties` within radius `searchRadius`
|
||||
findEntities = function(properties, searchRadius) {
|
||||
var entities = Entities.findEntities(MyAvatar.position, searchRadius);
|
||||
var matchedEntities = [];
|
||||
var keys = Object.keys(properties);
|
||||
for (var i = 0; i < entities.length; ++i) {
|
||||
var match = true;
|
||||
var candidateProperties = Entities.getEntityProperties(entities[i], keys);
|
||||
for (var key in properties) {
|
||||
if (candidateProperties[key] != properties[key]) {
|
||||
// This isn't a match, move to next entity
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
matchedEntities.push(entities[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return matchedEntities;
|
||||
}
|
|
@ -201,6 +201,33 @@ function entityIsGrabbedByOther(entityID) {
|
|||
return false;
|
||||
}
|
||||
|
||||
function getSpatialOffsetPosition(hand, spatialKey) {
|
||||
if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) {
|
||||
return spatialKey.leftRelativePosition;
|
||||
}
|
||||
if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) {
|
||||
return spatialKey.rightRelativePosition;
|
||||
}
|
||||
if (spatialKey.relativePosition) {
|
||||
return spatialKey.relativePosition;
|
||||
}
|
||||
|
||||
return Vec3.ZERO;
|
||||
}
|
||||
|
||||
function getSpatialOffsetRotation(hand, spatialKey) {
|
||||
if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) {
|
||||
return spatialKey.leftRelativeRotation;
|
||||
}
|
||||
if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) {
|
||||
return spatialKey.rightRelativeRotation;
|
||||
}
|
||||
if (spatialKey.relativeRotation) {
|
||||
return spatialKey.relativeRotation;
|
||||
}
|
||||
|
||||
return Quat.IDENTITY;
|
||||
}
|
||||
|
||||
function MyController(hand) {
|
||||
this.hand = hand;
|
||||
|
@ -224,20 +251,11 @@ function MyController(hand) {
|
|||
this.triggerValue = 0; // rolling average of trigger value
|
||||
this.rawTriggerValue = 0;
|
||||
this.rawBumperValue = 0;
|
||||
|
||||
|
||||
this.overlayLine = null;
|
||||
|
||||
this.offsetPosition = {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0
|
||||
};
|
||||
this.offsetRotation = {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
w: 1.0
|
||||
};
|
||||
|
||||
this.offsetPosition = Vec3.ZERO;
|
||||
this.offsetRotation = Quat.IDENTITY;
|
||||
|
||||
var _this = this;
|
||||
|
||||
|
@ -835,12 +853,8 @@ function MyController(hand) {
|
|||
|
||||
if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) {
|
||||
// if an object is "equipped" and has a spatialKey, use it.
|
||||
if (grabbableData.spatialKey.relativePosition) {
|
||||
this.offsetPosition = grabbableData.spatialKey.relativePosition;
|
||||
}
|
||||
if (grabbableData.spatialKey.relativeRotation) {
|
||||
this.offsetRotation = grabbableData.spatialKey.relativeRotation;
|
||||
}
|
||||
this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
|
||||
this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey);
|
||||
} else {
|
||||
var objectRotation = grabbedProperties.rotation;
|
||||
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
||||
|
@ -966,23 +980,8 @@ function MyController(hand) {
|
|||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
|
||||
// use a spring to pull the object to where it will be when equipped
|
||||
var relativeRotation = {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
w: 1.0
|
||||
};
|
||||
var relativePosition = {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0
|
||||
};
|
||||
if (grabbableData.spatialKey.relativePosition) {
|
||||
relativePosition = grabbableData.spatialKey.relativePosition;
|
||||
}
|
||||
if (grabbableData.spatialKey.relativeRotation) {
|
||||
relativeRotation = grabbableData.spatialKey.relativeRotation;
|
||||
}
|
||||
var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey);
|
||||
var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
|
||||
var handRotation = this.getHandRotation();
|
||||
var handPosition = this.getHandPosition();
|
||||
var targetRotation = Quat.multiply(handRotation, relativeRotation);
|
||||
|
|
|
@ -20,6 +20,9 @@ var leapHands = (function () {
|
|||
hasHandAndWristJoints,
|
||||
handToWristOffset = [], // For avatars without a wrist joint we control an estimate of a proper hand joint position
|
||||
HAND_OFFSET = 0.4, // Relative distance of wrist to hand versus wrist to index finger knuckle
|
||||
handAnimationStateHandlers,
|
||||
handAnimationStateFunctions,
|
||||
handAnimationStateProperties,
|
||||
hands,
|
||||
wrists,
|
||||
NUM_HANDS = 2, // 0 = left; 1 = right
|
||||
|
@ -37,7 +40,14 @@ var leapHands = (function () {
|
|||
avatarScale,
|
||||
avatarFaceModelURL,
|
||||
avatarSkeletonModelURL,
|
||||
settingsTimer;
|
||||
settingsTimer,
|
||||
HMD_CAMERA_TO_AVATAR_ROTATION = [
|
||||
Quat.angleAxis(180.0, { x: 0, y: 0, z: 1 }),
|
||||
Quat.angleAxis(-180.0, { x: 0, y: 0, z: 1 })
|
||||
],
|
||||
DESKTOP_CAMERA_TO_AVATAR_ROTATION =
|
||||
Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 })),
|
||||
LEAP_THUMB_ROOT_ADJUST = [Quat.fromPitchYawRollDegrees(0, 0, 20), Quat.fromPitchYawRollDegrees(0, 0, -20)];
|
||||
|
||||
function printSkeletonJointNames() {
|
||||
var jointNames,
|
||||
|
@ -125,6 +135,26 @@ var leapHands = (function () {
|
|||
*/
|
||||
}
|
||||
|
||||
function animateLeftHand() {
|
||||
var ROTATION_AND_POSITION = 0;
|
||||
|
||||
return {
|
||||
leftHandType: ROTATION_AND_POSITION,
|
||||
leftHandPosition: hands[0].position,
|
||||
leftHandRotation: hands[0].rotation
|
||||
};
|
||||
}
|
||||
|
||||
function animateRightHand() {
|
||||
var ROTATION_AND_POSITION = 0;
|
||||
|
||||
return {
|
||||
rightHandType: ROTATION_AND_POSITION,
|
||||
rightHandPosition: hands[1].position,
|
||||
rightHandRotation: hands[1].rotation
|
||||
};
|
||||
}
|
||||
|
||||
function finishCalibration() {
|
||||
var avatarPosition,
|
||||
handPosition,
|
||||
|
@ -166,10 +196,8 @@ var leapHands = (function () {
|
|||
|
||||
MyAvatar.clearJointData("LeftHand");
|
||||
MyAvatar.clearJointData("LeftForeArm");
|
||||
MyAvatar.clearJointData("LeftArm");
|
||||
MyAvatar.clearJointData("RightHand");
|
||||
MyAvatar.clearJointData("RightForeArm");
|
||||
MyAvatar.clearJointData("RightArm");
|
||||
|
||||
calibrationStatus = CALIBRATED;
|
||||
print("Leap Motion: Calibrated");
|
||||
|
@ -193,12 +221,10 @@ var leapHands = (function () {
|
|||
}
|
||||
|
||||
// Set avatar arms vertical, forearms horizontal, as "zero" position for calibration
|
||||
MyAvatar.setJointRotation("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0));
|
||||
MyAvatar.setJointRotation("LeftForeArm", Quat.fromPitchYawRollDegrees(0.0, 90.0, 90.0));
|
||||
MyAvatar.setJointRotation("LeftHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
|
||||
MyAvatar.setJointRotation("RightArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0));
|
||||
MyAvatar.setJointRotation("RightForeArm", Quat.fromPitchYawRollDegrees(0.0, -90.0, -90.0));
|
||||
MyAvatar.setJointRotation("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
|
||||
MyAvatar.setJointRotation("LeftForeArm", Quat.fromPitchYawRollDegrees(0.0, 0.0, 90.0));
|
||||
MyAvatar.setJointRotation("LeftHand", Quat.fromPitchYawRollDegrees(0.0, 90.0, 0.0));
|
||||
MyAvatar.setJointRotation("RightForeArm", Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0));
|
||||
MyAvatar.setJointRotation("RightHand", Quat.fromPitchYawRollDegrees(0.0, -90.0, 0.0));
|
||||
|
||||
// Wait for arms to assume their positions before calculating
|
||||
Script.setTimeout(finishCalibration, CALIBRATION_TIME);
|
||||
|
@ -319,6 +345,13 @@ var leapHands = (function () {
|
|||
]
|
||||
];
|
||||
|
||||
handAnimationStateHandlers = [null, null];
|
||||
handAnimationStateFunctions = [animateLeftHand, animateRightHand];
|
||||
handAnimationStateProperties = [
|
||||
["leftHandType", "leftHandPosition", "leftHandRotation"],
|
||||
["rightHandType", "rightHandPosition", "rightHandPosition"]
|
||||
];
|
||||
|
||||
setIsOnHMD();
|
||||
|
||||
settingsTimer = Script.setInterval(checkSettings, 2000);
|
||||
|
@ -348,6 +381,12 @@ var leapHands = (function () {
|
|||
return;
|
||||
}
|
||||
|
||||
// Hand animation handlers ...
|
||||
if (handAnimationStateHandlers[h] === null) {
|
||||
handAnimationStateHandlers[h] = MyAvatar.addAnimationStateHandler(handAnimationStateFunctions[h],
|
||||
handAnimationStateProperties[h]);
|
||||
}
|
||||
|
||||
// Hand position ...
|
||||
handOffset = hands[h].controller.getAbsTranslation();
|
||||
handRotation = hands[h].controller.getAbsRotation();
|
||||
|
@ -362,37 +401,41 @@ var leapHands = (function () {
|
|||
|
||||
// Hand offset in camera coordinates ...
|
||||
handOffset = {
|
||||
x: hands[h].zeroPosition.x - handOffset.x,
|
||||
y: hands[h].zeroPosition.y - handOffset.z,
|
||||
z: hands[h].zeroPosition.z + handOffset.y
|
||||
x: -handOffset.x,
|
||||
y: -handOffset.z,
|
||||
z: -handOffset.y - hands[h].zeroPosition.z
|
||||
};
|
||||
handOffset.z = -handOffset.z;
|
||||
|
||||
// Hand offset in world coordinates ...
|
||||
cameraOrientation = Camera.getOrientation();
|
||||
handOffset = Vec3.sum(Camera.getPosition(), Vec3.multiplyQbyV(cameraOrientation, handOffset));
|
||||
|
||||
// Hand offset in avatar coordinates ...
|
||||
// Hand offset in avatar coordinates ...
|
||||
inverseAvatarOrientation = Quat.inverse(MyAvatar.orientation);
|
||||
handOffset = Vec3.subtract(handOffset, MyAvatar.position);
|
||||
handOffset = Vec3.multiplyQbyV(inverseAvatarOrientation, handOffset);
|
||||
handOffset.z = -handOffset.z;
|
||||
handOffset.x = -handOffset.x;
|
||||
|
||||
|
||||
// Hand rotation in camera coordinates ...
|
||||
handRotation = {
|
||||
x: -handRotation.x,
|
||||
x: -handRotation.y,
|
||||
y: -handRotation.z,
|
||||
z: -handRotation.y,
|
||||
z: -handRotation.x,
|
||||
w: handRotation.w
|
||||
};
|
||||
|
||||
// Hand rotation in avatar coordinates ...
|
||||
handRotation = Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), handRotation);
|
||||
cameraOrientation.x = -cameraOrientation.x;
|
||||
cameraOrientation.z = -cameraOrientation.z;
|
||||
handRotation = Quat.multiply(cameraOrientation, handRotation);
|
||||
handRotation = Quat.multiply(inverseAvatarOrientation, handRotation);
|
||||
handRotation = Quat.multiply(HMD_CAMERA_TO_AVATAR_ROTATION[h], handRotation);
|
||||
cameraOrientation = {
|
||||
x: cameraOrientation.z,
|
||||
y: cameraOrientation.y,
|
||||
z: cameraOrientation.x,
|
||||
w: cameraOrientation.w
|
||||
};
|
||||
cameraOrientation = Quat.multiply(cameraOrientation, Quat.inverse(MyAvatar.orientation));
|
||||
handRotation = Quat.multiply(handRotation, cameraOrientation); // Works!!!
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -411,18 +454,19 @@ var leapHands = (function () {
|
|||
|
||||
// Hand rotation in camera coordinates ...
|
||||
handRotation = {
|
||||
x: -handRotation.x,
|
||||
y: -handRotation.z,
|
||||
z: -handRotation.y,
|
||||
x: handRotation.z,
|
||||
y: handRotation.y,
|
||||
z: handRotation.x,
|
||||
w: handRotation.w
|
||||
};
|
||||
|
||||
// Hand rotation in avatar coordinates ...
|
||||
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
|
||||
handRotation = Quat.multiply(DESKTOP_CAMERA_TO_AVATAR_ROTATION, handRotation);
|
||||
}
|
||||
|
||||
// Set hand position and orientation ...
|
||||
MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true);
|
||||
// Set hand position and orientation for animation state handler ...
|
||||
hands[h].position = handOffset;
|
||||
hands[h].rotation = handRotation;
|
||||
|
||||
// Set finger joints ...
|
||||
for (i = 0; i < NUM_FINGERS; i += 1) {
|
||||
|
@ -436,6 +480,10 @@ var leapHands = (function () {
|
|||
z: side * -locRotation.x,
|
||||
w: locRotation.w
|
||||
};
|
||||
if (j === 0) {
|
||||
// Adjust avatar thumb root joint rotation to make avatar hands look better
|
||||
locRotation = Quat.multiply(LEAP_THUMB_ROOT_ADJUST[h], locRotation);
|
||||
}
|
||||
} else {
|
||||
locRotation = {
|
||||
x: -locRotation.x,
|
||||
|
@ -458,14 +506,9 @@ var leapHands = (function () {
|
|||
hands[h].inactiveCount += 1;
|
||||
|
||||
if (hands[h].inactiveCount === MAX_HAND_INACTIVE_COUNT) {
|
||||
if (h === 0) {
|
||||
MyAvatar.clearJointData("LeftHand");
|
||||
MyAvatar.clearJointData("LeftForeArm");
|
||||
MyAvatar.clearJointData("LeftArm");
|
||||
} else {
|
||||
MyAvatar.clearJointData("RightHand");
|
||||
MyAvatar.clearJointData("RightForeArm");
|
||||
MyAvatar.clearJointData("RightArm");
|
||||
if (handAnimationStateHandlers[h] !== null) {
|
||||
MyAvatar.removeAnimationStateHandler(handAnimationStateHandlers[h]);
|
||||
handAnimationStateHandlers[h] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -483,6 +526,9 @@ var leapHands = (function () {
|
|||
for (h = 0; h < NUM_HANDS; h += 1) {
|
||||
Controller.releaseInputController(hands[h].controller);
|
||||
Controller.releaseInputController(wrists[h].controller);
|
||||
if (handAnimationStateHandlers[h] !== null) {
|
||||
MyAvatar.removeAnimationStateHandler(handAnimationStateHandlers[h]);
|
||||
}
|
||||
for (i = 0; i < NUM_FINGERS; i += 1) {
|
||||
for (j = 0; j < NUM_FINGER_JOINTS; j += 1) {
|
||||
if (fingers[h][i][j].controller !== null) {
|
||||
|
|
|
@ -226,6 +226,7 @@
|
|||
var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button");
|
||||
|
||||
var elParentID = document.getElementById("property-parent-id");
|
||||
var elParentJointIndex = document.getElementById("property-parent-joint-index");
|
||||
|
||||
var elRegistrationX = document.getElementById("property-reg-x");
|
||||
var elRegistrationY = document.getElementById("property-reg-y");
|
||||
|
@ -456,6 +457,7 @@
|
|||
elDimensionsZ.value = properties.dimensions.z.toFixed(2);
|
||||
|
||||
elParentID.value = properties.parentID;
|
||||
elParentJointIndex.value = properties.parentJointIndex;
|
||||
|
||||
elRegistrationX.value = properties.registrationPoint.x.toFixed(2);
|
||||
elRegistrationY.value = properties.registrationPoint.y.toFixed(2);
|
||||
|
@ -671,6 +673,7 @@
|
|||
elDimensionsZ.addEventListener('change', dimensionsChangeFunction);
|
||||
|
||||
elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID'));
|
||||
elParentJointIndex.addEventListener('change', createEmitNumberPropertyUpdateFunction('parentJointIndex'));
|
||||
|
||||
var registrationChangeFunction = createEmitVec3PropertyUpdateFunction(
|
||||
'registrationPoint', elRegistrationX, elRegistrationY, elRegistrationZ);
|
||||
|
@ -1067,6 +1070,12 @@
|
|||
<input type="text" id="property-parent-id">
|
||||
</div>
|
||||
</div>
|
||||
<div class="property">
|
||||
<span class="label" style="float: left; margin-right: 6px">ParentJointIndex</span>
|
||||
<div class="value" style="overflow: hidden;">
|
||||
<input type="text" id="property-parent-joint-index">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="property">
|
||||
<div class="label">Registration</div>
|
||||
|
|
|
@ -67,12 +67,17 @@
|
|||
}
|
||||
|
||||
var BOW_SPATIAL_KEY = {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
leftRelativePosition: {
|
||||
x: 0.05,
|
||||
y: 0.06,
|
||||
z: 0.11
|
||||
z: -0.05
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90)
|
||||
rightRelativePosition: {
|
||||
x: -0.05,
|
||||
y: 0.06,
|
||||
z: -0.05
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,12 +48,17 @@ var bow = Entities.addEntity({
|
|||
grabbableKey: {
|
||||
invertSolidWhileHeld: true,
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
leftRelativePosition: {
|
||||
x: 0.05,
|
||||
y: 0.06,
|
||||
z: 0.11
|
||||
z: -0.05
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90)
|
||||
rightRelativePosition: {
|
||||
x: -0.05,
|
||||
y: 0.06,
|
||||
z: -0.05
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -12,31 +12,57 @@
|
|||
Script.include("cookies.js");
|
||||
|
||||
var audioOptions = new AudioEffectOptions({
|
||||
maxRoomSize: 50,
|
||||
bandwidth: 10000,
|
||||
preDelay: 20,
|
||||
lateDelay: 0,
|
||||
reverbTime: 2,
|
||||
earlyDiffusion: 100,
|
||||
lateDiffusion: 100,
|
||||
roomSize: 50,
|
||||
reverbTime: 4,
|
||||
damping: 0.50,
|
||||
inputBandwidth: 0.8,
|
||||
earlyLevel: 0,
|
||||
tailLevel: 0,
|
||||
dryLevel: -6,
|
||||
wetLevel: -6
|
||||
density: 100,
|
||||
bassMult: 1.5,
|
||||
bassFreq: 250,
|
||||
highGain: -6,
|
||||
highFreq: 3000,
|
||||
modRate: 2.3,
|
||||
modDepth: 50,
|
||||
earlyGain: 0,
|
||||
lateGain: 0,
|
||||
earlyMixLeft: 20,
|
||||
earlyMixRight: 20,
|
||||
lateMixLeft: 90,
|
||||
lateMixRight: 90,
|
||||
wetDryMix: 50,
|
||||
});
|
||||
|
||||
AudioDevice.setReverbOptions(audioOptions);
|
||||
AudioDevice.setReverb(true);
|
||||
print("Reverb is ON.");
|
||||
|
||||
var panel = new Panel(10, 200);
|
||||
var panel = new Panel(10, 160);
|
||||
|
||||
var parameters = [
|
||||
{ name: "roomSize", min: 0, max: 100, units: " feet" },
|
||||
{ name: "reverbTime", min: 0, max: 10, units: " sec" },
|
||||
{ name: "damping", min: 0, max: 1, units: " " },
|
||||
{ name: "inputBandwidth", min: 0, max: 1, units: " " },
|
||||
{ name: "earlyLevel", min: -48, max: 0, units: " dB" },
|
||||
{ name: "tailLevel", min: -48, max: 0, units: " dB" },
|
||||
{ name: "wetLevel", min: -48, max: 0, units: " dB" },
|
||||
{ name: "bandwidth", min: 1000, max: 12000, units: " Hz" },
|
||||
{ name: "preDelay", min: 0, max: 333, units: " ms" },
|
||||
{ name: "lateDelay", min: 0, max: 166, units: " ms" },
|
||||
{ name: "reverbTime", min: 0.1, max: 10, units: " seconds" },
|
||||
{ name: "earlyDiffusion", min: 0, max: 100, units: " percent" },
|
||||
{ name: "lateDiffusion", min: 0, max: 100, units: " percent" },
|
||||
{ name: "roomSize", min: 0, max: 100, units: " percent" },
|
||||
{ name: "density", min: 0, max: 100, units: " percent" },
|
||||
{ name: "bassMult", min: 0.1, max: 4, units: " ratio" },
|
||||
{ name: "bassFreq", min: 10, max: 500, units: " Hz" },
|
||||
{ name: "highGain", min: -24, max: 0, units: " dB" },
|
||||
{ name: "highFreq", min: 1000, max: 12000, units: " Hz" },
|
||||
{ name: "modRate", min: 0.1, max: 10, units: " Hz" },
|
||||
{ name: "modDepth", min: 0, max: 100, units: " percent" },
|
||||
{ name: "earlyGain", min: -96, max: 24, units: " dB" },
|
||||
{ name: "lateGain", min: -96, max: 24, units: " dB" },
|
||||
{ name: "earlyMixLeft", min: 0, max: 100, units: " percent" },
|
||||
{ name: "earlyMixRight", min: 0, max: 100, units: " percent" },
|
||||
{ name: "lateMixLeft", min: 0, max: 100, units: " percent" },
|
||||
{ name: "lateMixRight", min: 0, max: 100, units: " percent" },
|
||||
{ name: "wetDryMix", min: 0, max: 100, units: " percent" },
|
||||
]
|
||||
|
||||
function setter(name) {
|
||||
|
@ -48,7 +74,7 @@ function getter(name) {
|
|||
}
|
||||
|
||||
function displayer(units) {
|
||||
return function(value) { return (value).toFixed(1) + units; };
|
||||
return function(value) { return (value).toFixed(1) + units; }
|
||||
}
|
||||
|
||||
// create a slider for each parameter
|
||||
|
|
|
@ -194,7 +194,6 @@ else (APPLE)
|
|||
|
||||
# link target to external libraries
|
||||
if (WIN32)
|
||||
# target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib)
|
||||
target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib)
|
||||
else (WIN32)
|
||||
# Nothing else required on linux apparently
|
||||
|
@ -202,3 +201,4 @@ else (APPLE)
|
|||
endif (APPLE)
|
||||
|
||||
package_libraries_for_deployment()
|
||||
consolidate_stack_components()
|
||||
|
|
|
@ -1077,6 +1077,11 @@ void Application::initializeUi() {
|
|||
}
|
||||
|
||||
void Application::paintGL() {
|
||||
// paintGL uses a queued connection, so we can get messages from the queue even after we've quit
|
||||
// and the plugins have shutdown
|
||||
if (_aboutToQuit) {
|
||||
return;
|
||||
}
|
||||
_frameCount++;
|
||||
|
||||
// update fps moving average
|
||||
|
@ -1117,29 +1122,6 @@ void Application::paintGL() {
|
|||
_inPaint = true;
|
||||
Finally clearFlagLambda([this] { _inPaint = false; });
|
||||
|
||||
// Some LOD-like controls need to know a smoothly varying "potential" frame rate that doesn't
|
||||
// include time waiting for vsync, and which can report a number above target if we've got the headroom.
|
||||
// For example, if we're shooting for 75fps and paintWait is 3.3333ms (= 75% * 13.33ms), our deducedNonVSyncFps
|
||||
// would be 100fps. In principle, a paintWait of zero would have deducedNonVSyncFps=75.
|
||||
// Here we make a guess for deducedNonVSyncFps = 1 / deducedNonVSyncPeriod.
|
||||
//
|
||||
// Time between previous paintGL call and this one, which can vary not only with vSync misses, but also with QT timing.
|
||||
// We're using this as a proxy for the time between vsync and displayEnd, below. (Not exact, but tends to be the same over time.)
|
||||
// This is not the same as update(deltaTime), because the latter attempts to throttle to 60hz and also clamps to 1/4 second.
|
||||
const float actualPeriod = diff / (float)USECS_PER_SECOND; // same as 1/instantaneousFps but easier for compiler to optimize
|
||||
// Note that _lastPaintWait (stored at end of last call) is for the same paint cycle.
|
||||
float deducedNonVSyncPeriod = actualPeriod - _lastPaintWait + _marginForDeducedFramePeriod; // plus a some non-zero time for machinery we can't measure
|
||||
// We don't know how much time to allow for that, but if we went over the target period, we know it's at least the portion
|
||||
// of paintWait up to the next vSync. This gives us enough of a penalty so that when actualPeriod crosses two cycles,
|
||||
// the key part (and not an exagerated part) of _lastPaintWait is accounted for.
|
||||
const float targetPeriod = getTargetFramePeriod();
|
||||
if (_lastPaintWait > EPSILON && actualPeriod > targetPeriod) {
|
||||
// Don't use C++ remainder(). It's authors are mathematically insane.
|
||||
deducedNonVSyncPeriod += fmod(actualPeriod, _lastPaintWait);
|
||||
}
|
||||
_lastDeducedNonVSyncFps = 1.0f / deducedNonVSyncPeriod;
|
||||
_lastInstantaneousFps = instantaneousFps;
|
||||
|
||||
auto displayPlugin = getActiveDisplayPlugin();
|
||||
// FIXME not needed anymore?
|
||||
_offscreenContext->makeCurrent();
|
||||
|
@ -1396,7 +1378,6 @@ void Application::paintGL() {
|
|||
Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture));
|
||||
_lockedFramebufferMap[finalTexture] = scratchFramebuffer;
|
||||
|
||||
uint64_t displayStart = usecTimestampNow();
|
||||
Q_ASSERT(isCurrentContext(_offscreenContext->getContext()));
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene");
|
||||
|
@ -1405,9 +1386,6 @@ void Application::paintGL() {
|
|||
}
|
||||
Q_ASSERT(isCurrentContext(_offscreenContext->getContext()));
|
||||
|
||||
uint64_t displayEnd = usecTimestampNow();
|
||||
const float displayPeriodUsec = (float)(displayEnd - displayStart); // usecs
|
||||
_lastPaintWait = displayPeriodUsec / (float)USECS_PER_SECOND;
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1418,6 +1396,14 @@ void Application::paintGL() {
|
|||
batch.resetStages();
|
||||
});
|
||||
}
|
||||
|
||||
// Some LOD-like controls need to know a smoothly varying "potential" frame rate that doesn't
|
||||
// include time waiting for sync, and which can report a number above target if we've got the headroom.
|
||||
// In my tests, the following is mostly less than 0.5ms, and never more than 3ms. I don't think its worth measuring during runtime.
|
||||
static const float paintWaitAndQTTimerAllowance = 0.001; // seconds
|
||||
// Store both values now for use by next cycle.
|
||||
_lastInstantaneousFps = instantaneousFps;
|
||||
_lastUnsynchronizedFps = 1.0f / (((usecTimestampNow() - now) / (float)USECS_PER_SECOND) + paintWaitAndQTTimerAllowance);
|
||||
}
|
||||
|
||||
void Application::runTests() {
|
||||
|
@ -2414,6 +2400,9 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
|
|||
exportTree->addEntity(entityItem->getEntityItemID(), properties);
|
||||
}
|
||||
|
||||
// remap IDs on export so that we aren't publishing the IDs of entities in our domain
|
||||
exportTree->remapIDs();
|
||||
|
||||
exportTree->writeToJSONFile(filename.toLocal8Bit().constData());
|
||||
|
||||
// restore the main window's active state
|
||||
|
@ -2436,6 +2425,10 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa
|
|||
properties.setPosition(properties.getPosition() - root);
|
||||
exportTree->addEntity(id, properties);
|
||||
}
|
||||
|
||||
// remap IDs on export so that we aren't publishing the IDs of entities in our domain
|
||||
exportTree->remapIDs();
|
||||
|
||||
exportTree->writeToSVOFile(filename.toLocal8Bit().constData());
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "No models were selected";
|
||||
|
@ -2480,6 +2473,7 @@ bool Application::importEntities(const QString& urlOrFilename) {
|
|||
|
||||
bool success = _entityClipboard->readFromURL(url.toString());
|
||||
if (success) {
|
||||
_entityClipboard->remapIDs();
|
||||
_entityClipboard->reaverageOctreeElements();
|
||||
}
|
||||
return success;
|
||||
|
@ -3241,8 +3235,6 @@ bool Application::isHMDMode() const {
|
|||
return getActiveDisplayPlugin()->isHmd();
|
||||
}
|
||||
float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); }
|
||||
float Application::getTargetFramePeriod() { return getActiveDisplayPlugin()->getTargetFramePeriod(); }
|
||||
bool Application::isVSynchronized() const { return getActiveDisplayPlugin()->isVSynchronized(); }
|
||||
|
||||
QRect Application::getDesirableApplicationGeometry() {
|
||||
QRect applicationGeometry = getWindow()->geometry();
|
||||
|
@ -4074,7 +4066,7 @@ bool Application::canAcceptURL(const QString& urlString) {
|
|||
QString lowerPath = url.path().toLower();
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (lowerPath.endsWith(i.key())) {
|
||||
if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -4094,7 +4086,7 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
|
|||
QString lowerPath = url.path().toLower();
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (lowerPath.endsWith(i.key())) {
|
||||
if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) {
|
||||
AcceptURLMethod method = i.value();
|
||||
return (this->*method)(urlString);
|
||||
}
|
||||
|
@ -4194,7 +4186,7 @@ bool Application::askToUploadAsset(const QString& filename) {
|
|||
messageBox.setDefaultButton(QMessageBox::Ok);
|
||||
|
||||
// Option to drop model in world for models
|
||||
if (filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION)) {
|
||||
if (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive)) {
|
||||
auto checkBox = new QCheckBox(&messageBox);
|
||||
checkBox->setText("Add to scene");
|
||||
messageBox.setCheckBox(checkBox);
|
||||
|
@ -4229,7 +4221,8 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash)
|
|||
auto filename = QFileInfo(upload->getFilename()).fileName();
|
||||
|
||||
if ((upload->getError() == AssetUpload::NoError) &&
|
||||
(filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION))) {
|
||||
(upload->getExtension().endsWith(FBX_EXTENSION, Qt::CaseInsensitive) ||
|
||||
upload->getExtension().endsWith(OBJ_EXTENSION, Qt::CaseInsensitive))) {
|
||||
|
||||
auto entities = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
|
|
|
@ -124,7 +124,6 @@ public:
|
|||
PickRay computePickRay() const;
|
||||
|
||||
bool isThrottleRendering() const;
|
||||
bool isVSynchronized() const;
|
||||
|
||||
Camera* getCamera() { return &_myCamera; }
|
||||
// Represents the current view frustum of the avatar.
|
||||
|
@ -162,11 +161,8 @@ public:
|
|||
uint32_t getFrameCount() { return _frameCount; }
|
||||
float getFps() const { return _fps; }
|
||||
float getTargetFrameRate(); // frames/second
|
||||
float getTargetFramePeriod(); // seconds
|
||||
float getLastInstanteousFps() const { return _lastInstantaneousFps; }
|
||||
float getLastPaintWait() const { return _lastPaintWait; };
|
||||
float getLastDeducedNonVSyncFps() const { return _lastDeducedNonVSyncFps; }
|
||||
void setMarginForDeducedFramePeriod(float newValue) { _marginForDeducedFramePeriod = newValue; }
|
||||
float getLastUnsynchronizedFps() const { return _lastUnsynchronizedFps; }
|
||||
|
||||
float getFieldOfView() { return _fieldOfView.get(); }
|
||||
void setFieldOfView(float fov);
|
||||
|
@ -441,9 +437,7 @@ private:
|
|||
QElapsedTimer _timerStart;
|
||||
QElapsedTimer _lastTimeUpdated;
|
||||
float _lastInstantaneousFps { 0.0f };
|
||||
float _lastPaintWait { 0.0f };
|
||||
float _lastDeducedNonVSyncFps { 0.0f };
|
||||
float _marginForDeducedFramePeriod{ 0.002f }; // 2ms, adjustable
|
||||
float _lastUnsynchronizedFps { 0.0f };
|
||||
|
||||
ShapeManager _shapeManager;
|
||||
PhysicalEntitySimulation _entitySimulation;
|
||||
|
|
|
@ -21,17 +21,17 @@
|
|||
EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) {
|
||||
switch (type) {
|
||||
case ACTION_TYPE_NONE:
|
||||
return nullptr;
|
||||
return EntityActionPointer();
|
||||
case ACTION_TYPE_OFFSET:
|
||||
return (EntityActionPointer) new ObjectActionOffset(id, ownerEntity);
|
||||
return std::make_shared<ObjectActionOffset>(id, ownerEntity);
|
||||
case ACTION_TYPE_SPRING:
|
||||
return (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
|
||||
return std::make_shared<ObjectActionSpring>(id, ownerEntity);
|
||||
case ACTION_TYPE_HOLD:
|
||||
return (EntityActionPointer) new AvatarActionHold(id, ownerEntity);
|
||||
return std::make_shared<AvatarActionHold>(id, ownerEntity);
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return nullptr;
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity action type");
|
||||
return EntityActionPointer();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -201,6 +201,7 @@ void Avatar::simulate(float deltaTime) {
|
|||
_skeletonModel.getRig()->copyJointsFromJointData(_jointData);
|
||||
_skeletonModel.simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations);
|
||||
simulateAttachments(deltaTime);
|
||||
locationChanged(); // joints changed, so if there are any children, update them.
|
||||
_hasNewJointRotations = false;
|
||||
_hasNewJointTranslations = false;
|
||||
}
|
||||
|
@ -868,6 +869,17 @@ glm::vec3 Avatar::getJointTranslation(int index) const {
|
|||
return translation;
|
||||
}
|
||||
|
||||
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||
glm::quat rotation;
|
||||
_skeletonModel.getAbsoluteJointRotationInRigFrame(index, rotation);
|
||||
return Quaternions::Y_180 * rotation;
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||
glm::vec3 translation;
|
||||
_skeletonModel.getAbsoluteJointTranslationInRigFrame(index, translation);
|
||||
return Quaternions::Y_180 * translation;
|
||||
}
|
||||
|
||||
int Avatar::getJointIndex(const QString& name) const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
|
@ -1145,12 +1157,12 @@ glm::quat Avatar::getRightPalmRotation() {
|
|||
return rightRotation;
|
||||
}
|
||||
|
||||
void Avatar::setPosition(const glm::vec3 position) {
|
||||
void Avatar::setPosition(const glm::vec3& position) {
|
||||
AvatarData::setPosition(position);
|
||||
updateAttitude();
|
||||
}
|
||||
|
||||
void Avatar::setOrientation(const glm::quat orientation) {
|
||||
void Avatar::setOrientation(const glm::quat& orientation) {
|
||||
AvatarData::setOrientation(orientation);
|
||||
updateAttitude();
|
||||
}
|
||||
|
|
|
@ -108,6 +108,9 @@ public:
|
|||
virtual int getJointIndex(const QString& name) const;
|
||||
virtual QStringList getJointNames() const;
|
||||
|
||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
|
||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
|
||||
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
|
||||
|
@ -155,8 +158,8 @@ public:
|
|||
void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; }
|
||||
AvatarMotionState* getMotionState() { return _motionState; }
|
||||
|
||||
virtual void setPosition(glm::vec3 position);
|
||||
virtual void setOrientation(glm::quat orientation);
|
||||
virtual void setPosition(const glm::vec3& position) override;
|
||||
virtual void setOrientation(const glm::quat& orientation) override;
|
||||
|
||||
public slots:
|
||||
|
||||
|
|
|
@ -9,63 +9,72 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "QVariantGLM.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
|
||||
#include "AvatarActionHold.h"
|
||||
|
||||
#include <QVariantGLM.h>
|
||||
|
||||
#include "avatar/AvatarManager.h"
|
||||
|
||||
const uint16_t AvatarActionHold::holdVersion = 1;
|
||||
|
||||
AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity) :
|
||||
ObjectActionSpring(id, ownerEntity),
|
||||
_relativePosition(glm::vec3(0.0f)),
|
||||
_relativeRotation(glm::quat()),
|
||||
_hand("right"),
|
||||
_holderID(QUuid()) {
|
||||
ObjectActionSpring(id, ownerEntity)
|
||||
{
|
||||
_type = ACTION_TYPE_HOLD;
|
||||
#if WANT_DEBUG
|
||||
#if WANT_DEBUG
|
||||
qDebug() << "AvatarActionHold::AvatarActionHold";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
AvatarActionHold::~AvatarActionHold() {
|
||||
#if WANT_DEBUG
|
||||
#if WANT_DEBUG
|
||||
qDebug() << "AvatarActionHold::~AvatarActionHold";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) {
|
||||
std::shared_ptr<Avatar> holdingAvatar = nullptr;
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID));
|
||||
|
||||
if (!holdingAvatar) {
|
||||
return holdingAvatar;
|
||||
}
|
||||
|
||||
withTryReadLock([&]{
|
||||
QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
|
||||
AvatarSharedPointer holdingAvatarData = avatarManager->getAvatarBySessionID(_holderID);
|
||||
holdingAvatar = std::static_pointer_cast<Avatar>(holdingAvatarData);
|
||||
|
||||
if (holdingAvatar) {
|
||||
glm::vec3 offset;
|
||||
glm::vec3 palmPosition;
|
||||
glm::quat palmRotation;
|
||||
if (_hand == "right") {
|
||||
bool isRightHand = (_hand == "right");
|
||||
glm::vec3 palmPosition { Vectors::ZERO };
|
||||
glm::quat palmRotation { Quaternions::IDENTITY };
|
||||
|
||||
if (_ignoreIK && holdingAvatar->isMyAvatar()) {
|
||||
// We cannot ignore other avatars IK and this is not the point of this option
|
||||
// This is meant to make the grabbing behavior more reactive.
|
||||
if (isRightHand) {
|
||||
palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition();
|
||||
palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation();
|
||||
} else {
|
||||
palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition();
|
||||
palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation();
|
||||
}
|
||||
} else {
|
||||
if (isRightHand) {
|
||||
palmPosition = holdingAvatar->getRightPalmPosition();
|
||||
palmRotation = holdingAvatar->getRightPalmRotation();
|
||||
} else {
|
||||
palmPosition = holdingAvatar->getLeftPalmPosition();
|
||||
palmRotation = holdingAvatar->getLeftPalmRotation();
|
||||
}
|
||||
|
||||
rotation = palmRotation * _relativeRotation;
|
||||
offset = rotation * _relativePosition;
|
||||
position = palmPosition + offset;
|
||||
}
|
||||
|
||||
rotation = palmRotation * _relativeRotation;
|
||||
position = palmPosition + rotation * _relativePosition;
|
||||
});
|
||||
|
||||
return holdingAvatar;
|
||||
}
|
||||
|
||||
void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
||||
glm::quat rotation;
|
||||
glm::vec3 position;
|
||||
glm::quat rotation { Quaternions::IDENTITY };
|
||||
glm::vec3 position { Vectors::ZERO };
|
||||
bool valid = false;
|
||||
int holdCount = 0;
|
||||
|
||||
|
@ -168,6 +177,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
|||
QUuid holderID;
|
||||
bool kinematic;
|
||||
bool kinematicSetVelocity;
|
||||
bool ignoreIK;
|
||||
bool needUpdate = false;
|
||||
|
||||
bool somethingChanged = ObjectAction::updateArguments(arguments);
|
||||
|
@ -203,14 +213,20 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
|||
ok = true;
|
||||
kinematic = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematic", ok, false);
|
||||
if (!ok) {
|
||||
_kinematic = false;
|
||||
kinematic = _kinematic;
|
||||
}
|
||||
|
||||
ok = true;
|
||||
kinematicSetVelocity = EntityActionInterface::extractBooleanArgument("hold", arguments,
|
||||
"kinematicSetVelocity", ok, false);
|
||||
if (!ok) {
|
||||
_kinematicSetVelocity = false;
|
||||
kinematicSetVelocity = _kinematicSetVelocity;
|
||||
}
|
||||
|
||||
ok = true;
|
||||
ignoreIK = EntityActionInterface::extractBooleanArgument("hold", arguments, "ignoreIK", ok, false);
|
||||
if (!ok) {
|
||||
ignoreIK = _ignoreIK;
|
||||
}
|
||||
|
||||
if (somethingChanged ||
|
||||
|
@ -220,7 +236,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
|||
hand != _hand ||
|
||||
holderID != _holderID ||
|
||||
kinematic != _kinematic ||
|
||||
kinematicSetVelocity != _kinematicSetVelocity) {
|
||||
kinematicSetVelocity != _kinematicSetVelocity ||
|
||||
ignoreIK != _ignoreIK) {
|
||||
needUpdate = true;
|
||||
}
|
||||
});
|
||||
|
@ -236,6 +253,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
|||
_holderID = holderID;
|
||||
_kinematic = kinematic;
|
||||
_kinematicSetVelocity = kinematicSetVelocity;
|
||||
_ignoreIK = ignoreIK;
|
||||
_active = true;
|
||||
|
||||
auto ownerEntity = _ownerEntity.lock();
|
||||
|
@ -260,6 +278,7 @@ QVariantMap AvatarActionHold::getArguments() {
|
|||
arguments["hand"] = _hand;
|
||||
arguments["kinematic"] = _kinematic;
|
||||
arguments["kinematicSetVelocity"] = _kinematicSetVelocity;
|
||||
arguments["ignoreIK"] = _ignoreIK;
|
||||
});
|
||||
return arguments;
|
||||
}
|
||||
|
|
|
@ -38,17 +38,19 @@ public:
|
|||
std::shared_ptr<Avatar> getTarget(glm::quat& rotation, glm::vec3& position);
|
||||
|
||||
private:
|
||||
void doKinematicUpdate(float deltaTimeStep);
|
||||
|
||||
static const uint16_t holdVersion;
|
||||
|
||||
glm::vec3 _relativePosition;
|
||||
glm::quat _relativeRotation;
|
||||
QString _hand;
|
||||
glm::vec3 _relativePosition { Vectors::ZERO };
|
||||
glm::quat _relativeRotation { Quaternions::IDENTITY };
|
||||
QString _hand { "right" };
|
||||
QUuid _holderID;
|
||||
|
||||
void doKinematicUpdate(float deltaTimeStep);
|
||||
bool _kinematic { false };
|
||||
bool _kinematicSetVelocity { false };
|
||||
bool _previousSet { false };
|
||||
bool _ignoreIK { false };
|
||||
glm::vec3 _previousPositionalTarget;
|
||||
glm::quat _previousRotationalTarget;
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@ void AvatarManager::init() {
|
|||
_renderDistanceController.setKP(0.0008f); // Usually about 0.6 of largest that doesn't oscillate when other parameters 0.
|
||||
_renderDistanceController.setKI(0.0006f); // Big enough to bring us to target with the above KP.
|
||||
_renderDistanceController.setKD(0.000001f); // A touch of kd increases the speed by which we get there.
|
||||
|
||||
}
|
||||
|
||||
void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||
|
@ -147,18 +146,16 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
PerformanceTimer perfTimer("otherAvatars");
|
||||
|
||||
float distance;
|
||||
if (qApp->isVSynchronized()) {
|
||||
if (!qApp->isThrottleRendering()) {
|
||||
_renderDistanceController.setMeasuredValueSetpoint(qApp->getTargetFrameRate()); // No problem updating in flight.
|
||||
// The PID controller raises the controlled value when the measured value goes up.
|
||||
// The measured value is frame rate. When the controlled value (1 / render cutoff distance)
|
||||
// goes up, the render cutoff distance gets closer, the number of rendered avatars is less, and frame rate
|
||||
// goes up.
|
||||
const float deduced = qApp->getLastDeducedNonVSyncFps();
|
||||
const float deduced = qApp->getLastUnsynchronizedFps();
|
||||
distance = 1.0f / _renderDistanceController.update(deduced, deltaTime);
|
||||
} else {
|
||||
// We could keep the controller running when not vsync'd, if getLastDeducedNonVSyncFps is still meaningful.
|
||||
// But the basic 2d controller doesn't try to adjust the timer for qt load or getLastPaintWait, so running the
|
||||
// Here we choose to just use the maximum render cutoff distance if: throttled, running without vsync, or 30-60 "fixed" targets.
|
||||
// Here we choose to just use the maximum render cutoff distance if throttled.
|
||||
distance = 1.0f / _renderDistanceController.getControlledValueLowLimit();
|
||||
}
|
||||
_renderDistanceAverage.updateAverage(distance);
|
||||
|
@ -417,7 +414,7 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) {
|
|||
|
||||
AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) {
|
||||
if (sessionID == _myAvatar->getSessionUUID()) {
|
||||
return std::static_pointer_cast<Avatar>(_myAvatar);
|
||||
return _myAvatar;
|
||||
}
|
||||
|
||||
return findAvatar(sessionID);
|
||||
|
|
|
@ -560,7 +560,7 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
|||
if (!_shouldRender) {
|
||||
return; // exit early
|
||||
}
|
||||
|
||||
|
||||
Avatar::render(renderArgs, cameraPosition);
|
||||
}
|
||||
|
||||
|
@ -967,8 +967,6 @@ void MyAvatar::clearJointData(int index) {
|
|||
QMetaObject::invokeMethod(this, "clearJointData", Q_ARG(int, index));
|
||||
return;
|
||||
}
|
||||
// HACK: ATM only JS scripts call clearJointData() on MyAvatar so we hardcode the priority
|
||||
_rig->setJointState(index, false, glm::quat(), glm::vec3(), 0.0f);
|
||||
_rig->clearJointAnimationPriority(index);
|
||||
}
|
||||
|
||||
|
@ -1188,7 +1186,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl
|
|||
if (!_skeletonModel.isRenderable()) {
|
||||
return; // wait until all models are loaded
|
||||
}
|
||||
|
||||
|
||||
fixupModelsInScene();
|
||||
|
||||
// Render head so long as the camera isn't inside it
|
||||
|
|
|
@ -254,6 +254,7 @@ public slots:
|
|||
void setEnableDebugDrawDefaultPose(bool isEnabled);
|
||||
void setEnableDebugDrawAnimPose(bool isEnabled);
|
||||
void setEnableDebugDrawPosition(bool isEnabled);
|
||||
bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); }
|
||||
void setEnableMeshVisible(bool isEnabled);
|
||||
Q_INVOKABLE void setAnimGraphUrl(const QUrl& url);
|
||||
|
||||
|
@ -276,7 +277,7 @@ private:
|
|||
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override;
|
||||
virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override;
|
||||
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override;
|
||||
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
|
||||
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; setEnableMeshVisible(shouldRender); }
|
||||
bool getShouldRenderLocally() const { return _shouldRender; }
|
||||
bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; };
|
||||
bool isMyAvatar() const override { return true; }
|
||||
|
|
|
@ -622,7 +622,8 @@ QScriptValue WindowScriptingInterface::showBrowse(const QString& title, const QS
|
|||
fileDialog.setAcceptMode(acceptMode);
|
||||
QUrl fileUrl(directory);
|
||||
if (acceptMode == QFileDialog::AcceptSave) {
|
||||
fileDialog.setFileMode(QFileDialog::Directory);
|
||||
// TODO -- Setting this breaks the dialog on Linux. Does it help something on other platforms?
|
||||
// fileDialog.setFileMode(QFileDialog::Directory);
|
||||
fileDialog.selectFile(fileUrl.fileName());
|
||||
}
|
||||
if (fileDialog.exec()) {
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
const int PREFERENCES_HEIGHT_PADDING = 20;
|
||||
|
||||
PreferencesDialog::PreferencesDialog(QWidget* parent) :
|
||||
QDialog(parent) {
|
||||
|
||||
QDialog(parent)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
ui.setupUi(this);
|
||||
|
@ -48,10 +48,8 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
|
|||
connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, qApp, &Application::loadDefaultScripts);
|
||||
|
||||
connect(ui.buttonChangeAppearance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser);
|
||||
connect(ui.appearanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) {
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->useFullAvatarURL(url, "");
|
||||
this->fullAvatarURLChanged(url, "");
|
||||
});
|
||||
connect(ui.appearanceDescription, &QLineEdit::editingFinished, this, &PreferencesDialog::changeFullAvatarURL);
|
||||
|
||||
connect(qApp, &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged);
|
||||
|
||||
// move dialog to left side
|
||||
|
@ -61,6 +59,11 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
|
|||
UIUtil::scaleWidgetFontSizes(this);
|
||||
}
|
||||
|
||||
void PreferencesDialog::changeFullAvatarURL() {
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->useFullAvatarURL(ui.appearanceDescription->text(), "");
|
||||
this->fullAvatarURLChanged(ui.appearanceDescription->text(), "");
|
||||
}
|
||||
|
||||
void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.appearanceDescription->setText(newValue);
|
||||
const QString APPEARANCE_LABEL_TEXT("Appearance: ");
|
||||
|
@ -69,9 +72,17 @@ void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QStr
|
|||
|
||||
void PreferencesDialog::accept() {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
// if there is an attempted change to the full avatar URL, apply it now
|
||||
if (QUrl(ui.appearanceDescription->text()) != myAvatar->getFullAvatarURLFromPreferences()) {
|
||||
changeFullAvatarURL();
|
||||
}
|
||||
|
||||
_lastGoodAvatarURL = myAvatar->getFullAvatarURLFromPreferences();
|
||||
_lastGoodAvatarName = myAvatar->getFullAvatarModelName();
|
||||
|
||||
savePreferences();
|
||||
|
||||
close();
|
||||
delete _marketplaceWindow;
|
||||
_marketplaceWindow = NULL;
|
||||
|
|
|
@ -49,6 +49,7 @@ private slots:
|
|||
void openFullAvatarModelBrowser();
|
||||
void openSnapshotLocationBrowser();
|
||||
void openScriptsLocationBrowser();
|
||||
void changeFullAvatarURL();
|
||||
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
||||
};
|
||||
|
||||
|
|
|
@ -294,6 +294,7 @@ void Rig::clearJointStates() {
|
|||
void Rig::clearJointAnimationPriority(int index) {
|
||||
if (isIndexValid(index)) {
|
||||
_internalPoseSet._overrideFlags[index] = false;
|
||||
_internalPoseSet._overridePoses[index] = _animSkeleton->getRelativeDefaultPose(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,6 +374,16 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool Rig::getAbsoluteJointRotationInRigFrame(int jointIndex, glm::quat& rotation) const {
|
||||
QReadLocker readLock(&_externalPoseSetLock);
|
||||
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._absolutePoses.size()) {
|
||||
rotation = _externalPoseSet._absolutePoses[jointIndex].rot;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const {
|
||||
QReadLocker readLock(&_externalPoseSetLock);
|
||||
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._relativePoses.size()) {
|
||||
|
@ -383,6 +394,16 @@ bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool Rig::getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& translation) const {
|
||||
QReadLocker readLock(&_externalPoseSetLock);
|
||||
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._absolutePoses.size()) {
|
||||
translation = _externalPoseSet._absolutePoses[jointIndex].trans;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
|
||||
// AJT: TODO: used by attachments
|
||||
ASSERT(false);
|
||||
|
|
|
@ -129,10 +129,12 @@ public:
|
|||
|
||||
// geometry space (thread-safe)
|
||||
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
|
||||
|
||||
// geometry space (thread-safe)
|
||||
bool getJointTranslation(int jointIndex, glm::vec3& translation) const;
|
||||
|
||||
// rig space (thread-safe)
|
||||
bool getAbsoluteJointRotationInRigFrame(int jointIndex, glm::quat& rotation) const;
|
||||
bool getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& translation) const;
|
||||
|
||||
// legacy
|
||||
bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
|
||||
|
||||
|
|
|
@ -541,26 +541,40 @@ bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) {
|
|||
|
||||
void AudioClient::configureReverb() {
|
||||
ReverbParameters p;
|
||||
_listenerReverb.getParameters(&p);
|
||||
|
||||
// for now, reuse the gverb parameters
|
||||
p.sampleRate = _outputFormat.sampleRate();
|
||||
p.roomSize = _reverbOptions->getRoomSize();
|
||||
|
||||
p.bandwidth = _reverbOptions->getBandwidth();
|
||||
p.preDelay = _reverbOptions->getPreDelay();
|
||||
p.lateDelay = _reverbOptions->getLateDelay();
|
||||
p.reverbTime = _reverbOptions->getReverbTime();
|
||||
p.highGain = -24.0f * (1.0f - _reverbOptions->getDamping());
|
||||
p.bandwidth = 10000.0f * _reverbOptions->getInputBandwidth();
|
||||
p.earlyGain = _reverbOptions->getEarlyLevel();
|
||||
p.lateGain = _reverbOptions->getTailLevel();
|
||||
p.wetDryMix = 100.0f * powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f));
|
||||
p.earlyDiffusion = _reverbOptions->getEarlyDiffusion();
|
||||
p.lateDiffusion = _reverbOptions->getLateDiffusion();
|
||||
p.roomSize = _reverbOptions->getRoomSize();
|
||||
p.density = _reverbOptions->getDensity();
|
||||
p.bassMult = _reverbOptions->getBassMult();
|
||||
p.bassFreq = _reverbOptions->getBassFreq();
|
||||
p.highGain = _reverbOptions->getHighGain();
|
||||
p.highFreq = _reverbOptions->getHighFreq();
|
||||
p.modRate = _reverbOptions->getModRate();
|
||||
p.modDepth = _reverbOptions->getModDepth();
|
||||
p.earlyGain = _reverbOptions->getEarlyGain();
|
||||
p.lateGain = _reverbOptions->getLateGain();
|
||||
p.earlyMixLeft = _reverbOptions->getEarlyMixLeft();
|
||||
p.earlyMixRight = _reverbOptions->getEarlyMixRight();
|
||||
p.lateMixLeft = _reverbOptions->getLateMixLeft();
|
||||
p.lateMixRight = _reverbOptions->getLateMixRight();
|
||||
p.wetDryMix = _reverbOptions->getWetDryMix();
|
||||
|
||||
_listenerReverb.setParameters(&p);
|
||||
|
||||
// used for adding self-reverb to loopback audio
|
||||
// used only for adding self-reverb to loopback audio
|
||||
p.wetDryMix = 100.0f;
|
||||
p.preDelay = 0.0f;
|
||||
p.earlyGain = -96.0f; // disable ER
|
||||
p.lateGain -= 12.0f; // quieter than listener reverb
|
||||
p.lateGain -= 12.0f; // quieter than listener reverb
|
||||
p.lateMixLeft = 0.0f;
|
||||
p.lateMixRight = 0.0f;
|
||||
|
||||
_sourceReverb.setParameters(&p);
|
||||
}
|
||||
|
||||
|
@ -572,10 +586,10 @@ void AudioClient::updateReverbOptions() {
|
|||
_zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime());
|
||||
reverbChanged = true;
|
||||
}
|
||||
if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) {
|
||||
_zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel());
|
||||
reverbChanged = true;
|
||||
}
|
||||
//if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) {
|
||||
// _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel());
|
||||
// reverbChanged = true;
|
||||
//}
|
||||
|
||||
if (_reverbOptions != &_zoneReverbOptions) {
|
||||
_reverbOptions = &_zoneReverbOptions;
|
||||
|
@ -602,17 +616,27 @@ void AudioClient::setReverb(bool reverb) {
|
|||
|
||||
void AudioClient::setReverbOptions(const AudioEffectOptions* options) {
|
||||
// Save the new options
|
||||
_scriptReverbOptions.setMaxRoomSize(options->getMaxRoomSize());
|
||||
_scriptReverbOptions.setRoomSize(options->getRoomSize());
|
||||
_scriptReverbOptions.setBandwidth(options->getBandwidth());
|
||||
_scriptReverbOptions.setPreDelay(options->getPreDelay());
|
||||
_scriptReverbOptions.setLateDelay(options->getLateDelay());
|
||||
_scriptReverbOptions.setReverbTime(options->getReverbTime());
|
||||
_scriptReverbOptions.setDamping(options->getDamping());
|
||||
_scriptReverbOptions.setSpread(options->getSpread());
|
||||
_scriptReverbOptions.setInputBandwidth(options->getInputBandwidth());
|
||||
_scriptReverbOptions.setEarlyLevel(options->getEarlyLevel());
|
||||
_scriptReverbOptions.setTailLevel(options->getTailLevel());
|
||||
|
||||
_scriptReverbOptions.setDryLevel(options->getDryLevel());
|
||||
_scriptReverbOptions.setWetLevel(options->getWetLevel());
|
||||
_scriptReverbOptions.setEarlyDiffusion(options->getEarlyDiffusion());
|
||||
_scriptReverbOptions.setLateDiffusion(options->getLateDiffusion());
|
||||
_scriptReverbOptions.setRoomSize(options->getRoomSize());
|
||||
_scriptReverbOptions.setDensity(options->getDensity());
|
||||
_scriptReverbOptions.setBassMult(options->getBassMult());
|
||||
_scriptReverbOptions.setBassFreq(options->getBassFreq());
|
||||
_scriptReverbOptions.setHighGain(options->getHighGain());
|
||||
_scriptReverbOptions.setHighFreq(options->getHighFreq());
|
||||
_scriptReverbOptions.setModRate(options->getModRate());
|
||||
_scriptReverbOptions.setModDepth(options->getModDepth());
|
||||
_scriptReverbOptions.setEarlyGain(options->getEarlyGain());
|
||||
_scriptReverbOptions.setLateGain(options->getLateGain());
|
||||
_scriptReverbOptions.setEarlyMixLeft(options->getEarlyMixLeft());
|
||||
_scriptReverbOptions.setEarlyMixRight(options->getEarlyMixRight());
|
||||
_scriptReverbOptions.setLateMixLeft(options->getLateMixLeft());
|
||||
_scriptReverbOptions.setLateMixRight(options->getLateMixRight());
|
||||
_scriptReverbOptions.setWetDryMix(options->getWetDryMix());
|
||||
|
||||
if (_reverbOptions == &_scriptReverbOptions) {
|
||||
// Apply them to the reverb instances
|
||||
|
|
|
@ -10,58 +10,76 @@
|
|||
|
||||
#include "AudioEffectOptions.h"
|
||||
|
||||
static const QString MAX_ROOM_SIZE_HANDLE = "maxRoomSize";
|
||||
static const QString ROOM_SIZE_HANDLE = "roomSize";
|
||||
static const QString BANDWIDTH_HANDLE = "bandwidth";
|
||||
static const QString PRE_DELAY_HANDLE = "preDelay";
|
||||
static const QString LATE_DELAY_HANDLE = "lateDelay";
|
||||
static const QString REVERB_TIME_HANDLE = "reverbTime";
|
||||
static const QString DAMPIMG_HANDLE = "damping";
|
||||
static const QString SPREAD_HANDLE = "spread";
|
||||
static const QString INPUT_BANDWIDTH_HANDLE = "inputBandwidth";
|
||||
static const QString EARLY_LEVEL_HANDLE = "earlyLevel";
|
||||
static const QString TAIL_LEVEL_HANDLE = "tailLevel";
|
||||
static const QString DRY_LEVEL_HANDLE = "dryLevel";
|
||||
static const QString WET_LEVEL_HANDLE = "wetLevel";
|
||||
static const QString EARLY_DIFFUSION_HANDLE = "earlyDiffusion";
|
||||
static const QString LATE_DIFFUSION_HANDLE = "lateDiffusion";
|
||||
static const QString ROOM_SIZE_HANDLE = "roomSize";
|
||||
static const QString DENSITY_HANDLE = "density";
|
||||
static const QString BASS_MULT_HANDLE = "bassMult";
|
||||
static const QString BASS_FREQ_HANDLE = "bassFreq";
|
||||
static const QString HIGH_GAIN_HANDLE = "highGain";
|
||||
static const QString HIGH_FREQ_HANDLE = "highFreq";
|
||||
static const QString MOD_RATE_HANDLE = "modRate";
|
||||
static const QString MOD_DEPTH_HANDLE = "modDepth";
|
||||
static const QString EARLY_GAIN_HANDLE = "earlyGain";
|
||||
static const QString LATE_GAIN_HANDLE = "lateGain";
|
||||
static const QString EARLY_MIX_LEFT_HANDLE = "earlyMixLeft";
|
||||
static const QString EARLY_MIX_RIGHT_HANDLE = "earlyMixRight";
|
||||
static const QString LATE_MIX_LEFT_HANDLE = "lateMixLeft";
|
||||
static const QString LATE_MIX_RIGHT_HANDLE = "lateMixRight";
|
||||
static const QString WET_DRY_MIX_HANDLE = "wetDryMix";
|
||||
|
||||
AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) :
|
||||
_maxRoomSize(50.0f),
|
||||
_roomSize(50.0f),
|
||||
_reverbTime(4.0f),
|
||||
_damping(0.5f),
|
||||
_spread(15.0f),
|
||||
_inputBandwidth(0.75f),
|
||||
_earlyLevel(-12.0f),
|
||||
_tailLevel(-18.0f),
|
||||
_dryLevel(0.0f),
|
||||
_wetLevel(0.0f) {
|
||||
if (arguments.property(MAX_ROOM_SIZE_HANDLE).isNumber()) {
|
||||
_maxRoomSize = arguments.property(MAX_ROOM_SIZE_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(ROOM_SIZE_HANDLE).isNumber()) {
|
||||
_roomSize = arguments.property(ROOM_SIZE_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(REVERB_TIME_HANDLE).isNumber()) {
|
||||
_reverbTime = arguments.property(REVERB_TIME_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(DAMPIMG_HANDLE).isNumber()) {
|
||||
_damping = arguments.property(DAMPIMG_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(SPREAD_HANDLE).isNumber()) {
|
||||
_spread = arguments.property(SPREAD_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(INPUT_BANDWIDTH_HANDLE).isNumber()) {
|
||||
_inputBandwidth = arguments.property(INPUT_BANDWIDTH_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(EARLY_LEVEL_HANDLE).isNumber()) {
|
||||
_earlyLevel = arguments.property(EARLY_LEVEL_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(TAIL_LEVEL_HANDLE).isNumber()) {
|
||||
_tailLevel = arguments.property(TAIL_LEVEL_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(DRY_LEVEL_HANDLE).isNumber()) {
|
||||
_dryLevel = arguments.property(DRY_LEVEL_HANDLE).toNumber();
|
||||
}
|
||||
if (arguments.property(WET_LEVEL_HANDLE).isNumber()) {
|
||||
_wetLevel = arguments.property(WET_LEVEL_HANDLE).toNumber();
|
||||
}
|
||||
static const float BANDWIDTH_DEFAULT = 10000.0f;
|
||||
static const float PRE_DELAY_DEFAULT = 20.0f;
|
||||
static const float LATE_DELAY_DEFAULT = 0.0f;
|
||||
static const float REVERB_TIME_DEFAULT = 2.0f;
|
||||
static const float EARLY_DIFFUSION_DEFAULT = 100.0f;
|
||||
static const float LATE_DIFFUSION_DEFAULT = 100.0f;
|
||||
static const float ROOM_SIZE_DEFAULT = 50.0f;
|
||||
static const float DENSITY_DEFAULT = 100.0f;
|
||||
static const float BASS_MULT_DEFAULT = 1.5f;
|
||||
static const float BASS_FREQ_DEFAULT = 250.0f;
|
||||
static const float HIGH_GAIN_DEFAULT = -6.0f;
|
||||
static const float HIGH_FREQ_DEFAULT = 3000.0f;
|
||||
static const float MOD_RATE_DEFAULT = 2.3f;
|
||||
static const float MOD_DEPTH_DEFAULT = 50.0f;
|
||||
static const float EARLY_GAIN_DEFAULT = 0.0f;
|
||||
static const float LATE_GAIN_DEFAULT = 0.0f;
|
||||
static const float EARLY_MIX_LEFT_DEFAULT = 20.0f;
|
||||
static const float EARLY_MIX_RIGHT_DEFAULT = 20.0f;
|
||||
static const float LATE_MIX_LEFT_DEFAULT = 90.0f;
|
||||
static const float LATE_MIX_RIGHT_DEFAULT = 90.0f;
|
||||
static const float WET_DRY_MIX_DEFAULT = 50.0f;
|
||||
|
||||
static void setOption(QScriptValue arguments, const QString name, float defaultValue, float& variable) {
|
||||
variable = arguments.property(name).isNumber() ? arguments.property(name).toNumber() : defaultValue;
|
||||
}
|
||||
|
||||
AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) {
|
||||
setOption(arguments, BANDWIDTH_HANDLE, BANDWIDTH_DEFAULT, _bandwidth);
|
||||
setOption(arguments, PRE_DELAY_HANDLE, PRE_DELAY_DEFAULT, _preDelay);
|
||||
setOption(arguments, LATE_DELAY_HANDLE, LATE_DELAY_DEFAULT, _lateDelay);
|
||||
setOption(arguments, REVERB_TIME_HANDLE, REVERB_TIME_DEFAULT, _reverbTime);
|
||||
setOption(arguments, EARLY_DIFFUSION_HANDLE, EARLY_DIFFUSION_DEFAULT, _earlyDiffusion);
|
||||
setOption(arguments, LATE_DIFFUSION_HANDLE, LATE_DIFFUSION_DEFAULT, _lateDiffusion);
|
||||
setOption(arguments, ROOM_SIZE_HANDLE, ROOM_SIZE_DEFAULT, _roomSize);
|
||||
setOption(arguments, DENSITY_HANDLE, DENSITY_DEFAULT, _density);
|
||||
setOption(arguments, BASS_MULT_HANDLE, BASS_MULT_DEFAULT, _bassMult);
|
||||
setOption(arguments, BASS_FREQ_HANDLE, BASS_FREQ_DEFAULT, _bassFreq);
|
||||
setOption(arguments, HIGH_GAIN_HANDLE, HIGH_GAIN_DEFAULT, _highGain);
|
||||
setOption(arguments, HIGH_FREQ_HANDLE, HIGH_FREQ_DEFAULT, _highFreq);
|
||||
setOption(arguments, MOD_RATE_HANDLE, MOD_RATE_DEFAULT, _modRate);
|
||||
setOption(arguments, MOD_DEPTH_HANDLE, MOD_DEPTH_DEFAULT, _modDepth);
|
||||
setOption(arguments, EARLY_GAIN_HANDLE, EARLY_GAIN_DEFAULT, _earlyGain);
|
||||
setOption(arguments, LATE_GAIN_HANDLE, LATE_GAIN_DEFAULT, _lateGain);
|
||||
setOption(arguments, EARLY_MIX_LEFT_HANDLE, EARLY_MIX_LEFT_DEFAULT, _earlyMixLeft);
|
||||
setOption(arguments, EARLY_MIX_RIGHT_HANDLE, EARLY_MIX_RIGHT_DEFAULT, _earlyMixRight);
|
||||
setOption(arguments, LATE_MIX_LEFT_HANDLE, LATE_MIX_LEFT_DEFAULT, _lateMixLeft);
|
||||
setOption(arguments, LATE_MIX_RIGHT_HANDLE, LATE_MIX_RIGHT_DEFAULT, _lateMixRight);
|
||||
setOption(arguments, WET_DRY_MIX_HANDLE, WET_DRY_MIX_DEFAULT, _wetDryMix);
|
||||
}
|
||||
|
||||
AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) : QObject() {
|
||||
|
@ -69,17 +87,28 @@ AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) : QObjec
|
|||
}
|
||||
|
||||
AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &other) {
|
||||
_maxRoomSize = other._maxRoomSize;
|
||||
_roomSize = other._roomSize;
|
||||
_bandwidth = other._bandwidth;
|
||||
_preDelay = other._preDelay;
|
||||
_lateDelay = other._lateDelay;
|
||||
_reverbTime = other._reverbTime;
|
||||
_damping = other._damping;
|
||||
_spread = other._spread;
|
||||
_inputBandwidth = other._inputBandwidth;
|
||||
_earlyLevel = other._earlyLevel;
|
||||
_tailLevel = other._tailLevel;
|
||||
_dryLevel = other._dryLevel;
|
||||
_wetLevel = other._wetLevel;
|
||||
|
||||
_earlyDiffusion = other._earlyDiffusion;
|
||||
_lateDiffusion = other._lateDiffusion;
|
||||
_roomSize = other._roomSize;
|
||||
_density = other._density;
|
||||
_bassMult = other._bassMult;
|
||||
_bassFreq = other._bassFreq;
|
||||
_highGain = other._highGain;
|
||||
_highFreq = other._highFreq;
|
||||
_modRate = other._modRate;
|
||||
_modDepth = other._modDepth;
|
||||
_earlyGain = other._earlyGain;
|
||||
_lateGain = other._lateGain;
|
||||
_earlyMixLeft = other._earlyMixLeft;
|
||||
_earlyMixRight = other._earlyMixRight;
|
||||
_lateMixLeft = other._lateMixLeft;
|
||||
_lateMixRight = other._lateMixRight;
|
||||
_wetDryMix = other._wetDryMix;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,32 +15,30 @@
|
|||
#include <QtScript/QScriptContext>
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include "AudioReverb.h"
|
||||
|
||||
class AudioEffectOptions : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
// Meters Square
|
||||
Q_PROPERTY(float maxRoomSize READ getMaxRoomSize WRITE setMaxRoomSize)
|
||||
Q_PROPERTY(float roomSize READ getRoomSize WRITE setRoomSize)
|
||||
|
||||
// Seconds
|
||||
Q_PROPERTY(float bandwidth READ getBandwidth WRITE setBandwidth)
|
||||
Q_PROPERTY(float preDelay READ getPreDelay WRITE setPreDelay)
|
||||
Q_PROPERTY(float lateDelay READ getLateDelay WRITE setLateDelay)
|
||||
Q_PROPERTY(float reverbTime READ getReverbTime WRITE setReverbTime)
|
||||
|
||||
// Ratio between 0 and 1
|
||||
Q_PROPERTY(float damping READ getDamping WRITE setDamping)
|
||||
|
||||
// (?) Does not appear to be set externally very often
|
||||
Q_PROPERTY(float spread READ getSpread WRITE setSpread)
|
||||
|
||||
// Ratio between 0 and 1
|
||||
Q_PROPERTY(float inputBandwidth READ getInputBandwidth WRITE setInputBandwidth)
|
||||
|
||||
// in dB
|
||||
Q_PROPERTY(float earlyLevel READ getEarlyLevel WRITE setEarlyLevel)
|
||||
Q_PROPERTY(float tailLevel READ getTailLevel WRITE setTailLevel)
|
||||
Q_PROPERTY(float dryLevel READ getDryLevel WRITE setDryLevel)
|
||||
Q_PROPERTY(float wetLevel READ getWetLevel WRITE setWetLevel)
|
||||
Q_PROPERTY(float earlyDiffusion READ getEarlyDiffusion WRITE setEarlyDiffusion)
|
||||
Q_PROPERTY(float lateDiffusion READ getLateDiffusion WRITE setLateDiffusion)
|
||||
Q_PROPERTY(float roomSize READ getRoomSize WRITE setRoomSize)
|
||||
Q_PROPERTY(float density READ getDensity WRITE setDensity)
|
||||
Q_PROPERTY(float bassMult READ getBassMult WRITE setBassMult)
|
||||
Q_PROPERTY(float bassFreq READ getBassFreq WRITE setBassFreq)
|
||||
Q_PROPERTY(float highGain READ getHighGain WRITE setHighGain)
|
||||
Q_PROPERTY(float highFreq READ getHighFreq WRITE setHighFreq)
|
||||
Q_PROPERTY(float modRate READ getModRate WRITE setModRate)
|
||||
Q_PROPERTY(float modDepth READ getModDepth WRITE setModDepth)
|
||||
Q_PROPERTY(float earlyGain READ getEarlyGain WRITE setEarlyGain)
|
||||
Q_PROPERTY(float lateGain READ getLateGain WRITE setLateGain)
|
||||
Q_PROPERTY(float earlyMixLeft READ getEarlyMixLeft WRITE setEarlyMixLeft)
|
||||
Q_PROPERTY(float earlyMixRight READ getEarlyMixRight WRITE setEarlyMixRight)
|
||||
Q_PROPERTY(float lateMixLeft READ getLateMixLeft WRITE setLateMixLeft)
|
||||
Q_PROPERTY(float lateMixRight READ getLateMixRight WRITE setLateMixRight)
|
||||
Q_PROPERTY(float wetDryMix READ getWetDryMix WRITE setWetDryMix)
|
||||
|
||||
public:
|
||||
AudioEffectOptions(QScriptValue arguments = QScriptValue());
|
||||
|
@ -49,60 +47,100 @@ public:
|
|||
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
float getRoomSize() const { return _roomSize; }
|
||||
void setRoomSize(float roomSize ) { _roomSize = roomSize; }
|
||||
float getBandwidth() const { return _bandwidth; }
|
||||
void setBandwidth(float bandwidth) { _bandwidth = bandwidth; }
|
||||
|
||||
float getMaxRoomSize() const { return _maxRoomSize; }
|
||||
void setMaxRoomSize(float maxRoomSize ) { _maxRoomSize = maxRoomSize; }
|
||||
float getPreDelay() const { return _preDelay; }
|
||||
void setPreDelay(float preDelay) { _preDelay = preDelay; }
|
||||
|
||||
float getLateDelay() const { return _lateDelay; }
|
||||
void setLateDelay(float lateDelay) { _lateDelay = lateDelay; }
|
||||
|
||||
float getReverbTime() const { return _reverbTime; }
|
||||
void setReverbTime(float reverbTime ) { _reverbTime = reverbTime; }
|
||||
void setReverbTime(float reverbTime) { _reverbTime = reverbTime; }
|
||||
|
||||
float getDamping() const { return _damping; }
|
||||
void setDamping(float damping ) { _damping = damping; }
|
||||
float getEarlyDiffusion() const { return _earlyDiffusion; }
|
||||
void setEarlyDiffusion(float earlyDiffusion) { _earlyDiffusion = earlyDiffusion; }
|
||||
|
||||
float getSpread() const { return _spread; }
|
||||
void setSpread(float spread ) { _spread = spread; }
|
||||
float getLateDiffusion() const { return _lateDiffusion; }
|
||||
void setLateDiffusion(float lateDiffusion) { _lateDiffusion = lateDiffusion; }
|
||||
|
||||
float getInputBandwidth() const { return _inputBandwidth; }
|
||||
void setInputBandwidth(float inputBandwidth ) { _inputBandwidth = inputBandwidth; }
|
||||
float getRoomSize() const { return _roomSize; }
|
||||
void setRoomSize(float roomSize) { _roomSize = roomSize; }
|
||||
|
||||
float getEarlyLevel() const { return _earlyLevel; }
|
||||
void setEarlyLevel(float earlyLevel ) { _earlyLevel = earlyLevel; }
|
||||
float getDensity() const { return _density; }
|
||||
void setDensity(float density) { _density = density; }
|
||||
|
||||
float getTailLevel() const { return _tailLevel; }
|
||||
void setTailLevel(float tailLevel ) { _tailLevel = tailLevel; }
|
||||
float getBassMult() const { return _bassMult; }
|
||||
void setBassMult(float bassMult) { _bassMult = bassMult; }
|
||||
|
||||
float getDryLevel() const { return _dryLevel; }
|
||||
void setDryLevel(float dryLevel) { _dryLevel = dryLevel; }
|
||||
float getBassFreq() const { return _bassFreq; }
|
||||
void setBassFreq(float bassFreq) { _bassFreq = bassFreq; }
|
||||
|
||||
float getWetLevel() const { return _wetLevel; }
|
||||
void setWetLevel(float wetLevel) { _wetLevel = wetLevel; }
|
||||
float getHighGain() const { return _highGain; }
|
||||
void setHighGain(float highGain) { _highGain = highGain; }
|
||||
|
||||
float getHighFreq() const { return _highFreq; }
|
||||
void setHighFreq(float highFreq) { _highFreq = highFreq; }
|
||||
|
||||
float getModRate() const { return _modRate; }
|
||||
void setModRate(float modRate) { _modRate = modRate; }
|
||||
|
||||
float getModDepth() const { return _modDepth; }
|
||||
void setModDepth(float modDepth) { _modDepth = modDepth; }
|
||||
|
||||
float getEarlyGain() const { return _earlyGain; }
|
||||
void setEarlyGain(float earlyGain) { _earlyGain = earlyGain; }
|
||||
|
||||
float getLateGain() const { return _lateGain; }
|
||||
void setLateGain(float lateGain) { _lateGain = lateGain; }
|
||||
|
||||
float getEarlyMixLeft() const { return _earlyMixLeft; }
|
||||
void setEarlyMixLeft(float earlyMixLeft) { _earlyMixLeft = earlyMixLeft; }
|
||||
|
||||
float getEarlyMixRight() const { return _earlyMixRight; }
|
||||
void setEarlyMixRight(float earlyMixRight) { _earlyMixRight = earlyMixRight; }
|
||||
|
||||
float getLateMixLeft() const { return _lateMixLeft; }
|
||||
void setLateMixLeft(float lateMixLeft) { _lateMixLeft = lateMixLeft; }
|
||||
|
||||
float getLateMixRight() const { return _lateMixRight; }
|
||||
void setLateMixRight(float lateMixRight) { _lateMixRight = lateMixRight; }
|
||||
|
||||
float getWetDryMix() const { return _wetDryMix; }
|
||||
void setWetDryMix(float wetDryMix) { _wetDryMix = wetDryMix; }
|
||||
|
||||
private:
|
||||
// http://wiki.audacityteam.org/wiki/GVerb#Instant_Reverberb_settings
|
||||
float _bandwidth; // [20, 24000] Hz
|
||||
|
||||
// Meters Square
|
||||
float _maxRoomSize;
|
||||
float _roomSize;
|
||||
float _preDelay; // [0, 333] ms
|
||||
float _lateDelay; // [0, 166] ms
|
||||
|
||||
// Seconds
|
||||
float _reverbTime;
|
||||
float _reverbTime; // [0.1, 100] seconds
|
||||
|
||||
// Ratio between 0 and 1
|
||||
float _damping;
|
||||
float _earlyDiffusion; // [0, 100] percent
|
||||
float _lateDiffusion; // [0, 100] percent
|
||||
|
||||
// ? (Does not appear to be set externally very often)
|
||||
float _spread;
|
||||
float _roomSize; // [0, 100] percent
|
||||
float _density; // [0, 100] percent
|
||||
|
||||
// Ratio between 0 and 1
|
||||
float _inputBandwidth;
|
||||
float _bassMult; // [0.1, 10] ratio
|
||||
float _bassFreq; // [10, 500] Hz
|
||||
float _highGain; // [-24, 0] dB
|
||||
float _highFreq; // [1000, 12000] Hz
|
||||
|
||||
// dB
|
||||
float _earlyLevel;
|
||||
float _tailLevel;
|
||||
float _dryLevel;
|
||||
float _wetLevel;
|
||||
float _modRate; // [0.1, 10] Hz
|
||||
float _modDepth; // [0, 100] percent
|
||||
|
||||
float _earlyGain; // [-96, +24] dB
|
||||
float _lateGain; // [-96, +24] dB
|
||||
|
||||
float _earlyMixLeft; // [0, 100] percent
|
||||
float _earlyMixRight; // [0, 100] percent
|
||||
float _lateMixLeft; // [0, 100] percent
|
||||
float _lateMixRight; // [0, 100] percent
|
||||
|
||||
float _wetDryMix; // [0, 100] percent
|
||||
};
|
||||
|
||||
#endif // hifi_AudioEffectOptions_h
|
||||
|
|
|
@ -1625,10 +1625,10 @@ void AvatarData::setBodyRoll(float bodyRoll) {
|
|||
setOrientation(glm::quat(glm::radians(eulerAngles)));
|
||||
}
|
||||
|
||||
void AvatarData::setPosition(const glm::vec3 position) {
|
||||
void AvatarData::setPosition(const glm::vec3& position) {
|
||||
SpatiallyNestable::setPosition(position);
|
||||
}
|
||||
|
||||
void AvatarData::setOrientation(const glm::quat orientation) {
|
||||
void AvatarData::setOrientation(const glm::quat& orientation) {
|
||||
SpatiallyNestable::setOrientation(orientation);
|
||||
}
|
||||
|
|
|
@ -201,8 +201,8 @@ public:
|
|||
float getBodyRoll() const;
|
||||
void setBodyRoll(float bodyRoll);
|
||||
|
||||
virtual void setPosition(glm::vec3 position);
|
||||
virtual void setOrientation(glm::quat orientation);
|
||||
virtual void setPosition(const glm::vec3& position) override;
|
||||
virtual void setOrientation(const glm::quat& orientation) override;
|
||||
|
||||
void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time.
|
||||
void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc.
|
||||
|
|
|
@ -113,10 +113,6 @@ bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
|
|||
return shouldThrottle;
|
||||
}
|
||||
|
||||
bool Basic2DWindowOpenGLDisplayPlugin::isVSynchronized() const {
|
||||
return (_framerateTarget == 0) && !_isThrottled;
|
||||
}
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() {
|
||||
QAction* checkedFramerate{ nullptr };
|
||||
foreach(auto action, _framerateActions) {
|
||||
|
@ -141,11 +137,8 @@ void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() {
|
|||
} else if (_isThrottled) {
|
||||
_framerateTarget = (float) THROTTLED_FRAMERATE;
|
||||
}
|
||||
_inverseFrameRate = _framerateTarget ? 1.0f / (float) _framerateTarget : 1.0f / TARGET_FRAMERATE_Basic2DWindowOpenGL; // not truncated
|
||||
|
||||
int newInterval = getDesiredInterval();
|
||||
// Note: when not isVSynchronized, we are often not likely to hit target with a newInterval timer.
|
||||
// We could try subtracting an allowance for qApp->getLastPaintWait() and qt timer machinery, but that starts getting complicated.
|
||||
qDebug() << newInterval;
|
||||
_timer.start(newInterval);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ public:
|
|||
virtual const QString & getName() const override;
|
||||
|
||||
virtual float getTargetFrameRate() override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; }
|
||||
virtual float getTargetFramePeriod() override { return _inverseFrameRate; }
|
||||
|
||||
virtual void activate() override;
|
||||
|
||||
|
@ -30,7 +29,6 @@ public:
|
|||
virtual void internalPresent() override;
|
||||
|
||||
virtual bool isThrottled() const override;
|
||||
virtual bool isVSynchronized() const override;
|
||||
|
||||
protected:
|
||||
int getDesiredInterval() const;
|
||||
|
@ -44,6 +42,5 @@ private:
|
|||
QAction* _vsyncAction { nullptr };
|
||||
uint32_t _framerateTarget { 0 };
|
||||
int _fullscreenTarget{ -1 };
|
||||
float _inverseFrameRate{ 1.0f }; //seconds
|
||||
bool _wantVsync { true };
|
||||
};
|
||||
|
|
|
@ -30,6 +30,12 @@ class PresentThread : public QThread, public Dependency {
|
|||
using Lock = std::unique_lock<Mutex>;
|
||||
public:
|
||||
|
||||
PresentThread() {
|
||||
connect(qApp, &QCoreApplication::aboutToQuit, [this]{
|
||||
_shutdown = true;
|
||||
});
|
||||
}
|
||||
|
||||
~PresentThread() {
|
||||
_shutdown = true;
|
||||
wait();
|
||||
|
@ -99,6 +105,10 @@ public:
|
|||
_context->doneCurrent();
|
||||
}
|
||||
|
||||
_context->makeCurrent();
|
||||
if (_activePlugin) {
|
||||
_activePlugin->uncustomizeContext();
|
||||
}
|
||||
_context->doneCurrent();
|
||||
_context->moveToThread(qApp->thread());
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ public:
|
|||
virtual bool isHmd() const override { return true; }
|
||||
|
||||
virtual float getTargetFrameRate() override { return TARGET_RATE_OpenVr; }
|
||||
virtual float getTargetFramePeriod() override { return 1.0f / TARGET_RATE_OpenVr; }
|
||||
|
||||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
|
|
|
@ -41,6 +41,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
Q_ASSERT(getType() == EntityTypes::Box);
|
||||
Q_ASSERT(args->_batch);
|
||||
|
||||
|
||||
if (!_procedural) {
|
||||
_procedural.reset(new Procedural(this->getUserData()));
|
||||
_procedural->_vertexSource = simple_vert;
|
||||
|
@ -64,4 +65,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor);
|
||||
}
|
||||
};
|
||||
static const auto triCount = DependencyManager::get<GeometryCache>()->getCubeTriangleCount();
|
||||
args->_details._trianglesRendered += triCount;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ RenderableModelEntityItem::~RenderableModelEntityItem() {
|
|||
}
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setDimensions(const glm::vec3 value) {
|
||||
void RenderableModelEntityItem::setDimensions(const glm::vec3& value) {
|
||||
_dimensionsInitialized = true;
|
||||
ModelEntityItem::setDimensions(value);
|
||||
}
|
||||
|
@ -565,20 +565,20 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
glm::quat RenderableModelEntityItem::getJointRotation(int index) const {
|
||||
glm::quat RenderableModelEntityItem::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||
if (_model) {
|
||||
glm::quat result;
|
||||
if (_model->getJointRotation(index, result)) {
|
||||
if (_model->getAbsoluteJointRotationInRigFrame(index, result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return glm::quat();
|
||||
}
|
||||
|
||||
glm::vec3 RenderableModelEntityItem::getJointTranslation(int index) const {
|
||||
glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||
if (_model) {
|
||||
glm::vec3 result;
|
||||
if (_model->getJointTranslation(index, result)) {
|
||||
if (_model->getAbsoluteJointTranslationInRigFrame(index, result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
|
||||
virtual ~RenderableModelEntityItem();
|
||||
|
||||
virtual void setDimensions(const glm::vec3 value) override;
|
||||
virtual void setDimensions(const glm::vec3& value) override;
|
||||
|
||||
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
|
||||
virtual bool setProperties(const EntityItemProperties& properties) override;
|
||||
|
@ -67,9 +67,9 @@ public:
|
|||
|
||||
virtual bool contains(const glm::vec3& point) const override;
|
||||
|
||||
// these are in the frame of this object
|
||||
virtual glm::quat getJointRotation(int index) const override;
|
||||
virtual glm::vec3 getJointTranslation(int index) const override;
|
||||
// these are in the frame of this object (model space)
|
||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
|
||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
|
||||
|
||||
private:
|
||||
void remapTextures();
|
||||
|
|
|
@ -71,4 +71,6 @@ void RenderableSphereEntityItem::render(RenderArgs* args) {
|
|||
batch.setModelTransform(Transform());
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch, modelTransform, sphereColor);
|
||||
}
|
||||
};
|
||||
static const auto triCount = DependencyManager::get<GeometryCache>()->getSphereTriangleCount();
|
||||
args->_details._trianglesRendered += triCount;
|
||||
}
|
||||
|
|
|
@ -1192,7 +1192,7 @@ const Transform EntityItem::getTransformToCenter() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setDimensions(const glm::vec3 value) {
|
||||
void EntityItem::setDimensions(const glm::vec3& value) {
|
||||
if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ public:
|
|||
|
||||
/// Dimensions in meters (0.0 - TREE_SCALE)
|
||||
inline const glm::vec3 getDimensions() const { return getScale(); }
|
||||
virtual void setDimensions(const glm::vec3 value);
|
||||
virtual void setDimensions(const glm::vec3& value);
|
||||
|
||||
float getGlowLevel() const { return _glowLevel; }
|
||||
void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; }
|
||||
|
@ -379,8 +379,8 @@ public:
|
|||
QList<EntityActionPointer> getActionsOfType(EntityActionType typeToGet);
|
||||
|
||||
// these are in the frame of this object
|
||||
virtual glm::quat getJointRotation(int index) const { return glm::quat(); }
|
||||
virtual glm::vec3 getJointTranslation(int index) const { return glm::vec3(0.0f); }
|
||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override { return glm::quat(); }
|
||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override { return glm::vec3(0.0f); }
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -1780,6 +1780,12 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (zPNeighborIDChanged()) {
|
||||
out += "zPNeighborID";
|
||||
}
|
||||
if (parentIDChanged()) {
|
||||
out += "parentID";
|
||||
}
|
||||
if (parentJointIndexChanged()) {
|
||||
out += "parentJointIndex";
|
||||
}
|
||||
|
||||
getAnimation().listChangedProperties(out);
|
||||
getKeyLight().listChangedProperties(out);
|
||||
|
@ -1790,6 +1796,6 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
return out;
|
||||
}
|
||||
|
||||
bool EntityItemProperties::parentDependentPropertyChanged() {
|
||||
bool EntityItemProperties::parentDependentPropertyChanged() const {
|
||||
return localPositionChanged() || positionChanged() || localRotationChanged() || rotationChanged();
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
|
||||
EntityPropertyFlags getChangedProperties() const;
|
||||
|
||||
bool parentDependentPropertyChanged(); // was there a changed in a property that requires parent info to interpret?
|
||||
bool parentDependentPropertyChanged() const; // was there a changed in a property that requires parent info to interpret?
|
||||
|
||||
AACube getMaximumAACube() const;
|
||||
AABox getAABox() const;
|
||||
|
|
|
@ -64,7 +64,7 @@ void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) {
|
|||
}
|
||||
}
|
||||
|
||||
EntityItemProperties convertLocationToScriptSemantics(EntityItemProperties entitySideProperties) {
|
||||
EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties& entitySideProperties) {
|
||||
// In EntityTree code, properties.position and properties.rotation are relative to the parent. In javascript,
|
||||
// they are in world-space. The local versions are put into localPosition and localRotation and position and
|
||||
// rotation are converted from local to world space.
|
||||
|
@ -85,7 +85,7 @@ EntityItemProperties convertLocationToScriptSemantics(EntityItemProperties entit
|
|||
}
|
||||
|
||||
|
||||
EntityItemProperties convertLocationFromScriptSemantics(EntityItemProperties scriptSideProperties) {
|
||||
EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperties& scriptSideProperties) {
|
||||
// convert position and rotation properties from world-space to local, unless localPosition and localRotation
|
||||
// are set. If they are set, they overwrite position and rotation.
|
||||
EntityItemProperties entitySideProperties = scriptSideProperties;
|
||||
|
@ -190,7 +190,7 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
|
|||
return convertLocationToScriptSemantics(results);
|
||||
}
|
||||
|
||||
QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties scriptSideProperties) {
|
||||
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
|
||||
EntityItemProperties properties = scriptSideProperties;
|
||||
EntityItemID entityID(id);
|
||||
// If we have a local entity tree set, then also update it.
|
||||
|
@ -201,17 +201,25 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties script
|
|||
|
||||
bool updatedEntity = false;
|
||||
_entityTree->withWriteLock([&] {
|
||||
if (scriptSideProperties.parentDependentPropertyChanged()) {
|
||||
// if the script sets a location property but didn't include parent information, grab the needed
|
||||
// properties from the entity.
|
||||
if (!scriptSideProperties.parentIDChanged() || !scriptSideProperties.parentJointIndexChanged()) {
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||
if (entity && !scriptSideProperties.parentIDChanged()) {
|
||||
properties.setParentID(entity->getParentID());
|
||||
}
|
||||
if (entity && !scriptSideProperties.parentJointIndexChanged()) {
|
||||
properties.setParentJointIndex(entity->getParentJointIndex());
|
||||
}
|
||||
if (scriptSideProperties.parentDependentPropertyChanged() ||
|
||||
scriptSideProperties.parentIDChanged() || scriptSideProperties.parentJointIndexChanged()) {
|
||||
// All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them.
|
||||
// If any of these changed, pull any missing properties from the entity.
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||
if (!entity) {
|
||||
return;
|
||||
}
|
||||
if (!scriptSideProperties.parentIDChanged()) {
|
||||
properties.setParentID(entity->getParentID());
|
||||
}
|
||||
if (!scriptSideProperties.parentJointIndexChanged()) {
|
||||
properties.setParentJointIndex(entity->getParentJointIndex());
|
||||
}
|
||||
if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) {
|
||||
properties.setPosition(entity->getPosition());
|
||||
}
|
||||
if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) {
|
||||
properties.setRotation(entity->getOrientation());
|
||||
}
|
||||
}
|
||||
properties = convertLocationFromScriptSemantics(properties);
|
||||
|
@ -746,82 +754,75 @@ QVariantMap EntityScriptingInterface::getActionArguments(const QUuid& entityID,
|
|||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 EntityScriptingInterface::voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords) {
|
||||
EntityItemPointer EntityScriptingInterface::checkForTreeEntityAndTypeMatch(const QUuid& entityID,
|
||||
EntityTypes::EntityType entityType) {
|
||||
if (!_entityTree) {
|
||||
return glm::vec3(0.0f);
|
||||
return EntityItemPointer();
|
||||
}
|
||||
|
||||
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||
if (!entity) {
|
||||
qCDebug(entities) << "EntityScriptingInterface::voxelCoordsToWorldCoords no entity with ID" << entityID;
|
||||
qDebug() << "EntityScriptingInterface::checkForTreeEntityAndTypeMatch - no entity with ID" << entityID;
|
||||
return entity;
|
||||
}
|
||||
|
||||
if (entityType != EntityTypes::Unknown && entity->getType() != entityType) {
|
||||
return EntityItemPointer();
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
glm::vec3 EntityScriptingInterface::voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords) {
|
||||
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) {
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity);
|
||||
return polyVoxEntity->voxelCoordsToWorldCoords(voxelCoords);
|
||||
} else {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
EntityTypes::EntityType entityType = entity->getType();
|
||||
if (entityType != EntityTypes::PolyVox) {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity);
|
||||
return polyVoxEntity->voxelCoordsToWorldCoords(voxelCoords);
|
||||
}
|
||||
|
||||
glm::vec3 EntityScriptingInterface::worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords) {
|
||||
if (!_entityTree) {
|
||||
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) {
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity);
|
||||
return polyVoxEntity->worldCoordsToVoxelCoords(worldCoords);
|
||||
} else {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||
if (!entity) {
|
||||
qCDebug(entities) << "EntityScriptingInterface::worldCoordsToVoxelCoords no entity with ID" << entityID;
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
EntityTypes::EntityType entityType = entity->getType();
|
||||
if (entityType != EntityTypes::PolyVox) {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity);
|
||||
return polyVoxEntity->worldCoordsToVoxelCoords(worldCoords);
|
||||
}
|
||||
|
||||
glm::vec3 EntityScriptingInterface::voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords) {
|
||||
if (!_entityTree) {
|
||||
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) {
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity);
|
||||
return polyVoxEntity->voxelCoordsToLocalCoords(voxelCoords);
|
||||
} else {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||
if (!entity) {
|
||||
qCDebug(entities) << "EntityScriptingInterface::voxelCoordsToLocalCoords no entity with ID" << entityID;
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
EntityTypes::EntityType entityType = entity->getType();
|
||||
if (entityType != EntityTypes::PolyVox) {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity);
|
||||
return polyVoxEntity->voxelCoordsToLocalCoords(voxelCoords);
|
||||
}
|
||||
|
||||
glm::vec3 EntityScriptingInterface::localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords) {
|
||||
if (!_entityTree) {
|
||||
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) {
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity);
|
||||
return polyVoxEntity->localCoordsToVoxelCoords(localCoords);
|
||||
} else {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||
if (!entity) {
|
||||
qCDebug(entities) << "EntityScriptingInterface::localCoordsToVoxelCoords no entity with ID" << entityID;
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
EntityTypes::EntityType entityType = entity->getType();
|
||||
if (entityType != EntityTypes::PolyVox) {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity);
|
||||
return polyVoxEntity->localCoordsToVoxelCoords(localCoords);
|
||||
}
|
||||
|
||||
glm::vec3 EntityScriptingInterface::getAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex) {
|
||||
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
||||
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
||||
return modelEntity->getAbsoluteJointTranslationInObjectFrame(jointIndex);
|
||||
} else {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
glm::quat EntityScriptingInterface::getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex) {
|
||||
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
||||
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
||||
return modelEntity->getAbsoluteJointRotationInObjectFrame(jointIndex);
|
||||
} else {
|
||||
return glm::quat();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ public slots:
|
|||
|
||||
/// edits a model updating only the included properties, will return the identified EntityItemID in case of
|
||||
/// successful edit, if the input entityID is for an unknown model this function will have no effect
|
||||
Q_INVOKABLE QUuid editEntity(QUuid entityID, EntityItemProperties properties);
|
||||
Q_INVOKABLE QUuid editEntity(QUuid entityID, const EntityItemProperties& properties);
|
||||
|
||||
/// deletes a model
|
||||
Q_INVOKABLE void deleteEntity(QUuid entityID);
|
||||
|
@ -149,6 +149,9 @@ public slots:
|
|||
Q_INVOKABLE glm::vec3 voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords);
|
||||
Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords);
|
||||
|
||||
Q_INVOKABLE glm::vec3 getAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex);
|
||||
Q_INVOKABLE glm::quat getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex);
|
||||
|
||||
signals:
|
||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||
|
||||
|
@ -179,6 +182,9 @@ private:
|
|||
bool setVoxels(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor);
|
||||
bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor);
|
||||
void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);
|
||||
|
||||
EntityItemPointer checkForTreeEntityAndTypeMatch(const QUuid& entityID,
|
||||
EntityTypes::EntityType entityType = EntityTypes::Unknown);
|
||||
|
||||
|
||||
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "EntitiesLogging.h"
|
||||
#include "RecurseOctreeToMapOperator.h"
|
||||
#include "LogHandler.h"
|
||||
#include "RemapIDOperator.h"
|
||||
|
||||
static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50;
|
||||
|
||||
|
@ -740,6 +741,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
|
|||
changedProperties[index] = QString("userData:") + changeHint;
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.parentJointIndexChanged()) {
|
||||
int index = changedProperties.indexOf("parentJointIndex");
|
||||
if (index >= 0) {
|
||||
quint16 value = properties.getParentJointIndex();
|
||||
changedProperties[index] = QString("parentJointIndex:") + QString::number((int)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
|
||||
|
@ -1186,6 +1195,11 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra
|
|||
return true;
|
||||
}
|
||||
|
||||
void EntityTree::remapIDs() {
|
||||
RemapIDOperator theOperator;
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
}
|
||||
|
||||
bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues) {
|
||||
if (! entityDescription.contains("Entities")) {
|
||||
entityDescription["Entities"] = QVariantList();
|
||||
|
|
|
@ -196,6 +196,8 @@ public:
|
|||
bool wantTerseEditLogging() const { return _wantTerseEditLogging; }
|
||||
void setWantTerseEditLogging(bool value) { _wantTerseEditLogging = value; }
|
||||
|
||||
void remapIDs();
|
||||
|
||||
bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues);
|
||||
bool readFromMap(QVariantMap& entityDescription);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem(
|
|||
_cutoff = PI;
|
||||
}
|
||||
|
||||
void LightEntityItem::setDimensions(const glm::vec3 value) {
|
||||
void LightEntityItem::setDimensions(const glm::vec3& value) {
|
||||
if (_isSpotlight) {
|
||||
// If we are a spotlight, treat the z value as our radius or length, and
|
||||
// recalculate the x/y dimensions to properly encapsulate the spotlight.
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
ALLOW_INSTANTIATION // This class can be instantiated
|
||||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
|
||||
virtual void setDimensions(const glm::vec3 value);
|
||||
virtual void setDimensions(const glm::vec3& value);
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
|
||||
|
|
|
@ -121,6 +121,9 @@ public:
|
|||
virtual bool shouldBePhysical() const;
|
||||
|
||||
static void cleanupLoadedAnimations();
|
||||
|
||||
virtual glm::vec3 getJointPosition(int jointIndex) const { return glm::vec3(); }
|
||||
virtual glm::quat getJointRotation(int jointIndex) const { return glm::quat(); }
|
||||
|
||||
private:
|
||||
void setAnimationSettings(const QString& value); // only called for old bitstream format
|
||||
|
|
33
libraries/entities/src/RemapIDOperator.cpp
Normal file
33
libraries/entities/src/RemapIDOperator.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// RemapIDOperator.cpp
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Seth Alves on 2015-12-6.
|
||||
// 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 "EntityTree.h"
|
||||
#include "RemapIDOperator.h"
|
||||
|
||||
QUuid RemapIDOperator::remap(const QUuid& oldID) {
|
||||
if (oldID.isNull()) {
|
||||
return oldID;
|
||||
}
|
||||
if (!_oldToNew.contains(oldID)) {
|
||||
_oldToNew[oldID] = QUuid::createUuid();
|
||||
}
|
||||
return _oldToNew[oldID];
|
||||
}
|
||||
|
||||
bool RemapIDOperator::postRecursion(OctreeElementPointer element) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) {
|
||||
entityItem->setID(remap(entityItem->getID()));
|
||||
entityItem->setParentID(remap(entityItem->getParentID()));
|
||||
});
|
||||
return true;
|
||||
}
|
30
libraries/entities/src/RemapIDOperator.h
Normal file
30
libraries/entities/src/RemapIDOperator.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// RemapIDOperator.h
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Seth Alves on 2015-12-6.
|
||||
// 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_RemapIDOperator_h
|
||||
#define hifi_RemapIDOperator_h
|
||||
|
||||
#include "Octree.h"
|
||||
|
||||
// this will change all the IDs in an EntityTree. Parent/Child relationships are maintained.
|
||||
|
||||
class RemapIDOperator : public RecurseOctreeOperator {
|
||||
public:
|
||||
RemapIDOperator() : RecurseOctreeOperator() {}
|
||||
~RemapIDOperator() {}
|
||||
virtual bool preRecursion(OctreeElementPointer element) { return true; }
|
||||
virtual bool postRecursion(OctreeElementPointer element);
|
||||
private:
|
||||
QUuid remap(const QUuid& oldID);
|
||||
QHash<QUuid, QUuid> _oldToNew;
|
||||
};
|
||||
|
||||
#endif // hifi_RemapIDOperator_h
|
|
@ -41,7 +41,7 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(en
|
|||
|
||||
const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f;
|
||||
|
||||
void TextEntityItem::setDimensions(const glm::vec3 value) {
|
||||
void TextEntityItem::setDimensions(const glm::vec3& value) {
|
||||
// NOTE: Text Entities always have a "depth" of 1cm.
|
||||
EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
ALLOW_INSTANTIATION // This class can be instantiated
|
||||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
|
||||
virtual void setDimensions(const glm::vec3 value);
|
||||
virtual void setDimensions(const glm::vec3& value);
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
|
|
|
@ -34,7 +34,7 @@ WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(enti
|
|||
|
||||
const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f;
|
||||
|
||||
void WebEntityItem::setDimensions(const glm::vec3 value) {
|
||||
void WebEntityItem::setDimensions(const glm::vec3& value) {
|
||||
// NOTE: Web Entities always have a "depth" of 1cm.
|
||||
EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH));
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
ALLOW_INSTANTIATION // This class can be instantiated
|
||||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
|
||||
virtual void setDimensions(const glm::vec3 value);
|
||||
virtual void setDimensions(const glm::vec3& value);
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
|
|
|
@ -337,6 +337,9 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
|||
// a timer with a small interval is used to get better performance.
|
||||
_updateTimer.setInterval(MIN_TIMER_MS);
|
||||
connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
||||
QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this]{
|
||||
disconnect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
||||
});
|
||||
_updateTimer.start();
|
||||
|
||||
_qmlComponent = new QQmlComponent(_qmlEngine);
|
||||
|
|
|
@ -35,16 +35,19 @@ vr::IVRSystem* acquireOpenVrSystem();
|
|||
void releaseOpenVrSystem();
|
||||
|
||||
|
||||
const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
|
||||
const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
|
||||
static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
|
||||
static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f,
|
||||
CONTROLLER_LENGTH_OFFSET / 2.0f,
|
||||
CONTROLLER_LENGTH_OFFSET * 2.0f);
|
||||
static const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
|
||||
|
||||
static const QString MENU_PARENT = "Avatar";
|
||||
static const QString MENU_NAME = "Vive Controllers";
|
||||
static const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
|
||||
static const QString RENDER_CONTROLLERS = "Render Hand Controllers";
|
||||
|
||||
const QString ViveControllerManager::NAME = "OpenVR";
|
||||
|
||||
const QString MENU_PARENT = "Avatar";
|
||||
const QString MENU_NAME = "Vive Controllers";
|
||||
const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
|
||||
const QString RENDER_CONTROLLERS = "Render Hand Controllers";
|
||||
|
||||
bool ViveControllerManager::isSupported() const {
|
||||
#ifdef Q_OS_WIN
|
||||
auto hmd = acquireOpenVrSystem();
|
||||
|
@ -320,14 +323,11 @@ void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool
|
|||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::handlePoseEvent(const mat4& mat, bool left) {
|
||||
glm::vec3 position = extractTranslation(mat);
|
||||
glm::quat rotation = glm::quat_cast(mat);
|
||||
|
||||
// When the sensor-to-world rotation is identity the coordinate axes look like this:
|
||||
//
|
||||
// user
|
||||
// forward
|
||||
// z
|
||||
// -z
|
||||
// |
|
||||
// y| user
|
||||
// y o----x right
|
||||
|
@ -372,17 +372,27 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const mat4& mat, bool l
|
|||
// Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX)
|
||||
//
|
||||
// Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX)
|
||||
|
||||
const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
float sign = left ? -1.0f : 1.0f;
|
||||
const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
const glm::quat offset = glm::inverse(signedQuaterZ * eighthX);
|
||||
rotation = rotation * offset * yFlip * quarterX;
|
||||
|
||||
position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET);
|
||||
static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y);
|
||||
static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X);
|
||||
static const glm::quat viveToHand = yFlip * quarterX;
|
||||
|
||||
static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z);
|
||||
static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z);
|
||||
static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X);
|
||||
|
||||
static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand;
|
||||
static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand;
|
||||
|
||||
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
|
||||
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
|
||||
|
||||
glm::vec3 position = extractTranslation(mat);
|
||||
glm::quat rotation = glm::quat_cast(mat);
|
||||
|
||||
position += rotation * (left ? leftTranslationOffset : rightTranslationOffset);
|
||||
rotation = rotation * (left ? leftRotationOffset : rightRotationOffset);
|
||||
|
||||
_poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = controller::Pose(position, rotation);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ void AssetResourceRequest::doSend() {
|
|||
}
|
||||
|
||||
connect(_assetRequest, &AssetRequest::progress, this, &AssetResourceRequest::progress);
|
||||
connect(_assetRequest, &AssetRequest::finished, [this](AssetRequest* req) {
|
||||
connect(_assetRequest, &AssetRequest::finished, this, [this](AssetRequest* req) {
|
||||
Q_ASSERT(_state == InProgress);
|
||||
Q_ASSERT(req == _assetRequest);
|
||||
Q_ASSERT(req->getState() == AssetRequest::Finished);
|
||||
|
|
|
@ -63,6 +63,7 @@ void AssetUpload::start() {
|
|||
|
||||
// file opened, read the data and grab the extension
|
||||
_extension = QFileInfo(_filename).suffix();
|
||||
_extension = _extension.toLower();
|
||||
|
||||
_data = file.readAll();
|
||||
} else {
|
||||
|
|
|
@ -296,8 +296,6 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer<ReceivedMessage> recei
|
|||
if (matchingNode) {
|
||||
emit dataReceived(matchingNode->getType(), receivedMessage->getSize());
|
||||
matchingNode->recordBytesReceived(receivedMessage->getSize());
|
||||
Node* n = matchingNode.data();
|
||||
auto addr = n->getActiveSocket();
|
||||
|
||||
QMetaMethod metaMethod = listener.method;
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ static const int HEAD_DATA_SIZE = 512;
|
|||
ReceivedMessage::ReceivedMessage(const NLPacketList& packetList)
|
||||
: _data(packetList.getMessage()),
|
||||
_headData(_data.mid(0, HEAD_DATA_SIZE)),
|
||||
_sourceID(packetList.getSourceID()),
|
||||
_numPackets(packetList.getNumPackets()),
|
||||
_sourceID(packetList.getSourceID()),
|
||||
_packetType(packetList.getType()),
|
||||
_packetVersion(packetList.getVersion()),
|
||||
_senderSockAddr(packetList.getSenderSockAddr()),
|
||||
|
@ -34,8 +34,8 @@ ReceivedMessage::ReceivedMessage(const NLPacketList& packetList)
|
|||
ReceivedMessage::ReceivedMessage(NLPacket& packet)
|
||||
: _data(packet.readAll()),
|
||||
_headData(_data.mid(0, HEAD_DATA_SIZE)),
|
||||
_sourceID(packet.getSourceID()),
|
||||
_numPackets(1),
|
||||
_sourceID(packet.getSourceID()),
|
||||
_packetType(packet.getType()),
|
||||
_packetVersion(packet.getVersion()),
|
||||
_senderSockAddr(packet.getSenderSockAddr()),
|
||||
|
|
|
@ -140,6 +140,7 @@ void ObjectMotionState::updateCCDConfiguration() {
|
|||
// TODO: Ideally the swept sphere radius would be contained by the object. Using the bounding sphere
|
||||
// radius works well for spherical objects, but may cause issues with other shapes. For arbitrary
|
||||
// objects we may want to consider a different approach, such as grouping rigid bodies together.
|
||||
|
||||
_body->setCcdSweptSphereRadius(radius);
|
||||
} else {
|
||||
// Disable CCD
|
||||
|
|
|
@ -58,9 +58,7 @@ public:
|
|||
/// By default, all HMDs are stereo
|
||||
virtual bool isStereo() const { return isHmd(); }
|
||||
virtual bool isThrottled() const { return false; }
|
||||
virtual bool isVSynchronized() const { return true; } // false when throttled or run by non vsync timer
|
||||
virtual float getTargetFrameRate() { return 0.0f; }
|
||||
virtual float getTargetFramePeriod() { return 0.0f; }
|
||||
|
||||
// Rendering support
|
||||
|
||||
|
|
|
@ -214,6 +214,19 @@ VertexVector tesselate(const VertexVector& startingTriangles, int count) {
|
|||
return triangles;
|
||||
}
|
||||
|
||||
size_t GeometryCache::getShapeTriangleCount(Shape shape) {
|
||||
return _shapes[shape]._indexCount / VERTICES_PER_TRIANGLE;
|
||||
}
|
||||
|
||||
size_t GeometryCache::getSphereTriangleCount() {
|
||||
return getShapeTriangleCount(Sphere);
|
||||
}
|
||||
|
||||
size_t GeometryCache::getCubeTriangleCount() {
|
||||
return getShapeTriangleCount(Cube);
|
||||
}
|
||||
|
||||
|
||||
// FIXME solids need per-face vertices, but smooth shaded
|
||||
// components do not. Find a way to support using draw elements
|
||||
// or draw arrays as appropriate
|
||||
|
@ -1727,3 +1740,4 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
|
|||
batch.setPipeline(_standardDrawPipeline);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -151,16 +151,19 @@ public:
|
|||
void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& transformBuffer, gpu::BufferPointer& colorBuffer);
|
||||
void renderShape(gpu::Batch& batch, Shape shape);
|
||||
void renderWireShape(gpu::Batch& batch, Shape shape);
|
||||
size_t getShapeTriangleCount(Shape shape);
|
||||
|
||||
void renderCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer);
|
||||
void renderWireCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer);
|
||||
void renderCube(gpu::Batch& batch);
|
||||
void renderWireCube(gpu::Batch& batch);
|
||||
size_t getCubeTriangleCount();
|
||||
|
||||
void renderSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer);
|
||||
void renderWireSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer);
|
||||
void renderSphere(gpu::Batch& batch);
|
||||
void renderWireSphere(gpu::Batch& batch);
|
||||
size_t getSphereTriangleCount();
|
||||
|
||||
void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color);
|
||||
void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID);
|
||||
|
|
|
@ -544,6 +544,7 @@ void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::Pendin
|
|||
pendingChanges.removeItem(item);
|
||||
}
|
||||
_renderItems.clear();
|
||||
_renderItemsSet.clear();
|
||||
_readyWhenAdded = false;
|
||||
}
|
||||
|
||||
|
@ -765,6 +766,14 @@ bool Model::getJointTranslation(int jointIndex, glm::vec3& translation) const {
|
|||
return _rig->getJointTranslation(jointIndex, translation);
|
||||
}
|
||||
|
||||
bool Model::getAbsoluteJointRotationInRigFrame(int jointIndex, glm::quat& rotation) const {
|
||||
return _rig->getAbsoluteJointRotationInRigFrame(jointIndex, rotation);
|
||||
}
|
||||
|
||||
bool Model::getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& translation) const {
|
||||
return _rig->getAbsoluteJointTranslationInRigFrame(jointIndex, translation);
|
||||
}
|
||||
|
||||
bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const {
|
||||
return _rig->getJointCombinedRotation(jointIndex, rotation, _rotation);
|
||||
}
|
||||
|
|
|
@ -166,6 +166,10 @@ public:
|
|||
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
|
||||
bool getJointTranslation(int jointIndex, glm::vec3& translation) const;
|
||||
|
||||
// model frame
|
||||
bool getAbsoluteJointRotationInRigFrame(int jointIndex, glm::quat& rotation) const;
|
||||
bool getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& translation) const;
|
||||
|
||||
/// Returns the index of the parent of the indexed joint, or -1 if not found.
|
||||
int getParentJointIndex(int jointIndex) const;
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName
|
|||
const auto exception = engine.uncaughtException().toString();
|
||||
const auto line = QString::number(engine.uncaughtExceptionLineNumber());
|
||||
engine.clearExceptions();
|
||||
|
||||
|
||||
auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
|
||||
if (!backtrace.empty()) {
|
||||
static const auto lineSeparator = "\n ";
|
||||
|
@ -326,7 +326,7 @@ void ScriptEngine::init() {
|
|||
}
|
||||
|
||||
_isInitialized = true;
|
||||
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
entityScriptingInterface->init();
|
||||
|
||||
|
@ -392,7 +392,7 @@ void ScriptEngine::init() {
|
|||
registerGlobalObject("Recording", recordingInterface.data());
|
||||
|
||||
registerGlobalObject("Assets", &_assetScriptingInterface);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
|
||||
|
@ -401,8 +401,8 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
|
|||
qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
|
||||
#endif
|
||||
QMetaObject::invokeMethod(this, "registerValue",
|
||||
Q_ARG(const QString&, valueName),
|
||||
Q_ARG(QScriptValue, value));
|
||||
Q_ARG(const QString&, valueName),
|
||||
Q_ARG(QScriptValue, value));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -428,17 +428,17 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
|
|||
|
||||
void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
|
||||
#endif
|
||||
#endif
|
||||
QMetaObject::invokeMethod(this, "registerGlobalObject",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QObject*, object));
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QObject*, object));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!globalObject().property(name).isValid()) {
|
||||
if (object) {
|
||||
|
@ -452,18 +452,18 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
|||
|
||||
void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
|
||||
#endif
|
||||
#endif
|
||||
QMetaObject::invokeMethod(this, "registerFunction",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
||||
Q_ARG(int, numArguments));
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
||||
Q_ARG(int, numArguments));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QScriptValue scriptFun = newFunction(functionSignature, numArguments);
|
||||
globalObject().setProperty(name, scriptFun);
|
||||
|
@ -471,18 +471,18 @@ void ScriptEngine::registerFunction(const QString& name, QScriptEngine::Function
|
|||
|
||||
void ScriptEngine::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name;
|
||||
#endif
|
||||
#endif
|
||||
QMetaObject::invokeMethod(this, "registerFunction",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
||||
Q_ARG(int, numArguments));
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
||||
Q_ARG(int, numArguments));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QScriptValue object = globalObject().property(parent);
|
||||
if (object.isValid()) {
|
||||
|
@ -492,22 +492,22 @@ void ScriptEngine::registerFunction(const QString& parent, const QString& name,
|
|||
}
|
||||
|
||||
void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter,
|
||||
QScriptEngine::FunctionSignature setter, const QString& parent) {
|
||||
QScriptEngine::FunctionSignature setter, const QString& parent) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
" name:" << name << "parent:" << parent;
|
||||
#endif
|
||||
" name:" << name << "parent:" << parent;
|
||||
#endif
|
||||
QMetaObject::invokeMethod(this, "registerGetterSetter",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, getter),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, setter),
|
||||
Q_ARG(const QString&, parent));
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, getter),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, setter),
|
||||
Q_ARG(const QString&, parent));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QScriptValue setterFunction = newFunction(setter, 1);
|
||||
QScriptValue getterFunction = newFunction(getter);
|
||||
|
@ -527,19 +527,19 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func
|
|||
// Unregister the handlers for this eventName and entityID.
|
||||
void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << " eventName:" << eventName;
|
||||
#endif
|
||||
"entityID:" << entityID << " eventName:" << eventName;
|
||||
#endif
|
||||
QMetaObject::invokeMethod(this, "removeEventHandler",
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, eventName),
|
||||
Q_ARG(QScriptValue, handler));
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, eventName),
|
||||
Q_ARG(QScriptValue, handler));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!_registeredHandlers.contains(entityID)) {
|
||||
return;
|
||||
|
@ -557,20 +557,20 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin
|
|||
// Register the handler.
|
||||
void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << " eventName:" << eventName;
|
||||
#endif
|
||||
"entityID:" << entityID << " eventName:" << eventName;
|
||||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "addEventHandler",
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, eventName),
|
||||
Q_ARG(QScriptValue, handler));
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, eventName),
|
||||
Q_ARG(QScriptValue, handler));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script...
|
||||
// Connect up ALL the handlers to the global entities object's signals.
|
||||
|
@ -579,7 +579,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
|
|||
connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) {
|
||||
_registeredHandlers.remove(entityID);
|
||||
});
|
||||
|
||||
|
||||
// Two common cases of event handler, differing only in argument signature.
|
||||
using SingleEntityHandler = std::function<void(const EntityItemID&)>;
|
||||
auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler {
|
||||
|
@ -587,22 +587,22 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
|
|||
forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) });
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
using MouseHandler = std::function<void(const EntityItemID&, const MouseEvent&)>;
|
||||
auto makeMouseHandler = [this](QString eventName) -> MouseHandler {
|
||||
return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) {
|
||||
forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) });
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
using CollisionHandler = std::function<void(const EntityItemID&, const EntityItemID&, const Collision&)>;
|
||||
auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler {
|
||||
return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) {
|
||||
forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this),
|
||||
collisionToScriptValue(this, collision) });
|
||||
collisionToScriptValue(this, collision) });
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity"));
|
||||
connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity"));
|
||||
|
||||
|
@ -635,18 +635,18 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi
|
|||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QScriptValue result;
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber;
|
||||
#endif
|
||||
#endif
|
||||
QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QScriptValue, result),
|
||||
Q_ARG(const QString&, sourceCode),
|
||||
Q_ARG(const QString&, fileName),
|
||||
Q_ARG(int, lineNumber));
|
||||
Q_RETURN_ARG(QScriptValue, result),
|
||||
Q_ARG(const QString&, sourceCode),
|
||||
Q_ARG(const QString&, fileName),
|
||||
Q_ARG(int, lineNumber));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Check syntax
|
||||
const QScriptProgram program(sourceCode, fileName, lineNumber);
|
||||
if (!hasCorrectSyntax(program)) {
|
||||
|
@ -656,7 +656,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi
|
|||
++_evaluatesPending;
|
||||
const auto result = QScriptEngine::evaluate(program);
|
||||
--_evaluatesPending;
|
||||
|
||||
|
||||
const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName());
|
||||
if (_wantSignals) {
|
||||
emit evaluationFinished(result, hadUncaughtException);
|
||||
|
@ -668,7 +668,7 @@ void ScriptEngine::run() {
|
|||
if (_stoppingAllScripts) {
|
||||
return; // bail early - avoid setting state in init(), as evaluate() will bail too
|
||||
}
|
||||
|
||||
|
||||
if (!_isInitialized) {
|
||||
init();
|
||||
}
|
||||
|
@ -899,7 +899,7 @@ void ScriptEngine::print(const QString& message) {
|
|||
void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {
|
||||
if (_stoppingAllScripts) {
|
||||
qCDebug(scriptengine) << "Script.include() while shutting down is ignored..."
|
||||
<< "includeFiles:" << includeFiles << "parent script:" << getFilename();
|
||||
<< "includeFiles:" << includeFiles << "parent script:" << getFilename();
|
||||
return; // bail early
|
||||
}
|
||||
QList<QUrl> urls;
|
||||
|
@ -955,7 +955,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac
|
|||
void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
|
||||
if (_stoppingAllScripts) {
|
||||
qCDebug(scriptengine) << "Script.include() while shutting down is ignored... "
|
||||
<< "includeFile:" << includeFile << "parent script:" << getFilename();
|
||||
<< "includeFile:" << includeFile << "parent script:" << getFilename();
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
|
@ -970,7 +970,7 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
|
|||
void ScriptEngine::load(const QString& loadFile) {
|
||||
if (_stoppingAllScripts) {
|
||||
qCDebug(scriptengine) << "Script.load() while shutting down is ignored... "
|
||||
<< "loadFile:" << loadFile << "parent script:" << getFilename();
|
||||
<< "loadFile:" << loadFile << "parent script:" << getFilename();
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
|
@ -1014,58 +1014,63 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin
|
|||
// for the download
|
||||
void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread ["
|
||||
<< QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "loadEntityScript",
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, entityScript),
|
||||
Q_ARG(bool, forceRedownload));
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, entityScript),
|
||||
Q_ARG(bool, forceRedownload));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we've been called our known entityScripts should not know about us..
|
||||
assert(!_entityScripts.contains(entityID));
|
||||
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread ["
|
||||
<< QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
DependencyManager::get<ScriptCache>()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread ["
|
||||
<< QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
|
||||
this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);
|
||||
}, forceRedownload);
|
||||
this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);
|
||||
}, forceRedownload);
|
||||
}
|
||||
|
||||
// since all of these operations can be asynch we will always do the actual work in the response handler
|
||||
// for the download
|
||||
void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success;
|
||||
#endif
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread ["
|
||||
<< QThread::currentThread() << "], invoking on correct thread [" << thread()
|
||||
<< "] " "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:"
|
||||
<< contents << "isURL:" << isURL << "success:" << success;
|
||||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "entityScriptContentAvailable",
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, scriptOrURL),
|
||||
Q_ARG(const QString&, contents),
|
||||
Q_ARG(bool, isURL),
|
||||
Q_ARG(bool, success));
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, scriptOrURL),
|
||||
Q_ARG(const QString&, contents),
|
||||
Q_ARG(bool, isURL),
|
||||
Q_ARG(bool, success));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||
bool isFileUrl = isURL && scriptOrURL.startsWith("file://");
|
||||
|
@ -1088,14 +1093,16 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
|||
if (hadUncaughtExceptions(sandbox, program.fileName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!testConstructor.isFunction()) {
|
||||
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n"
|
||||
" NOT CONSTRUCTOR\n"
|
||||
" SCRIPT:" << scriptOrURL;
|
||||
" NOT CONSTRUCTOR\n"
|
||||
" SCRIPT:" << scriptOrURL;
|
||||
|
||||
if (!isFileUrl) {
|
||||
scriptCache->addScriptToBadScriptList(scriptOrURL);
|
||||
}
|
||||
|
||||
return; // done processing script
|
||||
}
|
||||
|
||||
|
@ -1119,19 +1126,19 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
|||
|
||||
void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "unloadEntityScript",
|
||||
Q_ARG(const EntityItemID&, entityID));
|
||||
Q_ARG(const EntityItemID&, entityID));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (_entityScripts.contains(entityID)) {
|
||||
callEntityScriptMethod(entityID, "unload");
|
||||
|
@ -1193,21 +1200,21 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) {
|
|||
|
||||
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "methodName:" << methodName;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "callEntityScriptMethod",
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, methodName),
|
||||
Q_ARG(const QStringList&, params));
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, methodName),
|
||||
Q_ARG(const QStringList&, params));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "methodName:" << methodName;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
refreshFileScript(entityID);
|
||||
if (_entityScripts.contains(entityID)) {
|
||||
|
@ -1225,21 +1232,21 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
|
|||
|
||||
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "callEntityScriptMethod",
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, methodName),
|
||||
Q_ARG(const MouseEvent&, event));
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, methodName),
|
||||
Q_ARG(const MouseEvent&, event));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
refreshFileScript(entityID);
|
||||
if (_entityScripts.contains(entityID)) {
|
||||
|
@ -1257,23 +1264,23 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
|
|||
|
||||
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "callEntityScriptMethod",
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, methodName),
|
||||
Q_ARG(const EntityItemID&, otherID),
|
||||
Q_ARG(const Collision&, collision));
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(const QString&, methodName),
|
||||
Q_ARG(const EntityItemID&, otherID),
|
||||
Q_ARG(const Collision&, collision));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
|
||||
"entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
refreshFileScript(entityID);
|
||||
if (_entityScripts.contains(entityID)) {
|
||||
EntityScriptDetails details = _entityScripts[entityID];
|
||||
|
@ -1286,4 +1293,4 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
|
|||
entityScript.property(methodName).call(entityScript, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -67,7 +67,7 @@ public:
|
|||
|
||||
/// run the script in the callers thread, exit when stop() is called.
|
||||
void run();
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can
|
||||
// properly ensure they are only called on the correct thread
|
||||
|
@ -77,14 +77,14 @@ public:
|
|||
|
||||
/// registers a global getter/setter
|
||||
Q_INVOKABLE void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter,
|
||||
QScriptEngine::FunctionSignature setter, const QString& parent = QString(""));
|
||||
|
||||
QScriptEngine::FunctionSignature setter, const QString& parent = QString(""));
|
||||
|
||||
/// register a global function
|
||||
Q_INVOKABLE void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1);
|
||||
|
||||
/// register a function as a method on a previously registered global object
|
||||
Q_INVOKABLE void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature fun,
|
||||
int numArguments = -1);
|
||||
int numArguments = -1);
|
||||
|
||||
/// registers a global object by name
|
||||
Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value);
|
||||
|
@ -93,12 +93,12 @@ public:
|
|||
Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName, int lineNumber = 1); // this is also used by the script tool widget
|
||||
|
||||
/// if the script engine is not already running, this will download the URL and start the process of seting it up
|
||||
/// to run... NOTE - this is used by Application currently to load the url. We don't really want it to be exposed
|
||||
/// to run... NOTE - this is used by Application currently to load the url. We don't really want it to be exposed
|
||||
/// to scripts. we may not need this to be invokable
|
||||
void loadURL(const QUrl& scriptURL, bool reload);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE - these are intended to be public interfaces available to scripts
|
||||
// NOTE - these are intended to be public interfaces available to scripts
|
||||
Q_INVOKABLE void addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler);
|
||||
Q_INVOKABLE void removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler);
|
||||
|
||||
|
@ -209,4 +209,4 @@ protected:
|
|||
static bool _stoppingAllScripts;
|
||||
};
|
||||
|
||||
#endif // hifi_ScriptEngine_h
|
||||
#endif // hifi_ScriptEngine_h
|
|
@ -65,7 +65,7 @@ void PIDController::updateHistory(float measuredValue, float dt, float error, fl
|
|||
}
|
||||
}
|
||||
void PIDController::reportHistory() {
|
||||
qCDebug(shared) << _label << "measured dt FIXME || error accumulated changed || p i d controlled";
|
||||
qCDebug(shared) << _label << "measured dt || error accumulated changed || p i d controlled";
|
||||
for (int i = 0; i < _history.size(); i++) {
|
||||
Row& row = _history[i];
|
||||
qCDebug(shared) << row.measured << row.dt <<
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS.
|
||||
const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f;
|
||||
const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f;
|
||||
|
||||
// return incremental rotation (Bullet-style) caused by angularVelocity over timeStep
|
||||
glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep);
|
||||
|
|
|
@ -91,7 +91,7 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const {
|
|||
});
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setParentID(const QUuid parentID) {
|
||||
void SpatiallyNestable::setParentID(const QUuid& parentID) {
|
||||
if (_parentID != parentID) {
|
||||
_parentID = parentID;
|
||||
_parentKnowsMe = false;
|
||||
|
@ -99,7 +99,7 @@ void SpatiallyNestable::setParentID(const QUuid parentID) {
|
|||
parentChanged();
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) {
|
||||
glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
Transform parentTransform;
|
||||
if (parentFinder) {
|
||||
|
@ -122,7 +122,7 @@ glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, in
|
|||
return result.getTranslation();
|
||||
}
|
||||
|
||||
glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex) {
|
||||
glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
Transform parentTransform;
|
||||
if (parentFinder) {
|
||||
|
@ -144,7 +144,7 @@ glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID,
|
|||
return result.getRotation();
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex) {
|
||||
glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
Transform parentTransform;
|
||||
if (parentFinder) {
|
||||
|
@ -162,7 +162,7 @@ glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, in
|
|||
return result.getTranslation();
|
||||
}
|
||||
|
||||
glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex) {
|
||||
glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
Transform parentTransform;
|
||||
if (parentFinder) {
|
||||
|
@ -188,7 +188,7 @@ glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const {
|
|||
return getTransform(jointIndex).getTranslation();
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setPosition(glm::vec3 position) {
|
||||
void SpatiallyNestable::setPosition(const glm::vec3& position) {
|
||||
Transform parentTransform = getParentTransform();
|
||||
Transform myWorldTransform;
|
||||
_transformLock.withWriteLock([&] {
|
||||
|
@ -207,7 +207,7 @@ glm::quat SpatiallyNestable::getOrientation(int jointIndex) const {
|
|||
return getTransform(jointIndex).getRotation();
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setOrientation(glm::quat orientation) {
|
||||
void SpatiallyNestable::setOrientation(const glm::quat& orientation) {
|
||||
Transform parentTransform = getParentTransform();
|
||||
Transform myWorldTransform;
|
||||
_transformLock.withWriteLock([&] {
|
||||
|
@ -232,13 +232,13 @@ const Transform SpatiallyNestable::getTransform(int jointIndex) const {
|
|||
// this returns the world-space transform for this object. It finds its parent's transform (which may
|
||||
// cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it.
|
||||
Transform worldTransform = getTransform();
|
||||
Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex);
|
||||
Transform jointInObjectFrame = getAbsoluteJointTransformInObjectFrame(jointIndex);
|
||||
Transform jointInWorldFrame;
|
||||
Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame);
|
||||
return jointInWorldFrame;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setTransform(const Transform transform) {
|
||||
void SpatiallyNestable::setTransform(const Transform& transform) {
|
||||
Transform parentTransform = getParentTransform();
|
||||
_transformLock.withWriteLock([&] {
|
||||
Transform::inverseMult(_transform, parentTransform, transform);
|
||||
|
@ -259,7 +259,7 @@ glm::vec3 SpatiallyNestable::getScale(int jointIndex) const {
|
|||
return getScale();
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setScale(glm::vec3 scale) {
|
||||
void SpatiallyNestable::setScale(const glm::vec3& scale) {
|
||||
_transformLock.withWriteLock([&] {
|
||||
_transform.setScale(scale);
|
||||
});
|
||||
|
@ -274,7 +274,7 @@ const Transform SpatiallyNestable::getLocalTransform() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalTransform(const Transform transform) {
|
||||
void SpatiallyNestable::setLocalTransform(const Transform& transform) {
|
||||
_transformLock.withWriteLock([&] {
|
||||
_transform = transform;
|
||||
});
|
||||
|
@ -289,7 +289,7 @@ glm::vec3 SpatiallyNestable::getLocalPosition() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalPosition(glm::vec3 position) {
|
||||
void SpatiallyNestable::setLocalPosition(const glm::vec3& position) {
|
||||
_transformLock.withWriteLock([&] {
|
||||
_transform.setTranslation(position);
|
||||
});
|
||||
|
@ -304,7 +304,7 @@ glm::quat SpatiallyNestable::getLocalOrientation() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalOrientation(glm::quat orientation) {
|
||||
void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) {
|
||||
_transformLock.withWriteLock([&] {
|
||||
_transform.setRotation(orientation);
|
||||
});
|
||||
|
@ -319,7 +319,7 @@ glm::vec3 SpatiallyNestable::getLocalScale() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalScale(glm::vec3 scale) {
|
||||
void SpatiallyNestable::setLocalScale(const glm::vec3& scale) {
|
||||
_transformLock.withWriteLock([&] {
|
||||
_transform.setScale(scale);
|
||||
});
|
||||
|
@ -339,13 +339,13 @@ QList<SpatiallyNestablePointer> SpatiallyNestable::getChildren() const {
|
|||
return children;
|
||||
}
|
||||
|
||||
const Transform SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const {
|
||||
Transform jointInObjectFrame;
|
||||
glm::vec3 position = getJointTranslation(jointIndex);
|
||||
glm::quat orientation = getJointRotation(jointIndex);
|
||||
jointInObjectFrame.setRotation(orientation);
|
||||
jointInObjectFrame.setTranslation(position);
|
||||
return jointInObjectFrame;
|
||||
const Transform SpatiallyNestable::getAbsoluteJointTransformInObjectFrame(int jointIndex) const {
|
||||
Transform jointTransformInObjectFrame;
|
||||
glm::vec3 position = getAbsoluteJointTranslationInObjectFrame(jointIndex);
|
||||
glm::quat orientation = getAbsoluteJointRotationInObjectFrame(jointIndex);
|
||||
jointTransformInObjectFrame.setRotation(orientation);
|
||||
jointTransformInObjectFrame.setTranslation(position);
|
||||
return jointTransformInObjectFrame;
|
||||
}
|
||||
|
||||
SpatiallyNestablePointer SpatiallyNestable::getThisPointer() const {
|
||||
|
|
|
@ -42,32 +42,32 @@ public:
|
|||
virtual void setID(const QUuid& id) { _id = id; }
|
||||
|
||||
virtual const QUuid getParentID() const { return _parentID; }
|
||||
virtual void setParentID(const QUuid parentID);
|
||||
virtual void setParentID(const QUuid& parentID);
|
||||
|
||||
virtual quint16 getParentJointIndex() const { return _parentJointIndex; }
|
||||
virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; }
|
||||
|
||||
static glm::vec3 worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex);
|
||||
static glm::quat worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex);
|
||||
static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex);
|
||||
static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex);
|
||||
|
||||
static glm::vec3 localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex);
|
||||
static glm::quat localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex);
|
||||
static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex);
|
||||
static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex);
|
||||
|
||||
// world frame
|
||||
virtual const Transform getTransform() const;
|
||||
virtual void setTransform(const Transform transform);
|
||||
virtual void setTransform(const Transform& transform);
|
||||
|
||||
virtual Transform getParentTransform() const;
|
||||
|
||||
virtual glm::vec3 getPosition() const;
|
||||
virtual void setPosition(glm::vec3 position);
|
||||
virtual void setPosition(const glm::vec3& position);
|
||||
|
||||
virtual glm::quat getOrientation() const;
|
||||
virtual glm::quat getOrientation(int jointIndex) const;
|
||||
virtual void setOrientation(glm::quat orientation);
|
||||
virtual void setOrientation(const glm::quat& orientation);
|
||||
|
||||
virtual glm::vec3 getScale() const;
|
||||
virtual void setScale(glm::vec3 scale);
|
||||
virtual void setScale(const glm::vec3& scale);
|
||||
|
||||
// get world-frame values for a specific joint
|
||||
virtual const Transform getTransform(int jointIndex) const;
|
||||
|
@ -76,24 +76,24 @@ public:
|
|||
|
||||
// object's parent's frame
|
||||
virtual const Transform getLocalTransform() const;
|
||||
virtual void setLocalTransform(const Transform transform);
|
||||
virtual void setLocalTransform(const Transform& transform);
|
||||
|
||||
virtual glm::vec3 getLocalPosition() const;
|
||||
virtual void setLocalPosition(glm::vec3 position);
|
||||
virtual void setLocalPosition(const glm::vec3& position);
|
||||
|
||||
virtual glm::quat getLocalOrientation() const;
|
||||
virtual void setLocalOrientation(glm::quat orientation);
|
||||
virtual void setLocalOrientation(const glm::quat& orientation);
|
||||
|
||||
virtual glm::vec3 getLocalScale() const;
|
||||
virtual void setLocalScale(glm::vec3 scale);
|
||||
virtual void setLocalScale(const glm::vec3& scale);
|
||||
|
||||
QList<SpatiallyNestablePointer> getChildren() const;
|
||||
NestableTypes::NestableType getNestableType() const { return _nestableType; }
|
||||
|
||||
// this object's frame
|
||||
virtual const Transform getJointTransformInObjectFrame(int jointIndex) const;
|
||||
virtual glm::quat getJointRotation(int index) const { assert(false); return glm::quat(); }
|
||||
virtual glm::vec3 getJointTranslation(int index) const { assert(false); return glm::vec3(); }
|
||||
virtual const Transform getAbsoluteJointTransformInObjectFrame(int jointIndex) const;
|
||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const { assert(false); return glm::quat(); }
|
||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const { assert(false); return glm::vec3(); }
|
||||
|
||||
SpatiallyNestablePointer getThisPointer() const;
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ public:
|
|||
virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final;
|
||||
|
||||
virtual float getTargetFrameRate() override { return TARGET_RATE_Oculus; }
|
||||
virtual float getTargetFramePeriod() override { return 1.0f / TARGET_RATE_Oculus; }
|
||||
|
||||
protected:
|
||||
virtual void internalPresent() override;
|
||||
|
|
|
@ -28,7 +28,6 @@ public:
|
|||
virtual int getHmdScreen() const override;
|
||||
|
||||
virtual float getTargetFrameRate() override { return TARGET_RATE_OculusLegacy; }
|
||||
virtual float getTargetFramePeriod() override { return 1.0f / TARGET_RATE_OculusLegacy; }
|
||||
|
||||
// Stereo specific methods
|
||||
virtual bool isHmd() const override { return true; }
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
set(TARGET_NAME "stack-manager")
|
||||
set(BUILD_BUNDLE YES)
|
||||
setup_hifi_project(Widgets Gui Svg Core Network WebKitWidgets)
|
||||
add_dependencies(${TARGET_NAME} assignment-client domain-server)
|
||||
include_application_version()
|
||||
|
||||
if (WIN32)
|
||||
target_zlib()
|
||||
endif ()
|
||||
target_quazip()
|
||||
|
||||
set_target_properties(
|
||||
${TARGET_NAME} PROPERTIES
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
if (UNIX)
|
||||
set_target_properties(
|
||||
${TARGET_NAME} PROPERTIES
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
endif (UNIX)
|
||||
|
||||
if (DEFINED ENV{JOB_ID})
|
||||
set(PR_BUILD "false")
|
||||
|
@ -45,4 +49,5 @@ if (APPLE)
|
|||
set(SM_SRCS ${SM_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/assets/icon.icns")
|
||||
endif ()
|
||||
|
||||
package_libraries_for_deployment()
|
||||
package_libraries_for_deployment()
|
||||
consolidate_stack_components()
|
|
@ -81,10 +81,6 @@ void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const Q
|
|||
|
||||
AppDelegate::AppDelegate(int argc, char* argv[]) :
|
||||
QApplication(argc, argv),
|
||||
_qtReady(false),
|
||||
_dsReady(false),
|
||||
_dsResourcesReady(false),
|
||||
_acReady(false),
|
||||
_domainServerProcess(NULL),
|
||||
_acMonitorProcess(NULL),
|
||||
_domainServerName("localhost")
|
||||
|
@ -115,14 +111,15 @@ AppDelegate::AppDelegate(int argc, char* argv[]) :
|
|||
|
||||
_window = new MainWindow();
|
||||
|
||||
createExecutablePath();
|
||||
downloadLatestExecutablesAndRequirements();
|
||||
|
||||
_checkVersionTimer.setInterval(0);
|
||||
connect(&_checkVersionTimer, SIGNAL(timeout()), this, SLOT(checkVersion()));
|
||||
_checkVersionTimer.start();
|
||||
|
||||
connect(this, &QApplication::aboutToQuit, this, &AppDelegate::stopStack);
|
||||
|
||||
_window->setRequirementsLastChecked(QDateTime::currentDateTime().toString());
|
||||
_window->show();
|
||||
toggleStack(true);
|
||||
}
|
||||
|
||||
AppDelegate::~AppDelegate() {
|
||||
|
@ -427,227 +424,6 @@ void AppDelegate::handleContentSetDownloadFinished() {
|
|||
emit domainAddressChanged();
|
||||
}
|
||||
|
||||
void AppDelegate::onFileSuccessfullyInstalled(const QUrl& url) {
|
||||
if (url == GlobalData::getInstance().getRequirementsURL()) {
|
||||
_qtReady = true;
|
||||
} else if (url == GlobalData::getInstance().getAssignmentClientURL()) {
|
||||
_acReady = true;
|
||||
} else if (url == GlobalData::getInstance().getDomainServerURL()) {
|
||||
_dsReady = true;
|
||||
} else if (url == GlobalData::getInstance().getDomainServerResourcesURL()) {
|
||||
_dsResourcesReady = true;
|
||||
}
|
||||
|
||||
if (_qtReady && _acReady && _dsReady && _dsResourcesReady) {
|
||||
_window->setRequirementsLastChecked(QDateTime::currentDateTime().toString());
|
||||
_window->show();
|
||||
toggleStack(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AppDelegate::createExecutablePath() {
|
||||
QDir launchDir(GlobalData::getInstance().getClientsLaunchPath());
|
||||
QDir resourcesDir(GlobalData::getInstance().getClientsResourcesPath());
|
||||
QDir logsDir(GlobalData::getInstance().getLogsPath());
|
||||
if (!launchDir.exists()) {
|
||||
if (QDir().mkpath(launchDir.absolutePath())) {
|
||||
qDebug() << "Successfully created directory: "
|
||||
<< launchDir.absolutePath();
|
||||
} else {
|
||||
qCritical() << "Failed to create directory: "
|
||||
<< launchDir.absolutePath();
|
||||
}
|
||||
}
|
||||
if (!resourcesDir.exists()) {
|
||||
if (QDir().mkpath(resourcesDir.absolutePath())) {
|
||||
qDebug() << "Successfully created directory: "
|
||||
<< resourcesDir.absolutePath();
|
||||
} else {
|
||||
qCritical() << "Failed to create directory: "
|
||||
<< resourcesDir.absolutePath();
|
||||
}
|
||||
}
|
||||
if (!logsDir.exists()) {
|
||||
if (QDir().mkpath(logsDir.absolutePath())) {
|
||||
qDebug() << "Successfully created directory: "
|
||||
<< logsDir.absolutePath();
|
||||
} else {
|
||||
qCritical() << "Failed to create directory: "
|
||||
<< logsDir.absolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppDelegate::downloadLatestExecutablesAndRequirements() {
|
||||
// Check if Qt is already installed
|
||||
if (GlobalData::getInstance().getPlatform() == "mac") {
|
||||
if (QDir(GlobalData::getInstance().getClientsLaunchPath() + "QtCore.framework").exists()) {
|
||||
_qtReady = true;
|
||||
}
|
||||
} else if (GlobalData::getInstance().getPlatform() == "win") {
|
||||
if (QFileInfo(GlobalData::getInstance().getClientsLaunchPath() + "Qt5Core.dll").exists()) {
|
||||
_qtReady = true;
|
||||
}
|
||||
} else { // linux
|
||||
if (QFileInfo(GlobalData::getInstance().getClientsLaunchPath() + "libQt5Core.so.5").exists()) {
|
||||
_qtReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QFile reqZipFile(GlobalData::getInstance().getRequirementsZipPath());
|
||||
QByteArray reqZipData;
|
||||
if (reqZipFile.open(QIODevice::ReadOnly)) {
|
||||
reqZipData = reqZipFile.readAll();
|
||||
reqZipFile.close();
|
||||
}
|
||||
QFile resZipFile(GlobalData::getInstance().getDomainServerResourcesZipPath());
|
||||
QByteArray resZipData;
|
||||
if (resZipFile.open(QIODevice::ReadOnly)) {
|
||||
resZipData = resZipFile.readAll();
|
||||
resZipFile.close();
|
||||
}
|
||||
|
||||
QDir resourcesDir(GlobalData::getInstance().getClientsResourcesPath());
|
||||
if (!(resourcesDir.entryInfoList(QDir::AllEntries).size() < 3)) {
|
||||
_dsResourcesReady = true;
|
||||
}
|
||||
|
||||
// if the user has set hifiBuildDirectory, don't attempt to download the domain-server or assignement-client
|
||||
if (GlobalData::getInstance().isGetHifiBuildDirectorySet()) {
|
||||
_dsReady = true;
|
||||
_acReady = true;
|
||||
} else {
|
||||
QByteArray dsData;
|
||||
QFile dsFile(GlobalData::getInstance().getDomainServerExecutablePath());
|
||||
if (dsFile.open(QIODevice::ReadOnly)) {
|
||||
dsData = dsFile.readAll();
|
||||
dsFile.close();
|
||||
}
|
||||
QByteArray acData;
|
||||
QFile acFile(GlobalData::getInstance().getAssignmentClientExecutablePath());
|
||||
if (acFile.open(QIODevice::ReadOnly)) {
|
||||
acData = acFile.readAll();
|
||||
acFile.close();
|
||||
}
|
||||
|
||||
QNetworkRequest acReq(QUrl(GlobalData::getInstance().getAssignmentClientMD5URL()));
|
||||
QNetworkReply* acReply = _manager->get(acReq);
|
||||
QEventLoop acLoop;
|
||||
connect(acReply, SIGNAL(finished()), &acLoop, SLOT(quit()));
|
||||
acLoop.exec();
|
||||
QByteArray acMd5Data = acReply->readAll().trimmed();
|
||||
if (GlobalData::getInstance().getPlatform() == "win") {
|
||||
// fix for reading the MD5 hash from Windows-generated
|
||||
// binary data of the MD5 hash
|
||||
QTextStream stream(acMd5Data);
|
||||
stream >> acMd5Data;
|
||||
}
|
||||
|
||||
// fix for Mac and Linux network accessibility
|
||||
if (acMd5Data.size() == 0) {
|
||||
// network is not accessible
|
||||
qDebug() << "Could not connect to the internet.";
|
||||
_window->show();
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "AC MD5: " << acMd5Data;
|
||||
if (acMd5Data.toLower() == QCryptographicHash::hash(acData, QCryptographicHash::Md5).toHex()) {
|
||||
_acReady = true;
|
||||
}
|
||||
|
||||
|
||||
QNetworkRequest dsReq(QUrl(GlobalData::getInstance().getDomainServerMD5URL()));
|
||||
QNetworkReply* dsReply = _manager->get(dsReq);
|
||||
QEventLoop dsLoop;
|
||||
connect(dsReply, SIGNAL(finished()), &dsLoop, SLOT(quit()));
|
||||
dsLoop.exec();
|
||||
QByteArray dsMd5Data = dsReply->readAll().trimmed();
|
||||
if (GlobalData::getInstance().getPlatform() == "win") {
|
||||
// fix for reading the MD5 hash from Windows generated
|
||||
// binary data of the MD5 hash
|
||||
QTextStream stream(dsMd5Data);
|
||||
stream >> dsMd5Data;
|
||||
}
|
||||
qDebug() << "DS MD5: " << dsMd5Data;
|
||||
if (dsMd5Data.toLower() == QCryptographicHash::hash(dsData, QCryptographicHash::Md5).toHex()) {
|
||||
_dsReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_qtReady) {
|
||||
// check MD5 of requirements.zip only if Qt is found
|
||||
QNetworkRequest reqZipReq(QUrl(GlobalData::getInstance().getRequirementsMD5URL()));
|
||||
QNetworkReply* reqZipReply = _manager->get(reqZipReq);
|
||||
QEventLoop reqZipLoop;
|
||||
connect(reqZipReply, SIGNAL(finished()), &reqZipLoop, SLOT(quit()));
|
||||
reqZipLoop.exec();
|
||||
QByteArray reqZipMd5Data = reqZipReply->readAll().trimmed();
|
||||
if (GlobalData::getInstance().getPlatform() == "win") {
|
||||
// fix for reading the MD5 hash from Windows generated
|
||||
// binary data of the MD5 hash
|
||||
QTextStream stream(reqZipMd5Data);
|
||||
stream >> reqZipMd5Data;
|
||||
}
|
||||
qDebug() << "Requirements ZIP MD5: " << reqZipMd5Data;
|
||||
if (reqZipMd5Data.toLower() != QCryptographicHash::hash(reqZipData, QCryptographicHash::Md5).toHex()) {
|
||||
_qtReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_dsResourcesReady) {
|
||||
// check MD5 of resources.zip only if Domain Server
|
||||
// resources are installed
|
||||
QNetworkRequest resZipReq(QUrl(GlobalData::getInstance().getDomainServerResourcesMD5URL()));
|
||||
QNetworkReply* resZipReply = _manager->get(resZipReq);
|
||||
QEventLoop resZipLoop;
|
||||
connect(resZipReply, SIGNAL(finished()), &resZipLoop, SLOT(quit()));
|
||||
resZipLoop.exec();
|
||||
QByteArray resZipMd5Data = resZipReply->readAll().trimmed();
|
||||
if (GlobalData::getInstance().getPlatform() == "win") {
|
||||
// fix for reading the MD5 hash from Windows generated
|
||||
// binary data of the MD5 hash
|
||||
QTextStream stream(resZipMd5Data);
|
||||
stream >> resZipMd5Data;
|
||||
}
|
||||
qDebug() << "Domain Server Resources ZIP MD5: " << resZipMd5Data;
|
||||
if (resZipMd5Data.toLower() != QCryptographicHash::hash(resZipData, QCryptographicHash::Md5).toHex()) {
|
||||
_dsResourcesReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
DownloadManager* downloadManager = 0;
|
||||
if (!_qtReady || !_acReady || !_dsReady || !_dsResourcesReady) {
|
||||
// initialise DownloadManager
|
||||
downloadManager = new DownloadManager(_manager);
|
||||
downloadManager->setWindowModality(Qt::ApplicationModal);
|
||||
connect(downloadManager, SIGNAL(fileSuccessfullyInstalled(QUrl)),
|
||||
SLOT(onFileSuccessfullyInstalled(QUrl)));
|
||||
downloadManager->show();
|
||||
} else {
|
||||
_window->setRequirementsLastChecked(QDateTime::currentDateTime().toString());
|
||||
_window->show();
|
||||
toggleStack(true);
|
||||
}
|
||||
|
||||
if (!_qtReady) {
|
||||
downloadManager->downloadFile(GlobalData::getInstance().getRequirementsURL());
|
||||
}
|
||||
|
||||
if (!_acReady) {
|
||||
downloadManager->downloadFile(GlobalData::getInstance().getAssignmentClientURL());
|
||||
}
|
||||
|
||||
if (!_dsReady) {
|
||||
downloadManager->downloadFile(GlobalData::getInstance().getDomainServerURL());
|
||||
}
|
||||
|
||||
if (!_dsResourcesReady) {
|
||||
downloadManager->downloadFile(GlobalData::getInstance().getDomainServerResourcesURL());
|
||||
}
|
||||
}
|
||||
|
||||
void AppDelegate::checkVersion() {
|
||||
QNetworkRequest latestVersionRequest((QUrl(CHECK_BUILDS_URL)));
|
||||
latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
|
|
@ -53,7 +53,6 @@ signals:
|
|||
void indexPathChangeResponse(bool wasSuccessful);
|
||||
void stackStateChanged(bool isOn);
|
||||
private slots:
|
||||
void onFileSuccessfullyInstalled(const QUrl& url);
|
||||
void requestDomainServerID();
|
||||
void handleDomainIDReply();
|
||||
void handleDomainGetReply();
|
||||
|
@ -64,16 +63,10 @@ private slots:
|
|||
|
||||
private:
|
||||
void parseCommandLine();
|
||||
void createExecutablePath();
|
||||
void downloadLatestExecutablesAndRequirements();
|
||||
|
||||
void changeDomainServerIndexPath(const QString& newPath);
|
||||
|
||||
QNetworkAccessManager* _manager;
|
||||
bool _qtReady;
|
||||
bool _dsReady;
|
||||
bool _dsResourcesReady;
|
||||
bool _acReady;
|
||||
BackgroundProcess* _domainServerProcess;
|
||||
BackgroundProcess* _acMonitorProcess;
|
||||
QHash<QUuid, BackgroundProcess*> _scriptProcesses;
|
||||
|
|
|
@ -32,11 +32,8 @@ GlobalData::GlobalData() {
|
|||
_resourcePath = "resources/";
|
||||
_assignmentClientExecutable = "assignment-client";
|
||||
_domainServerExecutable = "domain-server";
|
||||
QString applicationSupportDirectory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
if (PR_BUILD) {
|
||||
applicationSupportDirectory += "/pr-binaries";
|
||||
}
|
||||
|
||||
QString applicationSupportDirectory = QCoreApplication::applicationDirPath();
|
||||
|
||||
_clientsLaunchPath = QDir::toNativeSeparators(applicationSupportDirectory + "/");
|
||||
_clientsResourcePath = QDir::toNativeSeparators(applicationSupportDirectory + "/" + _resourcePath);
|
||||
|
||||
|
@ -49,18 +46,6 @@ GlobalData::GlobalData() {
|
|||
_domainServerExecutablePath.append(".exe");
|
||||
}
|
||||
|
||||
_requirementsURL = urlBase + "/binaries/" + _platform + "/requirements/requirements.zip";
|
||||
_requirementsZipPath = _clientsLaunchPath + "requirements.zip";
|
||||
_requirementsMD5URL = urlBase + "/binaries/" + _platform + "/requirements/requirements.md5";
|
||||
_assignmentClientURL = urlBase + "/binaries/" + _platform + "/assignment-client" + (_platform == "win" ? "/assignment-client.exe" : "/assignment-client");
|
||||
_domainServerResourcesURL = urlBase + "/binaries/" + _platform + "/domain-server/resources.zip";
|
||||
_domainServerResourcesZipPath = _clientsLaunchPath + "resources.zip";
|
||||
_domainServerResourcesMD5URL = urlBase + "/binaries/" + _platform + "/domain-server/resources.md5";
|
||||
_domainServerURL = urlBase + "/binaries/" + _platform + "/domain-server" + (_platform == "win" ? "/domain-server.exe" : "/domain-server");
|
||||
|
||||
_assignmentClientMD5URL = urlBase + "/binaries/" + _platform + "/assignment-client/assignment-client.md5";
|
||||
_domainServerMD5URL = urlBase + "/binaries/" + _platform + "/domain-server/domain-server.md5";
|
||||
|
||||
_defaultDomain = "localhost";
|
||||
_logsPath = QDir::toNativeSeparators(_clientsLaunchPath + "logs/");
|
||||
_availableAssignmentTypes.insert("audio-mixer", 0);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef hifi_GlobalData_h
|
||||
#define hifi_GlobalData_h
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
|
|
Loading…
Reference in a new issue