Merge branch 'master' of github.com:highfidelity/hifi into serverless-domains

This commit is contained in:
Seth Alves 2018-03-13 09:24:18 -07:00
commit b39c7eadd2
197 changed files with 5817 additions and 671 deletions

4
.gitignore vendored
View file

@ -78,6 +78,8 @@ TAGS
node_modules node_modules
npm-debug.log npm-debug.log
# ignore qmlc files generated from qml as cache
*.qmlc
# Android studio files # Android studio files
*___jb_old___ *___jb_old___
@ -88,4 +90,4 @@ android/app/src/main/assets
interface/compiledResources interface/compiledResources
# GPUCache # GPUCache
interface/resources/GPUCache/* interface/resources/GPUCache/*

View file

@ -53,7 +53,7 @@ Enter the repository `android` directory
Execute a gradle pre-build setup. This step should only need to be done once Execute a gradle pre-build setup. This step should only need to be done once
`gradle setupDepedencies` `gradle setupDependencies`
# Building & Running # Building & Running

View file

@ -19,9 +19,9 @@
android:allowBackup="true" android:allowBackup="true"
android:screenOrientation="unspecified" android:screenOrientation="unspecified"
android:theme="@style/NoSystemUI" android:theme="@style/NoSystemUI"
android:icon="@mipmap/ic_launcher" android:icon="@drawable/ic_launcher"
android:launchMode="singleTop" android:launchMode="singleTop"
android:roundIcon="@mipmap/ic_launcher_round"> android:roundIcon="@drawable/ic_launcher">
<activity android:name="io.highfidelity.hifiinterface.PermissionChecker"> <activity android:name="io.highfidelity.hifiinterface.PermissionChecker">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress AndroidUnknownAttribute -->
<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="192"
android:viewportHeight="192"
android:width="192dp"
android:height="192dp">
<path
android:pathData="M189.5 96.5A93.5 93.5 0 0 1 96 190 93.5 93.5 0 0 1 2.5 96.5 93.5 93.5 0 0 1 96 3 93.5 93.5 0 0 1 189.5 96.5Z"
android:fillColor="#333333" />
<path
android:pathData="M96.2 173.1c-10.3 0 -20.4 -2.1 -29.8 -6 -9.2 -3.8 -17.3 -9.4 -24.3 -16.4 -7 -7 -12.6 -15.2 -16.4 -24.3 -4.1 -9.6 -6.2 -19.6 -6.2 -30 0 -10.3 2.1 -20.4 6 -29.8 3.8 -9.2 9.4 -17.3 16.4 -24.3 7 -7 15.2 -12.6 24.3 -16.4 9.5 -4 19.5 -6 29.8 -6 10.3 0 20.4 2.1 29.8 6 9.2 3.8 17.3 9.4 24.3 16.4 7 7 12.6 15.2 16.4 24.3 4 9.5 6 19.5 6 29.8 0 10.3 -2.1 20.4 -6 29.8 -3.8 9.2 -9.4 17.3 -16.4 24.3 -7 7 -15.2 12.6 -24.3 16.4 -9.2 4.1 -19.3 6.2 -29.6 6.2zm0 -145.3c-37.8 0 -68.6 30.8 -68.6 68.6 0 37.8 30.8 68.6 68.6 68.6 37.8 0 68.6 -30.8 68.6 -68.6 0 -37.8 -30.8 -68.6 -68.6 -68.6z"
android:fillColor="#00b4f0" />
<path
android:pathData="M119.6 129l0 -53.8c3.4 -1.1 5.8 -4.3 5.8 -8 0 -4.6 -3.8 -8.4 -8.4 -8.4 -4.6 0 -8.4 3.8 -8.4 8.4 0 3.6 2.2 6.6 5.4 7.9l0 25L79 83.8 79 64c3.4 -1.1 5.8 -4.3 5.8 -8 0 -4.6 -3.8 -8.4 -8.4 -8.4 -4.6 0 -8.4 3.8 -8.4 8.4 0 3.6 2.2 6.6 5.4 7.9l0 54.1c-3.1 1.2 -5.4 4.3 -5.4 7.9 0 4.6 3.8 8.4 8.4 8.4 4.6 0 8.4 -3.8 8.4 -8.4 0 -3.7 -2.4 -6.9 -5.8 -8l0 -27.3 35 16.3 0 22.2c-3.1 1.2 -5.4 4.3 -5.4 7.9 0 4.6 3.8 8.4 8.4 8.4 4.6 0 8.4 -3.8 8.4 -8.4 0 -3.8 -2.4 -6.9 -5.8 -8z"
android:fillColor="#00b4f0" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

View file

@ -137,6 +137,13 @@ def packages = [
checksum: '20768f298f53b195e71b414b0ae240c4', checksum: '20768f298f53b195e71b414b0ae240c4',
sharedLibFolder: 'lib/release', sharedLibFolder: 'lib/release',
includeLibs: ['libtbb.so', 'libtbbmalloc.so'], includeLibs: ['libtbb.so', 'libtbbmalloc.so'],
],
hifiAC: [
file: 'libplugins_libhifiCodec.zip',
versionId: 'mzKhsRCgVmloqq5bvE.0IwYK1NjGQc_G',
checksum: '9412a8e12c88a4096c1fc843bb9fe52d',
sharedLibFolder: '',
includeLibs: ['libplugins_libhifiCodec.so']
] ]
] ]
@ -353,6 +360,7 @@ task verifyGvr(type: Verify) { def p = packages['gvr']; src new File(baseFolder,
task verifyOpenSSL(type: Verify) { def p = packages['openssl']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyOpenSSL(type: Verify) { def p = packages['openssl']; src new File(baseFolder, p['file']); checksum p['checksum'] }
task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(baseFolder, p['file']); checksum p['checksum'] }
task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] }
task verifyHifiAC(type: Verify) { def p = packages['hifiAC']; src new File(baseFolder, p['file']); checksum p['checksum'] }
task verifyDependencyDownloads(dependsOn: downloadDependencies) { } task verifyDependencyDownloads(dependsOn: downloadDependencies) { }
verifyDependencyDownloads.dependsOn verifyQt verifyDependencyDownloads.dependsOn verifyQt
@ -362,6 +370,7 @@ verifyDependencyDownloads.dependsOn verifyGvr
verifyDependencyDownloads.dependsOn verifyOpenSSL verifyDependencyDownloads.dependsOn verifyOpenSSL
verifyDependencyDownloads.dependsOn verifyPolyvox verifyDependencyDownloads.dependsOn verifyPolyvox
verifyDependencyDownloads.dependsOn verifyTBB verifyDependencyDownloads.dependsOn verifyTBB
verifyDependencyDownloads.dependsOn verifyHifiAC
task extractDependencies(dependsOn: verifyDependencyDownloads) { task extractDependencies(dependsOn: verifyDependencyDownloads) {
doLast { doLast {

View file

@ -23,12 +23,22 @@ set(RESOURCES_QRC ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc)
set(RESOURCES_RCC ${CMAKE_CURRENT_SOURCE_DIR}/compiledResources/resources.rcc) set(RESOURCES_RCC ${CMAKE_CURRENT_SOURCE_DIR}/compiledResources/resources.rcc)
generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources CUSTOM_PATHS ${CUSTOM_INTERFACE_QRC_PATHS} GLOBS *) generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources CUSTOM_PATHS ${CUSTOM_INTERFACE_QRC_PATHS} GLOBS *)
add_custom_command( if (ANDROID)
OUTPUT ${RESOURCES_RCC} # on Android, don't compress the rcc binary
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS} add_custom_command(
COMMAND "${QT_DIR}/bin/rcc" OUTPUT ${RESOURCES_RCC}
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC} DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
) COMMAND "${QT_DIR}/bin/rcc"
ARGS ${RESOURCES_QRC} -no-compress -binary -o ${RESOURCES_RCC}
)
else ()
add_custom_command(
OUTPUT ${RESOURCES_RCC}
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
COMMAND "${QT_DIR}/bin/rcc"
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
)
endif()
list(APPEND GENERATE_QRC_DEPENDS ${RESOURCES_RCC}) list(APPEND GENERATE_QRC_DEPENDS ${RESOURCES_RCC})
add_custom_target(resources ALL DEPENDS ${GENERATE_QRC_DEPENDS}) add_custom_target(resources ALL DEPENDS ${GENERATE_QRC_DEPENDS})

View file

@ -76,33 +76,33 @@ Item {
HifiStyles.RalewayRegular { HifiStyles.RalewayRegular {
id: notice id: notice
text: "YOUR LOCATION" text: "YOUR LOCATION"
font.pixelSize: (hifi.fonts.pixelSize * 2.15)*(android.dimen.atLeast1440p?1:.75); font.pixelSize: (hifi.fonts.pixelSize * 2.15) * (android.dimen.atLeast1440p ? 1 : .75);
color: "#2CD7FF" color: "#2CD7FF"
anchors { anchors {
bottom: addressBackground.top bottom: addressBackground.top
bottomMargin: android.dimen.atLeast1440p?45:34 bottomMargin: android.dimen.atLeast1440p ? 45 : 34
left: addressBackground.left left: addressBackground.left
leftMargin: android.dimen.atLeast1440p?60:45 leftMargin: android.dimen.atLeast1440p ? 60 : 45
} }
} }
property int inputAreaHeight: android.dimen.atLeast1440p?210:156 property int inputAreaHeight: android.dimen.atLeast1440p ? 210 : 156
property int inputAreaStep: (height - inputAreaHeight) / 2 property int inputAreaStep: (height - inputAreaHeight) / 2
ToolbarButton { ToolbarButton {
id: homeButton id: homeButton
y: android.dimen.atLeast1440p?280:210 y: android.dimen.atLeast1440p ? 280 : 210
imageURL: "../../icons/home.svg" imageURL: "../../icons/home.svg"
onClicked: { onClicked: {
addressBarDialog.loadHome(); addressBarDialog.loadHome();
bar.shown = false; bar.shown = false;
} }
anchors { anchors {
leftMargin: android.dimen.atLeast1440p?75:56 leftMargin: android.dimen.atLeast1440p ? 75 : 56
left: parent.left left: parent.left
} }
size: android.dimen.atLeast1440p?150:150//112 size: android.dimen.atLeast1440p ? 150 : 150//112
} }
ToolbarButton { ToolbarButton {
@ -111,10 +111,10 @@ Item {
onClicked: addressBarDialog.loadBack(); onClicked: addressBarDialog.loadBack();
anchors { anchors {
left: homeButton.right left: homeButton.right
leftMargin: android.dimen.atLeast1440p?70:52 leftMargin: android.dimen.atLeast1440p ? 70 : 52
verticalCenter: homeButton.verticalCenter verticalCenter: homeButton.verticalCenter
} }
size: android.dimen.atLeast1440p?150:150 size: android.dimen.atLeast1440p ? 150 : 150
} }
ToolbarButton { ToolbarButton {
id: forwardArrow; id: forwardArrow;
@ -122,10 +122,10 @@ Item {
onClicked: addressBarDialog.loadForward(); onClicked: addressBarDialog.loadForward();
anchors { anchors {
left: backArrow.right left: backArrow.right
leftMargin: android.dimen.atLeast1440p?60:45 leftMargin: android.dimen.atLeast1440p ? 60 : 45
verticalCenter: homeButton.verticalCenter verticalCenter: homeButton.verticalCenter
} }
size: android.dimen.atLeast1440p?150:150 size: android.dimen.atLeast1440p ? 150 : 150
} }
HifiStyles.FiraSansRegular { HifiStyles.FiraSansRegular {
@ -140,25 +140,22 @@ Item {
Rectangle { Rectangle {
id: addressBackground id: addressBackground
x: android.dimen.atLeast1440p?780:585 x: android.dimen.atLeast1440p ? 780 : 585
y: android.dimen.atLeast1440p?280:235 // tweaking by hand y: android.dimen.atLeast1440p ? 280 : 235 // tweaking by hand
width: android.dimen.atLeast1440p?1270:952 width: android.dimen.atLeast1440p ? 1270 : 952
height: android.dimen.atLeast1440p?150:112 height: android.dimen.atLeast1440p ? 150 : 112
color: "#FFFFFF" color: "#FFFFFF"
} }
TextInput { TextInput {
id: addressLine id: addressLine
focus: true focus: true
x: android.dimen.atLeast1440p?870:652 x: android.dimen.atLeast1440p ? 870 : 652
y: android.dimen.atLeast1440p?300:245 // tweaking by hand y: android.dimen.atLeast1440p ? 300 : 245 // tweaking by hand
width: android.dimen.atLeast1440p?1200:900 width: android.dimen.atLeast1440p ? 1200 : 900
height: android.dimen.atLeast1440p?120:90 height: android.dimen.atLeast1440p ? 120 : 90
inputMethodHints: Qt.ImhNoPredictiveText inputMethodHints: Qt.ImhNoPredictiveText
//helperText: "Hint is here" //helperText: "Hint is here"
anchors {
//verticalCenter: addressBackground.verticalCenter
}
font.pixelSize: hifi.fonts.pixelSize * 3.75 font.pixelSize: hifi.fonts.pixelSize * 3.75
onTextChanged: { onTextChanged: {
//filterChoicesByText(); //filterChoicesByText();
@ -228,4 +225,4 @@ Item {
} }
} }
} }

View file

@ -42,8 +42,8 @@ Original.CheckBox {
style: CheckBoxStyle { style: CheckBoxStyle {
indicator: Rectangle { indicator: Rectangle {
id: box id: box
width: boxSize implicitWidth: boxSize
height: boxSize implicitHeight: boxSize
radius: boxRadius radius: boxRadius
border.width: 1 border.width: 1
border.color: pressed || hovered border.color: pressed || hovered
@ -101,8 +101,8 @@ Original.CheckBox {
} }
label: Label { label: Label {
text: control.text text: checkBox.text
color: control.color color: checkBox.color
x: 2 x: 2
wrapMode: checkBox.wrap ? Text.Wrap : Text.NoWrap wrapMode: checkBox.wrap ? Text.Wrap : Text.NoWrap
elide: checkBox.wrap ? Text.ElideNone : Text.ElideRight elide: checkBox.wrap ? Text.ElideNone : Text.ElideRight

View file

@ -26,13 +26,13 @@ ColumnLayout {
property string methodName: ""; property string methodName: "";
property string actionText: ""; property string actionText: "";
spacing: 4*3 spacing: 4 * 3
signal sendToParentQml(var message); signal sendToParentQml(var message);
Image { Image {
id: itemImage id: itemImage
Layout.preferredWidth: 250*3 Layout.preferredWidth: 250 * 3
Layout.preferredHeight: 140*3 Layout.preferredHeight: 140 * 3
source: thumbnailUrl source: thumbnailUrl
asynchronous: true asynchronous: true
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
@ -81,7 +81,7 @@ ColumnLayout {
HifiControlsUit.ImageButton { HifiControlsUit.ImageButton {
width: 140*3 width: 140*3
height: 35*3 height: 35*3
text: type=="extra"? actionText: "CHOOSE" text: type=="extra" ? actionText: "CHOOSE"
source: "../../../../icons/button.svg" source: "../../../../icons/button.svg"
hoverSource: "../../../../icons/button-a.svg" hoverSource: "../../../../icons/button-a.svg"
fontSize: 18*3 fontSize: 18*3
@ -102,8 +102,8 @@ ColumnLayout {
Image { Image {
id: tickImage id: tickImage
width: 35*3 width: 35 * 3
height: 35*3 height: 35 * 3
source: "../../../icons/tick.svg" source: "../../../icons/tick.svg"
anchors { anchors {
horizontalCenter: itemName.horizontalCenter horizontalCenter: itemName.horizontalCenter
@ -114,4 +114,4 @@ ColumnLayout {
Component.onCompleted:{ Component.onCompleted:{
sendToParentQml.connect(sendToScript); sendToParentQml.connect(sendToScript);
} }
} }

View file

@ -22,26 +22,26 @@ Item {
Item { Item {
id: dimen id: dimen
readonly property bool atLeast1440p: Screen.width >= 2560 && Screen.height >= 1440 readonly property bool atLeast1440p: Screen.width >= 2560 && Screen.height >= 1440
readonly property real windowLessWidth: atLeast1440p?378:284 readonly property real windowLessWidth: atLeast1440p ? 378 : 284
readonly property real windowLessHeight: atLeast1440p?192:144 readonly property real windowLessHeight: atLeast1440p ? 192 : 144
readonly property real windowZ: 100 readonly property real windowZ: 100
readonly property real headerHeight: atLeast1440p?276:207 readonly property real headerHeight: atLeast1440p ? 276 : 207
readonly property real headerIconPosX: atLeast1440p?90:67 readonly property real headerIconPosX: atLeast1440p ? 90 : 67
readonly property real headerIconPosY: atLeast1440p?108:81 readonly property real headerIconPosY: atLeast1440p ? 108 : 81
readonly property real headerIconWidth: atLeast1440p?111:83 readonly property real headerIconWidth: atLeast1440p ? 111 : 83
readonly property real headerIconHeight: atLeast1440p?111:83 readonly property real headerIconHeight: atLeast1440p ? 111 : 83
readonly property real headerIconTitleDistance: atLeast1440p?151:113 readonly property real headerIconTitleDistance: atLeast1440p ? 151 : 113
readonly property real headerHideWidth: atLeast1440p?150:112 readonly property real headerHideWidth: atLeast1440p ? 150 : 112
readonly property real headerHideHeight: atLeast1440p?150:112 readonly property real headerHideHeight: atLeast1440p ? 150 : 112
readonly property real headerHideRightMargin: atLeast1440p?110:82 readonly property real headerHideRightMargin: atLeast1440p ? 110 : 82
readonly property real headerHideTopMargin: atLeast1440p?90:67 readonly property real headerHideTopMargin: atLeast1440p ? 90 : 67
readonly property real headerHideIconWidth: atLeast1440p?70:52 readonly property real headerHideIconWidth: atLeast1440p ? 70 : 52
readonly property real headerHideIconHeight: atLeast1440p?45:33 readonly property real headerHideIconHeight: atLeast1440p ? 45 : 33
readonly property real headerHideTextTopMargin: atLeast1440p?36:27 readonly property real headerHideTextTopMargin: atLeast1440p ? 36 : 27
readonly property real botomHudWidth: 366 readonly property real botomHudWidth: 366
readonly property real botomHudHeight: 180 readonly property real botomHudHeight: 180

View file

@ -16,10 +16,11 @@ import "../js/Utils.js" as Utils
Item { Item {
id: frame id: frame
objectName: "Frame"
HifiConstants { id: hifi } HifiConstants { id: hifi }
default property var decoration default property var decoration
property string qmlFile: "N/A"
property bool gradientsSupported: desktop.gradientsSupported property bool gradientsSupported: desktop.gradientsSupported
readonly property int frameMarginLeft: frame.decoration ? frame.decoration.frameMarginLeft : 0 readonly property int frameMarginLeft: frame.decoration ? frame.decoration.frameMarginLeft : 0
@ -44,7 +45,7 @@ Item {
id: debugZ id: debugZ
visible: DebugQML visible: DebugQML
color: "red" color: "red"
text: (window ? "Z: " + window.z : "") text: (window ? "Z: " + window.z : "") + " " + qmlFile
y: window ? window.height + 4 : 0 y: window ? window.height + 4 : 0
} }

View file

@ -2032,20 +2032,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(_window, SIGNAL(windowMinimizedChanged(bool)), this, SLOT(windowMinimizedChanged(bool))); connect(_window, SIGNAL(windowMinimizedChanged(bool)), this, SLOT(windowMinimizedChanged(bool)));
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0); qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
{
PROFILE_RANGE(render, "Process Default Skybox");
auto textureCache = DependencyManager::get<TextureCache>();
QFileSelector fileSelector;
fileSelector.setExtraSelectors(FileUtils::getFileSelectors());
auto skyboxUrl = fileSelector.select(PathUtils::resourcesPath() + "images/Default-Sky-9-cubemap.ktx");
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl.toStdString());
_defaultSkyboxAmbientTexture = _defaultSkyboxTexture;
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
}
EntityTreeRenderer::setEntitiesShouldFadeFunction([this]() { EntityTreeRenderer::setEntitiesShouldFadeFunction([this]() {
SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer); SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer);
return entityServerNode && !isPhysicsEnabled(); return entityServerNode && !isPhysicsEnabled();
@ -2495,7 +2481,6 @@ void Application::initializeGL() {
DeadlockWatchdogThread::withPause([&] { DeadlockWatchdogThread::withPause([&] {
// Set up the render engine // Set up the render engine
render::CullFunctor cullFunctor = LODManager::shouldRender; render::CullFunctor cullFunctor = LODManager::shouldRender;
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
_renderEngine->addJob<UpdateSceneTask>("UpdateScene"); _renderEngine->addJob<UpdateSceneTask>("UpdateScene");
#ifndef Q_OS_ANDROID #ifndef Q_OS_ANDROID
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED); _renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
@ -5527,7 +5512,7 @@ void Application::update(float deltaTime) {
editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) { editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) {
PerformanceTimer perfTimer("editRenderArgs"); PerformanceTimer perfTimer("editRenderArgs");
appRenderArgs._headPose= getHMDSensorPose(); appRenderArgs._headPose = getHMDSensorPose();
auto myAvatar = getMyAvatar(); auto myAvatar = getMyAvatar();
@ -5547,10 +5532,10 @@ void Application::update(float deltaTime) {
{ {
QMutexLocker viewLocker(&_viewMutex); QMutexLocker viewLocker(&_viewMutex);
// adjust near clip plane to account for sensor scaling. // adjust near clip plane to account for sensor scaling.
auto adjustedProjection = glm::perspective(_viewFrustum.getFieldOfView(), auto adjustedProjection = glm::perspective(glm::radians(_fieldOfView.get()),
_viewFrustum.getAspectRatio(), getActiveDisplayPlugin()->getRecommendedAspectRatio(),
DEFAULT_NEAR_CLIP * sensorToWorldScale, DEFAULT_NEAR_CLIP * sensorToWorldScale,
_viewFrustum.getFarClip()); DEFAULT_FAR_CLIP);
_viewFrustum.setProjection(adjustedProjection); _viewFrustum.setProjection(adjustedProjection);
_viewFrustum.calculate(); _viewFrustum.calculate();
} }
@ -5632,6 +5617,7 @@ void Application::update(float deltaTime) {
{ {
QMutexLocker viewLocker(&_viewMutex); QMutexLocker viewLocker(&_viewMutex);
_myCamera.loadViewFrustum(_displayViewFrustum); _myCamera.loadViewFrustum(_displayViewFrustum);
appRenderArgs._view = glm::inverse(_displayViewFrustum.getView());
} }
{ {

View file

@ -272,10 +272,6 @@ public:
void shareSnapshot(const QString& filename, const QUrl& href = QUrl("")); void shareSnapshot(const QString& filename, const QUrl& href = QUrl(""));
graphics::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; }
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
OverlayID getTabletScreenID() const; OverlayID getTabletScreenID() const;
OverlayID getTabletHomeButtonID() const; OverlayID getTabletHomeButtonID() const;
QUuid getTabletFrameID() const; // may be an entity or an overlay QUuid getTabletFrameID() const; // may be an entity or an overlay
@ -627,6 +623,7 @@ private:
struct AppRenderArgs { struct AppRenderArgs {
render::Args _renderArgs; render::Args _renderArgs;
glm::mat4 _eyeToWorld; glm::mat4 _eyeToWorld;
glm::mat4 _view;
glm::mat4 _eyeOffsets[2]; glm::mat4 _eyeOffsets[2];
glm::mat4 _eyeProjections[2]; glm::mat4 _eyeProjections[2];
glm::mat4 _headPose; glm::mat4 _headPose;
@ -682,10 +679,6 @@ private:
ConnectionMonitor _connectionMonitor; ConnectionMonitor _connectionMonitor;
graphics::SkyboxPointer _defaultSkybox { new ProceduralSkybox() } ;
gpu::TexturePointer _defaultSkyboxTexture;
gpu::TexturePointer _defaultSkyboxAmbientTexture;
QTimer _addAssetToWorldResizeTimer; QTimer _addAssetToWorldResizeTimer;
QHash<QUuid, int> _addAssetToWorldResizeList; QHash<QUuid, int> _addAssetToWorldResizeList;

View file

@ -90,10 +90,10 @@ void Application::paintGL() {
{ {
PROFILE_RANGE(render, "/gpuContextReset"); PROFILE_RANGE(render, "/gpuContextReset");
_gpuContext->beginFrame(HMDSensorPose); _gpuContext->beginFrame(_appRenderArgs._view, HMDSensorPose);
// Reset the gpu::Context Stages // Reset the gpu::Context Stages
// Back to the default framebuffer; // Back to the default framebuffer;
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) { gpu::doInBatch("Application_render::gpuContextReset", _gpuContext, [&](gpu::Batch& batch) {
batch.resetStages(); batch.resetStages();
}); });
} }
@ -216,7 +216,7 @@ void Application::runRenderFrame(RenderArgs* renderArgs) {
// Make sure the WorldBox is in the scene // Make sure the WorldBox is in the scene
// For the record, this one RenderItem is the first one we created and added to the scene. // For the record, this one RenderItem is the first one we created and added to the scene.
// We could meoee that code elsewhere but you know... // We could move that code elsewhere but you know...
if (!render::Item::isValidID(WorldBoxRenderData::_item)) { if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>(); auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData); auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);

View file

@ -45,6 +45,9 @@
#include "LocationBookmarks.h" #include "LocationBookmarks.h"
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "AmbientOcclusionEffect.h"
#include "RenderShadowTask.h"
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
#include "SpeechRecognizer.h" #include "SpeechRecognizer.h"
#endif #endif
@ -361,18 +364,6 @@ Menu::Menu() {
// Developer menu ---------------------------------- // Developer menu ----------------------------------
MenuWrapper* developerMenu = addMenu("Developer", "Developer"); MenuWrapper* developerMenu = addMenu("Developer", "Developer");
// Developer > Graphics
MenuWrapper* graphicsOptionsMenu = developerMenu->addMenu("Render");
action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::Shadows, 0, true);
connect(action, &QAction::triggered, [action] {
DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(action->isChecked());
});
action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::AmbientOcclusion, 0, false);
connect(action, &QAction::triggered, [action] {
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(action->isChecked());
});
// Developer > UI >>> // Developer > UI >>>
MenuWrapper* uiOptionsMenu = developerMenu->addMenu("UI"); MenuWrapper* uiOptionsMenu = developerMenu->addMenu("UI");
action = addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::DesktopTabletToToolbar, 0, action = addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::DesktopTabletToToolbar, 0,
@ -389,6 +380,36 @@ Menu::Menu() {
// Developer > Render >>> // Developer > Render >>>
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, true);
connect(action, &QAction::triggered, [action] {
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
if (renderConfig) {
auto mainViewShadowTaskConfig = renderConfig->getConfig<RenderShadowTask>("RenderMainView.RenderShadowTask");
if (mainViewShadowTaskConfig) {
if (action->isChecked()) {
mainViewShadowTaskConfig->setPreset("Enabled");
} else {
mainViewShadowTaskConfig->setPreset("None");
}
}
}
});
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion, 0, false);
connect(action, &QAction::triggered, [action] {
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
if (renderConfig) {
auto mainViewAmbientOcclusionConfig = renderConfig->getConfig<AmbientOcclusionEffect>("RenderMainView.AmbientOcclusion");
if (mainViewAmbientOcclusionConfig) {
if (action->isChecked()) {
mainViewAmbientOcclusionConfig->setPreset("Enabled");
} else {
mainViewAmbientOcclusionConfig->setPreset("None");
}
}
}
});
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DefaultSkybox, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DefaultSkybox, 0, true);

View file

@ -205,7 +205,7 @@ namespace MenuOption {
const QString DesktopTabletToToolbar = "Desktop Tablet Becomes Toolbar"; const QString DesktopTabletToToolbar = "Desktop Tablet Becomes Toolbar";
const QString HMDTabletToToolbar = "HMD Tablet Becomes Toolbar"; const QString HMDTabletToToolbar = "HMD Tablet Becomes Toolbar";
const QString Shadows = "Shadows"; const QString Shadows = "Shadows";
const QString AmbientOcclusion = "AmbientOcclusion"; const QString AmbientOcclusion = "Ambient Occlusion";
} }
#endif // hifi_Menu_h #endif // hifi_Menu_h

View file

@ -107,7 +107,7 @@ public:
args->_displayMode = RenderArgs::MONO; args->_displayMode = RenderArgs::MONO;
args->_renderMode = RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE; args->_renderMode = RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { gpu::doInBatch("SecondaryCameraJob::run", args->_context, [&](gpu::Batch& batch) {
batch.disableContextStereo(); batch.disableContextStereo();
batch.disableContextViewCorrection(); batch.disableContextViewCorrection();
}); });
@ -196,7 +196,7 @@ public:
args->_displayMode = cachedArgs->_displayMode; args->_displayMode = cachedArgs->_displayMode;
args->_renderMode = cachedArgs->_renderMode; args->_renderMode = cachedArgs->_renderMode;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { gpu::doInBatch("EndSecondaryCameraFrame::run", args->_context, [&](gpu::Batch& batch) {
batch.restoreContextStereo(); batch.restoreContextStereo();
batch.restoreContextViewCorrection(); batch.restoreContextViewCorrection();
}); });

View file

@ -15,6 +15,24 @@
#include <EntityItem.h> #include <EntityItem.h>
#include <ObjectActionTractor.h> #include <ObjectActionTractor.h>
/**jsdoc
* The <code>"far-grab"</code> {@link Entities.ActionType|ActionType} moves and rotates an entity to a target position and
* orientation, optionally relative to another entity. Collisions between the entity and the user's avatar are disabled during
* the far-grab.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-FarGrab
* @property {Vec3} targetPosition=0,0,0 - The target position.
* @property {Quat} targetRotation=0,0,0,1 - The target rotation.
* @property {Uuid} otherID=null - If an entity ID, the <code>targetPosition</code> and <code>targetRotation</code> are
* relative to this entity's position and rotation.
* @property {number} linearTimeScale=3.4e+38 - Controls how long it takes for the entity's position to catch up with the
* target position. The value is the time for the action to catch up to 1/e = 0.368 of the target value, where the action
* is applied using an exponential decay.
* @property {number} angularTimeScale=3.4e+38 - Controls how long it takes for the entity's orientation to catch up with the
* target orientation. The value is the time for the action to catch up to 1/e = 0.368 of the target value, where the
* action is applied using an exponential decay.
*/
class AvatarActionFarGrab : public ObjectActionTractor { class AvatarActionFarGrab : public ObjectActionTractor {
public: public:
AvatarActionFarGrab(const QUuid& id, EntityItemPointer ownerEntity); AvatarActionFarGrab(const QUuid& id, EntityItemPointer ownerEntity);

View file

@ -416,6 +416,26 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
return true; return true;
} }
/**jsdoc
* The <code>"hold"</code> {@link Entities.ActionType|ActionType} positions and rotates an entity relative to an avatar's hand.
* Collisions between the entity and the user's avatar are disabled during the hold.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-Hold
* @property {Uuid} holderID=MyAvatar.sessionUUID - The ID of the avatar holding the entity.
* @property {Vec3} relativePosition=0,0,0 - The target position relative to the avatar's hand.
* @property {Vec3} relativeRotation=0,0,0,1 - The target rotation relative to the avatar's hand.
* @property {number} timeScale=3.4e+38 - Controls how long it takes for the entity's position and rotation to catch up with
* the target. The value is the time for the action to catch up to 1/e = 0.368 of the target value, where the action is
* applied using an exponential decay.
* @property {string} hand=right - The hand holding the entity: <code>"left"</code> or <code>"right"</code>.
* @property {boolean} kinematic=false - If <code>true</code>, the entity is made kinematic during the action; the entity won't
* lag behind the hand but constraint actions such as <code>"hinge"</code> won't act properly.
* @property {boolean} kinematicSetVelocity=false - If <code>true</code> and <code>kinematic</code> is <code>true</code>, the
* entity's <code>velocity</code> property will be set during the action, e.g., so that other scripts may use the value.
* @property {boolean} ignoreIK=false - If <code>true</code>, the entity follows the HMD controller rather than the avatar's
* hand.
*/
QVariantMap AvatarActionHold::getArguments() { QVariantMap AvatarActionHold::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments(); QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&]{ withReadLock([&]{

View file

@ -1115,7 +1115,6 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
void MyAvatar::setEnableMeshVisible(bool isEnabled) { void MyAvatar::setEnableMeshVisible(bool isEnabled) {
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
_skeletonModel->setCanCastShadow(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
} }
void MyAvatar::setEnableInverseKinematics(bool isEnabled) { void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
@ -1468,7 +1467,6 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
int skeletonModelChangeCount = _skeletonModelChangeCount; int skeletonModelChangeCount = _skeletonModelChangeCount;
Avatar::setSkeletonModelURL(skeletonModelURL); Avatar::setSkeletonModelURL(skeletonModelURL);
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
_skeletonModel->setCanCastShadow(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
_headBoneSet.clear(); _headBoneSet.clear();
_cauterizationNeedsUpdate = true; _cauterizationNeedsUpdate = true;
@ -2043,8 +2041,8 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
_attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(), _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(),
render::ItemKey::TAG_BITS_NONE, true); render::ItemKey::TAG_BITS_NONE, true);
_attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(), _attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(),
render::ItemKey::TAG_BITS_NONE, true); render::ItemKey::TAG_BITS_NONE, true);
} }
} }
} }

View file

@ -64,7 +64,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
} }
// Execute the batch into our framebuffer // Execute the batch into our framebuffer
doInBatch(renderArgs->_context, [&](gpu::Batch& batch) { doInBatch("ApplicationOverlay::render", renderArgs->_context, [&](gpu::Batch& batch) {
PROFILE_RANGE_BATCH(batch, "ApplicationOverlayRender"); PROFILE_RANGE_BATCH(batch, "ApplicationOverlayRender");
renderArgs->_batch = &batch; renderArgs->_batch = &batch;
batch.enableStereo(false); batch.enableStereo(false);

View file

@ -24,10 +24,6 @@
#include "SnapshotAnimated.h" #include "SnapshotAnimated.h"
#include "UserActivityLogger.h" #include "UserActivityLogger.h"
#include "AmbientOcclusionEffect.h"
#include "AntialiasingEffect.h"
#include "RenderShadowTask.h"
void setupPreferences() { void setupPreferences() {
auto preferences = DependencyManager::get<Preferences>(); auto preferences = DependencyManager::get<Preferences>();
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
@ -295,30 +291,6 @@ void setupPreferences() {
} }
#endif #endif
{
static const QString RENDER("Graphics");
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
if (renderConfig) {
auto mainViewAmbientOcclusionConfig = renderConfig->getConfig<AmbientOcclusionEffect>("RenderMainView.AmbientOcclusion");
if (mainViewAmbientOcclusionConfig) {
auto getter = [mainViewAmbientOcclusionConfig]()->QString { return mainViewAmbientOcclusionConfig->getPreset(); };
auto setter = [mainViewAmbientOcclusionConfig](QString preset) { mainViewAmbientOcclusionConfig->setPreset(preset); };
auto preference = new ComboBoxPreference(RENDER, "Ambient occlusion", getter, setter);
preference->setItems(mainViewAmbientOcclusionConfig->getPresetList());
preferences->addPreference(preference);
}
auto mainViewShadowConfig = renderConfig->getConfig<RenderShadowTask>("RenderMainView.RenderShadowTask");
if (mainViewShadowConfig) {
auto getter = [mainViewShadowConfig]()->QString { return mainViewShadowConfig->getPreset(); };
auto setter = [mainViewShadowConfig](QString preset) { mainViewShadowConfig->setPreset(preset); };
auto preference = new ComboBoxPreference(RENDER, "Shadows", getter, setter);
preference->setItems(mainViewShadowConfig->getPresetList());
preferences->addPreference(preference);
}
}
}
{ {
static const QString NETWORKING("Networking"); static const QString NETWORKING("Networking");

View file

@ -44,6 +44,8 @@ void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPro
const OverlayID UNKNOWN_OVERLAY_ID = OverlayID(); const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
/**jsdoc /**jsdoc
* The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection} or
* {@link Overlays.findRayIntersectionVector|findRayIntersectionVector}.
* @typedef {object} Overlays.RayToOverlayIntersectionResult * @typedef {object} Overlays.RayToOverlayIntersectionResult
* @property {boolean} intersects - <code>true</code> if the {@link PickRay} intersected with a 3D overlay, otherwise * @property {boolean} intersects - <code>true</code> if the {@link PickRay} intersected with a 3D overlay, otherwise
* <code>false</code>. * <code>false</code>.
@ -75,7 +77,8 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
* yourself and that aren't persisted to the domain. They are used for UI. * yourself and that aren't persisted to the domain. They are used for UI.
* @namespace Overlays * @namespace Overlays
* @property {Uuid} keyboardFocusOverlay - Get or set the {@link Overlays.OverlayType|web3d} overlay that has keyboard focus. * @property {Uuid} keyboardFocusOverlay - Get or set the {@link Overlays.OverlayType|web3d} overlay that has keyboard focus.
* If no overlay is set, get returns <code>null</code>; set to <code>null</code> to clear keyboard focus. * If no overlay has keyboard focus, get returns <code>null</code>; set to <code>null</code> or {@link Uuid|Uuid.NULL} to
* clear keyboard focus.
*/ */
class Overlays : public QObject { class Overlays : public QObject {
@ -116,7 +119,7 @@ public slots:
* @function Overlays.addOverlay * @function Overlays.addOverlay
* @param {Overlays.OverlayType} type - The type of the overlay to add. * @param {Overlays.OverlayType} type - The type of the overlay to add.
* @param {Overlays.OverlayProperties} properties - The properties of the overlay to add. * @param {Overlays.OverlayProperties} properties - The properties of the overlay to add.
* @returns {Uuid} The ID of the newly created overlay. * @returns {Uuid} The ID of the newly created overlay if successful, otherwise {@link Uuid|Uuid.NULL}.
* @example <caption>Add a cube overlay in front of your avatar.</caption> * @example <caption>Add a cube overlay in front of your avatar.</caption>
* var overlay = Overlays.addOverlay("cube", { * var overlay = Overlays.addOverlay("cube", {
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })), * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
@ -131,7 +134,7 @@ public slots:
* Create a clone of an existing overlay. * Create a clone of an existing overlay.
* @function Overlays.cloneOverlay * @function Overlays.cloneOverlay
* @param {Uuid} overlayID - The ID of the overlay to clone. * @param {Uuid} overlayID - The ID of the overlay to clone.
* @returns {Uuid} The ID of the new overlay. * @returns {Uuid} The ID of the new overlay if successful, otherwise {@link Uuid|Uuid.NULL}.
* @example <caption>Add an overlay in front of your avatar, clone it, and move the clone to be above the * @example <caption>Add an overlay in front of your avatar, clone it, and move the clone to be above the
* original.</caption> * original.</caption>
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })); * var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 }));
@ -322,10 +325,8 @@ public slots:
* @function Overlays.findRayIntersection * @function Overlays.findRayIntersection
* @param {PickRay} pickRay - The PickRay to use for finding overlays. * @param {PickRay} pickRay - The PickRay to use for finding overlays.
* @param {boolean} [precisionPicking=false] - <em>Unused</em>; exists to match Entity API. * @param {boolean} [precisionPicking=false] - <em>Unused</em>; exists to match Entity API.
* @param {Array.<Uuid>} [overlayIDsToInclude=[]] - Whitelist for intersection test. If empty then the result isn't limited * @param {Array.<Uuid>} [overlayIDsToInclude=[]] - If not empty then the search is restricted to these overlays.
* to overlays in the list. * @param {Array.<Uuid>} [overlayIDsToExclude=[]] - Overlays to ignore during the search.
* @param {Array.<Uuid>} [overlayIDsToExclude=[]] - Blacklist for intersection test. If empty then the result doesn't
* exclude overlays in the list.
* @param {boolean} [visibleOnly=false] - <em>Unused</em>; exists to match Entity API. * @param {boolean} [visibleOnly=false] - <em>Unused</em>; exists to match Entity API.
* @param {boolean} [collidableOnly=false] - <em>Unused</em>; exists to match Entity API. * @param {boolean} [collidableOnly=false] - <em>Unused</em>; exists to match Entity API.
* @returns {Overlays.RayToOverlayIntersectionResult} The closest 3D overlay intersected by <code>pickRay</code>, taking * @returns {Overlays.RayToOverlayIntersectionResult} The closest 3D overlay intersected by <code>pickRay</code>, taking
@ -531,7 +532,7 @@ public slots:
* Set the Web3D overlay that has keyboard focus. * Set the Web3D overlay that has keyboard focus.
* @function Overlays.setKeyboardFocusOverlay * @function Overlays.setKeyboardFocusOverlay
* @param {Uuid} overlayID - The ID of the {@link Overlays.OverlayType|web3d} overlay to set keyboard focus to. Use * @param {Uuid} overlayID - The ID of the {@link Overlays.OverlayType|web3d} overlay to set keyboard focus to. Use
* {@link Uuid|Uuid.NULL} or <code>null</code> to unset keyboard focus from an overlay. * <code>null</code> or {@link Uuid|Uuid.NULL} to unset keyboard focus from an overlay.
*/ */
void setKeyboardFocusOverlay(const OverlayID& id); void setKeyboardFocusOverlay(const OverlayID& id);

View file

@ -67,6 +67,32 @@ Shape3DOverlay* Shape3DOverlay::createClone() const {
} }
/**jsdoc
* <p>A <code>shape</code> {@link Overlays.OverlayType|OverlayType} may display as one of the following geometrical shapes:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Dimensions</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"Circle"</code></td><td>2D</td><td>A circle oriented in 3D.</td></td></tr>
* <tr><td><code>"Cone"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cube"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cylinder"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Dodecahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Hexagon"</code></td><td>3D</td><td>A hexagonal prism.</td></tr>
* <tr><td><code>"Icosahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Line"</code></td><td>1D</td><td>A line oriented in 3D.</td></tr>
* <tr><td><code>"Octagon"</code></td><td>3D</td><td>An octagonal prism.</td></tr>
* <tr><td><code>"Octahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Quad"</code></td><td>2D</td><td>A square oriented in 3D.</tr>
* <tr><td><code>"Sphere"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Tetrahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Torus"</code></td><td>3D</td><td><em>Not implemented.</em></td></tr>
* <tr><td><code>"Triangle"</code></td><td>3D</td><td>A triangular prism.</td></tr>
* </tbody>
* </table>
* @typedef {string} Overlays.Shape
*/
static const std::array<QString, GeometryCache::Shape::NUM_SHAPES> shapeStrings { { static const std::array<QString, GeometryCache::Shape::NUM_SHAPES> shapeStrings { {
"Line", "Line",
"Triangle", "Triangle",
@ -80,7 +106,7 @@ static const std::array<QString, GeometryCache::Shape::NUM_SHAPES> shapeStrings
"Octahedron", "Octahedron",
"Dodecahedron", "Dodecahedron",
"Icosahedron", "Icosahedron",
"Torus", "Torus", // Not implemented yet.
"Cone", "Cone",
"Cylinder" "Cylinder"
} }; } };
@ -145,7 +171,7 @@ void Shape3DOverlay::setProperties(const QVariantMap& properties) {
* *
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>. * @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>.
* *
* @property {Shape} shape=Hexagon - The geometrical shape of the overlay. * @property {Overlays.Shape} shape=Hexagon - The geometrical shape of the overlay.
*/ */
QVariant Shape3DOverlay::getProperty(const QString& property) { QVariant Shape3DOverlay::getProperty(const QString& property) {
if (property == "shape") { if (property == "shape") {

View file

@ -78,6 +78,20 @@ int AnimSkeleton::getParentIndex(int jointIndex) const {
return _joints[jointIndex].parentIndex; return _joints[jointIndex].parentIndex;
} }
std::vector<int> AnimSkeleton::getChildrenOfJoint(int jointIndex) const {
// Children and grandchildren, etc.
std::vector<int> result;
if (jointIndex != -1) {
for (int i = jointIndex + 1; i < (int)_joints.size(); i++) {
if (_joints[i].parentIndex == jointIndex
|| (std::find(result.begin(), result.end(), _joints[i].parentIndex) != result.end())) {
result.push_back(i);
}
}
}
return result;
}
const QString& AnimSkeleton::getJointName(int jointIndex) const { const QString& AnimSkeleton::getJointName(int jointIndex) const {
return _joints[jointIndex].name; return _joints[jointIndex].name;
} }

View file

@ -43,6 +43,7 @@ public:
const AnimPose& getPostRotationPose(int jointIndex) const; const AnimPose& getPostRotationPose(int jointIndex) const;
int getParentIndex(int jointIndex) const; int getParentIndex(int jointIndex) const;
std::vector<int> getChildrenOfJoint(int jointIndex) const;
AnimPose getAbsolutePose(int jointIndex, const AnimPoseVec& relativePoses) const; AnimPose getAbsolutePose(int jointIndex, const AnimPoseVec& relativePoses) const;

View file

@ -199,6 +199,8 @@ void Rig::destroyAnimGraph() {
_internalPoseSet._overridePoses.clear(); _internalPoseSet._overridePoses.clear();
_internalPoseSet._overrideFlags.clear(); _internalPoseSet._overrideFlags.clear();
_numOverrides = 0; _numOverrides = 0;
_leftEyeJointChildren.clear();
_rightEyeJointChildren.clear();
} }
void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) { void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) {
@ -225,12 +227,17 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
_rootJointIndex = geometry.rootJointIndex; _rootJointIndex = geometry.rootJointIndex;
_leftEyeJointIndex = geometry.leftEyeJointIndex;
_rightEyeJointIndex = geometry.rightEyeJointIndex;
_leftHandJointIndex = geometry.leftHandJointIndex; _leftHandJointIndex = geometry.leftHandJointIndex;
_leftElbowJointIndex = _leftHandJointIndex >= 0 ? geometry.joints.at(_leftHandJointIndex).parentIndex : -1; _leftElbowJointIndex = _leftHandJointIndex >= 0 ? geometry.joints.at(_leftHandJointIndex).parentIndex : -1;
_leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? geometry.joints.at(_leftElbowJointIndex).parentIndex : -1; _leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? geometry.joints.at(_leftElbowJointIndex).parentIndex : -1;
_rightHandJointIndex = geometry.rightHandJointIndex; _rightHandJointIndex = geometry.rightHandJointIndex;
_rightElbowJointIndex = _rightHandJointIndex >= 0 ? geometry.joints.at(_rightHandJointIndex).parentIndex : -1; _rightElbowJointIndex = _rightHandJointIndex >= 0 ? geometry.joints.at(_rightHandJointIndex).parentIndex : -1;
_rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? geometry.joints.at(_rightElbowJointIndex).parentIndex : -1; _rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? geometry.joints.at(_rightElbowJointIndex).parentIndex : -1;
_leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.leftEyeJointIndex);
_rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.rightEyeJointIndex);
} }
void Rig::reset(const FBXGeometry& geometry) { void Rig::reset(const FBXGeometry& geometry) {
@ -253,6 +260,8 @@ void Rig::reset(const FBXGeometry& geometry) {
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
_rootJointIndex = geometry.rootJointIndex; _rootJointIndex = geometry.rootJointIndex;
_leftEyeJointIndex = geometry.leftEyeJointIndex;
_rightEyeJointIndex = geometry.rightEyeJointIndex;
_leftHandJointIndex = geometry.leftHandJointIndex; _leftHandJointIndex = geometry.leftHandJointIndex;
_leftElbowJointIndex = _leftHandJointIndex >= 0 ? geometry.joints.at(_leftHandJointIndex).parentIndex : -1; _leftElbowJointIndex = _leftHandJointIndex >= 0 ? geometry.joints.at(_leftHandJointIndex).parentIndex : -1;
_leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? geometry.joints.at(_leftElbowJointIndex).parentIndex : -1; _leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? geometry.joints.at(_leftElbowJointIndex).parentIndex : -1;
@ -260,6 +269,9 @@ void Rig::reset(const FBXGeometry& geometry) {
_rightElbowJointIndex = _rightHandJointIndex >= 0 ? geometry.joints.at(_rightHandJointIndex).parentIndex : -1; _rightElbowJointIndex = _rightHandJointIndex >= 0 ? geometry.joints.at(_rightHandJointIndex).parentIndex : -1;
_rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? geometry.joints.at(_rightElbowJointIndex).parentIndex : -1; _rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? geometry.joints.at(_rightElbowJointIndex).parentIndex : -1;
_leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.leftEyeJointIndex);
_rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.rightEyeJointIndex);
if (!_animGraphURL.isEmpty()) { if (!_animGraphURL.isEmpty()) {
_animNode.reset(); _animNode.reset();
initAnimGraph(_animGraphURL); initAnimGraph(_animGraphURL);
@ -1430,6 +1442,15 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
// directly set absolutePose rotation // directly set absolutePose rotation
_internalPoseSet._absolutePoses[index].rot() = deltaQuat * headQuat; _internalPoseSet._absolutePoses[index].rot() = deltaQuat * headQuat;
// Update eye joint's children.
auto children = index == _leftEyeJointIndex ? _leftEyeJointChildren : _rightEyeJointChildren;
for (int i = 0; i < (int)children.size(); i++) {
int jointIndex = children[i];
int parentIndex = _animSkeleton->getParentIndex(jointIndex);
_internalPoseSet._absolutePoses[jointIndex] =
_internalPoseSet._absolutePoses[parentIndex] * _internalPoseSet._relativePoses[jointIndex];
}
} }
} }

View file

@ -267,6 +267,11 @@ protected:
int _rootJointIndex { -1 }; int _rootJointIndex { -1 };
int _leftEyeJointIndex { -1 };
int _rightEyeJointIndex { -1 };
std::vector<int> _leftEyeJointChildren;
std::vector<int> _rightEyeJointChildren;
int _leftHandJointIndex { -1 }; int _leftHandJointIndex { -1 };
int _leftElbowJointIndex { -1 }; int _leftElbowJointIndex { -1 };
int _leftShoulderJointIndex { -1 }; int _leftShoulderJointIndex { -1 };

View file

@ -43,14 +43,19 @@ void AudioClient::checkPeakValues() {
// prepare the windows environment // prepare the windows environment
CoInitialize(NULL); CoInitialize(NULL);
std::unique_lock<std::mutex> lock(_deviceMutex, std::defer_lock);
// if disabled, clean up active clients // if disabled, clean up active clients
if (!_enablePeakValues) { if (!_enablePeakValues) {
activeClients.clear(); if (lock.try_lock()) {
// deferred, if timer callbacks overlap
activeClients.clear();
}
return; return;
} }
// lock the devices so the _inputDevices list is static // lock the devices so the _inputDevices list is static
std::unique_lock<std::mutex> lock(_deviceMutex); lock.lock();
HRESULT result; HRESULT result;
// initialize the payload // initialize the payload

View file

@ -33,6 +33,10 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
{ {
// SkeletonModels, and by extention Avatars, use Dual Quaternion skinning. // SkeletonModels, and by extention Avatars, use Dual Quaternion skinning.
_useDualQuaternionSkinning = true; _useDualQuaternionSkinning = true;
// Avatars all cast shadow
_canCastShadow = true;
assert(_owningAvatar); assert(_owningAvatar);
} }

View file

@ -28,7 +28,7 @@ void Basic2DWindowOpenGLDisplayPlugin::customizeContext() {
auto iconPath = PathUtils::resourcesPath() + "images/analog_stick.png"; auto iconPath = PathUtils::resourcesPath() + "images/analog_stick.png";
auto image = QImage(iconPath); auto image = QImage(iconPath);
qreal dpi = getFullscreenTarget()->physicalDotsPerInch(); qreal dpi = getFullscreenTarget()->physicalDotsPerInch();
_virtualPadPixelSize = dpi * 512 / 534; // 534 dpi for Pixel XL and Mate 9 Pro _virtualPadPixelSize = dpi * VirtualPad::Manager::PIXEL_SIZE / VirtualPad::Manager::DPI;
if (image.format() != QImage::Format_ARGB32) { if (image.format() != QImage::Format_ARGB32) {
image = image.convertToFormat(QImage::Format_ARGB32); image = image.convertToFormat(QImage::Format_ARGB32);

View file

@ -90,7 +90,7 @@ public:
glm::vec2 getReticleMaximumPosition() const; glm::vec2 getReticleMaximumPosition() const;
glm::mat4 getReticleTransform(const glm::mat4& eyePose = glm::mat4(), const glm::vec3& headPosition = glm::vec3()) const; glm::mat4 getReticleTransform(const glm::mat4& eyePose = glm::mat4(), const glm::vec3& headPosition = glm::vec3()) const;
glm::mat4 getPoint2DTransform(const glm::vec2& point = glm::vec2(), float sizeX = 512.0f, float sizeY = 512.0f) const; glm::mat4 getPoint2DTransform(const glm::vec2& point, float sizeX , float sizeY) const;
ReticleInterface* getReticleInterface() { return _reticleInterface; } ReticleInterface* getReticleInterface() { return _reticleInterface; }

View file

@ -361,7 +361,7 @@ void OpenGLDisplayPlugin::customizeContext() {
auto presentThread = DependencyManager::get<PresentThread>(); auto presentThread = DependencyManager::get<PresentThread>();
Q_ASSERT(thread() == presentThread->thread()); Q_ASSERT(thread() == presentThread->thread());
getGLBackend()->setCameraCorrection(mat4()); getGLBackend()->setCameraCorrection(mat4(), mat4(), true);
for (auto& cursorValue : _cursorsData) { for (auto& cursorValue : _cursorsData) {
auto& cursorData = cursorValue.second; auto& cursorData = cursorValue.second;
@ -692,6 +692,9 @@ void OpenGLDisplayPlugin::present() {
incrementPresentCount(); incrementPresentCount();
if (_currentFrame) { if (_currentFrame) {
auto correction = getViewCorrection();
getGLBackend()->setCameraCorrection(correction, _prevRenderView);
_prevRenderView = correction * _currentFrame->view;
{ {
withPresentThreadLock([&] { withPresentThreadLock([&] {
_renderRate.increment(); _renderRate.increment();

View file

@ -118,6 +118,7 @@ protected:
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor, gpu::FramebufferPointer fbo); void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor, gpu::FramebufferPointer fbo);
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor); void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor);
virtual void updateFrameData(); virtual void updateFrameData();
virtual glm::mat4 getViewCorrection() { return glm::mat4(); }
void withOtherThreadContext(std::function<void()> f) const; void withOtherThreadContext(std::function<void()> f) const;
@ -137,6 +138,7 @@ protected:
gpu::FramePointer _currentFrame; gpu::FramePointer _currentFrame;
gpu::Frame* _lastFrame { nullptr }; gpu::Frame* _lastFrame { nullptr };
mat4 _prevRenderView;
gpu::FramebufferPointer _compositeFramebuffer; gpu::FramebufferPointer _compositeFramebuffer;
gpu::PipelinePointer _hudPipeline; gpu::PipelinePointer _hudPipeline;
gpu::PipelinePointer _mirrorHUDPipeline; gpu::PipelinePointer _mirrorHUDPipeline;

View file

@ -7,6 +7,8 @@
// //
#include "DebugHmdDisplayPlugin.h" #include "DebugHmdDisplayPlugin.h"
#include <ui-plugins/PluginContainer.h>
#include <QtCore/QProcessEnvironment> #include <QtCore/QProcessEnvironment>
#include <ViewFrustum.h> #include <ViewFrustum.h>
@ -41,7 +43,15 @@ bool DebugHmdDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
} }
bool DebugHmdDisplayPlugin::internalActivate() { bool DebugHmdDisplayPlugin::internalActivate() {
_isAutoRotateEnabled = _container->getBoolSetting("autoRotate", true);
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), tr("Auto Rotate"),
[this](bool clicked) {
_isAutoRotateEnabled = clicked;
_container->setBoolSetting("autoRotate", _isAutoRotateEnabled);
}, true, _isAutoRotateEnabled);
_ipd = 0.0327499993f * 2.0f; _ipd = 0.0327499993f * 2.0f;
// Would be nice to know why the left and right projection matrices are slightly dissymetrical
_eyeProjections[0][0] = vec4{ 0.759056330, 0.000000000, 0.000000000, 0.000000000 }; _eyeProjections[0][0] = vec4{ 0.759056330, 0.000000000, 0.000000000, 0.000000000 };
_eyeProjections[0][1] = vec4{ 0.000000000, 0.682773232, 0.000000000, 0.000000000 }; _eyeProjections[0][1] = vec4{ 0.000000000, 0.682773232, 0.000000000, 0.000000000 };
_eyeProjections[0][2] = vec4{ -0.0580431037, -0.00619550655, -1.00000489, -1.00000000 }; _eyeProjections[0][2] = vec4{ -0.0580431037, -0.00619550655, -1.00000489, -1.00000000 };
@ -50,10 +60,15 @@ bool DebugHmdDisplayPlugin::internalActivate() {
_eyeProjections[1][1] = vec4{ 0.000000000, 0.678060353, 0.000000000, 0.000000000 }; _eyeProjections[1][1] = vec4{ 0.000000000, 0.678060353, 0.000000000, 0.000000000 };
_eyeProjections[1][2] = vec4{ 0.0578232110, -0.00669418881, -1.00000489, -1.000000000 }; _eyeProjections[1][2] = vec4{ 0.0578232110, -0.00669418881, -1.00000489, -1.000000000 };
_eyeProjections[1][3] = vec4{ 0.000000000, 0.000000000, -0.0800003856, 0.000000000 }; _eyeProjections[1][3] = vec4{ 0.000000000, 0.000000000, -0.0800003856, 0.000000000 };
_eyeInverseProjections[0] = glm::inverse(_eyeProjections[0]); // No need to do so here as this will done in Parent::internalActivate
_eyeInverseProjections[1] = glm::inverse(_eyeProjections[1]); //_eyeInverseProjections[0] = glm::inverse(_eyeProjections[0]);
//_eyeInverseProjections[1] = glm::inverse(_eyeProjections[1]);
_eyeOffsets[0][3] = vec4{ -0.0327499993, 0.0, 0.0149999997, 1.0 }; _eyeOffsets[0][3] = vec4{ -0.0327499993, 0.0, 0.0149999997, 1.0 };
_eyeOffsets[1][3] = vec4{ 0.0327499993, 0.0, 0.0149999997, 1.0 }; _eyeOffsets[1][3] = vec4{ 0.0327499993, 0.0, 0.0149999997, 1.0 };
_eyeInverseProjections[0] = glm::inverse(_eyeProjections[0]);
_eyeInverseProjections[1] = glm::inverse(_eyeProjections[1]);
_eyeOffsets[0][3] = vec4{ -0.0327499993, 0.0, -0.0149999997, 1.0 };
_eyeOffsets[1][3] = vec4{ 0.0327499993, 0.0, -0.0149999997, 1.0 };
_renderTargetSize = { 3024, 1680 }; _renderTargetSize = { 3024, 1680 };
_cullingProjection = _eyeProjections[0]; _cullingProjection = _eyeProjections[0];
// This must come after the initialization, so that the values calculated // This must come after the initialization, so that the values calculated
@ -63,10 +78,13 @@ bool DebugHmdDisplayPlugin::internalActivate() {
} }
void DebugHmdDisplayPlugin::updatePresentPose() { void DebugHmdDisplayPlugin::updatePresentPose() {
float yaw = sinf(secTimestampNow()) * 0.25f; Parent::updatePresentPose();
float pitch = cosf(secTimestampNow()) * 0.25f; if (_isAutoRotateEnabled) {
// Simulates head pose latency correction float yaw = sinf(secTimestampNow()) * 0.25f;
_currentPresentFrameInfo.presentPose = float pitch = cosf(secTimestampNow()) * 0.25f;
glm::mat4_cast(glm::angleAxis(yaw, Vectors::UP)) * // Simulates head pose latency correction
glm::mat4_cast(glm::angleAxis(pitch, Vectors::RIGHT)); _currentPresentFrameInfo.presentPose =
glm::mat4_cast(glm::angleAxis(yaw, Vectors::UP)) *
glm::mat4_cast(glm::angleAxis(pitch, Vectors::RIGHT)) ;
}
} }

View file

@ -28,5 +28,7 @@ protected:
bool isHmdMounted() const override { return true; } bool isHmdMounted() const override { return true; }
bool internalActivate() override; bool internalActivate() override;
private: private:
static const QString NAME; static const QString NAME;
bool _isAutoRotateEnabled{ true };
}; };

View file

@ -58,6 +58,18 @@ QRect HmdDisplayPlugin::getRecommendedHUDRect() const {
return CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT; return CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT;
} }
glm::mat4 HmdDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
return _eyeOffsets[eye];
}
glm::mat4 HmdDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const {
return _eyeProjections[eye];
}
glm::mat4 HmdDisplayPlugin::getCullingProjection(const glm::mat4& baseProjection) const {
return _cullingProjection;
}
#define DISABLE_PREVIEW_MENU_ITEM_DELAY_MS 500 #define DISABLE_PREVIEW_MENU_ITEM_DELAY_MS 500
bool HmdDisplayPlugin::internalActivate() { bool HmdDisplayPlugin::internalActivate() {
@ -324,12 +336,14 @@ void HmdDisplayPlugin::updateFrameData() {
} }
updatePresentPose(); updatePresentPose();
}
glm::mat4 HmdDisplayPlugin::getViewCorrection() {
if (_currentFrame) { if (_currentFrame) {
auto batchPose = _currentFrame->pose; auto batchPose = _currentFrame->pose;
auto currentPose = _currentPresentFrameInfo.presentPose; return glm::inverse(_currentPresentFrameInfo.presentPose) * batchPose;
auto correction = glm::inverse(batchPose) * currentPose; } else {
getGLBackend()->setCameraCorrection(correction); return glm::mat4();
} }
} }

View file

@ -26,9 +26,9 @@ public:
~HmdDisplayPlugin(); ~HmdDisplayPlugin();
bool isHmd() const override final { return true; } bool isHmd() const override final { return true; }
float getIPD() const override final { return _ipd; } float getIPD() const override final { return _ipd; }
glm::mat4 getEyeToHeadTransform(Eye eye) const override final { return _eyeOffsets[eye]; } glm::mat4 getEyeToHeadTransform(Eye eye) const override final;
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override { return _eyeProjections[eye]; } glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override;
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override { return _cullingProjection; } glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override;
glm::uvec2 getRecommendedUiSize() const override final; glm::uvec2 getRecommendedUiSize() const override final;
glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; } glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; }
bool isDisplayVisible() const override { return isHmdMounted(); } bool isDisplayVisible() const override { return isHmdMounted(); }
@ -59,6 +59,7 @@ protected:
void customizeContext() override; void customizeContext() override;
void uncustomizeContext() override; void uncustomizeContext() override;
void updateFrameData() override; void updateFrameData() override;
glm::mat4 getViewCorrection() override;
std::array<mat4, 2> _eyeOffsets; std::array<mat4, 2> _eyeOffsets;
std::array<mat4, 2> _eyeProjections; std::array<mat4, 2> _eyeProjections;

View file

@ -101,3 +101,4 @@ void StereoDisplayPlugin::internalDeactivate() {
float StereoDisplayPlugin::getRecommendedAspectRatio() const { float StereoDisplayPlugin::getRecommendedAspectRatio() const {
return aspect(Parent::getRecommendedRenderSize()); return aspect(Parent::getRecommendedRenderSize());
} }

View file

@ -26,7 +26,7 @@ public:
// the IPD at the Application level, the way we now allow with HMDs. // the IPD at the Application level, the way we now allow with HMDs.
// If that becomes an issue then we'll need to break up the functionality similar // If that becomes an issue then we'll need to break up the functionality similar
// to the HMD plugins. // to the HMD plugins.
// virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; //virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
protected: protected:
virtual bool internalActivate() override; virtual bool internalActivate() override;

View file

@ -433,7 +433,7 @@ void ZoneEntityRenderer::setAmbientURL(const QString& ambientUrl) {
_ambientTexture = textureCache->getTexture(_ambientTextureURL, image::TextureUsage::CUBE_TEXTURE); _ambientTexture = textureCache->getTexture(_ambientTextureURL, image::TextureUsage::CUBE_TEXTURE);
// keep whatever is assigned on the ambient map/sphere until texture is loaded // keep whatever is assigned on the ambient map/sphere until texture is loaded
} }
} }
void ZoneEntityRenderer::updateAmbientMap() { void ZoneEntityRenderer::updateAmbientMap() {

View file

@ -30,7 +30,7 @@ void main(void) {
varTexcoord = inTexCoord0.st; varTexcoord = inTexCoord0.st;
// pass along the diffuse color // pass along the diffuse color
varColor = colorToLinearRGBA(inColor); varColor = color_sRGBAToLinear(inColor);
// standard transform // standard transform

View file

@ -31,7 +31,7 @@ void main(void) {
varTexcoord = inTexCoord0.st; varTexcoord = inTexCoord0.st;
// pass along the diffuse color // pass along the diffuse color
varColor = colorToLinearRGBA(inColor); varColor = color_sRGBAToLinear(inColor);
// standard transform // standard transform

View file

@ -27,6 +27,14 @@ class OctreePacketData;
class EntityTreeElementExtraEncodeData; class EntityTreeElementExtraEncodeData;
class ReadBitstreamToTreeParams; class ReadBitstreamToTreeParams;
/**jsdoc
* Ambient light is defined by the following properties.
* @typedef {object} Entities.AmbientLight
* @property {number} ambientIntensity=0.5 - The intensity of the light.
* @property {string} ambientURL="" - A cube map image that defines the color of the light coming from each direction. If
* <code>""</code> then the entity's {@link Entities.Skybox|Skybox} <code>url</code> property value is used, unless that also is <code>""</code> in which
* case the entity's <code>ambientLightMode</code> property is set to <code>"inherit"</code>.
*/
class AmbientLightPropertyGroup : public PropertyGroup { class AmbientLightPropertyGroup : public PropertyGroup {
public: public:
// EntityItemProperty related helpers // EntityItemProperty related helpers

View file

@ -44,6 +44,19 @@ bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b
} }
/**jsdoc
* The AnimationProperties are used to configure an animation.
* @typedef Entities.AnimationProperties
* @property {string} url="" - The URL of the FBX file that has the animation.
* @property {number} fps=30 - The speed in frames/s that the animation is played at.
* @property {number} firstFrame=0 - The first frame to play in the animation.
* @property {number} lastFrame=100000 - The last frame to play in the animation.
* @property {number} currentFrame=0 - The current frame being played in the animation.
* @property {boolean} running=false - If <code>true</code> then the animation should play.
* @property {boolean} loop=true - If <code>true</code> then the animation should be continuously repeated in a loop.
* @property {boolean} hold=false - If <code>true</code> then the rotations and translations of the last frame played should be
* maintained when the animation stops playing.
*/
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);

View file

@ -94,6 +94,49 @@ variables. These argument variables are used by the code which is run when bull
#include "EntityDynamicInterface.h" #include "EntityDynamicInterface.h"
/**jsdoc
* <p>An entity action may be one of the following types:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Type</th><th>Description</th><th>Arguments</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"far-grab"</code></td><td>Avatar action</td>
* <td>Moves and rotates an entity to a target position and orientation, optionally relative to another entity. Collisions
* between the entity and the user's avatar are disabled during the far-grab.</td>
* <td>{@link Entities.ActionArguments-FarGrab}</td></tr>
* <tr><td><code>"hold"</code></td><td>Avatar action</td>
* <td>Positions and rotates an entity relative to an avatar's hand. Collisions between the entity and the user's avatar
* are disabled during the hold.</td>
* <td>{@link Entities.ActionArguments-Hold}</td></tr>
* <tr><td><code>"offset"</code></td><td>Object action</td>
* <td>Moves an entity so that it is a set distance away from a target point.</td>
* <td>{@link Entities.ActionArguments-Offset}</td></tr>
* <tr><td><code>"tractor"</code></td><td>Object action</td>
* <td>Moves and rotates an entity to a target position and orientation, optionally relative to another entity.</td>
* <td>{@link Entities.ActionArguments-Tractor}</td></tr>
* <tr><td><code>"travel-oriented"</code></td><td>Object action</td>
* <td>Orients an entity to align with its direction of travel.</td>
* <td>{@link Entities.ActionArguments-TravelOriented}</td></tr>
* <tr><td><code>"hinge"</code></td><td>Object constraint</td>
* <td>Lets an entity pivot about an axis or connects two entities with a hinge joint.</td>
* <td>{@link Entities.ActionArguments-Hinge}</td></tr>
* <tr><td><code>"slider"</code></td><td>Object constraint</td>
* <td>Lets an entity slide and rotate along an axis, or connects two entities that slide and rotate along a shared
* axis.</td>
* <td>{@link Entities.ActionArguments-Slider|ActionArguments-Slider}</td></tr>
* <tr><td><code>"cone-twist"</code></td><td>Object constraint</td>
* <td>Connects two entities with a joint that can move through a cone and can twist.</td>
* <td>{@link Entities.ActionArguments-ConeTwist}</td></tr>
* <tr><td><code>"ball-socket"</code></td><td>Object constraint</td>
* <td>Connects two entities with a ball and socket joint.</td>
* <td>{@link Entities.ActionArguments-BallSocket}</td></tr>
* <tr><td><code>"spring"</code></td><td colspan="3">Synonym for <code>"tractor"</code>. <em>Legacy value.</em></td></tr>
* </tbody>
* </table>
* @typedef {string} Entities.ActionType
*/
// Note: The "none" action type is not listed because it's an internal "uninitialized" value and not useful for scripts.
EntityDynamicType EntityDynamicInterface::dynamicTypeFromString(QString dynamicTypeString) { EntityDynamicType EntityDynamicInterface::dynamicTypeFromString(QString dynamicTypeString) {
QString normalizedDynamicTypeString = dynamicTypeString.toLower().remove('-').remove('_'); QString normalizedDynamicTypeString = dynamicTypeString.toLower().remove('-').remove('_');
if (normalizedDynamicTypeString == "none") { if (normalizedDynamicTypeString == "none") {

View file

@ -440,6 +440,707 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
return changedProperties; return changedProperties;
} }
/**jsdoc
* Different entity types have different properties: some common to all entities (listed below) and some specific to each
* {@link Entities.EntityType|EntityType} (linked to below). The properties are accessed as an object of property names and
* values.
*
* @typedef {object} Entities.EntityProperties
* @property {Uuid} id - The ID of the entity. <em>Read-only.</em>
* @property {string} name="" - A name for the entity. Need not be unique.
* @property {Entities.EntityType} type - The entity type. You cannot change the type of an entity after it's created. (Though
* its value may switch among <code>"Box"</code>, <code>"Shape"</code>, and <code>"Sphere"</code> depending on changes to
* the <code>shape</code> property set for entities of these types.) <em>Read-only.</em>
* @property {boolean} clientOnly=false - If <code>true</code> then the entity is an avatar entity, otherwise it is a server
* entity. <em>Read-only.</em>
* @property {Uuid} owningAvatarID=Uuid.NULL - The session ID of the owning avatar if <code>clientOnly</code> is
* <code>true</code>, otherwise {@link Uuid|Uuid.NULL}. <em>Read-only.</em>
*
* @property {string} created - The UTC date and time that the entity was created, in ISO 8601 format as
* <code>yyyy-MM-ddTHH:mm:ssZ</code>. <em>Read-only.</em>
* @property {number} age - The age of the entity in seconds since it was created. <em>Read-only.</em>
* @property {string} ageAsText - The age of the entity since it was created, formatted as <code>h hours m minutes s
* seconds</code>.
* @property {number} lifetime=-1 - How long an entity lives for, in seconds, before being automatically deleted. A value of
* <code>-1</code> means that the entity lives for ever.
* @property {number} lastEdited - When the entity was last edited, expressed as the number of microseconds since
* 1970-01-01T00:00:00 UTC. <em>Read-only.</em>
* @property {Uuid} lastEditedBy - The session ID of the avatar or agent that most recently created or edited the entity.
* <em>Read-only.</em>
*
* @property {boolean} locked=false - Whether or not the entity can be edited or deleted. If <code>true</code> then the
* entity's properties other than <code>locked</code> cannot be changed, and the entity cannot be deleted.
* @property {boolean} visible=true - Whether or not the entity is rendered. If <code>true</code> then the entity is rendered.
* @property {boolean} canCastShadows=true - Whether or not the entity casts shadows. Currently applicable only to
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities. Shadows are cast if inside a
* {@link Entities.EntityType|Zone} entity with <code>castShadows</code> enabled in its {@link Entities.EntityProperties-Zone|keyLight} property.
*
* @property {Vec3} position=0,0,0 - The position of the entity.
* @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates.
* @property {Vec3} registrationPoint=0.5,0.5,0.5 - The point in the entity that is set to the entity's position and is rotated
* about, {@link Vec3|Vec3.ZERO} &ndash; {@link Vec3|Vec3.ONE}. A value of {@link Vec3|Vec3.ZERO} is the entity's
* minimum x, y, z corner; a value of {@link Vec3|Vec3.ONE} is the entity's maximum x, y, z corner.
*
* @property {Vec3} naturalPosition=0,0,0 - The center of the entity's unscaled mesh model if it has one, otherwise
* {@link Vec3|Vec3.ZERO}. <em>Read-only.</em>
* @property {Vec3} naturalDimensions - The dimensions of the entity's unscaled mesh model if it has one, otherwise
* {@link Vec3|Vec3.ONE}. <em>Read-only.</em>
*
* @property {Vec3} velocity=0,0,0 - The linear velocity of the entity in m/s with respect to world coordinates.
* @property {number} damping=0.39347 - How much to slow down the linear velocity of an entity over time, <code>0.0</code>
* &ndash; <code>1.0</code>. A higher damping value slows down the entity more quickly. The default value is for an
* exponential decay timescale of 2.0s, where it takes 2.0s for the movement to slow to <code>1/e = 0.368</code> of its
* initial value.
* @property {Vec3} angularVelocity=0,0,0 - The angular velocity of the entity in rad/s with respect to its axes, about its
* registration point.
* @property {number} angularDamping=0.39347 - How much to slow down the angular velocity of an entity over time,
* <code>0.0</code> &ndash; <code>1.0</code>. A higher damping value slows down the entity more quickly. The default value
* is for an exponential decay timescale of 2.0s, where it takes 2.0s for the movement to slow to <code>1/e = 0.368</code>
* of its initial value.
*
* @property {Vec3} gravity=0,0,0 - The acceleration due to gravity in m/s<sup>2</sup> that the entity should move with, in
* world coordinates. Set to <code>{ x: 0, y: -9.8, z: 0 }</code> to simulate Earth's gravity. Gravity is applied to an
* entity's motion only if its <code>dynamic</code> property is <code>true</code>. If changing an entity's
* <code>gravity</code> from {@link Vec3|Vec3.ZERO}, you need to give it a small <code>velocity</code> in order to kick off
* physics simulation.
* The <code>gravity</code> value is applied in addition to the <code>acceleration</code> value.
* @property {Vec3} acceleration=0,0,0 - A general acceleration in m/s<sup>2</sup> that the entity should move with, in world
* coordinates. The acceleration is applied to an entity's motion only if its <code>dynamic</code> property is
* <code>true</code>. If changing an entity's <code>acceleration</code> from {@link Vec3|Vec3.ZERO}, you need to give it a
* small <code>velocity</code> in order to kick off physics simulation.
* The <code>acceleration</code> value is applied in addition to the <code>gravity</code> value.
* @property {number} restitution=0.5 - The "bounciness" of an entity when it collides, <code>0.0</code> &ndash;
* <code>0.99</code>. The higher the value, the more bouncy.
* @property {number} friction=0.5 - How much to slow down an entity when it's moving against another, <code>0.0</code> &ndash;
* <code>10.0</code>. The higher the value, the more quickly it slows down. Examples: <code>0.1</code> for ice,
* <code>0.9</code> for sandpaper.
* @property {number} density=1000 - The density of the entity in kg/m<sup>3</sup>, <code>100</code> for balsa wood &ndash;
* <code>10000</code> for silver. The density is used in conjunction with the entity's bounding box volume to work out its
* mass in the application of physics.
*
* @property {boolean} collisionless=false - Whether or not the entity should collide with items per its
* <code>collisionMask<code> property. If <code>true</code> then the entity does not collide.
* @property {boolean} ignoreForCollisions=false - Synonym for <code>collisionless</code>.
* @property {Entities.CollisionMask} collisionMask=31 - What types of items the entity should collide with.
* @property {string} collidesWith="static,dynamic,kinematic,myAvatar,otherAvatar," - Synonym for <code>collisionMask</code>,
* in text format.
* @property {string} collisionSoundURL="" - The sound to play when the entity experiences a collision. Valid file formats are
* as per the {@link SoundCache} object.
* @property {boolean} dynamic=false - Whether or not the entity should be affected by collisions. If <code>true</code> then
* the entity's movement is affected by collisions.
* @property {boolean} collisionsWillMove=false - Synonym for <code>dynamic</code>.
*
* @property {string} href="" - A "hifi://" metaverse address that a user is taken to when they click on the entity.
* @property {string} description="" - A description of the <code>href</code> property value.
*
* @property {string} userData="" - Used to store extra data about the entity in JSON format. WARNING: Other apps such as the
* Create app can also use this property, so make sure you handle data stored by other apps &mdash; edit only your bit and
* leave the rest of the data intact. You can use <code>JSON.parse()</code> to parse the string into a JavaScript object
* which you can manipulate the properties of, and use <code>JSON.stringify()</code> to convert the object into a string to
* put in the property.
*
* @property {string} script="" - The URL of the client entity script, if any, that is attached to the entity.
* @property {number} scriptTimestamp=0 - Intended to be used to indicate when the client entity script was loaded. Should be
* an integer number of milliseconds since midnight GMT on January 1, 1970 (e.g., as supplied by <code>Date.now()</code>.
* If you update the property's value, the <code>script</code> is re-downloaded and reloaded. This is how the "reload"
* button beside the "script URL" field in properties tab of the Create app works.
* @property {string} serverScripts="" - The URL of the server entity script, if any, that is attached to the entity.
*
* @property {Uuid} parentID=Uuid.NULL - The ID of the entity or avatar that this entity is parented to. {@link Uuid|Uuid.NULL}
* if the entity is not parented.
* @property {number} parentJointIndex=65535 - The joint of the entity or avatar that this entity is parented to. Use
* <code>65535</code> or <code>-1</code> to parent to the entity or avatar's position and orientation rather than a joint.
* @property {Vec3} localPosition=0,0,0 - The position of the entity relative to its parent if the entity is parented,
* otherwise the same value as <code>position</code>. If the entity is parented to an avatar and is <code>clientOnly</code>
* so that it scales with the avatar, this value remains the original local position value while the avatar scale changes.
* @property {Quat} localRotation=0,0,0,1 - The rotation of the entity relative to its parent if the entity is parented,
* otherwise the same value as <code>rotation</code>.
* @property {Vec3} localVelocity=0,0,0 - The velocity of the entity relative to its parent if the entity is parented,
* otherwise the same value as <code>velocity</code>.
* @property {Vec3} localAngularVelocity=0,0,0 - The angular velocity of the entity relative to its parent if the entity is
* parented, otherwise the same value as <code>position</code>.
* @property {Vec3} localDimensions - The dimensions of the entity. If the entity is parented to an avatar and is
* <code>clientOnly</code> so that it scales with the avatar, this value remains the original dimensions value while the
* avatar scale changes.
*
* @property {Entities.BoundingBox} boundingBox - The axis-aligned bounding box that tightly encloses the entity.
* <em>Read-only.</em>
* @property {AACube} queryAACube - The axis-aligned cube that determines where the entity lives in the entity server's octree.
* The cube may be considerably larger than the entity in some situations, e.g., when the entity is grabbed by an avatar:
* the position of the entity is determined through avatar mixer updates and so the AA cube is expanded in order to reduce
* unnecessary entity server updates. Scripts should not change this property's value.
*
* @property {string} actionData="" - Base-64 encoded compressed dump of the actions associated with the entity. This property
* is typically not used in scripts directly; rather, functions that manipulate an entity's actions update it.
* The size of this property increases with the number of actions. Because this property value has to fit within a High
* Fidelity datagram packet there is a limit to the number of actions that an entity can have, and edits which would result
* in overflow are rejected.
* <em>Read-only.</em>
* @property {Entities.RenderInfo} renderInfo - Information on the cost of rendering the entity. Currently information is only
* provided for <code>Model</code> entities. <em>Read-only.</em>
*
* @property {string} itemName="" - Certifiable name of the Marketplace item.
* @property {string} itemDescription="" - Certifiable description of the Marketplace item.
* @property {string} itemCategories="" - Certifiable category of the Marketplace item.
* @property {string} itemArtist="" - Certifiable artist that created the Marketplace item.
* @property {string} itemLicense="" - Certifiable license URL for the Marketplace item.
* @property {number} limitedRun=4294967295 - Certifiable maximum integer number of editions (copies) of the Marketplace item
* allowed to be sold.
* @property {number} editionNumber=0 - Certifiable integer edition (copy) number or the Marketplace item. Each copy sold in
* the Marketplace is numbered sequentially, starting at 1.
* @property {number} entityInstanceNumber=0 - Certifiable integer instance number for identical entities in a Marketplace
* item. A Marketplace item may have identical parts. If so, then each is numbered sequentially with an instance number.
* @property {string} marketplaceID="" - Certifiable UUID for the Marketplace item, as used in the URL of the item's download
* and its Marketplace Web page.
* @property {string} certificateID="" - Hash of the entity's static certificate JSON, signed by the artist's private key.
* @property {number} staticCertificateVersion=0 - The version of the method used to generate the <code>certificateID</code>.
*
* @see The different entity types have additional properties as follows:
* @see {@link Entities.EntityProperties-Box|EntityProperties-Box}
* @see {@link Entities.EntityProperties-Light|EntityProperties-Light}
* @see {@link Entities.EntityProperties-Line|EntityProperties-Line}
* @see {@link Entities.EntityProperties-Material|EntityProperties-Material}
* @see {@link Entities.EntityProperties-Model|EntityProperties-Model}
* @see {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect}
* @see {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine}
* @see {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox}
* @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape}
* @see {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere}
* @see {@link Entities.EntityProperties-Text|EntityProperties-Text}
* @see {@link Entities.EntityProperties-Web|EntityProperties-Web}
* @see {@link Entities.EntityProperties-Zone|EntityProperties-Zone}
*/
/**jsdoc
* The <code>"Box"</code> {@link Entities.EntityType|EntityType} is the same as the <code>"Shape"</code>
* {@link Entities.EntityType|EntityType} except that its <code>shape</code> value is always set to <code>"Cube"</code>
* when the entity is created. If its <code>shape</code> property value is subsequently changed then the entity's
* <code>type</code> will be reported as <code>"Sphere"</code> if the <code>shape</code> is set to <code>"Sphere"</code>,
* otherwise it will be reported as <code>"Shape"</code>.
* @typedef {object} Entities.EntityProperties-Box
*/
/**jsdoc
* The <code>"Light"</code> {@link Entities.EntityType|EntityType} adds local lighting effects.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-Light
* @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. Entity surface outside these dimensions are not lit
* by the light.
* @property {Color} color=255,255,255 - The color of the light emitted.
* @property {number} intensity=1 - The brightness of the light.
* @property {number} falloffRadius=0.1 - The distance from the light's center at which intensity is reduced by 25%.
* @property {boolean} isSpotlight=false - If <code>true</code> then the light is directional, emitting along the entity's
* local negative z-axis; otherwise the light is a point light which emanates in all directions.
* @property {number} exponent=0 - Affects the softness of the spotlight beam: the higher the value the softer the beam.
* @property {number} cutoff=1.57 - Affects the size of the spotlight beam: the higher the value the larger the beam.
* @example <caption>Create a spotlight pointing at the ground.</caption>
* Entities.addEntity({
* type: "Light",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -4 })),
* rotation: Quat.fromPitchYawRollDegrees(-75, 0, 0),
* dimensions: { x: 5, y: 5, z: 5 },
* intensity: 100,
* falloffRadius: 0.3,
* isSpotlight: true,
* exponent: 20,
* cutoff: 30,
* lifetime: 300 // Delete after 5 minutes.
* });
*/
/**jsdoc
* The <code>"Line"</code> {@link Entities.EntityType|EntityType} draws thin, straight lines between a sequence of two or more
* points.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-Line
* @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. Must be sufficient to contain all the
* <code>linePoints</code>.
* @property {Vec3[]} linePoints=[]] - The sequence of points to draw lines between. The values are relative to the entity's
* position. A maximum of 70 points can be specified. The property's value is set only if all the <code>linePoints</code>
* lie within the entity's <code>dimensions</code>.
* @property {number} lineWidth=2 - <em>Currently not used.</em>
* @property {Color} color=255,255,255 - The color of the line.
* @example <caption>Draw lines in a "V".</caption>
* var entity = Entities.addEntity({
* type: "Line",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })),
* rotation: MyAvatar.orientation,
* dimensions: { x: 2, y: 2, z: 1 },
* linePoints: [
* { x: -1, y: 1, z: 0 },
* { x: 0, y: -1, z: 0 },
* { x: 1, y: 1, z: 0 },
* ],
* color: { red: 255, green: 0, blue: 0 },
* lifetime: 300 // Delete after 5 minutes.
* });
*/
/**jsdoc
* The <code>"Material"</code> {@link Entities.EntityType|EntityType} modifies the existing materials on
* {@link Entities.EntityType|Model} entities, {@link Entities.EntityType|Shape} entities (albedo only),
* {@link Overlays.OverlayType|model overlays}, and avatars.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.<br />
* To apply a material to an entity or overlay, set the material entity's <code>parentID</code> property to the entity or
* overlay's ID.
* To apply a material to an avatar, set the material entity's <code>parentID</code> property to the avatar's session UUID.
* To apply a material to your avatar such that it persists across domains and log-ins, create the material as an avatar entity
* by setting the <code>clientOnly</code> parameter in {@link Entities.addEntity} to <code>true</code>.
* Material entities render as non-scalable spheres if they don't have their parent set.
* @typedef {object} Entities.EntityProperties-Material
* @property {string} materialURL="" - URL to a {@link MaterialResource}. If you append <code>?name</code> to the URL, the
* material with that name in the {@link MaterialResource} will be applied to the entity. <br />
* Alternatively, set the property value to <code>"userData"</code> to use the {@link Entities.EntityProperties|userData}
* entity property to live edit the material resource values.
* @property {number} priority=0 - The priority for applying the material to its parent. Only the highest priority material is
* applied, with materials of the same priority randomly assigned. Materials that come with the model have a priority of
* <code>0</code>.
* @property {string|number} parentMaterialName="0" - Selects the submesh or submeshes within the parent to apply the material
* to. If in the format <code>"mat::string"</code>, all submeshes with material name <code>"string"</code> are replaced.
* Otherwise the property value is parsed as an unsigned integer, specifying the mesh index to modify. Invalid values are
* parsed to <code>0</code>.
* @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either <code>"uv"</code> or
* <code>"projected"</code>. <em>Currently, only <code>"uv"</code> is supported.
* @property {Vec2} materialMappingPos=0,0 - Offset position in UV-space of the top left of the material, range
* <code>{ x: 0, y: 0 }</code> &ndash; <code>{ x: 1, y: 1 }</code>.
* @property {Vec2} materialMappingScale=1,1 - How much to scale the material within the parent's UV-space.
* @property {number} materialMappingRot=0 - How much to rotate the material within the parent's UV-space, in degrees.
* @example <caption>Color a sphere using a Material entity.</caption>
* var entityID = Entities.addEntity({
* type: "Sphere",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* dimensions: { x: 1, y: 1, z: 1 },
* color: { red: 128, green: 128, blue: 128 },
* lifetime: 300 // Delete after 5 minutes.
* });
*
* var materialID = Entities.addEntity({
* type: "Material",
* parentID: entityID,
* materialURL: "userData",
* priority: 1,
* userData: JSON.stringify({
* materials: {
* // Can only set albedo on a Shape entity.
* // Value overrides entity's "color" property.
* albedo: [1.0, 0, 0]
* }
* }),
* });
*/
/**jsdoc
* The <code>"Model"</code> {@link Entities.EntityType|EntityType} displays an FBX or OBJ model.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-Model
* @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. When adding an entity, if no <code>dimensions</code>
* value is specified then the model is automatically sized to its
* <code>{@link Entities.EntityProperties|naturalDimensions}</code>.
* @property {Color} color=255,255,255 - <em>Currently not used.</em>
* @property {string} modelURL="" - The URL of the FBX of OBJ model. Baked FBX models' URLs end in ".baked.fbx".<br />
* Note: If the name ends with <code>"default-image-model.fbx"</code> then the entity is considered to be an "Image"
* entity, in which case the <code>textures</code> property should be set per the example.
* @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the
* model's original textures. Use a texture name from the <code>originalTextures</code> property to override that texture.
* Only the texture names and URLs to be overridden need be specified; original textures are used where there are no
* overrides. You can use <code>JSON.stringify()</code> to convert a JavaScript object of name, URL pairs into a JSON
* string.
* @property {string} originalTextures="{}" - A JSON string of texture name, URL pairs used in the model. The property value is
* filled in after the entity has finished rezzing (i.e., textures have loaded). You can use <code>JSON.parse()</code> to
* parse the JSON string into a JavaScript object of name, URL pairs. <em>Read-only.</em>
*
* @property {ShapeType} shapeType="none" - The shape of the collision hull used if collisions are enabled.
* @property {string} compoundShapeURL="" - The OBJ file to use for the compound shape if <code>shapeType</code> is
* <code>"compound"</code>.
*
* @property {Entities.AnimationProperties} animation - An animation to play on the model.
*
* @property {Quat[]} jointRotations=[]] - Joint rotations applied to the model; <code>[]</code> if none are applied or the
* model hasn't loaded. The array indexes are per {@link Entities.getJointIndex|getJointIndex}. Rotations are relative to
* each joint's parent.<br />
* Joint rotations can be set by {@link Entities.setLocalJointRotation|setLocalJointRotation} and similar functions, or by
* setting the value of this property. If you set a joint rotation using this property you also need to set the
* corresponding <code>jointRotationsSet</code> value to <code>true</code>.
* @property {boolean[]} jointRotationsSet=[]] - <code>true</code> values for joints that have had rotations applied,
* <code>false</code> otherwise; <code>[]</code> if none are applied or the model hasn't loaded. The array indexes are per
* {@link Entities.getJointIndex|getJointIndex}.
* @property {Vec3[]} jointTranslations=[]] - Joint translations applied to the model; <code>[]</code> if none are applied or
* the model hasn't loaded. The array indexes are per {@link Entities.getJointIndex|getJointIndex}. Rotations are relative
* to each joint's parent.<br />
* Joint translations can be set by {@link Entities.setLocalJointTranslation|setLocalJointTranslation} and similar
* functions, or by setting the value of this property. If you set a joint translation using this property you also need to
* set the corresponding <code>jointTranslationsSet</code> value to <code>true</code>.
* @property {boolean[]} jointTranslationsSet=[]] - <code>true</code> values for joints that have had translations applied,
* <code>false</code> otherwise; <code>[]</code> if none are applied or the model hasn't loaded. The array indexes are per
* {@link Entities.getJointIndex|getJointIndex}.
* @property {boolean} relayParentJoints=false - If <code>true</code> and the entity is parented to an avatar, then the
* avatar's joint rotations are applied to the entity's joints.
*
* @example <caption>Rez a Vive tracker puck.</caption>
* var entity = Entities.addEntity({
* type: "Model",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -2 })),
* rotation: MyAvatar.orientation,
* modelURL: "http://content.highfidelity.com/seefo/production/puck-attach/vive_tracker_puck.obj",
* dimensions: { x: 0.0945, y: 0.0921, z: 0.0423 },
* lifetime: 300 // Delete after 5 minutes.
* });
* @example <caption>Create an "Image" entity like you can in the Create app.</caption>
* var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx";
* var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg";
* var entity = Entities.addEntity({
* type: "Model",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -3 })),
* rotation: MyAvatar.orientation,
* dimensions: {
* x: 0.5385,
* y: 0.2819,
* z: 0.0092
* },
* shapeType: "box",
* collisionless: true,
* modelURL: IMAGE_MODEL,
* textures: JSON.stringify({ "tex.picture": DEFAULT_IMAGE }),
* lifetime: 300 // Delete after 5 minutes
* });
*/
/**jsdoc
* The <code>"ParticleEffect"</code> {@link Entities.EntityType|EntityType} displays a particle system that can be used to
* simulate things such as fire, smoke, snow, magic spells, etc. The particles emanate from an ellipsoid or part thereof.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-ParticleEffect
* @property {boolean} isEmitting=true - If <code>true</code> then particles are emitted.
* @property {number} maxParticles=1000 - The maximum number of particles to render at one time. Older particles are deleted if
* necessary when new ones are created.
* @property {number} lifespan=3s - How long, in seconds, each particle lives.
* @property {number} emitRate=15 - The number of particles per second to emit.
* @property {number} emitSpeed=5 - The speed, in m/s, that each particle is emitted at.
* @property {number} speedSpread=1 - The spread in speeds at which particles are emitted at. If <code>emitSpeed == 5</code>
* and <code>speedSpread == 1</code>, particles will be emitted with speeds in the range 4m/s &ndash; 6m/s.
* @property {vec3} emitAcceleration=0,-9.8,0 - The acceleration that is applied to each particle during its lifetime. The
* default is Earth's gravity value.
* @property {vec3} accelerationSpread=0,0,0 - The spread in accelerations that each particle is given. If
* <code>emitAccelerations == {x: 0, y: -9.8, z: 0}</code> and <code>accelerationSpread ==
* {x: 0, y: 1, z: 0}</code>, each particle will have an acceleration in the range, <code>{x: 0, y: -10.8, z: 0}</code>
* &ndash; <code>{x: 0, y: -8.8, z: 0}</code>.
* @property {Vec3} dimensions - The dimensions of the particle effect, i.e., a bounding box containing all the particles
* during their lifetimes, assuming that <code>emitterShouldTrail</code> is <code>false</code>. <em>Read-only.</em>
* @property {boolean} emitterShouldTrail=false - If <code>true</code> then particles are "left behind" as the emitter moves,
* otherwise they stay with the entity's dimensions.
*
* @property {Quat} emitOrientation=-0.707,0,0,0.707 - The orientation of particle emission relative to the entity's axes. By
* default, particles emit along the entity's local z-axis, and <code>azimuthStart</code> and <code>azimuthFinish</code>
* are relative to the entity's local x-axis. The default value is a rotation of -90 degrees about the local x-axis, i.e.,
* the particles emit vertically.
* @property {vec3} emitDimensions=0,0,0 - The dimensions of the ellipsoid from which particles are emitted.
* @property {number} emitRadiusStart=1 - The starting radius within the ellipsoid at which particles start being emitted;
* range <code>0.0</code> &ndash; <code>1.0</code> for the ellipsoid center to the ellipsoid surface, respectively.
* Particles are emitted from the portion of the ellipsoid that lies between <code>emitRadiusStart</code> and the
* ellipsoid's surface.
* @property {number} polarStart=0 - The angle in radians from the entity's local z-axis at which particles start being emitted
* within the ellipsoid; range <code>0</code> &ndash; <code>Math.PI</code>. Particles are emitted from the portion of the
* ellipsoid that lies between <code>polarStart<code> and <code>polarFinish</code>.
* @property {number} polarFinish=0 - The angle in radians from the entity's local z-axis at which particles stop being emitted
* within the ellipsoid; range <code>0</code> &ndash; <code>Math.PI</code>. Particles are emitted from the portion of the
* ellipsoid that lies between <code>polarStart<code> and <code>polarFinish</code>.
* @property {number} azimuthStart=-Math.PI - The angle in radians from the entity's local x-axis about the entity's local
* z-axis at which particles start being emitted; range <code>-Math.PI</code> &ndash; <code>Math.PI</code>. Particles are
* emitted from the portion of the ellipsoid that lies between <code>azimuthStart<code> and <code>azimuthFinish</code>.
* @property {number} azimuthFinish=Math.PI - The angle in radians from the entity's local x-axis about the entity's local
* z-axis at which particles stop being emitted; range <code>-Math.PI</code> &ndash; <code>Math.PI</code>. Particles are
* emitted from the portion of the ellipsoid that lies between <code>azimuthStart<code> and <code>azimuthFinish</code>.
*
* @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency,
* use PNG format.
* @property {number} particleRadius=0.025 - The radius of each particle at the middle of its life.
* @property {number} radiusStart=0.025 - The radius of each particle at the start of its life. If not explicitly set, the
* <code>particleRadius</code> value is used.
* @property {number} radiusFinish=0.025 - The radius of each particle at the end of its life. If not explicitly set, the
* <code>particleRadius</code> value is used.
* @property {number} radiusSpread=0 - <em>Currently not used.</em>
* @property {Color} color=255,255,255 - The color of each particle at the middle of its life.
* @property {Color} colorStart=255,255,255 - The color of each particle at the start of its life. If not explicitly set, the
* <code>color</code> value is used.
* @property {Color} colorFinish=255,255,255 - The color of each particle at the end of its life. If not explicitly set, the
* <code>color</code> value is used.
* @property {Color} colorSpread=0,0,0 - <em>Currently not used.</em>
* @property {number} alpha=1 - The alpha of each particle at the middle of its life.
* @property {number} alphaStart=1 - The alpha of each particle at the start of its life. If not explicitly set, the
* <code>alpha</code> value is used.
* @property {number} alphaFinish=1 - The alpha of each particle at the end of its life. If not explicitly set, the
* <code>alpha</code> value is used.
* @property {number} alphaSpread=0 - <em>Currently not used.</em>
*
* @property {ShapeType} shapeType="none" - <em>Currently not used.</em> <em>Read-only.</em>
*
* @example <caption>Create a ball of green smoke.</caption>
* particles = Entities.addEntity({
* type: "ParticleEffect",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -4 })),
* lifespan: 5,
* emitRate: 10,
* emitSpeed: 0.02,
* speedSpread: 0.01,
* emitAcceleration: { x: 0, y: 0.02, z: 0 },
* polarFinish: Math.PI,
* textures: "https://content.highfidelity.com/DomainContent/production/Particles/wispy-smoke.png",
* particleRadius: 0.1,
* color: { red: 0, green: 255, blue: 0 },
* alphaFinish: 0,
* lifetime: 300 // Delete after 5 minutes.
* });
*/
/**jsdoc
* The <code>"PolyLine"</code> {@link Entities.EntityType|EntityType} draws textured, straight lines between a sequence of
* points.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-PolyLine
* @property {Vec3} dimensions=1,1,1 - The dimensions of the entity, i.e., the size of the bounding box that contains the
* lines drawn.
* @property {Vec3[]} linePoints=[]] - The sequence of points to draw lines between. The values are relative to the entity's
* position. A maximum of 70 points can be specified. Must be specified in order for the entity to render.
* @property {Vec3[]} normals=[]] - The normal vectors for the line's surface at the <code>linePoints</code>. The values are
* relative to the entity's orientation. Must be specified in order for the entity to render.
* @property {number[]} strokeWidths=[]] - The widths, in m, of the line at the <code>linePoints</code>. Must be specified in
* order for the entity to render.
* @property {number} lineWidth=2 - <em>Currently not used.</code>
* @property {Vec3[]} strokeColors=[]] - <em>Currently not used.</em>
* @property {Color} color=255,255,255 - The base color of the line, which is multiplied with the color of the texture for
* rendering.
* @property {string} textures="" - The URL of a JPG or PNG texture to use for the lines. If you want transparency, use PNG
* format.
* @property {boolean} isUVModeStretch=true - If <code>true</code>, the texture is stretched to fill the whole line, otherwise
* the texture repeats along the line.
* @example <caption>Draw a textured "V".</caption>
* var entity = Entities.addEntity({
* type: "PolyLine",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })),
* rotation: MyAvatar.orientation,
* linePoints: [
* { x: -1, y: 0.5, z: 0 },
* { x: 0, y: 0, z: 0 },
* { x: 1, y: 0.5, z: 0 }
* ],
* normals: [
* { x: 0, y: 0, z: 1 },
* { x: 0, y: 0, z: 1 },
* { x: 0, y: 0, z: 1 }
* ],
* strokeWidths: [ 0.1, 0.1, 0.1 ],
* color: { red: 255, green: 0, blue: 0 }, // Use just the red channel from the image.
* textures: "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/flowArts/trails.png",
* isUVModeStretch: true,
* lifetime: 300 // Delete after 5 minutes.
* });
*/
/**jsdoc
* The <code>"PolyVox"</code> {@link Entities.EntityType|EntityType} displays a set of textured voxels.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* If you have two or more neighboring PolyVox entities of the same size abutting each other, you can display them as joined by
* configuring their <code>voxelSurfaceStyle</code> and neighbor ID properties.<br />
* PolyVox entities uses a library from <a href="http://www.volumesoffun.com/">Volumes of Fun</a>. Their
* <a href="http://www.volumesoffun.com/polyvox-documentation/">library documentation</a> may be useful to read.
* @typedef {object} Entities.EntityProperties-PolyVox
* @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity.
* @property {Vec3} voxelVolumeSize=32,32,32 - Integer number of voxels along each axis of the entity, in the range
* <code>1,1,1</code> to <code>128,128,128</code>. The dimensions of each voxel is
* <code>dimensions / voxelVolumesize</code>.
* @property {string} voxelData="ABAAEAAQAAAAHgAAEAB42u3BAQ0AAADCoPdPbQ8HFAAAAPBuEAAAAQ==" - Base-64 encoded compressed dump of
* the PolyVox data. This property is typically not used in scripts directly; rather, functions that manipulate a PolyVox
* entity update it.<br />
* The size of this property increases with the size and complexity of the PolyVox entity, with the size depending on how
* the particular entity's voxels compress. Because this property value has to fit within a High Fidelity datagram packet
* there is a limit to the size and complexity of a PolyVox entity, and edits which would result in an overflow are
* rejected.
* @property {Entities.PolyVoxSurfaceStyle} voxelSurfaceStyle=2 - The style of rendering the voxels' surface and how
* neighboring PolyVox entities are joined.
* @property {string} xTextureURL="" - URL of the texture to map to surfaces perpendicular to the entity's local x-axis. JPG or
* PNG format. If no texture is specified the surfaces display white.
* @property {string} yTextureURL="" - URL of the texture to map to surfaces perpendicular to the entity's local y-axis. JPG or
* PNG format. If no texture is specified the surfaces display white.
* @property {string} zTextureURL="" - URL of the texture to map to surfaces perpendicular to the entity's local z-axis. JPG or
* PNG format. If no texture is specified the surfaces display white.
* @property {Uuid} xNNeighborID=Uuid.NULL - ID of the neighboring PolyVox entity in the entity's -ve local x-axis direction,
* if you want them joined. Set to {@link Uuid|Uuid.NULL} if there is none or you don't want to join them.
* @property {Uuid} yNNeighborID=Uuid.NULL - ID of the neighboring PolyVox entity in the entity's -ve local y-axis direction,
* if you want them joined. Set to {@link Uuid|Uuid.NULL} if there is none or you don't want to join them.
* @property {Uuid} zNNeighborID=Uuid.NULL - ID of the neighboring PolyVox entity in the entity's -ve local z-axis direction,
* if you want them joined. Set to {@link Uuid|Uuid.NULL} if there is none or you don't want to join them.
* @property {Uuid} xPNeighborID=Uuid.NULL - ID of the neighboring PolyVox entity in the entity's +ve local x-axis direction,
* if you want them joined. Set to {@link Uuid|Uuid.NULL} if there is none or you don't want to join them.
* @property {Uuid} yPNeighborID=Uuid.NULL - ID of the neighboring PolyVox entity in the entity's +ve local y-axis direction,
* if you want them joined. Set to {@link Uuid|Uuid.NULL} if there is none or you don't want to join them.
* @property {Uuid} zPNeighborID=Uuid.NULL - ID of the neighboring PolyVox entity in the entity's +ve local z-axis direction,
* if you want them joined. Set to {@link Uuid|Uuid.NULL} if there is none or you don't want to join them.
* @example <caption>Create a textured PolyVox sphere.</caption>
* var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 }));
* var texture = "http://public.highfidelity.com/cozza13/tuscany/Concrete2.jpg";
* var polyVox = Entities.addEntity({
* type: "PolyVox",
* position: position,
* dimensions: { x: 2, y: 2, z: 2 },
* xTextureURL: texture,
* yTextureURL: texture,
* zTextureURL: texture,
* lifetime: 300 // Delete after 5 minutes.
* });
* Entities.setVoxelSphere(polyVox, position, 0.8, 255);
*/
/**jsdoc
* The <code>"Shape"</code> {@link Entities.EntityType|EntityType} displays an entity of a specified <code>shape</code>.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-Shape
* @property {Entities.Shape} shape="Sphere" - The shape of the entity.
* @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity.
* @property {Color} color=255,255,255 - The color of the entity.
* @example <caption>Create a cylinder.</caption>
* var shape = Entities.addEntity({
* type: "Shape",
* shape: "Cylinder",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* dimensions: { x: 0.4, y: 0.6, z: 0.4 },
* lifetime: 300 // Delete after 5 minutes.
* });
*/
/**jsdoc
* The <code>"Sphere"</code> {@link Entities.EntityType|EntityType} is the same as the <code>"Shape"</code>
* {@link Entities.EntityType|EntityType} except that its <code>shape</code> value is always set to <code>"Sphere"</code>
* when the entity is created. If its <code>shape</code> property value is subsequently changed then the entity's
* <code>type</code> will be reported as <code>"Box"</code> if the <code>shape</code> is set to <code>"Cube"</code>,
* otherwise it will be reported as <code>"Shape"</code>.
* @typedef {object} Entities.EntityProperties-Sphere
*/
/**jsdoc
* The <code>"Text"</code> {@link Entities.EntityType|EntityType} displays a 2D rectangle of text in the domain.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-Text
* @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity.
* @property {string} text="" - The text to display on the face of the entity. Text wraps if necessary to fit. New lines can be
* created using <code>\n</code>. Overflowing lines are not displayed.
* @property {number} lineHeight=0.1 - The height of each line of text (thus determining the font size).
* @property {Color} textColor=255,255,255 - The color of the text.
* @property {Color} backgroundColor=0,0,0 - The color of the background rectangle.
* @property {boolean} faceCamera=false - If <code>true</code>, the entity is oriented to face each user's camera (i.e., it
* differs for each user present).
* @example <caption>Create a text entity.</caption>
* var text = Entities.addEntity({
* type: "Text",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })),
* dimensions: { x: 0.6, y: 0.3, z: 0.01 },
* lineHeight: 0.12,
* text: "Hello\nthere!",
* faceCamera: true,
* lifetime: 300 // Delete after 5 minutes.
* });
*/
/**jsdoc
* The <code>"Web"</code> {@link Entities.EntityType|EntityType} displays a browsable Web page. Each user views their own copy
* of the Web page: if one user navigates to another page on the entity, other users do not see the change; if a video is being
* played, users don't see it in sync.
* The entity has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-Web
* @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity.
* @property {string} sourceUrl="" - The URL of the Web page to display. This value does not change as you or others navigate
* on the Web entity.
* @property {number} dpi=30 - The resolution to display the page at, in dots per inch. If you convert this to dots per meter
* (multiply by 1 / 0.0254 = 39.3701) then multiply <code>dimensions.x</code> and <code>dimensions.y</code> by that value
* you get the resolution in pixels.
* @example <caption>Create a Web entity displaying at 1920 x 1080 resolution.</caption>
* var METERS_TO_INCHES = 39.3701;
* var entity = Entities.addEntity({
* type: "Web",
* sourceUrl: "https://highfidelity.com/",
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -4 })),
* rotation: MyAvatar.orientation,
* dimensions: {
* x: 3,
* y: 3 * 1080 / 1920,
* z: 0.01
* },
* dpi: 1920 / (3 * METERS_TO_INCHES),
* lifetime: 300 // Delete after 5 minutes.
* });
*/
/**jsdoc
* The <code>"Zone"</code> {@link Entities.EntityType|EntityType} is a volume of lighting effects and avatar permissions.
* Avatar interaction events such as {@link Entities.enterEntity} are also often used with a Zone entity.
* It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}.
* @typedef {object} Entities.EntityProperties-Zone
* @property {Vec3} dimensions=0.1,0.1,0.1 - The size of the volume in which the zone's lighting effects and avatar permissions
* have effect.
*
* @property {ShapeType} shapeType="box" - The shape of the volume in which the zone's lighting effects and avatar
* permissions have effect. Reverts to the default value if set to <code>"none"</code>, or set to <code>"compound"</code>
* and <code>compoundShapeURL</code> is <code>""</code>.
* @property {string} compoundShapeURL="" - The OBJ file to use for the compound shape if <code>shapeType</code> is
* <code>"compound"</code>.
*
* @property {string} keyLightMode="inherit" - Configures the key light in the zone. Possible values:<br />
* <code>"inherit"</code>: The key light from any enclosing zone continues into this zone.<br />
* <code>"disabled"</code>: The key light from any enclosing zone and the key light of this zone are disabled in this
* zone.<br />
* <code>"enabled"</code>: The key light properties of this zone are enabled, overriding the key light of from any
* enclosing zone.
* @property {Entities.KeyLight} keyLight - The key light properties of the zone.
*
* @property {string} ambientLightMode="inherit" - Configures the ambient light in the zone. Possible values:<br />
* <code>"inherit"</code>: The ambient light from any enclosing zone continues into this zone.<br />
* <code>"disabled"</code>: The ambient light from any enclosing zone and the ambient light of this zone are disabled in
* this zone.<br />
* <code>"enabled"</code>: The ambient light properties of this zone are enabled, overriding the ambient light from any
* enclosing zone.
* @property {Entities.AmbientLight} ambientLight - The ambient light properties of the zone.
*
* @property {string} skyboxMode="inherit" - Configures the skybox displayed in the zone. Possible values:<br />
* <code>"inherit"</code>: The skybox from any enclosing zone is dislayed in this zone.<br />
* <code>"disabled"</code>: The skybox from any enclosing zone and the skybox of this zone are disabled in this zone.<br />
* <code>"enabled"</code>: The skybox properties of this zone are enabled, overriding the skybox from any enclosing zone.
* @property {Entities.Skybox} skybox - The skybox properties of the zone.
*
* @property {string} hazeMode="inherit" - Configures the haze in the zone. Possible values:<br />
* <code>"inherit"</code>: The haze from any enclosing zone continues into this zone.<br />
* <code>"disabled"</code>: The haze from any enclosing zone and the haze of this zone are disabled in this zone.<br />
* <code>"enabled"</code>: The haze properties of this zone are enabled, overriding the haze from any enclosing zone.
* @property {Entities.Haze} haze - The haze properties of the zone.
*
* @property {boolean} flyingAllowed=true - If <code>true</code> then visitors can fly in the zone; otherwise they cannot.
* @property {boolean} ghostingAllowed=true - If <code>true</code> then visitors with avatar collisions turned off will not
* collide with content in the zone; otherwise visitors will always collide with content in the zone.
* @property {string} filterURL="" - The URL of a JavaScript file that filters changes to properties of entities within the
* zone. It is periodically executed for each entity in the zone. It can, for example, be used to not allow changes to
* certain properties.<br />
* <pre>
* function filter(properties) {
* // Test and edit properties object values,
* // e.g., properties.modelURL, as required.
* return properties;
* }
* </pre>
*
* @example <caption>Create a zone that casts a red key light along the x-axis.</caption>
* var zone = Entities.addEntity({
* type: "Zone",
* position: MyAvatar.position,
* dimensions: { x: 100, y: 100, z: 100 },
* keyLightMode: "enabled",
* keyLight: {
* "color": { "red": 255, "green": 0, "blue": 0 },
* "direction": { "x": 1, "y": 0, "z": 0 }
* },
* lifetime: 300 // Delete after 5 minutes.
* });
*/
QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, bool strictSemantics) const { QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, bool strictSemantics) const {
// If strictSemantics is true and skipDefaults is false, then all and only those properties are copied for which the property flag // If strictSemantics is true and skipDefaults is false, then all and only those properties are copied for which the property flag
// is included in _desiredProperties, or is one of the specially enumerated ALWAYS properties below. // is included in _desiredProperties, or is one of the specially enumerated ALWAYS properties below.
@ -491,7 +1192,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CAN_CAST_SHADOW, canCastShadow); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CAN_CAST_SHADOW, canCastShadow); // Relevant to Shape and Model entities only.
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONLESS, collisionless); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONLESS, collisionless);
COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISIONLESS, collisionless, ignoreForCollisions, getCollisionless()); // legacy support COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISIONLESS, collisionless, ignoreForCollisions, getCollisionless()); // legacy support
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask);
@ -500,7 +1201,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_DYNAMIC, dynamic, collisionsWillMove, getDynamic()); // legacy support COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_DYNAMIC, dynamic, collisionsWillMove, getDynamic()); // legacy support
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FACE_CAMERA, faceCamera); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FACE_CAMERA, faceCamera); // Text only.
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData);
@ -521,7 +1222,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
// Boxes, Spheres, Light, Line, Model(??), Particle, PolyLine // Light, Line, Model, ParticleEffect, PolyLine, Shape
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR, color); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR, color);
// Particles only // Particles only
@ -569,12 +1270,15 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
if (_type == EntityTypes::Model || _type == EntityTypes::Zone || _type == EntityTypes::ParticleEffect) { if (_type == EntityTypes::Model || _type == EntityTypes::Zone || _type == EntityTypes::ParticleEffect) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString());
} }
// FIXME: Shouldn't provide a shapeType property for Box and Sphere entities.
if (_type == EntityTypes::Box) { if (_type == EntityTypes::Box) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Box")); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Box"));
} }
if (_type == EntityTypes::Sphere) { if (_type == EntityTypes::Sphere) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Sphere")); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Sphere"));
} }
if (_type == EntityTypes::Box || _type == EntityTypes::Sphere || _type == EntityTypes::Shape) { if (_type == EntityTypes::Box || _type == EntityTypes::Sphere || _type == EntityTypes::Shape) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHAPE, shape); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHAPE, shape);
} }
@ -653,11 +1357,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
if (_type == EntityTypes::Line || _type == EntityTypes::PolyLine) { if (_type == EntityTypes::Line || _type == EntityTypes::PolyLine) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals); // Polyline only.
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_COLORS, strokeColors); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_COLORS, strokeColors); // Polyline only.
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths); // Polyline only.
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); // Polyline only.
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch); // Polyline only.
} }
// Materials // Materials
@ -671,6 +1375,14 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot);
} }
/**jsdoc
* The axis-aligned bounding box of an entity.
* @typedef Entities.BoundingBox
* @property {Vec3} brn - The bottom right near (minimum axes values) corner of the AA box.
* @property {Vec3} tfl - The top far left (maximum axes values) corner of the AA box.
* @property {Vec3} center - The center of the AA box.
* @property {Vec3} dimensions - The dimensions of the AA box.
*/
if (!skipDefaults && !strictSemantics) { if (!skipDefaults && !strictSemantics) {
AABox aaBox = getAABox(); AABox aaBox = getAABox();
QScriptValue boundingBox = engine->newObject(); QScriptValue boundingBox = engine->newObject();
@ -692,6 +1404,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_QUERY_AA_CUBE, queryAACube); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_QUERY_AA_CUBE, queryAACube);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition);
@ -700,13 +1413,23 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_DIMENSIONS, localDimensions); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_DIMENSIONS, localDimensions);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly); // Gettable but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); // Gettable but not settable
// Rendering info // Rendering info
if (!skipDefaults && !strictSemantics) { if (!skipDefaults && !strictSemantics) {
QScriptValue renderInfo = engine->newObject(); QScriptValue renderInfo = engine->newObject();
/**jsdoc
* Information on how an entity is rendered. Properties are only filled in for <code>Model</code> entities; other
* entity types have an empty object, <code>{}</code>.
* @typedef {object} Entities.RenderInfo
* @property {number} verticesCount - The number of vertices in the entity.
* @property {number} texturesCount - The number of textures in the entity.
* @property {number} textureSize - The total size of the textures in the entity, in bytes.
* @property {boolean} hasTransparent - Is <code>true</code> if any of the textures has transparency.
* @property {number} drawCalls - The number of draw calls required to render the entity.
*/
// currently only supported by models // currently only supported by models
if (_type == EntityTypes::Model) { if (_type == EntityTypes::Model) {
renderInfo.setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int renderInfo.setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int
@ -719,6 +1442,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable
} }
// FIXME: These properties should already have been set above.
properties.setProperty("clientOnly", convertScriptValue(engine, getClientOnly())); properties.setProperty("clientOnly", convertScriptValue(engine, getClientOnly()));
properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID())); properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID()));

View file

@ -208,7 +208,7 @@ public:
DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector<glm::vec3>, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector<glm::vec3>, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC);
DEFINE_PROPERTY(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector<glm::vec3>, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); DEFINE_PROPERTY(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector<glm::vec3>, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC);
DEFINE_PROPERTY(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector<float>, QVector<float>()); DEFINE_PROPERTY(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector<float>, QVector<float>());
DEFINE_PROPERTY(PROP_IS_UV_MODE_STRETCH, IsUVModeStretch, isUVModeStretch, bool, true); DEFINE_PROPERTY(PROP_IS_UV_MODE_STRETCH, IsUVModeStretch, isUVModeStretch, bool, true);
DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString, ""); DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString, "");
DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString, ""); DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString, "");
DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString, ""); DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString, "");

View file

@ -538,7 +538,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
NestableType nestableType = nestable->getNestableType(); NestableType nestableType = nestable->getNestableType();
if (nestableType == NestableType::Overlay || nestableType == NestableType::Avatar) { if (nestableType == NestableType::Overlay || nestableType == NestableType::Avatar) {
qCWarning(entities) << "attempted edit on non-entity: " << id << nestable->getName(); qCWarning(entities) << "attempted edit on non-entity: " << id << nestable->getName();
return QUuid(); // null UUID to indicate failure return QUuid(); // null script value to indicate failure
} }
} }
} }
@ -1017,6 +1017,25 @@ QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, c
QString faceName = ""; QString faceName = "";
// handle BoxFace // handle BoxFace
/**jsdoc
* <p>A <code>BoxFace</code> specifies the face of an axis-aligned (AA) box.
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"MIN_X_FACE"</code></td><td>The minimum x-axis face.</td></tr>
* <tr><td><code>"MAX_X_FACE"</code></td><td>The maximum x-axis face.</td></tr>
* <tr><td><code>"MIN_Y_FACE"</code></td><td>The minimum y-axis face.</td></tr>
* <tr><td><code>"MAX_Y_FACE"</code></td><td>The maximum y-axis face.</td></tr>
* <tr><td><code>"MIN_Z_FACE"</code></td><td>The minimum z-axis face.</td></tr>
* <tr><td><code>"MAX_Z_FACE"</code></td><td>The maximum z-axis face.</td></tr>
* <tr><td><code>"UNKNOWN_FACE"</code></td><td>Unknown value.</td></tr>
* </tbody>
* </table>
* @typedef {string} BoxFace
*/
// FIXME: Move enum to string function to BoxBase.cpp.
switch (value.face) { switch (value.face) {
case MIN_X_FACE: case MIN_X_FACE:
faceName = "MIN_X_FACE"; faceName = "MIN_X_FACE";

File diff suppressed because it is too large Load diff

View file

@ -35,6 +35,56 @@ typedef EntityItemPointer (*EntityTypeFactory)(const EntityItemID& entityID, con
class EntityTypes { class EntityTypes {
public: public:
/**jsdoc
* <p>An entity may be one of the following types:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th><th>Properties</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"Box"</code></td><td>A rectangular prism. This is a synonym of <code>"Shape"</code> for the case
* where the entity's <code>shape</code> property value is <code>"Cube"</code>.<br />
* If an entity is created with its <code>type</code>
* set to <code>"Box"</code> it will always be created with a <code>shape</code> property value of
* <code>"Cube"</code>. If an entity of type <code>Shape</code> or <code>Sphere</code> has its <code>shape</code> set
* to <code>"Cube"</code> then its <code>type</code> will be reported as <code>"Box"</code>.
* <td>{@link Entities.EntityProperties-Box|EntityProperties-Box}</td></tr>
* <tr><td><code>"Light"</code></td><td>A local lighting effect.</td>
* <td>{@link Entities.EntityProperties-Light|EntityProperties-Light}</td></tr>
* <tr><td><code>"Line"</code></td><td>A sequence of one or more simple straight lines.</td>
* <td>{@link Entities.EntityProperties-Line|EntityProperties-Line}</td></tr>
* <tr><td><code>"Material"</code></td><td>Modifies the existing materials on Model entities, Shape entities (albedo
* only), {@link Overlays.OverlayType|model overlays}, and avatars.</td>
* <td>{@link Entities.EntityProperties-Material|EntityProperties-Material}</td></tr>
* <tr><td><code>"Model"</code></td><td>A mesh model from an FBX or OBJ file.</td>
* <td>{@link Entities.EntityProperties-Model|EntityProperties-Model}</td></tr>
* <tr><td><code>"ParticleEffect"</code></td><td>A particle system that can be used to simulate things such as fire,
* smoke, snow, magic spells, etc.</td>
* <td>{@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect}</td></tr>
* <tr><td><code>"PolyLine"</code></td><td>A sequence of one or more textured straight lines.</td>
* <td>{@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine}</td></tr>
* <tr><td><code>"PolyVox"</code></td><td>A set of textured voxels.</td>
* <td>{@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox}</td></tr>
* <tr><td><code>"Shape"</code></td><td>A basic entity such as a cube.
* See also, the <code>"Box"</code> and <code>"Sphere"</code> entity types.</td>
* <td>{@link Entities.EntityProperties-Shape|EntityProperties-Shape}</td></tr>
* <tr><td><code>"Sphere"</code></td><td>A sphere. This is a synonym of <code>"Shape"</code> for the case
* where the entity's <code>shape</code> property value is <code>"Sphere"</code>.<br />
* If an entity is created with its <code>type</code>
* set to <code>"Sphere"</code> it will always be created with a <code>shape</code> property value of
* <code>"Sphere"</code>. If an entity of type <code>Box</code> or <code>Shape</code> has its <code>shape</code> set
* to <code>"Sphere"</code> then its <code>type</code> will be reported as <code>"Sphere"</code>.
* <td>{@link Entities.EntityProperties-Sphere|EntityProperties-Sphere}</td></tr>
* <tr><td><code>"Text"</code></td><td>A pane of text oriented in space.</td>
* <td>{@link Entities.EntityProperties-Text|EntityProperties-Text}</td></tr>
* <tr><td><code>"Web"</code></td><td>A browsable Web page.</td>
* <td>{@link Entities.EntityProperties-Web|EntityProperties-Web}</td></tr>
* <tr><td><code>"Zone"</code></td><td>A volume of lighting effects and avatar permissions.</td>
* <td>{@link Entities.EntityProperties-Zone|EntityProperties-Zone}</td></tr>
* </tbody>
* </table>
* @typedef {string} Entities.EntityType
*/
typedef enum EntityType_t { typedef enum EntityType_t {
Unknown, Unknown,
Model, Model,

View file

@ -40,6 +40,35 @@ static const float INITIAL_HAZE_BACKGROUND_BLEND{ 0.0f };
static const float INITIAL_KEY_LIGHT_RANGE{ 1000.0f }; static const float INITIAL_KEY_LIGHT_RANGE{ 1000.0f };
static const float INITIAL_KEY_LIGHT_ALTITUDE{ 200.0f }; static const float INITIAL_KEY_LIGHT_ALTITUDE{ 200.0f };
// FIXME: Document hazeAttenuationKeyLight, hazeKeyLightRange, and hazeKeyLightAltitude once they're working and are provided
// in the Create app's UI.
/**jsdoc
* Haze is defined by the following properties.
* @typedef {object} Entities.Haze
*
* @property {number} hazeRange=1000 - The horizontal distance at which visibility is reduced to 95%; i.e., 95% of each pixel's
* color is haze.
* @property {Color} hazeColor=128,154,179 - The color of the haze when looking away from the key light.
* @property {boolean} hazeEnableGlare=false - If <code>true</code> then the haze is colored with glare from the key light;
* <code>hazeGlareColor</code> and <code>hazeGlareAngle</code> are used.
* @property {Color} hazeGlareColor=255,299,179 - The color of the haze when looking towards the key light.
* @property {number} hazeGlareAngle=20 - The angle in degrees across the circle around the key light that the glare color and
* haze color are blended 50/50.
*
* @property {boolean} hazeAltitudeEffect=false - If <code>true</code> then haze decreases with altitude as defined by the
* entity's local coordinate system; <code>hazeBaseRef</code> and </code>hazeCeiling</code> are used.
* @property {number} hazeBaseRef=0 - The y-axis value in the entity's local coordinate system at which the haze density starts
* reducing with altitude.
* @property {number} hazeCeiling=200 - The y-axis value in the entity's local coordinate system at which the haze density has
* reduced to 5%.
*
* @property {number} hazeBackgroundBlend=0 - The proportion of the skybox image to show through the haze: <code>0.0</code>
* displays no skybox image; <code>1.0</code> displays no haze.
*
* @property {boolean} hazeAttenuateKeyLight=false - <em>Currently not supported.</em>
* @property {number} hazeKeyLightRange=1000 - <em>Currently not supported.</em>
* @property {number} hazeKeyLightAltitude=200 - <em>Currently not supported.</em>
*/
class HazePropertyGroup : public PropertyGroup { class HazePropertyGroup : public PropertyGroup {
public: public:
// EntityItemProperty related helpers // EntityItemProperty related helpers

View file

@ -27,6 +27,16 @@ class OctreePacketData;
class EntityTreeElementExtraEncodeData; class EntityTreeElementExtraEncodeData;
class ReadBitstreamToTreeParams; class ReadBitstreamToTreeParams;
/**jsdoc
* A key light is defined by the following properties.
* @typedef {object} Entities.KeyLight
* @property {Color} color=255,255,255 - The color of the light.
* @property {number} intensity=1 - The intensity of the light.
* @property {Vec3} direction=0,-1,0 - The direction the light is shining.
* @property {boolean} castShadows=false - If <code>true</code> then shadows are cast. Shadows are cast by avatars, plus
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities that have their
* <code>{@link Entities.EntityProperties|canCastShadows}</code> property set to <code>true</code>.
*/
class KeyLightPropertyGroup : public PropertyGroup { class KeyLightPropertyGroup : public PropertyGroup {
public: public:
// EntityItemProperty related helpers // EntityItemProperty related helpers

View file

@ -59,6 +59,25 @@ class PolyVoxEntityItem : public EntityItem {
virtual int getOnCount() const { return 0; } virtual int getOnCount() const { return 0; }
/**jsdoc
* <p>A <code>PolyVoxSurfaceStyle</code> may be one of the following:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Type</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>0</code></td><td>Marching cubes.</td><td>Chamfered edges. Open volume.
* Joins neighboring PolyVox entities reasonably well.</td></tr>
* <tr><td><code>1</code></td><td>Cubic.</td><td>Square edges. Open volume.
* Joins neighboring PolyVox entities cleanly.</td></tr>
* <tr><td><code>2</code></td><td>Edged cubic.</td><td>Square edges. Enclosed volume.
* Joins neighboring PolyVox entities cleanly.</td></tr>
* <tr><td><code>3</code></td><td>Edged marching cubes.</td><td>Chamfered edges. Enclosed volume.
* Doesn't join neighboring PolyVox entities.</td></tr>
* </tbody>
* </table>
* @typedef {number} Entities.PolyVoxSurfaceStyle
*/
enum PolyVoxSurfaceStyle { enum PolyVoxSurfaceStyle {
SURFACE_MARCHING_CUBES, SURFACE_MARCHING_CUBES,
SURFACE_CUBIC, SURFACE_CUBIC,

View file

@ -20,6 +20,33 @@
#include "ShapeEntityItem.h" #include "ShapeEntityItem.h"
namespace entity { namespace entity {
/**jsdoc
* <p>A <code>Shape</code>, <code>Box</code>, or <code>Sphere</code> {@link Entities.EntityType|EntityType} may display as
* one of the following geometrical shapes:</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Dimensions</th><th>Notes</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"Circle"</code></td><td>2D</td><td>A circle oriented in 3D.</td></tr>
* <tr><td><code>"Cube"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cone"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Cylinder"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Dodecahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Hexagon"</code></td><td>3D</td><td>A hexagonal prism.</td></tr>
* <tr><td><code>"Icosahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Octagon"</code></td><td>3D</td><td>An octagonal prism.</td></tr>
* <tr><td><code>"Octahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Quad"</code></td><td>2D</td><td>A square oriented in 3D.</td></tr>
* <tr><td><code>"Sphere"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Tetrahedron"</code></td><td>3D</td><td></td></tr>
* <tr><td><code>"Torus"</code></td><td>3D</td><td><em>Not implemented.</em></td></tr>
* <tr><td><code>"Triangle"</code></td><td>3D</td><td>A triangular prism.</td></tr>
* </tbody>
* </table>
* @typedef {string} Entities.Shape
*/
static const std::array<QString, Shape::NUM_SHAPES> shapeStrings { { static const std::array<QString, Shape::NUM_SHAPES> shapeStrings { {
"Triangle", "Triangle",
"Quad", "Quad",
@ -32,7 +59,7 @@ namespace entity {
"Octahedron", "Octahedron",
"Dodecahedron", "Dodecahedron",
"Icosahedron", "Icosahedron",
"Torus", "Torus", // Not implemented yet.
"Cone", "Cone",
"Cylinder" "Cylinder"
} }; } };

View file

@ -105,7 +105,7 @@ public:
protected: protected:
float _alpha { 1 }; float _alpha { 1 }; // FIXME: This property is not used.
rgbColor _color; rgbColor _color;
entity::Shape _shape { entity::Shape::Sphere }; entity::Shape _shape { entity::Shape::Sphere };

View file

@ -27,6 +27,13 @@ class OctreePacketData;
class EntityTreeElementExtraEncodeData; class EntityTreeElementExtraEncodeData;
class ReadBitstreamToTreeParams; class ReadBitstreamToTreeParams;
/**jsdoc
* A skybox is defined by the following properties.
* @typedef {object} Entities.Skybox
* @property {Color} color=0,0,0 - Sets the color of the sky if <code>url</code> is <code>""</code>, otherwise modifies the
* color of the cube map image.
* @property {string} url="" - A cube map image that is used to render the sky.
*/
class SkyboxPropertyGroup : public PropertyGroup { class SkyboxPropertyGroup : public PropertyGroup {
public: public:
// EntityItemProperty related helpers // EntityItemProperty related helpers

View file

@ -99,12 +99,16 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
(&::gpu::gl::GLBackend::do_setUniformBuffer), (&::gpu::gl::GLBackend::do_setUniformBuffer),
(&::gpu::gl::GLBackend::do_setResourceBuffer), (&::gpu::gl::GLBackend::do_setResourceBuffer),
(&::gpu::gl::GLBackend::do_setResourceTexture), (&::gpu::gl::GLBackend::do_setResourceTexture),
(&::gpu::gl::GLBackend::do_setResourceFramebufferSwapChainTexture),
(&::gpu::gl::GLBackend::do_setFramebuffer), (&::gpu::gl::GLBackend::do_setFramebuffer),
(&::gpu::gl::GLBackend::do_setFramebufferSwapChain),
(&::gpu::gl::GLBackend::do_clearFramebuffer), (&::gpu::gl::GLBackend::do_clearFramebuffer),
(&::gpu::gl::GLBackend::do_blit), (&::gpu::gl::GLBackend::do_blit),
(&::gpu::gl::GLBackend::do_generateTextureMips), (&::gpu::gl::GLBackend::do_generateTextureMips),
(&::gpu::gl::GLBackend::do_advance),
(&::gpu::gl::GLBackend::do_beginQuery), (&::gpu::gl::GLBackend::do_beginQuery),
(&::gpu::gl::GLBackend::do_endQuery), (&::gpu::gl::GLBackend::do_endQuery),
(&::gpu::gl::GLBackend::do_getQuery), (&::gpu::gl::GLBackend::do_getQuery),
@ -756,9 +760,13 @@ void GLBackend::recycle() const {
Texture::KtxStorage::releaseOpenKtxFiles(); Texture::KtxStorage::releaseOpenKtxFiles();
} }
void GLBackend::setCameraCorrection(const Mat4& correction) { void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset) {
auto invCorrection = glm::inverse(correction);
auto invPrevView = glm::inverse(prevRenderView);
_transform._correction.prevView = (reset ? Mat4() : prevRenderView);
_transform._correction.prevViewInverse = (reset ? Mat4() : invPrevView);
_transform._correction.correction = correction; _transform._correction.correction = correction;
_transform._correction.correctionInverse = glm::inverse(correction); _transform._correction.correctionInverse = invCorrection;
_pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction);
_pipeline._cameraCorrectionBuffer._buffer->flush(); _pipeline._cameraCorrectionBuffer._buffer->flush();
} }

View file

@ -68,7 +68,7 @@ public:
virtual ~GLBackend(); virtual ~GLBackend();
void setCameraCorrection(const Mat4& correction); void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false);
void render(const Batch& batch) final override; void render(const Batch& batch) final override;
// This call synchronize the Full Backend cache with the current GLState // This call synchronize the Full Backend cache with the current GLState
@ -126,15 +126,19 @@ public:
// Resource Stage // Resource Stage
virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final;
virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final;
virtual void do_setResourceFramebufferSwapChainTexture(const Batch& batch, size_t paramOffset) final;
// Pipeline Stage // Pipeline Stage
virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final; virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final;
// Output stage // Output stage
virtual void do_setFramebuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setFramebuffer(const Batch& batch, size_t paramOffset) final;
virtual void do_setFramebufferSwapChain(const Batch& batch, size_t paramOffset) final;
virtual void do_clearFramebuffer(const Batch& batch, size_t paramOffset) final; virtual void do_clearFramebuffer(const Batch& batch, size_t paramOffset) final;
virtual void do_blit(const Batch& batch, size_t paramOffset) = 0; virtual void do_blit(const Batch& batch, size_t paramOffset) = 0;
virtual void do_advance(const Batch& batch, size_t paramOffset) final;
// Query section // Query section
virtual void do_beginQuery(const Batch& batch, size_t paramOffset) final; virtual void do_beginQuery(const Batch& batch, size_t paramOffset) final;
virtual void do_endQuery(const Batch& batch, size_t paramOffset) final; virtual void do_endQuery(const Batch& batch, size_t paramOffset) final;
@ -245,6 +249,8 @@ protected:
void setupStereoSide(int side); void setupStereoSide(int side);
#endif #endif
virtual void setResourceTexture(unsigned int slot, const TexturePointer& resourceTexture);
virtual void setFramebuffer(const FramebufferPointer& framebuffer);
virtual void initInput() final; virtual void initInput() final;
virtual void killInput() final; virtual void killInput() final;
virtual void syncInputStateCache() final; virtual void syncInputStateCache() final;
@ -303,9 +309,12 @@ protected:
// Allows for correction of the camera pose to account for changes // Allows for correction of the camera pose to account for changes
// between the time when a was recorded and the time(s) when it is // between the time when a was recorded and the time(s) when it is
// executed // executed
// Prev is the previous correction used at previous frame
struct CameraCorrection { struct CameraCorrection {
Mat4 correction; mat4 correction;
Mat4 correctionInverse; mat4 correctionInverse;
mat4 prevView;
mat4 prevViewInverse;
}; };
struct TransformStageState { struct TransformStageState {

View file

@ -37,6 +37,19 @@ void GLBackend::resetOutputStage() {
void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) { void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) {
auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
setFramebuffer(framebuffer);
}
void GLBackend::do_setFramebufferSwapChain(const Batch& batch, size_t paramOffset) {
auto swapChain = batch._swapChains.get(batch._params[paramOffset]._uint);
if (swapChain) {
auto index = batch._params[paramOffset + 1]._uint;
FramebufferPointer framebuffer = static_cast<const FramebufferSwapChain*>(swapChain.get())->get(index);
setFramebuffer(framebuffer);
}
}
void GLBackend::setFramebuffer(const FramebufferPointer& framebuffer) {
if (_output._framebuffer != framebuffer) { if (_output._framebuffer != framebuffer) {
auto newFBO = getFramebufferID(framebuffer); auto newFBO = getFramebufferID(framebuffer);
if (_output._drawFBO != newFBO) { if (_output._drawFBO != newFBO) {
@ -47,6 +60,13 @@ void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) {
} }
} }
void GLBackend::do_advance(const Batch& batch, size_t paramOffset) {
auto ringbuffer = batch._swapChains.get(batch._params[paramOffset]._uint);
if (ringbuffer) {
ringbuffer->advance();
}
}
void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) { void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
if (_stereo.isStereo() && !_pipeline._stateCache.scissorEnable) { if (_stereo.isStereo() && !_pipeline._stateCache.scissorEnable) {
qWarning("Clear without scissor in stereo mode"); qWarning("Clear without scissor in stereo mode");

View file

@ -253,6 +253,31 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
releaseResourceTexture(slot); releaseResourceTexture(slot);
return; return;
} }
setResourceTexture(slot, resourceTexture);
}
void GLBackend::do_setResourceFramebufferSwapChainTexture(const Batch& batch, size_t paramOffset) {
GLuint slot = batch._params[paramOffset + 1]._uint;
if (slot >= (GLuint)MAX_NUM_RESOURCE_TEXTURES) {
qCDebug(gpugllogging) << "GLBackend::do_setResourceFramebufferSwapChainTexture: Trying to set a resource Texture at slot #" << slot << " which doesn't exist. MaxNumResourceTextures = " << getMaxNumResourceTextures();
return;
}
SwapChainPointer swapChain = batch._swapChains.get(batch._params[paramOffset + 0]._uint);
if (!swapChain) {
releaseResourceTexture(slot);
return;
}
auto index = batch._params[paramOffset + 2]._uint;
auto renderBufferSlot = batch._params[paramOffset + 3]._uint;
FramebufferPointer resourceFramebuffer = static_cast<const FramebufferSwapChain*>(swapChain.get())->get(index);
TexturePointer resourceTexture = resourceFramebuffer->getRenderBuffer(renderBufferSlot);
setResourceTexture(slot, resourceTexture);
}
void GLBackend::setResourceTexture(unsigned int slot, const TexturePointer& resourceTexture) {
// check cache before thinking // check cache before thinking
if (_resource._textures[slot] == resourceTexture) { if (_resource._textures[slot] == resourceTexture) {
return; return;
@ -269,11 +294,11 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
glActiveTexture(GL_TEXTURE0 + slot); glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(target, to); glBindTexture(target, to);
(void) CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
_resource._textures[slot] = resourceTexture; _resource._textures[slot] = resourceTexture;
_stats._RSAmountTextureMemoryBounded += (int) object->size(); _stats._RSAmountTextureMemoryBounded += (int)object->size();
} else { } else {
releaseResourceTexture(slot); releaseResourceTexture(slot);

View file

@ -105,7 +105,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != glm::mat4())) { if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != glm::mat4())) {
// FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out? // FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out?
Transform result; Transform result;
_view.mult(result, _view, _correction.correction); _view.mult(result, _view, _correction.correctionInverse);
if (_skybox) { if (_skybox) {
result.setTranslation(vec3()); result.setTranslation(vec3());
} }

View file

@ -146,7 +146,51 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
case gpu::RGB: case gpu::RGB:
case gpu::RGBA: case gpu::RGBA:
case gpu::XY: case gpu::XY:
result = GL_RG8; switch (dstFormat.getType()) {
case gpu::UINT32:
result = GL_RG32UI;
break;
case gpu::INT32:
result = GL_RG32I;
break;
case gpu::FLOAT:
result = GL_RG32F;
break;
case gpu::UINT16:
result = GL_RG16UI;
break;
case gpu::INT16:
result = GL_RG16I;
break;
case gpu::NUINT16:
result = GL_RG16;
break;
case gpu::NINT16:
result = GL_RG16_SNORM;
break;
case gpu::HALF:
result = GL_RG16F;
break;
case gpu::UINT8:
result = GL_RG8UI;
break;
case gpu::INT8:
result = GL_RG8I;
break;
case gpu::NUINT8:
result = GL_RG8;
break;
case gpu::NINT8:
result = GL_RG8_SNORM;
break;
case gpu::NUINT32:
case gpu::NINT32:
case gpu::NUINT2:
case gpu::NINT2_10_10_10:
case gpu::COMPRESSED:
case gpu::NUM_TYPES: // quiet compiler
Q_UNREACHABLE();
}
break; break;
default: default:
qCWarning(gpugllogging) << "Unknown combination of texel format"; qCWarning(gpugllogging) << "Unknown combination of texel format";
@ -581,7 +625,52 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
case gpu::RGB: case gpu::RGB:
case gpu::RGBA: case gpu::RGBA:
case gpu::XY: case gpu::XY:
texel.internalFormat = GL_RG8; switch (dstFormat.getType()) {
case gpu::UINT32:
texel.internalFormat = GL_RG32UI;
break;
case gpu::INT32:
texel.internalFormat = GL_RG32I;
break;
case gpu::FLOAT:
texel.internalFormat = GL_RG32F;
break;
case gpu::UINT16:
texel.internalFormat = GL_RG16UI;
break;
case gpu::INT16:
texel.internalFormat = GL_RG16I;
break;
case gpu::NUINT16:
texel.internalFormat = GL_RG16;
break;
case gpu::NINT16:
texel.internalFormat = GL_RG16_SNORM;
break;
case gpu::HALF:
texel.type = GL_FLOAT;
texel.internalFormat = GL_RG16F;
break;
case gpu::UINT8:
texel.internalFormat = GL_RG8UI;
break;
case gpu::INT8:
texel.internalFormat = GL_RG8I;
break;
case gpu::NUINT8:
texel.internalFormat = GL_RG8;
break;
case gpu::NINT8:
texel.internalFormat = GL_RG8_SNORM;
break;
case gpu::NUINT32:
case gpu::NINT32:
case gpu::NUINT2:
case gpu::NINT2_10_10_10:
case gpu::COMPRESSED:
case gpu::NUM_TYPES: // quiet compiler
Q_UNREACHABLE();
}
break; break;
default: default:
qCWarning(gpugllogging) << "Unknown combination of texel format"; qCWarning(gpugllogging) << "Unknown combination of texel format";

View file

@ -749,9 +749,13 @@ void GLBackend::recycle() const {
Texture::KtxStorage::releaseOpenKtxFiles(); Texture::KtxStorage::releaseOpenKtxFiles();
} }
void GLBackend::setCameraCorrection(const Mat4& correction) { void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset) {
auto invCorrection = glm::inverse(correction);
auto invPrevView = glm::inverse(prevRenderView);
_transform._correction.prevView = (reset ? Mat4() : prevRenderView);
_transform._correction.prevViewInverse = (reset ? Mat4() : invPrevView);
_transform._correction.correction = correction; _transform._correction.correction = correction;
_transform._correction.correctionInverse = glm::inverse(correction); _transform._correction.correctionInverse = invCorrection;
_pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction);
_pipeline._cameraCorrectionBuffer._buffer->flush(); _pipeline._cameraCorrectionBuffer._buffer->flush();
} }

View file

@ -65,7 +65,7 @@ public:
virtual ~GLBackend(); virtual ~GLBackend();
void setCameraCorrection(const Mat4& correction); void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false);
void render(const Batch& batch) final override; void render(const Batch& batch) final override;
// This call synchronize the Full Backend cache with the current GLState // This call synchronize the Full Backend cache with the current GLState
@ -303,6 +303,8 @@ protected:
struct CameraCorrection { struct CameraCorrection {
Mat4 correction; Mat4 correction;
Mat4 correctionInverse; Mat4 correctionInverse;
Mat4 prevView;
Mat4 prevViewInverse;
}; };
struct TransformStageState { struct TransformStageState {

View file

@ -45,7 +45,12 @@ size_t Batch::_dataMax { BATCH_PREALLOCATE_MIN };
size_t Batch::_objectsMax { BATCH_PREALLOCATE_MIN }; size_t Batch::_objectsMax { BATCH_PREALLOCATE_MIN };
size_t Batch::_drawCallInfosMax { BATCH_PREALLOCATE_MIN }; size_t Batch::_drawCallInfosMax { BATCH_PREALLOCATE_MIN };
Batch::Batch() { Batch::Batch(const char* name) {
#ifdef DEBUG
if (name) {
_name = name;
}
#endif
_commands.reserve(_commandsMax); _commands.reserve(_commandsMax);
_commandOffsets.reserve(_commandOffsetsMax); _commandOffsets.reserve(_commandOffsetsMax);
_params.reserve(_paramsMax); _params.reserve(_paramsMax);
@ -56,6 +61,9 @@ Batch::Batch() {
Batch::Batch(const Batch& batch_) { Batch::Batch(const Batch& batch_) {
Batch& batch = *const_cast<Batch*>(&batch_); Batch& batch = *const_cast<Batch*>(&batch_);
#ifdef DEBUG
_name = batch_._name;
#endif
_commands.swap(batch._commands); _commands.swap(batch._commands);
_commandOffsets.swap(batch._commandOffsets); _commandOffsets.swap(batch._commandOffsets);
_params.swap(batch._params); _params.swap(batch._params);
@ -71,6 +79,7 @@ Batch::Batch(const Batch& batch_) {
_transforms._items.swap(batch._transforms._items); _transforms._items.swap(batch._transforms._items);
_pipelines._items.swap(batch._pipelines._items); _pipelines._items.swap(batch._pipelines._items);
_framebuffers._items.swap(batch._framebuffers._items); _framebuffers._items.swap(batch._framebuffers._items);
_swapChains._items.swap(batch._swapChains._items);
_drawCallInfos.swap(batch._drawCallInfos); _drawCallInfos.swap(batch._drawCallInfos);
_queries._items.swap(batch._queries._items); _queries._items.swap(batch._queries._items);
_lambdas._items.swap(batch._lambdas._items); _lambdas._items.swap(batch._lambdas._items);
@ -108,6 +117,7 @@ void Batch::clear() {
_transforms.clear(); _transforms.clear();
_pipelines.clear(); _pipelines.clear();
_framebuffers.clear(); _framebuffers.clear();
_swapChains.clear();
_objects.clear(); _objects.clear();
_drawCallInfos.clear(); _drawCallInfos.clear();
} }
@ -327,6 +337,15 @@ void Batch::setResourceTexture(uint32 slot, const TextureView& view) {
setResourceTexture(slot, view._texture); setResourceTexture(slot, view._texture);
} }
void Batch::setResourceFramebufferSwapChainTexture(uint32 slot, const FramebufferSwapChainPointer& framebuffer, unsigned int swapChainIndex, unsigned int renderBufferSlot) {
ADD_COMMAND(setResourceFramebufferSwapChainTexture);
_params.emplace_back(_swapChains.cache(framebuffer));
_params.emplace_back(slot);
_params.emplace_back(swapChainIndex);
_params.emplace_back(renderBufferSlot);
}
void Batch::setFramebuffer(const FramebufferPointer& framebuffer) { void Batch::setFramebuffer(const FramebufferPointer& framebuffer) {
ADD_COMMAND(setFramebuffer); ADD_COMMAND(setFramebuffer);
@ -334,6 +353,19 @@ void Batch::setFramebuffer(const FramebufferPointer& framebuffer) {
} }
void Batch::setFramebufferSwapChain(const FramebufferSwapChainPointer& framebuffer, unsigned int swapChainIndex) {
ADD_COMMAND(setFramebufferSwapChain);
_params.emplace_back(_swapChains.cache(framebuffer));
_params.emplace_back(swapChainIndex);
}
void Batch::advance(const SwapChainPointer& swapChain) {
ADD_COMMAND(advance);
_params.emplace_back(_swapChains.cache(swapChain));
}
void Batch::clearFramebuffer(Framebuffer::Masks targets, const Vec4& color, float depth, int stencil, bool enableScissor) { void Batch::clearFramebuffer(Framebuffer::Masks targets, const Vec4& color, float depth, int stencil, bool enableScissor) {
ADD_COMMAND(clearFramebuffer); ADD_COMMAND(clearFramebuffer);

View file

@ -91,7 +91,7 @@ public:
void captureDrawCallInfo(); void captureDrawCallInfo();
void captureNamedDrawCallInfo(std::string name); void captureNamedDrawCallInfo(std::string name);
Batch(); Batch(const char* name = nullptr);
Batch(const Batch& batch); Batch(const Batch& batch);
~Batch(); ~Batch();
@ -187,11 +187,14 @@ public:
void setResourceTexture(uint32 slot, const TexturePointer& texture); void setResourceTexture(uint32 slot, const TexturePointer& texture);
void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView
void setResourceFramebufferSwapChainTexture(uint32 slot, const FramebufferSwapChainPointer& framebuffer, unsigned int swpaChainIndex, unsigned int renderBufferSlot = 0U); // not a command, just a shortcut from a TextureView
// Ouput Stage // Ouput Stage
void setFramebuffer(const FramebufferPointer& framebuffer); void setFramebuffer(const FramebufferPointer& framebuffer);
void setFramebufferSwapChain(const FramebufferSwapChainPointer& framebuffer, unsigned int swapChainIndex);
void advance(const SwapChainPointer& swapChain);
// Clear framebuffer layers // Clear framebuffer layers
// Targets can be any of the render buffers contained in the currnetly bound Framebuffer // Targets can be any of the render buffers contained in the currnetly bound Framebuffer
// Optionally the scissor test can be enabled locally for this command and to restrict the clearing command to the pixels contained in the scissor rectangle // Optionally the scissor test can be enabled locally for this command and to restrict the clearing command to the pixels contained in the scissor rectangle
@ -299,12 +302,16 @@ public:
COMMAND_setUniformBuffer, COMMAND_setUniformBuffer,
COMMAND_setResourceBuffer, COMMAND_setResourceBuffer,
COMMAND_setResourceTexture, COMMAND_setResourceTexture,
COMMAND_setResourceFramebufferSwapChainTexture,
COMMAND_setFramebuffer, COMMAND_setFramebuffer,
COMMAND_setFramebufferSwapChain,
COMMAND_clearFramebuffer, COMMAND_clearFramebuffer,
COMMAND_blit, COMMAND_blit,
COMMAND_generateTextureMips, COMMAND_generateTextureMips,
COMMAND_advance,
COMMAND_beginQuery, COMMAND_beginQuery,
COMMAND_endQuery, COMMAND_endQuery,
COMMAND_getQuery, COMMAND_getQuery,
@ -421,6 +428,7 @@ public:
typedef Cache<Transform>::Vector TransformCaches; typedef Cache<Transform>::Vector TransformCaches;
typedef Cache<PipelinePointer>::Vector PipelineCaches; typedef Cache<PipelinePointer>::Vector PipelineCaches;
typedef Cache<FramebufferPointer>::Vector FramebufferCaches; typedef Cache<FramebufferPointer>::Vector FramebufferCaches;
typedef Cache<SwapChainPointer>::Vector SwapChainCaches;
typedef Cache<QueryPointer>::Vector QueryCaches; typedef Cache<QueryPointer>::Vector QueryCaches;
typedef Cache<std::string>::Vector StringCaches; typedef Cache<std::string>::Vector StringCaches;
typedef Cache<std::function<void()>>::Vector LambdaCache; typedef Cache<std::function<void()>>::Vector LambdaCache;
@ -475,6 +483,7 @@ public:
TransformCaches _transforms; TransformCaches _transforms;
PipelineCaches _pipelines; PipelineCaches _pipelines;
FramebufferCaches _framebuffers; FramebufferCaches _framebuffers;
SwapChainCaches _swapChains;
QueryCaches _queries; QueryCaches _queries;
LambdaCache _lambdas; LambdaCache _lambdas;
StringCaches _profileRanges; StringCaches _profileRanges;
@ -486,6 +495,11 @@ public:
bool _enableSkybox { false }; bool _enableSkybox { false };
protected: protected:
#ifdef DEBUG
std::string _name;
#endif
friend class Context; friend class Context;
friend class Frame; friend class Frame;

View file

@ -98,8 +98,9 @@ Buffer::Update::Update(const Buffer& parent) : buffer(parent) {
void Buffer::Update::apply() const { void Buffer::Update::apply() const {
// Make sure we're loaded in order // Make sure we're loaded in order
++buffer._applyUpdateCount; buffer._applyUpdateCount++;
assert(buffer._applyUpdateCount.load() == updateNumber); assert(buffer._applyUpdateCount == updateNumber);
const auto pageSize = buffer._pages._pageSize; const auto pageSize = buffer._pages._pageSize;
buffer._renderSysmem.resize(size); buffer._renderSysmem.resize(size);
buffer._renderPages.accommodate(size); buffer._renderPages.accommodate(size);

View file

@ -11,18 +11,45 @@
<@if not GPU_COLOR_SLH@> <@if not GPU_COLOR_SLH@>
<@def GPU_COLOR_SLH@> <@def GPU_COLOR_SLH@>
float sRGBFloatToLinear(float value) { // Linear ====> linear RGB
// sRGB ======> standard RGB with gamma of 2.2
// YCoCg =====> Luma (Y) chrominance green (Cg) and chrominance orange (Co)
// https://software.intel.com/en-us/node/503873
float color_scalar_sRGBToLinear(float value) {
const float SRGB_ELBOW = 0.04045; const float SRGB_ELBOW = 0.04045;
return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4); return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4);
} }
vec3 colorToLinearRGB(vec3 srgb) { vec3 color_sRGBToLinear(vec3 srgb) {
return vec3(sRGBFloatToLinear(srgb.r), sRGBFloatToLinear(srgb.g), sRGBFloatToLinear(srgb.b)); return vec3(color_scalar_sRGBToLinear(srgb.r), color_scalar_sRGBToLinear(srgb.g), color_scalar_sRGBToLinear(srgb.b));
} }
vec4 colorToLinearRGBA(vec4 srgba) { vec4 color_sRGBAToLinear(vec4 srgba) {
return vec4(colorToLinearRGB(srgba.xyz), srgba.w); return vec4(color_sRGBToLinear(srgba.xyz), srgba.w);
}
vec3 color_LinearToYCoCg(vec3 rgb) {
// Y = R/4 + G/2 + B/4
// Co = R/2 - B/2
// Cg = -R/4 + G/2 - B/4
return vec3(
rgb.x/4.0 + rgb.y/2.0 + rgb.z/4.0,
rgb.x/2.0 - rgb.z/2.0,
-rgb.x/4.0 + rgb.y/2.0 - rgb.z/4.0
);
}
vec3 color_YCoCgToLinear(vec3 ycocg) {
// R = Y + Co - Cg
// G = Y + Cg
// B = Y - Co - Cg
return clamp(vec3(
ycocg.x + ycocg.y - ycocg.z,
ycocg.x + ycocg.z,
ycocg.x - ycocg.y - ycocg.z
), vec3(0.0), vec3(1.0));
} }
<@func declareColorWheel()@> <@func declareColorWheel()@>

View file

@ -53,11 +53,12 @@ const std::string& Context::getBackendVersion() const {
return _backend->getVersion(); return _backend->getVersion();
} }
void Context::beginFrame(const glm::mat4& renderPose) { void Context::beginFrame(const glm::mat4& renderView, const glm::mat4& renderPose) {
assert(!_frameActive); assert(!_frameActive);
_frameActive = true; _frameActive = true;
_currentFrame = std::make_shared<Frame>(); _currentFrame = std::make_shared<Frame>();
_currentFrame->pose = renderPose; _currentFrame->pose = renderPose;
_currentFrame->view = renderView;
if (!_frameRangeTimer) { if (!_frameRangeTimer) {
_frameRangeTimer = std::make_shared<RangeTimer>("gpu::Context::Frame"); _frameRangeTimer = std::make_shared<RangeTimer>("gpu::Context::Frame");
@ -108,7 +109,7 @@ void Context::executeFrame(const FramePointer& frame) const {
consumeFrameUpdates(frame); consumeFrameUpdates(frame);
_backend->setStereoState(frame->stereoState); _backend->setStereoState(frame->stereoState);
{ {
Batch beginBatch; Batch beginBatch("Context::executeFrame::begin");
_frameRangeTimer->begin(beginBatch); _frameRangeTimer->begin(beginBatch);
_backend->render(beginBatch); _backend->render(beginBatch);
@ -117,7 +118,7 @@ void Context::executeFrame(const FramePointer& frame) const {
_backend->render(batch); _backend->render(batch);
} }
Batch endBatch; Batch endBatch("Context::executeFrame::end");
_frameRangeTimer->end(endBatch); _frameRangeTimer->end(endBatch);
_backend->render(endBatch); _backend->render(endBatch);
} }

View file

@ -161,7 +161,7 @@ public:
const std::string& getBackendVersion() const; const std::string& getBackendVersion() const;
void beginFrame(const glm::mat4& renderPose = glm::mat4()); void beginFrame(const glm::mat4& renderView = glm::mat4(), const glm::mat4& renderPose = glm::mat4());
void appendFrameBatch(Batch& batch); void appendFrameBatch(Batch& batch);
FramePointer endFrame(); FramePointer endFrame();
@ -274,8 +274,8 @@ protected:
typedef std::shared_ptr<Context> ContextPointer; typedef std::shared_ptr<Context> ContextPointer;
template<typename F> template<typename F>
void doInBatch(std::shared_ptr<gpu::Context> context, F f) { void doInBatch(const char* name, std::shared_ptr<gpu::Context> context, F f) {
gpu::Batch batch; gpu::Batch batch(name);
f(batch); f(batch);
context->appendFrameBatch(batch); context->appendFrameBatch(batch);
} }

View file

@ -28,6 +28,8 @@ namespace gpu {
StereoState stereoState; StereoState stereoState;
uint32_t frameIndex{ 0 }; uint32_t frameIndex{ 0 };
/// The view matrix used for rendering the frame, only applicable for HMDs
Mat4 view;
/// The sensor pose used for rendering the frame, only applicable for HMDs /// The sensor pose used for rendering the frame, only applicable for HMDs
Mat4 pose; Mat4 pose;
/// The collection of batches which make up the frame /// The collection of batches which make up the frame

View file

@ -12,6 +12,7 @@
#define hifi_gpu_Framebuffer_h #define hifi_gpu_Framebuffer_h
#include "Texture.h" #include "Texture.h"
#include "ResourceSwapChain.h"
#include <memory> #include <memory>
class Transform; // Texcood transform util class Transform; // Texcood transform util
@ -177,6 +178,8 @@ protected:
Framebuffer() {} Framebuffer() {}
}; };
typedef std::shared_ptr<Framebuffer> FramebufferPointer; typedef std::shared_ptr<Framebuffer> FramebufferPointer;
typedef ResourceSwapChain<Framebuffer> FramebufferSwapChain;
typedef std::shared_ptr<FramebufferSwapChain> FramebufferSwapChainPointer;
} }

View file

@ -0,0 +1,62 @@
//
// Created by Olivier Prat on 2018/02/19
// Copyright 2013-2018 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_gpu_ResourceSwapChain_h
#define hifi_gpu_ResourceSwapChain_h
#include <memory>
#include <array>
namespace gpu {
class SwapChain {
public:
SwapChain(unsigned int size = 2U) : _size{ size } {}
virtual ~SwapChain() {}
void advance() {
_frontIndex = (_frontIndex + 1) % _size;
}
unsigned int getSize() const { return _size; }
protected:
unsigned int _size;
unsigned int _frontIndex{ 0U };
};
typedef std::shared_ptr<SwapChain> SwapChainPointer;
template <class R>
class ResourceSwapChain : public SwapChain {
public:
enum {
MAX_SIZE = 4
};
using Type = R;
using TypePointer = std::shared_ptr<R>;
ResourceSwapChain(unsigned int size = 2U) : SwapChain{ size } {}
void reset() {
for (auto& ptr : _resources) {
ptr.reset();
}
}
TypePointer& edit(unsigned int index) { return _resources[(index + _frontIndex) % _size]; }
const TypePointer& get(unsigned int index) const { return _resources[(index + _frontIndex) % _size]; }
private:
std::array<TypePointer, MAX_SIZE> _resources;
};
}
#endif

View file

@ -38,7 +38,7 @@ public slots:
* Returns a model reference object associated with the specified UUID ({@link EntityID}, {@link OverlayID}, or {@link AvatarID}). * Returns a model reference object associated with the specified UUID ({@link EntityID}, {@link OverlayID}, or {@link AvatarID}).
* *
* @function Graphics.getModel * @function Graphics.getModel
* @param {UUID} The objectID of the model whose meshes are to be retrieved. * @param {UUID} entityID - The objectID of the model whose meshes are to be retrieved.
* @return {Graphics.Model} the resulting Model object * @return {Graphics.Model} the resulting Model object
*/ */
scriptable::ScriptableModelPointer getModel(QUuid uuid); scriptable::ScriptableModelPointer getModel(QUuid uuid);

View file

@ -50,8 +50,8 @@ void TouchscreenVirtualPadDevice::init() {
_screenDPIProvided = eventScreen->physicalDotsPerInch(); _screenDPIProvided = eventScreen->physicalDotsPerInch();
_screenDPI = eventScreen->physicalDotsPerInch(); _screenDPI = eventScreen->physicalDotsPerInch();
_fixedRadius = _screenDPI * 256 / 534; _fixedRadius = _screenDPI * 0.5f * VirtualPad::Manager::PIXEL_SIZE / VirtualPad::Manager::DPI;
_fixedRadiusForCalc = _fixedRadius - _screenDPI * 105 / 534; // 105 is the radius of the stick circle _fixedRadiusForCalc = _fixedRadius - _screenDPI * VirtualPad::Manager::STICK_RADIUS / VirtualPad::Manager::DPI;
} }
auto& virtualPadManager = VirtualPad::Manager::instance(); auto& virtualPadManager = VirtualPad::Manager::instance();
@ -69,7 +69,7 @@ void TouchscreenVirtualPadDevice::setupFixedCenter(VirtualPad::Manager& virtualP
if (_extraBottomMargin == virtualPadManager.extraBottomMargin() && !force) return; // Our only criteria to decide a center change is the bottom margin if (_extraBottomMargin == virtualPadManager.extraBottomMargin() && !force) return; // Our only criteria to decide a center change is the bottom margin
_extraBottomMargin = virtualPadManager.extraBottomMargin(); _extraBottomMargin = virtualPadManager.extraBottomMargin();
float margin = _screenDPI * 59 / 534; // 59px is for our 'base' of 534dpi (Pixel XL or Huawei Mate 9 Pro) float margin = _screenDPI * VirtualPad::Manager::BASE_MARGIN / VirtualPad::Manager::DPI;
QScreen* eventScreen = qApp->primaryScreen(); // do not call every time QScreen* eventScreen = qApp->primaryScreen(); // do not call every time
_fixedCenterPosition = glm::vec2( _fixedRadius + margin, eventScreen->size().height() - margin - _fixedRadius - _extraBottomMargin); _fixedCenterPosition = glm::vec2( _fixedRadius + margin, eventScreen->size().height() - margin - _fixedRadius - _extraBottomMargin);
@ -82,10 +82,10 @@ float clip(float n, float lower, float upper) {
} }
glm::vec2 TouchscreenVirtualPadDevice::clippedPointInCircle(float radius, glm::vec2 origin, glm::vec2 touchPoint) { glm::vec2 TouchscreenVirtualPadDevice::clippedPointInCircle(float radius, glm::vec2 origin, glm::vec2 touchPoint) {
float deltaX = touchPoint.x-origin.x; float deltaX = touchPoint.x - origin.x;
float deltaY = touchPoint.y-origin.y; float deltaY = touchPoint.y - origin.y;
float distance = sqrt(pow(deltaX,2)+pow(deltaY,2)); float distance = sqrt(pow(deltaX, 2) + pow(deltaY, 2));
// First case, inside the boundaires, just use the distance // First case, inside the boundaires, just use the distance
if (distance <= radius) { if (distance <= radius) {
@ -99,18 +99,18 @@ glm::vec2 TouchscreenVirtualPadDevice::clippedPointInCircle(float radius, glm::v
// Third case, calculate point in circumference // Third case, calculate point in circumference
// line formula // line formula
float m = deltaY/deltaX; float m = deltaY / deltaX;
float b = touchPoint.y - m * touchPoint.x; float b = touchPoint.y - m * touchPoint.x;
// quadtratic coefs of circumference and line intersection // quadtratic coefs of circumference and line intersection
float qa = pow(m,2)+1; float qa = powf(m, 2.0f) + 1.0f;
float qb = 2 * ( m * b - origin.x - origin.y * m ); float qb = 2.0f * ( m * b - origin.x - origin.y * m);
float qc = powf(origin.x, 2) - powf(radius,2) + b * b - 2 * b * origin.y + powf(origin.y, 2); float qc = powf(origin.x, 2.0f) - powf(radius, 2.0f) + b * b - 2.0f * b * origin.y + powf(origin.y, 2.0f);
float discr = qb * qb - 4 * qa * qc; float discr = qb * qb - 4.0f * qa * qc;
float discrSign = deltaX>0?1.0:-1.0; float discrSign = deltaX > 0.0f ? 1.0f : - 1.0f;
float finalX = (- qb + discrSign * sqrtf(discr)) / (2 * qa); float finalX = (-qb + discrSign * sqrtf(discr)) / (2.0f * qa);
float finalY = m * finalX + b; float finalY = m * finalX + b;
return vec2(finalX, finalY); return vec2(finalX, finalY);

View file

@ -28,6 +28,25 @@ void NetworkMaterialResource::downloadFinished(const QByteArray& data) {
finishedLoading(true); finishedLoading(true);
} }
/**jsdoc
* <p>An RGB or SRGB color value.</p>
* <table>
* <thead>
* <tr><th>Index</th><th>Type</th><th>Attributes</th><th>Default</th><th>Value</th></tr>
* </thead>
* <tbody>
* <tr><td><code>0</code></td><td>number</td><td></td><td></td>
* <td>Red component value. Number in the range <code>0.0</code> &ndash; <code>1.0</code>.</td></tr>
* <tr><td><code>1</code></td><td>number</td><td></td><td></td>
* <td>Green component value. Number in the range <code>0.0</code> &ndash; <code>1.0</code>.</td></tr>
* <tr><td><code>2</code></td><td>number</td><td></td><td></td>
* <td>Blue component value. Number in the range <code>0.0</code> &ndash; <code>1.0</code>.</td></tr>
* <tr><td><code>3</code></td><td>boolean</td><td>&lt;optional&gt;</td><td>false</td>
* <td>If <code>true</code> then the color is an SRGB color.</td></tr>
* </tbody>
* </table>
* @typedef {array} RGBS
*/
bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) { bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) {
if (array.isArray()) { if (array.isArray()) {
QJsonArray colorArray = array.toArray(); QJsonArray colorArray = array.toArray();
@ -50,6 +69,12 @@ bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3&
return false; return false;
} }
/**jsdoc
* A material or set of materials such as may be used by a {@link Entities.EntityType|Material} entity.
* @typedef {object} MaterialResource
* @property {number} materialVersion=1 - The version of the material. <em>Currently not used.</em>
* @property {Material|Material[]} materials - The details of the material or materials.
*/
NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMaterials(const QJsonDocument& materialJSON) { NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMaterials(const QJsonDocument& materialJSON) {
ParsedMaterials toReturn; ParsedMaterials toReturn;
if (!materialJSON.isNull() && materialJSON.isObject()) { if (!materialJSON.isNull() && materialJSON.isObject()) {
@ -83,6 +108,36 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater
return toReturn; return toReturn;
} }
/**jsdoc
* A material such as may be used by a {@link Entities.EntityType|Material} entity.
* @typedef {object} Material
* @property {string} name="" - A name for the material.
* @property {string} model="hifi_pbr" - <em>Currently not used.</em>
* @property {Vec3Color|RGBS} emissive - The emissive color, i.e., the color that the material emits. A {@link Vec3Color} value
* is treated as sRGB. A {@link RGBS} value can be either RGB or sRGB.
* @property {number} opacity=1.0 - The opacity, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {boolean} unlit=false - If <code>true</code>, the material is not lit.
* @property {Vec3Color|RGBS} albedo - The albedo color. A {@link Vec3Color} value is treated as sRGB. A {@link RGBS} value can
* be either RGB or sRGB.
* @property {number} roughness - The roughness, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} metallic - The metallicness, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} scattering - The scattering, <code>0.0</code> &ndash; <code>1.0</code>.
* @property {string} emissiveMap - URL of emissive texture image.
* @property {string} albedoMap - URL of albedo texture image.
* @property {string} opacityMap - URL of opacity texture image. Set value the same as the <code>albedoMap</code> value for
* transparency.
* @property {string} roughnessMap - URL of roughness texture image. Can use this or <code>glossMap</code>, but not both.
* @property {string} glossMap - URL of gloss texture image. Can use this or <code>roughnessMap</code>, but not both.
* @property {string} metallicMap - URL of metallic texture image. Can use this or <code>specularMap</code>, but not both.
* @property {string} specularMap - URL of specular texture image. Can use this or <code>metallicMap</code>, but not both.
* @property {string} normalMap - URL of normal texture image. Can use this or <code>bumpMap</code>, but not both.
* @property {string} bumpMap - URL of bump texture image. Can use this or <code>normalMap</code>, but not both.
* @property {string} occlusionMap - URL of occlusion texture image.
* @property {string} scatteringMap - URL of scattering texture image. Only used if <code>normalMap</code> or
* <code>bumpMap</code> is specified.
* @property {string} lightMap - URL of light map texture image. <em>Currently not used.</em>
*/
// Note: See MaterialEntityItem.h for default values used in practice.
std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) { std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) {
std::string name = ""; std::string name = "";
std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>(); std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>();

View file

@ -460,6 +460,10 @@ void NetworkTexture::makeRequest() {
} }
void NetworkTexture::handleLocalRequestCompleted() {
TextureCache::requestCompleted(_self);
}
void NetworkTexture::makeLocalRequest() { void NetworkTexture::makeLocalRequest() {
const QString scheme = _url.scheme(); const QString scheme = _url.scheme();
QString path; QString path;
@ -469,6 +473,8 @@ void NetworkTexture::makeLocalRequest() {
path = ":" + _url.path(); path = ":" + _url.path();
} }
connect(this, &Resource::finished, this, &NetworkTexture::handleLocalRequestCompleted);
path = FileUtils::selectFile(path); path = FileUtils::selectFile(path);
auto storage = std::make_shared<storage::FileStorage>(path); auto storage = std::make_shared<storage::FileStorage>(path);

View file

@ -71,6 +71,7 @@ public slots:
protected: protected:
void makeRequest() override; void makeRequest() override;
void makeLocalRequest(); void makeLocalRequest();
Q_INVOKABLE void handleLocalRequestCompleted();
virtual bool isCacheable() const override { return _loaded; } virtual bool isCacheable() const override { return _loaded; }

View file

@ -35,48 +35,126 @@ private slots:
void cleanupManagedObjects(); void cleanupManagedObjects();
public slots: public slots:
/**jsdoc
* Set the maximum number of entity packets that the client can send per second.
* @function Entities.setPacketsPerSecond
* @param {number} packetsPerSecond - Integer maximum number of entity packets that the client can send per second.
*/
/// set the max packets per second send rate /// set the max packets per second send rate
void setPacketsPerSecond(int packetsPerSecond) { return _packetSender->setPacketsPerSecond(packetsPerSecond); } void setPacketsPerSecond(int packetsPerSecond) { return _packetSender->setPacketsPerSecond(packetsPerSecond); }
/**jsdoc
* Get the maximum number of entity packets that the client can send per second.
* @function Entities.getPacketsPerSecond
* @returns {number} Integer maximum number of entity packets that the client can send per second.
*/
/// get the max packets per second send rate /// get the max packets per second send rate
int getPacketsPerSecond() const { return _packetSender->getPacketsPerSecond(); } int getPacketsPerSecond() const { return _packetSender->getPacketsPerSecond(); }
/// does a particle server exist to send to /**jsdoc
* Check whether servers exist for the client to send entity packets to, i.e., whether you are connected to a domain and
* its entity server is working.
* @function Entities.serversExist
* @returns {boolean} <code>true</code> if servers exist for the client to send entity packets to, otherwise
* <code>false</code>.
*/
/// does a server exist to send to
bool serversExist() const { return _packetSender->serversExist(); } bool serversExist() const { return _packetSender->serversExist(); }
/**jsdoc
* Check whether the client has entity packets waiting to be sent.
* @function Entities.hasPacketsToSend
* @returns {boolean} <code>true</code> if the client has entity packets waiting to be sent, otherwise <code>false</code>.
*/
/// are there packets waiting in the send queue to be sent /// are there packets waiting in the send queue to be sent
bool hasPacketsToSend() const { return _packetSender->hasPacketsToSend(); } bool hasPacketsToSend() const { return _packetSender->hasPacketsToSend(); }
/**jsdoc
* Get the number of entity packets the client has waiting to be sent.
* @function Entities.packetsToSendCount
* @returns {number} Integer number of entity packets the client has waiting to be sent.
*/
/// how many packets are there in the send queue waiting to be sent /// how many packets are there in the send queue waiting to be sent
int packetsToSendCount() const { return (int)_packetSender->packetsToSendCount(); } int packetsToSendCount() const { return (int)_packetSender->packetsToSendCount(); }
/**jsdoc
* Get the entity packets per second send rate of the client over its lifetime.
* @function Entities.getLifetimePPS
* @returns {number} Entity packets per second send rate of the client over its lifetime.
*/
/// returns the packets per second send rate of this object over its lifetime /// returns the packets per second send rate of this object over its lifetime
float getLifetimePPS() const { return _packetSender->getLifetimePPS(); } float getLifetimePPS() const { return _packetSender->getLifetimePPS(); }
/**jsdoc
* Get the entity bytes per second send rate of the client over its lifetime.
* @function Entities.getLifetimeBPS
* @returns {number} Entity bytes per second send rate of the client over its lifetime.
*/
/// returns the bytes per second send rate of this object over its lifetime /// returns the bytes per second send rate of this object over its lifetime
float getLifetimeBPS() const { return _packetSender->getLifetimeBPS(); } float getLifetimeBPS() const { return _packetSender->getLifetimeBPS(); }
/**jsdoc
* Get the entity packets per second queued rate of the client over its lifetime.
* @function Entities.getLifetimePPSQueued
* @returns {number} Entity packets per second queued rate of the client over its lifetime.
*/
/// returns the packets per second queued rate of this object over its lifetime /// returns the packets per second queued rate of this object over its lifetime
float getLifetimePPSQueued() const { return _packetSender->getLifetimePPSQueued(); } float getLifetimePPSQueued() const { return _packetSender->getLifetimePPSQueued(); }
/**jsdoc
* Get the entity bytes per second queued rate of the client over its lifetime.
* @function Entities.getLifetimeBPSQueued
* @returns {number} Entity bytes per second queued rate of the client over its lifetime.
*/
/// returns the bytes per second queued rate of this object over its lifetime /// returns the bytes per second queued rate of this object over its lifetime
float getLifetimeBPSQueued() const { return _packetSender->getLifetimeBPSQueued(); } float getLifetimeBPSQueued() const { return _packetSender->getLifetimeBPSQueued(); }
/**jsdoc
* Get the lifetime of the client from the first entity packet sent until now, in microseconds.
* @function Entities.getLifetimeInUsecs
* @returns {number} Lifetime of the client from the first entity packet sent until now, in microseconds.
*/
/// returns lifetime of this object from first packet sent to now in usecs /// returns lifetime of this object from first packet sent to now in usecs
long long unsigned int getLifetimeInUsecs() const { return _packetSender->getLifetimeInUsecs(); } long long unsigned int getLifetimeInUsecs() const { return _packetSender->getLifetimeInUsecs(); }
/// returns lifetime of this object from first packet sent to now in usecs /**jsdoc
* Get the lifetime of the client from the first entity packet sent until now, in seconds.
* @function Entities.getLifetimeInSeconds
* @returns {number} Lifetime of the client from the first entity packet sent until now, in seconds.
*/
/// returns lifetime of this object from first packet sent to now in secs
float getLifetimeInSeconds() const { return _packetSender->getLifetimeInSeconds(); } float getLifetimeInSeconds() const { return _packetSender->getLifetimeInSeconds(); }
/**jsdoc
* Get the total number of entity packets sent by the client over its lifetime.
* @function Entities.getLifetimePacketsSent
* @returns {number} The total number of entity packets sent by the client over its lifetime.
*/
/// returns the total packets sent by this object over its lifetime /// returns the total packets sent by this object over its lifetime
long long unsigned int getLifetimePacketsSent() const { return _packetSender->getLifetimePacketsSent(); } long long unsigned int getLifetimePacketsSent() const { return _packetSender->getLifetimePacketsSent(); }
/**jsdoc
* Get the total bytes of entity packets sent by the client over its lifetime.
* @function Entities.getLifetimeBytesSent
* @returns {number} The total bytes of entity packets sent by the client over its lifetime.
*/
/// returns the total bytes sent by this object over its lifetime /// returns the total bytes sent by this object over its lifetime
long long unsigned int getLifetimeBytesSent() const { return _packetSender->getLifetimeBytesSent(); } long long unsigned int getLifetimeBytesSent() const { return _packetSender->getLifetimeBytesSent(); }
/**jsdoc
* Get the total number of entity packets queued by the client over its lifetime.
* @function Entities.getLifetimePacketsQueued
* @returns {number} The total number of entity packets queued by the client over its lifetime.
*/
/// returns the total packets queued by this object over its lifetime /// returns the total packets queued by this object over its lifetime
long long unsigned int getLifetimePacketsQueued() const { return _packetSender->getLifetimePacketsQueued(); } long long unsigned int getLifetimePacketsQueued() const { return _packetSender->getLifetimePacketsQueued(); }
/**jsdoc
* Get the total bytes of entity packets queued by the client over its lifetime.
* @function Entities.getLifetimeBytesQueued
* @returns {number} The total bytes of entity packets queued by the client over its lifetime.
*/
/// returns the total bytes queued by this object over its lifetime /// returns the total bytes queued by this object over its lifetime
long long unsigned int getLifetimeBytesQueued() const { return _packetSender->getLifetimeBytesQueued(); } long long unsigned int getLifetimeBytesQueued() const { return _packetSender->getLifetimeBytesQueued(); }

View file

@ -756,6 +756,9 @@ void CharacterController::updateState() {
SET_STATE(State::Hover, "double jump button"); SET_STATE(State::Hover, "double jump button");
} else if ((jumpButtonHeld || vertTargetSpeedIsNonZero) && (now - _jumpButtonDownStartTime) > JUMP_TO_HOVER_PERIOD) { } else if ((jumpButtonHeld || vertTargetSpeedIsNonZero) && (now - _jumpButtonDownStartTime) > JUMP_TO_HOVER_PERIOD) {
SET_STATE(State::Hover, "jump button held"); SET_STATE(State::Hover, "jump button held");
} else if (_floorDistance > _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT) {
// Transition to hover if we are above the fall threshold
SET_STATE(State::Hover, "above fall threshold");
} }
} }
break; break;

View file

@ -142,6 +142,18 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
return true; return true;
} }
/**jsdoc
* The <code>"offset"</code> {@link Entities.ActionType|ActionType} moves an entity so that it is a set distance away from a
* target point.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-Offset
* @property {Vec3} pointToOffsetFrom=0,0,0 - The target point to offset the entity from.
* @property {number} linearDistance=0 - The distance away from the target point to position the entity.
* @property {number} linearTimeScale=34e+38 - Controls how long it takes for the entity's position to catch up with the
* target offset. The value is the time for the action to catch up to 1/e = 0.368 of the target value, where the action
* is applied using an exponential decay.
*/
QVariantMap ObjectActionOffset::getArguments() { QVariantMap ObjectActionOffset::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments(); QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] { withReadLock([&] {

View file

@ -307,6 +307,23 @@ bool ObjectActionTractor::updateArguments(QVariantMap arguments) {
return true; return true;
} }
/**jsdoc
* The <code>"tractor"</code> {@link Entities.ActionType|ActionType} moves and rotates an entity to a target position and
* orientation, optionally relative to another entity.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-Tractor
* @property {Vec3} targetPosition=0,0,0 - The target position.
* @property {Quat} targetRotation=0,0,0,1 - The target rotation.
* @property {Uuid} otherID=null - If an entity ID, the <code>targetPosition</code> and <code>targetRotation</code> are
* relative to this entity's position and rotation.
* @property {number} linearTimeScale=3.4e+38 - Controls how long it takes for the entity's position to catch up with the
* target position. The value is the time for the action to catch up to 1/e = 0.368 of the target value, where the action
* is applied using an exponential decay.
* @property {number} angularTimeScale=3.4e+38 - Controls how long it takes for the entity's orientation to catch up with the
* target orientation. The value is the time for the action to catch up to 1/e = 0.368 of the target value, where the
* action is applied using an exponential decay.
*/
QVariantMap ObjectActionTractor::getArguments() { QVariantMap ObjectActionTractor::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments(); QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] { withReadLock([&] {

View file

@ -146,6 +146,17 @@ bool ObjectActionTravelOriented::updateArguments(QVariantMap arguments) {
return true; return true;
} }
/**jsdoc
* The <code>"travel-oriented"</code> {@link Entities.ActionType|ActionType} orients an entity to align with its direction of
* travel.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-TravelOriented
* @property {Vec3} forward=0,0,0 - The axis of the entity to align with the entity's direction of travel.
* @property {number} angularTimeScale=0.1 - Controls how long it takes for the entity's orientation to catch up with the
* direction of travel. The value is the time for the action to catch up to 1/e = 0.368 of the target value, where the
* action is applied using an exponential decay.
*/
QVariantMap ObjectActionTravelOriented::getArguments() { QVariantMap ObjectActionTravelOriented::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments(); QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] { withReadLock([&] {

View file

@ -181,6 +181,15 @@ bool ObjectConstraintBallSocket::updateArguments(QVariantMap arguments) {
return true; return true;
} }
/**jsdoc
* The <code>"ball-socket"</code> {@link Entities.ActionType|ActionType} connects two entities with a ball and socket joint.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-BallSocket
* @property {Vec3} pivot=0,0,0 - The local offset of the joint relative to the entity's position.
* @property {Uuid} otherEntityID=null - The ID of the other entity that is connected to the joint.
* @property {Vec3} otherPivot=0,0,0 - The local offset of the joint relative to the other entity's position.
*/
QVariantMap ObjectConstraintBallSocket::getArguments() { QVariantMap ObjectConstraintBallSocket::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments(); QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] { withReadLock([&] {

View file

@ -261,6 +261,21 @@ bool ObjectConstraintConeTwist::updateArguments(QVariantMap arguments) {
return true; return true;
} }
/**jsdoc
* The <code>"cone-twist"</code> {@link Entities.ActionType|ActionType} connects two entities with a joint that can move
* through a cone and can twist.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-ConeTwist
* @property {Vec3} pivot=0,0,0 - The local offset of the joint relative to the entity's position.
* @property {Vec3} axis=1,0,0 - The axis of the entity that moves through the cone. Must be a non-zero vector.
* @property {Uuid} otherEntityID=null - The ID of the other entity that is connected to the joint.
* @property {Vec3} otherPivot=0,0,0 - The local offset of the joint relative to the other entity's position.
* @property {Vec3} otherAxis=1,0,0 - The axis of the other entity that moves through the cone. Must be a non-zero vector.
* @property {number} swingSpan1=6.238 - The angle through which the joint can move in one axis of the cone, in radians.
* @property {number} swingSpan2=6.238 - The angle through which the joint can move in the other axis of the cone, in radians.
* @property {number} twistSpan=6.238 - The angle through with the joint can twist, in radians.
*/
QVariantMap ObjectConstraintConeTwist::getArguments() { QVariantMap ObjectConstraintConeTwist::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments(); QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] { withReadLock([&] {

View file

@ -245,6 +245,22 @@ bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) {
return true; return true;
} }
/**jsdoc
* The <code>"hinge"</code> {@link Entities.ActionType|ActionType} lets an entity pivot about an axis or connects two entities
* with a hinge joint.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-Hinge
* @property {Vec3} pivot=0,0,0 - The local offset of the joint relative to the entity's position.
* @property {Vec3} axis=1,0,0 - The axis of the entity that it pivots about. Must be a non-zero vector.
* @property {Uuid} otherEntityID=null - The ID of the other entity that is connected to the joint, if any. If none is
* specified then the first entity simply pivots about its specified <code>axis</code>.
* @property {Vec3} otherPivot=0,0,0 - The local offset of the joint relative to the other entity's position.
* @property {Vec3} otherAxis=1,0,0 - The axis of the other entity that it pivots about. Must be a non-zero vector.
* @property {number} low=-6.283 - The most negative angle that the hinge can take, in radians.
* @property {number} high=6.283 - The most positive angle that the hinge can take, in radians.
* @property {number} angle=0 - The current angle of the hinge. <em>Read-only.</em>
*/
QVariantMap ObjectConstraintHinge::getArguments() { QVariantMap ObjectConstraintHinge::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments(); QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] { withReadLock([&] {

View file

@ -261,6 +261,31 @@ bool ObjectConstraintSlider::updateArguments(QVariantMap arguments) {
return true; return true;
} }
/**jsdoc
* The <code>"slider"</code> {@link Entities.ActionType|ActionType} lets an entity slide and rotate along an axis, or connects
* two entities that slide and rotate along a shared axis.
* It has arguments in addition to the common {@link Entities.ActionArguments|ActionArguments}.
*
* @typedef {object} Entities.ActionArguments-Slider
* @property {Vec3} point=0,0,0 - The local position of a point in the entity that slides along the axis.
* @property {Vec3} axis=1,0,0 - The axis of the entity that slides along the joint. Must be a non-zero vector.
* @property {Uuid} otherEntityID=null - The ID of the other entity that is connected to the joint, if any. If non is
* specified then the first entity simply slides and rotates about its specified <code>axis</code>.
* @property {Vec3} otherPoint=0,0,0 - The local position of a point in the other entity that slides along the axis.
* @property {Vec3} axis=1,0,0 - The axis of the other entity that slides along the joint. Must be a non-zero vector.
* @property {number} linearLow=1.17e-38 - The most negative linear offset from the entity's initial point that the entity can
* have along the slider.
* @property {number} linearHigh=3.40e+38 - The most positive linear offset from the entity's initial point that the entity can
* have along the slider.
* @property {number} angularLow=-6.283 - The most negative angle that the entity can rotate about the axis if the action
* involves only one entity, otherwise the most negative angle the rotation can be between the two entities. In radians.
* @property {number} angularHigh=6.283 - The most positive angle that the entity can rotate about the axis if the action
* involves only one entity, otherwise the most positive angle the rotation can be between the two entities. In radians.
* @property {number} linearPosition=0 - The current linear offset the entity is from its initial point if the action involves
* only one entity, otherwise the linear offset between the two entities' action points. <em>Read-only.</em>
* @property {number} angularPosition=0 - The current angular offset of the entity from its initial rotation if the action
* involves only one entity, otherwise the angular offset between the two entities. <em>Read-only.</em>
*/
QVariantMap ObjectConstraintSlider::getArguments() { QVariantMap ObjectConstraintSlider::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments(); QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] { withReadLock([&] {

View file

@ -93,6 +93,38 @@ bool ObjectDynamic::updateArguments(QVariantMap arguments) {
return somethingChanged; return somethingChanged;
} }
/**jsdoc
* Different entity action types have different arguments: some common to all actions (listed below) and some specific to each
* {@link Entities.ActionType|ActionType} (linked to below). The arguments are accessed as an object of property names and
* values.
*
* @typedef {object} Entities.ActionArguments
* @property {Entities.ActionType} type - The type of action.
* @property {string} tag="" - A string that a script can use for its own purposes.
* @property {number} ttl=0 - How long the action should exist, in seconds, before it is automatically deleted. A value of
* <code>0</code> means that the action should not be deleted.
* @property {boolean} isMine=true - Is <code>true</code> if you created the action during your current Interface session,
* <code>false</code> otherwise. <em>Read-only.</em>
* @property {boolean} ::no-motion-state - Is present when the entity hasn't been registered with the physics engine yet (e.g.,
* if the action hasn't been properly configured), otherwise <code>undefined</code>. <em>Read-only.</em>
* @property {boolean} ::active - Is <code>true</code> when the action is modifying the entity's motion, <code>false</code>
* otherwise. Is present once the entity has been registered with the physics engine, otherwise <code>undefined</code>.
* <em>Read-only.</em>
* @property {Entities.PhysicsMotionType} ::motion-type - How the entity moves with the action. Is present once the entity has
* been registered with the physics engine, otherwise <code>undefined</code>. <em>Read-only.</em>
*
* @see The different action types have additional arguments as follows:
* @see {@link Entities.ActionArguments-FarGrab|ActionArguments-FarGrab}
* @see {@link Entities.ActionArguments-Hold|ActionArguments-Hold}
* @see {@link Entities.ActionArguments-Offset|ActionArguments-Offset}
* @see {@link Entities.ActionArguments-Tractor|ActionArguments-Tractor}
* @see {@link Entities.ActionArguments-TravelOriented|ActionArguments-TravelOriented}
* @see {@link Entities.ActionArguments-Hinge|ActionArguments-Hinge}
* @see {@link Entities.ActionArguments-Slider|ActionArguments-Slider}
* @see {@link Entities.ActionArguments-ConeTwist|ActionArguments-ConeTwist}
* @see {@link Entities.ActionArguments-BallSocket|ActionArguments-BallSocket}
*/
// Note: The "type" property is set in EntityItem::getActionArguments().
QVariantMap ObjectDynamic::getArguments() { QVariantMap ObjectDynamic::getArguments() {
QVariantMap arguments; QVariantMap arguments;
withReadLock([&]{ withReadLock([&]{

Some files were not shown because too many files have changed in this diff Show more