3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-26 10:35:27 +02:00

Merge branch 'master' into 20855

This commit is contained in:
David Rowe 2016-03-31 17:00:09 +13:00
commit 2ac9f282c7
84 changed files with 1305 additions and 633 deletions
cmake
examples/utilities
ice-server/src
interface/src
libraries
plugins
server-console
tests/octree/src

View file

@ -12,19 +12,16 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
# 0.5 public
# URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip
# URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9
# 0.6 public
# URL http://static.oculus.com/sdk-downloads/0.6.0.1/Public/1435190862/ovr_sdk_win_0.6.0.1.zip
# URL_MD5 4b3ef825f9a1d6d3035c9f6820687da9
# 0.8 public
# URL http://static.oculus.com/sdk-downloads/0.8.0.0/Public/1445451746/ovr_sdk_win_0.8.0.0.zip
# URL_MD5 54944b03b95149d6010f84eb701b9647
# 1.3 public
# URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.3.0_public.zip
# URL_MD5 4d26faba0c1f35ff80bf674c96ed9259
if (WIN32)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://static.oculus.com/sdk-downloads/0.8.0.0/Public/1445451746/ovr_sdk_win_0.8.0.0.zip
URL_MD5 54944b03b95149d6010f84eb701b9647
URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.3.0_public.zip
URL_MD5 a2dcf695e0f03a70fdd1ed7480585e82
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
@ -33,14 +30,16 @@ if (WIN32)
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL)
set(LIBOVR_DIR ${SOURCE_DIR}/OculusSDK/LibOVR)
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/x64/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
set(LIBOVR_LIB_DIR ${LIBOVR_DIR}/Lib/Windows/x64/Release/VS2013 CACHE TYPE INTERNAL)
else()
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
set(LIBOVR_LIB_DIR ${LIBOVR_DIR}/Lib/Windows/Win32/Release/VS2013 CACHE TYPE INTERNAL)
endif()
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${LIBOVR_DIR}/Include CACHE TYPE INTERNAL)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${LIBOVR_LIB_DIR}/LibOVR.lib CACHE TYPE INTERNAL)
elseif(APPLE)
ExternalProject_Add(

View file

@ -85,8 +85,8 @@ macro(GENERATE_INSTALLERS)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Client")
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Server")
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface")
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox")
include(CPack)
endmacro()

View file

@ -53,7 +53,7 @@ macro(SET_PACKAGING_PARAMETERS)
set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
set(INTERFACE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
set(CONSOLE_EXEC_NAME "Server Console.app")
set(CONSOLE_EXEC_NAME "Sandbox.app")
set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${CONSOLE_EXEC_NAME}")
set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents")
@ -84,12 +84,19 @@ macro(SET_PACKAGING_PARAMETERS)
# shortcut names
if (PRODUCTION_BUILD)
set(INTERFACE_SHORTCUT_NAME "High Fidelity")
set(CONSOLE_SHORTCUT_NAME "Server Console")
set(INTERFACE_SHORTCUT_NAME "Interface")
set(CONSOLE_SHORTCUT_NAME "Sandbox")
else ()
set(INTERFACE_SHORTCUT_NAME "High Fidelity - ${BUILD_VERSION}")
set(CONSOLE_SHORTCUT_NAME "Server Console - ${BUILD_VERSION}")
set(INTERFACE_SHORTCUT_NAME "Interface - ${BUILD_VERSION}")
set(CONSOLE_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION}")
endif ()
set(INTERFACE_HF_SHORTCUT_NAME "High Fidelity ${INTERFACE_SHORTCUT_NAME}")
set(CONSOLE_HF_SHORTCUT_NAME "High Fidelity ${CONSOLE_SHORTCUT_NAME}")
set(PRE_SANDBOX_INTERFACE_SHORTCUT_NAME "High Fidelity")
set(PRE_SANDBOX_CONSOLE_SHORTCUT_NAME "Server Console")
# check if we need to find signtool
if (PRODUCTION_BUILD OR PR_BUILD)
find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64")

View file

@ -10,10 +10,14 @@
#
set(INTERFACE_SHORTCUT_NAME "@INTERFACE_SHORTCUT_NAME@")
set(INTERFACE_HF_SHORTCUT_NAME "@INTERFACE_HF_SHORTCUT_NAME@")
set(INTERFACE_WIN_EXEC_NAME "@INTERFACE_EXEC_PREFIX@.exe")
set(CONSOLE_INSTALL_SUBDIR "@CONSOLE_INSTALL_DIR@")
set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SHORTCUT_NAME@")
set(CONSOLE_HF_SHORTCUT_NAME "@CONSOLE_HF_SHORTCUT_NAME@")
set(CONSOLE_WIN_EXEC_NAME "@CONSOLE_EXEC_NAME@")
set(PRE_SANDBOX_INTERFACE_SHORTCUT_NAME "@PRE_SANDBOX_INTERFACE_SHORTCUT_NAME@")
set(PRE_SANDBOX_CONSOLE_SHORTCUT_NAME "@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@")
set(DS_EXEC_NAME "@DS_EXEC_NAME@")
set(AC_EXEC_NAME "@AC_EXEC_NAME@")
set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@")

View file

@ -387,7 +387,7 @@ Function PostInstallOptionsPage
StrCpy $OffsetUnits u
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_SHORTCUT_NAME@"
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_HF_SHORTCUT_NAME@"
Pop $DesktopClientCheckbox
IntOp $CurrentOffset $CurrentOffset + 15
@ -396,7 +396,7 @@ Function PostInstallOptionsPage
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for High Fidelity @CONSOLE_SHORTCUT_NAME@"
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
Pop $DesktopServerCheckbox
; set the checkbox state depending on what is present in the registry
@ -404,7 +404,7 @@ Function PostInstallOptionsPage
IntOp $CurrentOffset $CurrentOffset + 15
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch High Fidelity @CONSOLE_SHORTCUT_NAME@ on startup"
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
Pop $ServerStartupCheckbox
; set the checkbox state depending on what is present in the registry
@ -414,9 +414,9 @@ Function PostInstallOptionsPage
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch High Fidelity Server Console after install"
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install"
${Else}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch High Fidelity after install"
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
${EndIf}
Pop $LaunchNowCheckbox
@ -465,10 +465,10 @@ Function ReadPostInstallOptions
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
; check if the user asked for a desktop shortcut to Server Console
; check if the user asked for a desktop shortcut to Sandbox
${NSD_GetState} $DesktopServerCheckbox $DesktopServerState
; check if the user asked to have Server Console launched every startup
; check if the user asked to have Sandbox launched every startup
${NSD_GetState} $ServerStartupCheckbox $ServerStartupState
${EndIf}
@ -485,7 +485,7 @@ Function HandlePostInstallOptions
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
; check if the user asked for a desktop shortcut to High Fidelity
${If} $DesktopClientState == ${BST_CHECKED}
CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
CreateShortCut "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
!insertmacro WritePostInstallOption "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" YES
${Else}
!insertmacro WritePostInstallOption @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ NO
@ -494,23 +494,23 @@ Function HandlePostInstallOptions
${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
; check if the user asked for a desktop shortcut to Server Console
; check if the user asked for a desktop shortcut to Sandbox
${If} $DesktopServerState == ${BST_CHECKED}
CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
!insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES
${Else}
!insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO
${EndIf}
; check if the user asked to have Server Console launched every startup
; check if the user asked to have Sandbox launched every startup
${If} $ServerStartupState == ${BST_CHECKED}
; in case we added a shortcut in the global context, pull that now
SetShellVarContext all
Delete "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk"
Delete "$SMSTARTUP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk"
; make a startup shortcut in this user's current context
SetShellVarContext current
CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
CreateShortCut "$SMSTARTUP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
; reset the shell var context back
SetShellVarContext all
@ -589,6 +589,19 @@ Section "-Core installation"
Delete "$INSTDIR\version"
Delete "$INSTDIR\xinput1_3.dll"
; Delete old desktop shortcuts before they were renamed during Sandbox rename
Delete "$DESKTOP\@PRE_SANDBOX_INTERFACE_SHORTCUT_NAME@.lnk"
Delete "$DESKTOP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk"
; Delete old Start Menu shortcuts before Sandbox rename
Delete "$SMPROGRAMS\$STARTMENU_FOLDER\@PRE_SANDBOX_INTERFACE_SHORTCUT_NAME@.lnk"
Delete "$SMPROGRAMS\$STARTMENU_FOLDER\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk"
; Delete old startup item for Server Console before Sandbox rename
SetShellVarContext current
Delete "$SMSTARTUP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk"
SetShellVarContext all
; Rename the incorrectly cased Raleway font
Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml"
@ -724,8 +737,8 @@ SectionEnd
!macroend
!macro CheckForRunningApplications action prompter
!insertmacro PromptForRunningApplication "@INTERFACE_WIN_EXEC_NAME@" "High Fidelity client" ${action} ${prompter}
!insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "Server Console" ${action} ${prompter}
!insertmacro PromptForRunningApplication "@INTERFACE_WIN_EXEC_NAME@" "@CONSOLE_SHORTCUT_NAME@" ${action} ${prompter}
!insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "@INTERFACE_SHORTCUT_NAME@" ${action} ${prompter}
!insertmacro PromptForRunningApplication "@DS_EXEC_NAME@" "Domain Server" ${action} ${prompter}
!insertmacro PromptForRunningApplication "@AC_EXEC_NAME@" "Assignment Client" ${action} ${prompter}
!macroend
@ -869,12 +882,12 @@ Section "Uninstall"
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
Delete "$SMPROGRAMS\$MUI_TEMP\@INTERFACE_SHORTCUT_NAME@.lnk"
Delete "$SMPROGRAMS\$MUI_TEMP\@CONSOLE_SHORTCUT_NAME@.lnk"
Delete "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk"
Delete "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk"
Delete "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk"
Delete "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk"
; if it exists, delete the startup shortcut for the current user
SetShellVarContext current
Delete "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk"
Delete "$SMSTARTUP\@CONSOLE_HF_SHORTCUT_NAME@.lnk"
SetShellVarContext all
@CPACK_NSIS_DELETE_ICONS@

View file

@ -0,0 +1 @@
ConfigSlider 1.0 ConfigSlider.qml

View file

@ -0,0 +1,114 @@
//
// culling.qml
// examples/utilities/render
//
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "configSlider"
Column {
id: root
spacing: 8
property var sceneOctree: Render.getConfig("DrawSceneOctree");
property var itemSelection: Render.getConfig("DrawItemSelection");
Component.onCompleted: {
sceneOctree.enabled = true;
itemSelection.enabled = true;
sceneOctree.showVisibleCells = false;
sceneOctree.showEmptyCells = false;
itemSelection.showInsideItems = false;
itemSelection.showInsideSubcellItems = false;
itemSelection.showPartialItems = false;
itemSelection.showPartialSubcellItems = false;
}
Component.onDestruction: {
sceneOctree.enabled = false;
itemSelection.enabled = false;
Render.getConfig("FetchSceneSelection").freezeFrustum = false;
Render.getConfig("CullSceneSelection").freezeFrustum = false;
}
GroupBox {
title: "Culling"
Row {
spacing: 8
Column {
spacing: 8
CheckBox {
text: "Freeze Culling Frustum"
checked: false
onCheckedChanged: {
Render.getConfig("FetchSceneSelection").freezeFrustum = checked;
Render.getConfig("CullSceneSelection").freezeFrustum = checked;
}
}
Label {
text: "Octree"
}
CheckBox {
text: "Visible Cells"
checked: root.sceneOctree.showVisibleCells
onCheckedChanged: { root.sceneOctree.showVisibleCells = checked }
}
CheckBox {
text: "Empty Cells"
checked: false
onCheckedChanged: { root.sceneOctree.showEmptyCells = checked }
}
}
Column {
spacing: 8
Label {
text: "Frustum Items"
}
CheckBox {
text: "Inside Items"
checked: false
onCheckedChanged: { root.itemSelection.showInsideItems = checked }
}
CheckBox {
text: "Inside Sub-cell Items"
checked: false
onCheckedChanged: { root.itemSelection.showInsideSubcellItems = checked }
}
CheckBox {
text: "Partial Items"
checked: false
onCheckedChanged: { root.itemSelection.showPartialItems = checked }
}
CheckBox {
text: "Partial Sub-cell Items"
checked: false
onCheckedChanged: { root.itemSelection.showPartialSubcellItems = checked }
}
}
}
}
GroupBox {
title: "Render Items"
Column{
Repeater {
model: [ "Opaque:DrawOpaqueDeferred", "Transparent:DrawTransparentDeferred", "Light:DrawLight",
"Opaque Overlays:DrawOverlay3DOpaque", "Transparent Overlays:DrawOverlay3DTransparent" ]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: true
config: Render.getConfig(modelData.split(":")[1])
property: "maxDrawn"
max: config.numDrawn
min: -1
}
}
}
}
}

View file

@ -0,0 +1,21 @@
//
// debugRender.js
// examples/utilities/render
//
// Sam Gateau, created on 3/22/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Set up the qml ui
var qml = Script.resolvePath('culling.qml');
var window = new OverlayWindow({
title: 'Render Draws',
source: qml,
width: 300,
height: 200
});
window.setPosition(200, 50);
window.closed.connect(function() { Script.stop(); });

View file

@ -10,6 +10,7 @@
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "configSlider"
Column {
id: root

View file

@ -1,6 +1,6 @@
//
// PlotPerf.qml
// examples/utilities/tools/render
// examples/utilities/render/plotperf
//
// Created by Sam Gateau on 3//2016
// Copyright 2016 High Fidelity, Inc.
@ -15,40 +15,64 @@ Item {
id: root
width: parent.width
height: 100
// The title of the graph
property string title
property var config
property string parameters
// THis is my hack to get the name of the first property and assign it to a trigger var in order to get
// THe object used as the default source object for the prop plots
property var object
// THis is my hack to get a property and assign it to a trigger var in order to get
// a signal called whenever the value changed
property var trigger: config[parameters.split(":")[3].split("-")[0]]
property var trigger
// Plots is an array of plot descriptor
// a default plot descriptor expects the following object:
// prop: [ {
// object: {} // Optional: this is the object from which the prop will be fetched,
// if nothing than the object from root is used
// prop:"bufferCPUCount", // Needed the name of the property from the object to feed the plot
// label: "CPU", // Optional: Label as displayed on the plot
// color: "#00B4EF" // Optional: Color of the curve
// unit: "km/h" // Optional: Unit added to the value displayed, if nothing then the default unit is used
// scale: 1 // Optional: Extra scaling used to represent the value, this scale is combined with the global scale.
// },
property var plots
// Default value scale used to define the max value of the chart
property var valueScale: 1
// Default value unit appended to the value displayed
property var valueUnit: ""
// Default number of digits displayed
property var valueNumDigits: 0
property var inputs: parameters.split(":")
property var valueScale: +inputs[0]
property var valueUnit: inputs[1]
property var valueNumDigits: inputs[2]
property var input_VALUE_OFFSET: 3
property var valueMax : 1
property var _values : new Array()
property var tick : 0
function createValues() {
if (inputs.length > input_VALUE_OFFSET) {
for (var i = input_VALUE_OFFSET; i < inputs.length; i++) {
var varProps = inputs[i].split("-")
_values.push( {
value: varProps[0],
valueMax: 1,
numSamplesConstantMax: 0,
valueHistory: new Array(),
label: varProps[1],
color: varProps[2],
scale: (varProps.length > 3 ? varProps[3] : 1),
unit: (varProps.length > 4 ? varProps[4] : valueUnit)
})
}
}
print("trigger is: " + JSON.stringify(trigger))
if (Array.isArray(plots)) {
for (var i =0; i < plots.length; i++) {
var plot = plots[i];
print(" a pnew Plot:" + JSON.stringify(plot));
_values.push( {
object: (plot["object"] !== undefined ? plot["object"] : root.object),
value: plot["prop"],
valueMax: 1,
numSamplesConstantMax: 0,
valueHistory: new Array(),
label: (plot["label"] !== undefined ? plot["label"] : ""),
color: (plot["color"] !== undefined ? plot["color"] : "white"),
scale: (plot["scale"] !== undefined ? plot["scale"] : 1),
unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit)
})
}
}
print("in creator" + JSON.stringify(_values));
}
@ -69,7 +93,8 @@ Item {
var currentValueMax = 0
for (var i = 0; i < _values.length; i++) {
var currentVal = config[_values[i].value] * _values[i].scale;
var currentVal = _values[i].object[_values[i].value] * _values[i].scale;
_values[i].valueHistory.push(currentVal)
_values[i].numSamplesConstantMax++;

View file

@ -0,0 +1,195 @@
//
// stats.qml
// examples/utilities/render
//
// Created by Zach Pomerantz on 2/8/2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "plotperf"
Item {
id: statsUI
anchors.fill:parent
Column {
id: stats
spacing: 8
anchors.fill:parent
property var config: Render.getConfig("Stats")
function evalEvenHeight() {
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
return (height - spacing * (children.length - 1)) / children.length
}
PlotPerf {
title: "Num Buffers"
height: parent.evalEvenHeight()
object: stats.config
trigger: stats.config["bufferCPUCount"]
plots: [
{
prop: "bufferCPUCount",
label: "CPU",
color: "#00B4EF"
},
{
prop: "bufferGPUCount",
label: "GPU",
color: "#1AC567"
}
]
}
PlotPerf {
title: "gpu::Buffer Memory"
height: parent.evalEvenHeight()
object: stats.config
trigger: stats.config["bufferCPUMemoryUsage"]
valueScale: 1048576
valueUnit: "Mb"
valueNumDigits: "1"
plots: [
{
prop: "bufferCPUMemoryUsage",
label: "CPU",
color: "#00B4EF"
},
{
prop: "bufferGPUMemoryUsage",
label: "GPU",
color: "#1AC567"
}
]
}
PlotPerf {
title: "Num Textures"
height: parent.evalEvenHeight()
object: stats.config
trigger: stats.config["textureCPUCount"]
plots: [
{
prop: "textureCPUCount",
label: "CPU",
color: "#00B4EF"
},
{
prop: "textureGPUCount",
label: "GPU",
color: "#1AC567"
},
{
prop: "frameTextureCount",
label: "Frame",
color: "#E2334D"
}
]
}
PlotPerf {
title: "gpu::Texture Memory"
height: parent.evalEvenHeight()
object: stats.config
trigger: stats.config["textureCPUMemoryUsage"]
valueScale: 1048576
valueUnit: "Mb"
valueNumDigits: "1"
plots: [
{
prop: "textureCPUMemoryUsage",
label: "CPU",
color: "#00B4EF"
},
{
prop: "textureGPUMemoryUsage",
label: "GPU",
color: "#1AC567"
}
]
}
PlotPerf {
title: "Triangles"
height: parent.evalEvenHeight()
object: stats.config
trigger: stats.config["frameTriangleCount"]
valueScale: 1000
valueUnit: "K"
plots: [
{
prop: "frameTriangleCount",
label: "Triangles",
color: "#1AC567"
},
{
prop: "frameTriangleRate",
label: "rate",
color: "#E2334D",
scale: 0.001,
unit: "MT/s"
}
]
}
PlotPerf {
title: "Drawcalls"
height: parent.evalEvenHeight()
object: stats.config
trigger: stats.config["frameDrawcallCount"]
plots: [
{
prop: "frameAPIDrawcallCount",
label: "API Drawcalls",
color: "#00B4EF"
},
{
prop: "frameDrawcallCount",
label: "GPU Drawcalls",
color: "#1AC567"
},
{
prop: "frameDrawcallRate",
label: "rate",
color: "#E2334D",
scale: 0.001,
unit: "K/s"
}
]
}
property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred")
property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred")
property var drawLightConfig: Render.getConfig("DrawLight")
PlotPerf {
title: "Items"
height: parent.evalEvenHeight()
object: parent.drawOpaqueConfig
trigger: Render.getConfig("DrawOpaqueDeferred")["numDrawn"]
plots: [
{
object: Render.getConfig("DrawOpaqueDeferred"),
prop: "numDrawn",
label: "Opaques",
color: "#1AC567"
},
{
object: Render.getConfig("DrawTransparentDeferred"),
prop: "numDrawn",
label: "Translucents",
color: "#00B4EF"
},
{
object: Render.getConfig("DrawLight"),
prop: "numDrawn",
label: "Lights",
color: "#E2334D"
}
]
}
}
}

View file

@ -1,99 +0,0 @@
//
// debugRenderOctree.js
// examples/utilities/tools
//
// Sam Gateau
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("cookies.js");
var panel = new Panel(10, 300);
var drawOctree = Render.RenderDeferredTask.DrawSceneOctree;
Render.RenderDeferredTask.DrawSceneOctree.enabled = true;
Render.RenderDeferredTask.DrawItemSelection.enabled = true;
panel.newCheckbox("Show Octree Cells",
function(value) { Render.RenderDeferredTask.DrawSceneOctree.showVisibleCells = value; },
function() { return (Render.RenderDeferredTask.DrawSceneOctree.showVisibleCells); },
function(value) { return (value); }
);
panel.newCheckbox("Show Empty Cells",
function(value) { Render.RenderDeferredTask.DrawSceneOctree.showEmptyCells = value; },
function() { return (Render.RenderDeferredTask.DrawSceneOctree.showEmptyCells); },
function(value) { return (value); }
);
panel.newCheckbox("Freeze Frustum",
function(value) { Render.RenderDeferredTask.FetchSceneSelection.freezeFrustum = value; Render.RenderDeferredTask.CullSceneSelection.freezeFrustum = value; },
function() { return (Render.RenderDeferredTask.FetchSceneSelection.freezeFrustum); },
function(value) { return (value); }
);
panel.newCheckbox("Show Inside Items",
function(value) { Render.RenderDeferredTask.DrawItemSelection.showInsideItems = value; },
function() { return (Render.RenderDeferredTask.DrawItemSelection.showInsideItems); },
function(value) { return (value); }
);
panel.newCheckbox("Show Inside Subcell Items",
function(value) { Render.RenderDeferredTask.DrawItemSelection.showInsideSubcellItems = value; },
function() { return (Render.RenderDeferredTask.DrawItemSelection.showInsideSubcellItems); },
function(value) { return (value); }
);
panel.newCheckbox("Show Partial Items",
function(value) { Render.RenderDeferredTask.DrawItemSelection.showPartialItems = value; },
function() { return (Render.RenderDeferredTask.DrawItemSelection.showPartialItems); },
function(value) { return (value); }
);
panel.newCheckbox("Show Partial Subcell Items",
function(value) { Render.RenderDeferredTask.DrawItemSelection.showPartialSubcellItems = value; },
function() { return (Render.RenderDeferredTask.DrawItemSelection.showPartialSubcellItems); },
function(value) { return (value); }
);
/*
panel.newSlider('Cells Free / Allocated', -1, 1,
function(value) { value; }, // setter
function() { return Render.RenderDeferredTask.DrawSceneOctree.numFreeCells; }, // getter
function(value) { return value; });
this.update = function () {
var numFree = Render.RenderDeferredTask.DrawSceneOctree.numFreeCells;
var numAlloc = Render.RenderDeferredTask.DrawSceneOctree.numAllocatedCells;
var title = [
' ' + name,
numFree + ' / ' + numAlloc
].join('\t');
widget.editTitle({ text: title });
slider.setMaxValue(numAlloc);
};
*/
function mouseMoveEvent(event) {
panel.mouseMoveEvent(event);
}
function mousePressEvent(event) {
panel.mousePressEvent(event);
}
function mouseReleaseEvent(event) {
panel.mouseReleaseEvent(event);
}
Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
function scriptEnding() {
panel.destroy();
Render.RenderDeferredTask.DrawSceneOctree.enabled = false;
Render.RenderDeferredTask.DrawItemSelection.enabled = false;
}
Script.scriptEnding.connect(scriptEnding);

View file

@ -1,69 +0,0 @@
//
// stats.qml
// examples/utilities/tools/render
//
// Created by Zach Pomerantz on 2/8/2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "plotperf"
Item {
id: statsUI
anchors.fill:parent
Column {
id: stats
spacing: 8
anchors.fill:parent
property var config: Render.getConfig("Stats")
function evalEvenHeight() {
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
return (height - spacing * (children.length - 1)) / children.length
}
PlotPerf {
title: "Num Buffers"
config: stats.config
height: parent.evalEvenHeight()
parameters: "1::0:bufferCPUCount-CPU-#00B4EF:bufferGPUCount-GPU-#1AC567"
}
PlotPerf {
title: "gpu::Buffer Memory"
config: stats.config
height: parent.evalEvenHeight()
parameters: "1048576:Mb:1:bufferCPUMemoryUsage-CPU-#00B4EF:bufferGPUMemoryUsage-GPU-#1AC567"
}
PlotPerf {
title: "Num Textures"
config: stats.config
height: parent.evalEvenHeight()
parameters: "1::0:textureCPUCount-CPU-#00B4EF:textureGPUCount-GPU-#1AC567:frameTextureCount-Frame-#E2334D"
}
PlotPerf {
title: "gpu::Texture Memory"
config: stats.config
height: parent.evalEvenHeight()
parameters: "1048576:Mb:1:textureCPUMemoryUsage-CPU-#00B4EF:textureGPUMemoryUsage-GPU-#1AC567"
}
PlotPerf {
title: "Drawcalls"
config: stats.config
height: parent.evalEvenHeight()
parameters: "1::0:frameDrawcallCount-frame-#E2334D:frameDrawcallRate-rate-#1AC567-0.001-K/s"
}
PlotPerf {
title: "Triangles"
config: stats.config
height: parent.evalEvenHeight()
parameters: "1000:K:0:frameTriangleCount-frame-#E2334D:frameTriangleRate-rate-#1AC567-0.001-MT/s"
}
}
}

View file

@ -19,6 +19,7 @@
#include <QtNetwork/QNetworkRequest>
#include <LimitedNodeList.h>
#include <NetworkAccessManager.h>
#include <NetworkingConstants.h>
#include <udt/PacketHeaders.h>
#include <SharedUtil.h>
@ -33,7 +34,8 @@ IceServer::IceServer(int argc, char* argv[]) :
_id(QUuid::createUuid()),
_serverSocket(),
_activePeers(),
_httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this)
_httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this),
_lastInactiveCheckTimestamp(QDateTime::currentMSecsSinceEpoch())
{
// start the ice-server socket
qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT;
@ -68,8 +70,6 @@ bool IceServer::packetVersionMatch(const udt::Packet& packet) {
void IceServer::processPacket(std::unique_ptr<udt::Packet> packet) {
_lastPacketTimestamp = QDateTime::currentMSecsSinceEpoch();
auto nlPacket = NLPacket::fromBase(std::move(packet));
// make sure that this packet at least looks like something we can read
@ -201,8 +201,8 @@ bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& pla
void IceServer::requestDomainPublicKey(const QUuid& domainID) {
// send a request to the metaverse API for the public key for this domain
QNetworkAccessManager* manager = new QNetworkAccessManager { this };
connect(manager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished);
auto& networkAccessManager = NetworkAccessManager::getInstance();
connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished);
QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL };
QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID));
@ -213,7 +213,7 @@ void IceServer::requestDomainPublicKey(const QUuid& domainID) {
qDebug() << "Requesting public key for domain with ID" << domainID;
manager->get(publicKeyRequest);
networkAccessManager.get(publicKeyRequest);
}
void IceServer::publicKeyReplyFinished(QNetworkReply* reply) {
@ -281,6 +281,8 @@ void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSoc
void IceServer::clearInactivePeers() {
NetworkPeerHash::iterator peerItem = _activePeers.begin();
_lastInactiveCheckTimestamp = QDateTime::currentMSecsSinceEpoch();
while (peerItem != _activePeers.end()) {
SharedNetworkPeer peer = peerItem.value();
@ -309,11 +311,14 @@ bool IceServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, b
const quint64 MAX_PACKET_GAP_MS_FOR_STUCK_SOCKET = 10 * 1000;
int statusNumber = (QDateTime::currentMSecsSinceEpoch() - _lastPacketTimestamp > MAX_PACKET_GAP_MS_FOR_STUCK_SOCKET)
? 1 : 0;
auto sinceLastInactiveCheck = QDateTime::currentMSecsSinceEpoch() - _lastInactiveCheckTimestamp;
int statusNumber = (sinceLastInactiveCheck > MAX_PACKET_GAP_MS_FOR_STUCK_SOCKET) ? 1 : 0;
connection->respond(HTTPConnection::StatusCode200, QByteArray::number(statusNumber));
return true;
}
}
return true;
return false;
}

View file

@ -58,7 +58,7 @@ private:
using DomainPublicKeyHash = std::unordered_map<QUuid, RSAUniquePtr>;
DomainPublicKeyHash _domainPublicKeys;
quint64 _lastPacketTimestamp;
quint64 _lastInactiveCheckTimestamp;
};
#endif // hifi_IceServer_h

View file

@ -224,7 +224,6 @@ static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStanda
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/script.js");
#endif
const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js";
Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
@ -1490,11 +1489,15 @@ void Application::paintGL() {
// FIXME not needed anymore?
_offscreenContext->makeCurrent();
displayPlugin->updateHeadPose(_frameCount);
displayPlugin->beginFrameRender(_frameCount);
// update the avatar with a fresh HMD pose
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
// update sensorToWorldMatrix for camera and hand controllers
getMyAvatar()->updateSensorToWorldMatrix();
auto lodManager = DependencyManager::get<LODManager>();
@ -2007,6 +2010,12 @@ void Application::keyPressEvent(QKeyEvent* event) {
}
break;
case Qt::Key_Y:
if (isShifted && isMeta) {
getActiveDisplayPlugin()->cycleDebugOutput();
}
break;
case Qt::Key_B:
if (isMeta) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
@ -2572,11 +2581,6 @@ void Application::idle(uint64_t now) {
return; // bail early, nothing to do here.
}
checkChangeCursor();
Stats::getInstance()->updateStats();
AvatarInputs::getInstance()->update();
// These tasks need to be done on our first idle, because we don't want the showing of
// overlay subwindows to do a showDesktop() until after the first time through
static bool firstIdle = true;
@ -2625,6 +2629,11 @@ void Application::idle(uint64_t now) {
// We're going to execute idle processing, so restart the last idle timer
_lastTimeUpdated.start();
checkChangeCursor();
Stats::getInstance()->updateStats();
AvatarInputs::getInstance()->update();
{
static uint64_t lastIdleStart{ now };
uint64_t idleStartToStartDuration = now - lastIdleStart;
@ -3389,9 +3398,6 @@ void Application::update(float deltaTime) {
qApp->updateMyAvatarLookAtPosition();
// update sensorToWorldMatrix for camera and hand controllers
myAvatar->updateSensorToWorldMatrix();
{
PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
avatarManager->updateMyAvatar(deltaTime);

View file

@ -373,32 +373,34 @@ void MyAvatar::simulate(float deltaTime) {
EntityTreeRenderer* entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
if (entityTree) {
auto now = usecTimestampNow();
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
MovingEntitiesOperator moveOperator(entityTree);
forEachDescendant([&](SpatiallyNestablePointer object) {
// if the queryBox has changed, tell the entity-server
if (object->computePuffedQueryAACube() && object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
bool success;
AACube newCube = entity->getQueryAACube(success);
if (success) {
moveOperator.addEntityToMoveList(entity, newCube);
}
if (packetSender) {
EntityItemProperties properties = entity->getProperties();
properties.setQueryAACubeDirty();
properties.setLastEdited(now);
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties);
entity->setLastBroadcast(usecTimestampNow());
entityTree->withWriteLock([&] {
auto now = usecTimestampNow();
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
MovingEntitiesOperator moveOperator(entityTree);
forEachDescendant([&](SpatiallyNestablePointer object) {
// if the queryBox has changed, tell the entity-server
if (object->computePuffedQueryAACube() && object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
bool success;
AACube newCube = entity->getQueryAACube(success);
if (success) {
moveOperator.addEntityToMoveList(entity, newCube);
}
if (packetSender) {
EntityItemProperties properties = entity->getProperties();
properties.setQueryAACubeDirty();
properties.setLastEdited(now);
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties);
entity->setLastBroadcast(usecTimestampNow());
}
}
});
// also update the position of children in our local octree
if (moveOperator.hasMovingEntities()) {
PerformanceTimer perfTimer("recurseTreeWithOperator");
entityTree->recurseTreeWithOperator(&moveOperator);
}
});
// also update the position of children in our local octree
if (moveOperator.hasMovingEntities()) {
PerformanceTimer perfTimer("recurseTreeWithOperator");
entityTree->recurseTreeWithOperator(&moveOperator);
}
}
}

View file

@ -555,7 +555,7 @@ void AudioClient::configureReverb() {
p.wetDryMix = 100.0f;
p.preDelay = 0.0f;
p.earlyGain = -96.0f; // disable ER
p.lateGain -= 12.0f; // quieter than listener reverb
p.lateGain += _reverbOptions->getWetDryMix() * (24.0f/100.0f) - 24.0f; // -0dB to -24dB, based on wetDryMix
p.lateMixLeft = 0.0f;
p.lateMixRight = 0.0f;

View file

@ -81,6 +81,9 @@ namespace controller {
// Triggers
LT,
RT,
// Grips (Oculus touch squeeze)
LG,
RG,
NUM_STANDARD_AXES,
LZ = LT,
RZ = RT

View file

@ -552,9 +552,9 @@ float OpenGLDisplayPlugin::presentRate() {
{
Lock lock(_mutex);
result = _usecsPerFrame.getAverage();
result = 1.0f / result;
result *= USECS_PER_SECOND;
}
result = 1.0f / result;
result *= USECS_PER_SECOND;
return result;
}

View file

@ -17,9 +17,9 @@
#include <GLMHelpers.h>
#include <SimpleMovingAverage.h>
#include <gl/OglplusHelpers.h>
#include <gl/GLEscrow.h>
#define THREADED_PRESENT 1
#include <gl/GLEscrow.h>
class OpenGLDisplayPlugin : public DisplayPlugin {
protected:

View file

@ -69,10 +69,11 @@ void HmdDisplayPlugin::compositeOverlay() {
// set the alpha
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
auto eyePoses = _currentPresentFrameInfo.eyePoses;
_sphereSection->Use();
for_each_eye([&](Eye eye) {
eyeViewport(eye);
auto modelView = glm::inverse(_currentRenderEyePoses[eye]); // *glm::translate(mat4(), vec3(0, 0, -1));
auto modelView = glm::inverse(eyePoses[eye]); // *glm::translate(mat4(), vec3(0, 0, -1));
auto mvp = _eyeProjections[eye] * modelView;
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
_sphereSection->Draw();
@ -95,10 +96,10 @@ void HmdDisplayPlugin::compositePointer() {
// Mouse pointer
_plane->Use();
// Reconstruct the headpose from the eye poses
auto headPosition = (vec3(_currentRenderEyePoses[Left][3]) + vec3(_currentRenderEyePoses[Right][3])) / 2.0f;
auto headPosition = vec3(_currentPresentFrameInfo.headPose[3]);
for_each_eye([&](Eye eye) {
eyeViewport(eye);
auto reticleTransform = compositorHelper->getReticleTransform(_currentRenderEyePoses[eye], headPosition);
auto reticleTransform = compositorHelper->getReticleTransform(_currentPresentFrameInfo.eyePoses[eye], headPosition);
auto mvp = _eyeProjections[eye] * reticleTransform;
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
_plane->Draw();
@ -160,15 +161,28 @@ void HmdDisplayPlugin::internalPresent() {
void HmdDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) {
Lock lock(_mutex);
_renderEyePoses[frameIndex][eye] = pose;
FrameInfo& frame = _frameInfos[frameIndex];
frame.eyePoses[eye] = pose;
}
void HmdDisplayPlugin::updateFrameData() {
// Check if we have old frame data to discard
{
Lock lock(_mutex);
auto itr = _frameInfos.find(_currentRenderFrameIndex);
if (itr != _frameInfos.end()) {
_frameInfos.erase(itr);
}
}
Parent::updateFrameData();
Lock lock(_mutex);
_currentRenderEyePoses = _renderEyePoses[_currentRenderFrameIndex];
{
Lock lock(_mutex);
_currentPresentFrameInfo = _frameInfos[_currentRenderFrameIndex];
}
}
glm::mat4 HmdDisplayPlugin::getHeadPose() const {
return _headPoseCache.get();
return _currentRenderFrameInfo.get().headPose;
}

View file

@ -28,6 +28,16 @@ public:
virtual glm::mat4 getHeadPose() const override;
using EyePoses = std::array<glm::mat4, 2>;
struct FrameInfo {
EyePoses eyePoses;
glm::mat4 headPose;
double sensorSampleTime { 0 };
double predictedDisplayTime { 0 };
};
protected:
virtual void hmdPresent() = 0;
virtual bool isHmdMounted() const = 0;
@ -46,10 +56,10 @@ protected:
glm::mat4 _cullingProjection;
glm::uvec2 _renderTargetSize;
float _ipd { 0.064f };
using EyePoses = std::array<glm::mat4, 2>;
QMap<uint32_t, EyePoses> _renderEyePoses;
EyePoses _currentRenderEyePoses;
ThreadSafeValueCache<glm::mat4> _headPoseCache { glm::mat4() };
QMap<uint32_t, FrameInfo> _frameInfos;
FrameInfo _currentPresentFrameInfo;
ThreadSafeValueCache<FrameInfo> _currentRenderFrameInfo;
private:
bool _enablePreview { false };

View file

@ -117,12 +117,11 @@ QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) {
QJsonParseError error;
QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << _textures;
qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << textures;
return _originalTextures;
}
auto parsed = texturesJson.toVariant();
return parsed.toMap();
return texturesJson.toVariant().toMap();
}
void RenderableModelEntityItem::remapTextures() {
@ -144,11 +143,17 @@ void RenderableModelEntityItem::remapTextures() {
_currentTextures = _originalTextures;
}
auto textures = parseTexturesToMap(_textures);
auto textures = getTextures();
if (textures == _lastTextures) {
return;
}
if (textures != _currentTextures) {
geometry->setTextures(textures);
_currentTextures = textures;
_lastTextures = textures;
auto newTextures = parseTexturesToMap(textures);
if (newTextures != _currentTextures) {
geometry->setTextures(newTextures);
_currentTextures = newTextures;
}
}

View file

@ -90,6 +90,7 @@ private:
bool _needsInitialSimulation = true;
bool _needsModelReload = true;
EntityTreeRenderer* _myRenderer = nullptr;
QString _lastTextures;
QVariantMap _currentTextures;
QVariantMap _originalTextures;
bool _originalTexturesRead = false;

View file

@ -42,6 +42,17 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(
_color[0] = _color[1] = _color[2] = 0;
}
const QString ModelEntityItem::getTextures() const {
QReadLocker locker(&_texturesLock);
auto textures = _textures;
return textures;
}
void ModelEntityItem::setTextures(const QString& textures) {
QWriteLocker locker(&_texturesLock);
_textures = textures;
}
EntityItemProperties ModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);

View file

@ -110,8 +110,8 @@ public:
float getAnimationFPS() const { return _animationLoop.getFPS(); }
static const QString DEFAULT_TEXTURES;
const QString& getTextures() const { return _textures; }
void setTextures(const QString& textures) { _textures = textures; }
const QString getTextures() const;
void setTextures(const QString& textures);
virtual bool shouldBePhysical() const;
@ -159,7 +159,9 @@ protected:
AnimationPropertyGroup _animationProperties;
AnimationLoop _animationLoop;
mutable QReadWriteLock _texturesLock;
QString _textures;
ShapeType _shapeType = SHAPE_TYPE_NONE;
// used on client side

View file

@ -38,11 +38,13 @@ bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) {
_context->setShareContext(sharedContext);
}
_context->setFormat(getDefaultOpenGLSurfaceFormat());
if (_context->create()) {
_offscreenSurface->setFormat(_context->format());
_offscreenSurface->create();
return true;
return _offscreenSurface->isValid();
}
qWarning("Failed to create OffscreenGLCanvas context");
return false;
}

View file

@ -134,14 +134,13 @@ QEvent* OffscreenQmlRenderThread::Queue::take() {
}
OffscreenQmlRenderThread::OffscreenQmlRenderThread(OffscreenQmlSurface* surface, QOpenGLContext* shareContext) : _surface(surface) {
qDebug() << "Building QML Renderer: creating context";
qDebug() << "Building QML Renderer";
if (!_canvas.create(shareContext)) {
static const char* error = "Failed to create OffscreenGLCanvas";
qWarning() << error;
throw error;
qWarning("Failed to create OffscreenGLCanvas");
_quit = true;
return;
};
qDebug() << "Building QML Renderer: creating render control";
_renderControl = new QMyQuickRenderControl();
QQuickWindow::setDefaultAlphaBuffer(true);
// Create a QQuickWindow that is associated with our render control.
@ -149,19 +148,15 @@ OffscreenQmlRenderThread::OffscreenQmlRenderThread(OffscreenQmlSurface* surface,
// NOTE: Must be created on the main thread so that OffscreenQmlSurface can send it events
// NOTE: Must be created on the rendering thread or it will refuse to render,
// so we wait until after its ctor to move object/context to this thread.
qDebug() << "Building QML Renderer: creating window";
_quickWindow = new QQuickWindow(_renderControl);
_quickWindow->setColor(QColor(255, 255, 255, 0));
_quickWindow->setFlags(_quickWindow->flags() | static_cast<Qt::WindowFlags>(Qt::WA_TranslucentBackground));
// We can prepare, but we must wait to start() the thread until after the ctor
qDebug() << "Building QML Renderer: moving to own thread";
_renderControl->prepareThread(this);
_canvas.getContextObject()->moveToThread(this);
moveToThread(this);
qDebug() << "Building QML Renderer: complete";
_queue.add(INIT);
}

View file

@ -35,6 +35,7 @@ public:
int _RSNumTextureBounded = 0;
int _DSNumAPIDrawcalls = 0;
int _DSNumDrawcalls = 0;
int _DSNumTriangles = 0;

View file

@ -326,6 +326,7 @@ void GLBackend::do_draw(Batch& batch, size_t paramOffset) {
glDrawArrays(mode, startVertex, numVertices);
_stats._DSNumTriangles += numVertices / 3;
_stats._DSNumDrawcalls++;
_stats._DSNumAPIDrawcalls++;
(void)CHECK_GL_ERROR();
}
@ -344,6 +345,7 @@ void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) {
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
_stats._DSNumTriangles += numIndices / 3;
_stats._DSNumDrawcalls++;
_stats._DSNumAPIDrawcalls++;
(void) CHECK_GL_ERROR();
}
@ -358,6 +360,7 @@ void GLBackend::do_drawInstanced(Batch& batch, size_t paramOffset) {
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
_stats._DSNumTriangles += (numInstances * numVertices) / 3;
_stats._DSNumDrawcalls += numInstances;
_stats._DSNumAPIDrawcalls++;
(void) CHECK_GL_ERROR();
}
@ -383,6 +386,7 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) {
#endif
_stats._DSNumTriangles += (numInstances * numIndices) / 3;
_stats._DSNumDrawcalls += numInstances;
_stats._DSNumAPIDrawcalls++;
(void)CHECK_GL_ERROR();
}
@ -395,6 +399,8 @@ void GLBackend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) {
glMultiDrawArraysIndirect(mode, reinterpret_cast<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
_stats._DSNumDrawcalls += commandCount;
_stats._DSNumAPIDrawcalls++;
#else
// FIXME implement the slow path
#endif
@ -410,7 +416,7 @@ void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) {
glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
_stats._DSNumDrawcalls += commandCount;
_stats._DSNumAPIDrawcalls++;
#else
// FIXME implement the slow path
#endif

View file

@ -610,6 +610,8 @@ void GLBackend::do_setStateDepthBias(Vec2 bias) {
glDisable(GL_POLYGON_OFFSET_LINE);
glDisable(GL_POLYGON_OFFSET_POINT);
}
(void) CHECK_GL_ERROR();
_pipeline._stateCache.depthBias = bias.x;
_pipeline._stateCache.depthBiasSlopeScale = bias.y;
}
@ -690,6 +692,7 @@ void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) {
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
(void) CHECK_GL_ERROR();
_pipeline._stateCache.alphaToCoverageEnable = enable;
}
}
@ -703,6 +706,7 @@ void GLBackend::do_setStateSampleMask(uint32 mask) {
glEnable(GL_SAMPLE_MASK);
glSampleMaski(0, mask);
}
(void) CHECK_GL_ERROR();
#endif
_pipeline._stateCache.sampleMask = mask;
}
@ -743,10 +747,10 @@ void GLBackend::do_setStateBlend(State::BlendFunction function) {
glBlendFuncSeparate(BLEND_ARGS[function.getSourceColor()], BLEND_ARGS[function.getDestinationColor()],
BLEND_ARGS[function.getSourceAlpha()], BLEND_ARGS[function.getDestinationAlpha()]);
(void) CHECK_GL_ERROR();
} else {
glDisable(GL_BLEND);
}
(void) CHECK_GL_ERROR();
_pipeline._stateCache.blendFunction = function;
}
@ -758,6 +762,7 @@ void GLBackend::do_setStateColorWriteMask(uint32 mask) {
mask & State::ColorMask::WRITE_GREEN,
mask & State::ColorMask::WRITE_BLUE,
mask & State::ColorMask::WRITE_ALPHA );
(void) CHECK_GL_ERROR();
_pipeline._stateCache.colorWriteMask = mask;
}
@ -765,7 +770,6 @@ void GLBackend::do_setStateColorWriteMask(uint32 mask) {
void GLBackend::do_setStateBlendFactor(Batch& batch, size_t paramOffset) {
Vec4 factor(batch._params[paramOffset + 0]._float,
batch._params[paramOffset + 1]._float,
batch._params[paramOffset + 2]._float,

View file

@ -225,6 +225,12 @@ public:
}
break;
case gpu::R11G11B10:
texel.format = GL_RGB;
// the type should be float
texel.internalFormat = GL_R11F_G11F_B10F;
break;
case gpu::DEPTH:
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
texel.internalFormat = GL_DEPTH_COMPONENT;
@ -302,11 +308,6 @@ public:
case gpu::SRGBA:
texel.internalFormat = GL_SRGB; // standard 2.2 gamma correction color
break;
case gpu::R11G11B10: {
// the type should be float
texel.internalFormat = GL_R11F_G11F_B10F;
break;
}
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
}

View file

@ -285,7 +285,7 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt
}
// Here the Texture has been fully defined from the gpu point of view (size and format)
_defined = true;
_defined = true;
} else {
_stamp++;
}

View file

@ -122,7 +122,7 @@ public:
}
// will query the underlying hmd api to compute the most recent head pose
virtual void updateHeadPose(uint32_t frameIndex) {}
virtual void beginFrameRender(uint32_t frameIndex) {}
// returns a copy of the most recent head pose, computed via updateHeadPose
virtual glm::mat4 getHeadPose() const {
@ -142,6 +142,8 @@ public:
virtual float presentRate() { return -1.0f; }
uint32_t presentCount() const { return _presentedFrameIndex; }
virtual void cycleDebugOutput() {}
static const QString& MENU_PATH();
signals:

View file

@ -435,8 +435,9 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
// TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
// we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
const float OVER_CONSERVATIVE_SCALE = 1.1f;
if ((eyeHalfPlaneDistance > -nearRadius) &&
(glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) {
(glm::distance(eyePoint, glm::vec3(light->getPosition())) < (expandedRadius * OVER_CONSERVATIVE_SCALE) + nearRadius)) {
coneParam.w = 0.0f;
batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
@ -452,6 +453,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo
batch.setProjectionTransform( projMats[side]);
batch.setViewTransform(viewTransforms[side]);
} else {
light->setShowContour(false);
coneParam.w = 1.0f;
batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));

View file

@ -97,7 +97,7 @@ void FramebufferCache::createPrimaryFramebuffer() {
// FIXME: Decide on the proper one, let s stick to R11G11B10 for now
//_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler));
_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler));
_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler));
//_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler));
_lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_lightingFramebuffer->setRenderBuffer(0, _lightingTexture);

View file

@ -131,6 +131,8 @@ void Model::setOffset(const glm::vec3& offset) {
void Model::enqueueLocationChange() {
_needsUpdateClusterMatrices = true;
// queue up this work for later processing, at the end of update and just before rendering.
// the application will ensure only the last lambda is actually invoked.
void* key = (void*)this;
@ -536,7 +538,7 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scen
pendingChanges.resetItem(item, _modelMeshRenderItems[item]);
}
foreach (auto item, _collisionRenderItems.keys()) {
pendingChanges.resetItem(item, _modelMeshRenderItems[item]);
pendingChanges.resetItem(item, _collisionRenderItems[item]);
}
scene->enqueuePendingChanges(pendingChanges);
}

View file

@ -32,9 +32,10 @@ public:
class RenderDeferred {
public:
using JobModel = render::Job::Model<RenderDeferred>;
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Job::Model<RenderDeferred>;
};
class DrawConfig : public render::Job::Config {

View file

@ -25,6 +25,7 @@ in vec4 _texCoord0;
out vec4 _fragColor;
void main(void) {
DeferredTransform deferredTransform = getDeferredTransform();
// Grab the fragment data from the uv

View file

@ -20,17 +20,14 @@ namespace render {
class DrawSceneOctreeConfig : public Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty())
Q_PROPERTY(bool showVisibleCells MEMBER showVisibleCells WRITE setShowVisibleCells)
Q_PROPERTY(bool showEmptyCells MEMBER showEmptyCells WRITE setShowEmptyCells)
Q_PROPERTY(bool showVisibleCells READ getShowVisibleCells WRITE setShowVisibleCells NOTIFY dirty())
Q_PROPERTY(bool showEmptyCells READ getShowEmptyCells WRITE setShowEmptyCells NOTIFY dirty())
Q_PROPERTY(int numAllocatedCells READ getNumAllocatedCells)
Q_PROPERTY(int numFreeCells READ getNumFreeCells)
public:
DrawSceneOctreeConfig() : Job::Config(false) {}
bool showVisibleCells{ true };
bool showEmptyCells{ false };
int numAllocatedCells{ 0 };
int numFreeCells{ 0 };
@ -38,6 +35,12 @@ namespace render {
int getNumAllocatedCells() const { return numAllocatedCells; }
int getNumFreeCells() const { return numFreeCells; }
bool showVisibleCells{ true };
bool showEmptyCells{ false };
bool getShowVisibleCells() { return showVisibleCells; }
bool getShowEmptyCells() { return showEmptyCells; }
public slots:
void setShowVisibleCells(bool show) { showVisibleCells = show; emit dirty(); }
void setShowEmptyCells(bool show) { showEmptyCells = show; emit dirty(); }
@ -79,10 +82,10 @@ namespace render {
class DrawItemSelectionConfig : public Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty())
Q_PROPERTY(bool showInsideItems MEMBER showInsideItems WRITE setShowInsideItems)
Q_PROPERTY(bool showInsideSubcellItems MEMBER showInsideSubcellItems WRITE setShowInsideSubcellItems)
Q_PROPERTY(bool showPartialItems MEMBER showPartialItems WRITE setShowPartialItems)
Q_PROPERTY(bool showPartialSubcellItems MEMBER showPartialSubcellItems WRITE setShowPartialSubcellItems)
Q_PROPERTY(bool showInsideItems READ getShowInsideItems WRITE setShowInsideItems NOTIFY dirty())
Q_PROPERTY(bool showInsideSubcellItems READ getShowInsideSubcellItems WRITE setShowInsideSubcellItems NOTIFY dirty())
Q_PROPERTY(bool showPartialItems READ getShowPartialItems WRITE setShowPartialItems NOTIFY dirty())
Q_PROPERTY(bool showPartialSubcellItems READ getShowPartialSubcellItems WRITE setShowPartialSubcellItems NOTIFY dirty())
public:
DrawItemSelectionConfig() : Job::Config(false) {}
@ -92,7 +95,12 @@ namespace render {
bool showPartialItems{ true };
bool showPartialSubcellItems{ true };
public slots:
bool getShowInsideItems() const { return showInsideItems; };
bool getShowInsideSubcellItems() const { return showInsideSubcellItems; };
bool getShowPartialItems() const { return showPartialItems; };
bool getShowPartialSubcellItems() const { return showPartialSubcellItems; };
public slots:
void setShowInsideItems(bool show) { showInsideItems = show; emit dirty(); }
void setShowInsideSubcellItems(bool show) { showInsideSubcellItems = show; emit dirty(); }
void setShowPartialItems(bool show) { showPartialItems = show; emit dirty(); }

View file

@ -20,12 +20,16 @@
using namespace render;
void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems) {
void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems) {
auto& scene = sceneContext->_scene;
RenderArgs* args = renderContext->args;
for (const auto& itemDetails : inItems) {
auto& item = scene->getItem(itemDetails.id);
int numItemsToDraw = (int)inItems.size();
if (maxDrawnItems != -1) {
numItemsToDraw = glm::min(numItemsToDraw, maxDrawnItems);
}
for (auto i = 0; i < numItemsToDraw; ++i) {
auto& item = scene->getItem(inItems[i].id);
item.render(args);
}
}
@ -69,7 +73,10 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext
// render lights
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
renderItems(sceneContext, renderContext, inLights);
renderItems(sceneContext, renderContext, inLights, _maxDrawn);
args->_batch = nullptr;
});
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
config->setNumDrawn((int)inLights.size());
}

View file

@ -16,15 +16,37 @@
namespace render {
void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems);
void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems = -1);
void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1);
class DrawLightConfig : public Job::Config {
Q_OBJECT
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
public:
int getNumDrawn() { return numDrawn; }
void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); }
int maxDrawn{ -1 };
signals:
void numDrawnChanged();
void dirty();
protected:
int numDrawn{ 0 };
};
class DrawLight {
public:
using JobModel = Job::ModelI<DrawLight, ItemBounds>;
using Config = DrawLightConfig;
using JobModel = Job::ModelI<DrawLight, ItemBounds, Config>;
void configure(const Config& config) { _maxDrawn = config.maxDrawn; }
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inLights);
protected:
int _maxDrawn; // initialized by Config
};
}

View file

@ -36,6 +36,7 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte
gpu::ContextStats gpuStats(_gpuStats);
renderContext->args->_context->getStats(_gpuStats);
config->frameAPIDrawcallCount = _gpuStats._DSNumAPIDrawcalls - gpuStats._DSNumAPIDrawcalls;
config->frameDrawcallCount = _gpuStats._DSNumDrawcalls - gpuStats._DSNumDrawcalls;
config->frameDrawcallRate = config->frameDrawcallCount * frequency;

View file

@ -34,6 +34,7 @@ namespace render {
Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty)
Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage NOTIFY dirty)
Q_PROPERTY(quint32 frameAPIDrawcallCount MEMBER frameAPIDrawcallCount NOTIFY dirty)
Q_PROPERTY(quint32 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty)
Q_PROPERTY(quint32 frameDrawcallRate MEMBER frameDrawcallRate NOTIFY dirty)
@ -57,6 +58,7 @@ namespace render {
qint64 textureCPUMemoryUsage{ 0 };
qint64 textureGPUMemoryUsage{ 0 };
quint32 frameAPIDrawcallCount{ 0 };
quint32 frameDrawcallCount{ 0 };
quint32 frameDrawcallRate{ 0 };

View file

@ -16,8 +16,13 @@
using namespace render;
void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) {
_resetItems.push_back(id);
_resetPayloads.push_back(payload);
if (payload) {
_resetItems.push_back(id);
_resetPayloads.push_back(payload);
} else {
qDebug() << "WARNING: PendingChanges::resetItem with a null payload!";
removeItem(id);
}
}
void PendingChanges::removeItem(ItemID id) {

View file

@ -234,7 +234,7 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scriptContents) {
_scriptContents = scriptContents;
if (_wantSignals) {
emit scriptLoaded(_fileNameString);
emit scriptLoaded(url.toString());
}
}

View file

@ -13,13 +13,14 @@
#include <SettingHandle.h>
#include <UserActivityLogger.h>
#include <PathUtils.h>
#include "ScriptEngine.h"
#include "ScriptEngineLogging.h"
#define __STR2__(x) #x
#define __STR1__(x) __STR2__(x)
#define __LOC__ __FILE__ "("__STR1__(__LINE__)") : Warning Msg: "
#define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : Warning Msg: "
#ifndef __APPLE__
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
@ -41,25 +42,53 @@ ScriptEngines::ScriptEngines()
_scriptsModelFilter.setDynamicSortFilter(true);
}
QString normalizeScriptUrl(const QString& rawScriptUrl) {
if (!rawScriptUrl.startsWith("http:") && !rawScriptUrl.startsWith("https:") && !rawScriptUrl.startsWith("atp:")) {
#ifdef Q_OS_LINUX
if (rawScriptUrl.startsWith("file:")) {
return rawScriptUrl;
}
return QUrl::fromLocalFile(rawScriptUrl).toString();
#else
if (rawScriptUrl.startsWith("file:")) {
return rawScriptUrl.toLower();
}
// Force lowercase on file scripts because of drive letter weirdness.
return QUrl::fromLocalFile(rawScriptUrl).toString().toLower();
#endif
QUrl normalizeScriptURL(const QUrl& rawScriptURL) {
if (rawScriptURL.scheme() == "file") {
QUrl fullNormal = rawScriptURL;
QUrl defaultScriptLoc = defaultScriptsLocation();
#ifdef Q_OS_LINUX
#else
// Force lowercase on file scripts because of drive letter weirdness.
if (rawScriptURL.isLocalFile()) {
fullNormal.setPath(fullNormal.path().toLower());
}
#endif
// if this url is something "beneath" the default script url, replace the local path with ~
if (fullNormal.scheme() == defaultScriptLoc.scheme() &&
fullNormal.host() == defaultScriptLoc.host() &&
fullNormal.path().startsWith(defaultScriptLoc.path())) {
fullNormal.setPath("/~/" + fullNormal.path().mid(defaultScriptLoc.path().size()));
}
return fullNormal;
} else if (rawScriptURL.scheme() == "http" || rawScriptURL.scheme() == "https" || rawScriptURL.scheme() == "atp") {
return rawScriptURL;
} else {
// don't accidently support gopher
return QUrl("");
}
return QUrl(rawScriptUrl).toString();
}
QUrl expandScriptUrl(const QUrl& normalizedScriptURL) {
if (normalizedScriptURL.scheme() == "http" ||
normalizedScriptURL.scheme() == "https" ||
normalizedScriptURL.scheme() == "atp") {
return normalizedScriptURL;
} else if (normalizedScriptURL.scheme() == "file") {
if (normalizedScriptURL.path().startsWith("/~/")) {
QUrl url = normalizedScriptURL;
QStringList splitPath = url.path().split("/");
QUrl defaultScriptsLoc = defaultScriptsLocation();
url.setPath(defaultScriptsLoc.path() + "/" + splitPath.mid(2).join("/")); // 2 to skip the slashes in /~/
return url;
}
return normalizedScriptURL;
} else {
return QUrl("");
}
}
QObject* scriptsModel();
void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) {
@ -192,19 +221,25 @@ QVariantList ScriptEngines::getLocal() {
}
QVariantList ScriptEngines::getRunning() {
const int WINDOWS_DRIVE_LETTER_SIZE = 1;
QVariantList result;
auto runningScripts = getRunningScripts();
foreach(const QString& runningScript, runningScripts) {
QUrl runningScriptURL = QUrl(runningScript);
if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
if (!runningScriptURL.isValid()) {
runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)));
}
QVariantMap resultNode;
resultNode.insert("name", runningScriptURL.fileName());
resultNode.insert("url", runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)));
QUrl displayURL = expandScriptUrl(QUrl(runningScriptURL));
QString displayURLString;
if (displayURL.isLocalFile()) {
displayURLString = displayURL.toLocalFile();
} else {
displayURLString = displayURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded));
}
resultNode.insert("url", displayURLString);
// The path contains the exact path/URL of the script, which also is used in the stopScript function.
resultNode.insert("path", runningScript);
resultNode.insert("path", normalizeScriptURL(runningScript).toString());
resultNode.insert("local", runningScriptURL.isLocalFile());
result.append(resultNode);
}
@ -213,10 +248,11 @@ QVariantList ScriptEngines::getRunning() {
static const QString SETTINGS_KEY = "Settings";
static const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js";
void ScriptEngines::loadDefaultScripts() {
loadScript(DEFAULT_SCRIPTS_JS_URL);
QUrl defaultScriptsLoc = defaultScriptsLocation();
defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "/scripts/defaultScripts.js");
loadScript(defaultScriptsLoc.toString());
}
void ScriptEngines::loadOneScript(const QString& scriptFilename) {
@ -265,7 +301,7 @@ void ScriptEngines::saveScripts() {
for (auto it = runningScripts.begin(); it != runningScripts.end(); ++it) {
if (getScriptEngine(*it)->isUserLoaded()) {
settings.setArrayIndex(i);
settings.setValue("script", *it);
settings.setValue("script", normalizeScriptURL(*it).toString());
++i;
}
}
@ -307,11 +343,16 @@ void ScriptEngines::stopAllScripts(bool restart) {
}
}
bool ScriptEngines::stopScript(const QString& rawScriptUrl, bool restart) {
bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) {
bool stoppedScript = false;
{
QUrl scriptURL = normalizeScriptURL(QUrl(rawScriptURL));
if (!scriptURL.isValid()) {
scriptURL = normalizeScriptURL(QUrl::fromLocalFile(rawScriptURL));
}
const QString scriptURLString = scriptURL.toString();
QReadLocker lock(&_scriptEnginesHashLock);
const QString scriptURLString = normalizeScriptUrl(rawScriptUrl);
if (_scriptEnginesHash.contains(scriptURLString)) {
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURLString];
if (restart) {
@ -344,18 +385,30 @@ void ScriptEngines::reloadAllScripts() {
stopAllScripts(true);
}
ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, bool activateMainWindow, bool reload) {
ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor,
bool activateMainWindow, bool reload) {
if (thread() != QThread::currentThread()) {
ScriptEngine* result { nullptr };
QMetaObject::invokeMethod(this, "loadScript", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ScriptEngine*, result),
Q_ARG(QString, scriptFilename),
Q_ARG(QUrl, scriptFilename),
Q_ARG(bool, isUserLoaded),
Q_ARG(bool, loadScriptFromEditor),
Q_ARG(bool, activateMainWindow),
Q_ARG(bool, reload));
return result;
}
QUrl scriptUrl(scriptFilename);
QUrl scriptUrl;
if (!scriptFilename.isValid() ||
(scriptFilename.scheme() != "http" &&
scriptFilename.scheme() != "https" &&
scriptFilename.scheme() != "atp" &&
scriptFilename.scheme() != "file")) {
// deal with a "url" like c:/something
scriptUrl = normalizeScriptURL(QUrl::fromLocalFile(scriptFilename.toString()));
} else {
scriptUrl = normalizeScriptURL(scriptFilename);
}
auto scriptEngine = getScriptEngine(scriptUrl.toString());
if (scriptEngine) {
return scriptEngine;
@ -368,7 +421,7 @@ ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUs
}, Qt::QueuedConnection);
if (scriptFilename.isNull()) {
if (scriptFilename.isEmpty()) {
launchScriptEngine(scriptEngine);
} else {
// connect to the appropriate signals of this script engine
@ -376,17 +429,17 @@ ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUs
connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError);
// get the script engine object to load the script at the designated script URL
scriptEngine->loadURL(scriptUrl, reload);
scriptEngine->loadURL(QUrl(expandScriptUrl(scriptUrl.toString())), reload);
}
return scriptEngine;
}
ScriptEngine* ScriptEngines::getScriptEngine(const QString& rawScriptUrl) {
ScriptEngine* ScriptEngines::getScriptEngine(const QString& rawScriptURL) {
ScriptEngine* result = nullptr;
{
QReadLocker lock(&_scriptEnginesHashLock);
const QString scriptURLString = normalizeScriptUrl(rawScriptUrl);
const QString scriptURLString = normalizeScriptURL(QUrl(rawScriptURL)).toString();
auto it = _scriptEnginesHash.find(scriptURLString);
if (it != _scriptEnginesHash.end()) {
result = it.value();
@ -396,15 +449,17 @@ ScriptEngine* ScriptEngines::getScriptEngine(const QString& rawScriptUrl) {
}
// FIXME - change to new version of ScriptCache loading notification
void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptUrl) {
UserActivityLogger::getInstance().loadedScript(rawScriptUrl);
void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
UserActivityLogger::getInstance().loadedScript(rawScriptURL);
ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender());
launchScriptEngine(scriptEngine);
{
QWriteLocker lock(&_scriptEnginesHashLock);
const QString scriptURLString = normalizeScriptUrl(rawScriptUrl);
QUrl url = QUrl(rawScriptURL);
QUrl normalized = normalizeScriptURL(url);
const QString scriptURLString = normalized.toString();
_scriptEnginesHash.insertMulti(scriptURLString, scriptEngine);
}
emit scriptCountChanged();
@ -427,11 +482,11 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) {
}
void ScriptEngines::onScriptFinished(const QString& rawScriptUrl, ScriptEngine* engine) {
void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) {
bool removed = false;
{
QWriteLocker lock(&_scriptEnginesHashLock);
const QString scriptURLString = normalizeScriptUrl(rawScriptUrl);
const QString scriptURLString = normalizeScriptURL(QUrl(rawScriptURL)).toString();
for (auto it = _scriptEnginesHash.find(scriptURLString); it != _scriptEnginesHash.end(); ++it) {
if (it.value() == engine) {
_scriptEnginesHash.erase(it);

View file

@ -51,7 +51,7 @@ public:
ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; };
Q_INVOKABLE void loadOneScript(const QString& scriptFilename);
Q_INVOKABLE ScriptEngine* loadScript(const QString& scriptFilename = QString(),
Q_INVOKABLE ScriptEngine* loadScript(const QUrl& scriptFilename = QString(),
bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false);
Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false);
@ -96,4 +96,7 @@ protected:
ScriptsModelFilter _scriptsModelFilter;
};
QUrl normalizeScriptURL(const QUrl& rawScriptURL);
QUrl expandScriptUrl(const QUrl& normalizedScriptURL);
#endif // hifi_ScriptEngine_h

View file

@ -13,21 +13,19 @@
#include <QUrl>
#include <QUrlQuery>
#include <QXmlStreamReader>
#include <QDirIterator>
#include <NetworkAccessManager.h>
#include <PathUtils.h>
#include "ScriptEngine.h"
#include "ScriptEngines.h"
#include "ScriptEngineLogging.h"
#define __STR2__(x) #x
#define __STR1__(x) __STR2__(x)
#define __LOC__ __FILE__ "("__STR1__(__LINE__)") : Warning Msg: "
#define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : Warning Msg: "
static const QString S3_URL = "http://s3.amazonaws.com/hifi-public";
static const QString PUBLIC_URL = "http://public.highfidelity.io";
static const QString MODELS_LOCATION = "scripts/";
static const QString PREFIX_PARAMETER_NAME = "prefix";
static const QString MARKER_PARAMETER_NAME = "marker";
static const QString IS_TRUNCATED_NAME = "IsTruncated";
@ -63,7 +61,7 @@ ScriptsModel::ScriptsModel(QObject* parent) :
connect(&_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &ScriptsModel::reloadLocalFiles);
reloadLocalFiles();
reloadRemoteFiles();
reloadDefaultFiles();
}
ScriptsModel::~ScriptsModel() {
@ -140,36 +138,56 @@ void ScriptsModel::updateScriptsLocation(const QString& newPath) {
reloadLocalFiles();
}
void ScriptsModel::reloadRemoteFiles() {
void ScriptsModel::reloadDefaultFiles() {
if (!_loadingScripts) {
_loadingScripts = true;
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
TreeNodeBase* node = _treeNodes.at(i);
if (node->getType() == TREE_NODE_TYPE_SCRIPT &&
static_cast<TreeNodeScript*>(node)->getOrigin() == SCRIPT_ORIGIN_REMOTE)
static_cast<TreeNodeScript*>(node)->getOrigin() == SCRIPT_ORIGIN_DEFAULT)
{
delete node;
_treeNodes.removeAt(i);
}
}
requestRemoteFiles();
requestDefaultFiles();
}
}
void ScriptsModel::requestRemoteFiles(QString marker) {
QUrl url(S3_URL);
QUrlQuery query;
query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION);
if (!marker.isEmpty()) {
query.addQueryItem(MARKER_PARAMETER_NAME, marker);
}
url.setQuery(query);
void ScriptsModel::requestDefaultFiles(QString marker) {
QUrl url(defaultScriptsLocation());
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
if (url.isLocalFile()) {
// if the url indicates a local directory, use QDirIterator
// QString localDir = url.toLocalFile() + "/scripts";
QString localDir = expandScriptUrl(url).toLocalFile() + "/scripts";
int localDirPartCount = localDir.split("/").size();
#ifdef Q_OS_WIN
localDirPartCount++; // one for the drive letter
#endif
QDirIterator it(localDir, QStringList() << "*.js", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
QUrl jsFullPath = QUrl::fromLocalFile(it.next());
QString jsPartialPath = jsFullPath.path().split("/").mid(localDirPartCount).join("/");
jsFullPath = normalizeScriptURL(jsFullPath);
_treeNodes.append(new TreeNodeScript(jsPartialPath, jsFullPath.toString(), SCRIPT_ORIGIN_DEFAULT));
}
_loadingScripts = false;
} else {
// the url indicates http(s), use QNetworkRequest
QUrlQuery query;
query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION);
if (!marker.isEmpty()) {
query.addQueryItem(MARKER_PARAMETER_NAME, marker);
}
url.setQuery(query);
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
}
}
void ScriptsModel::downloadFinished() {
@ -182,8 +200,10 @@ void ScriptsModel::downloadFinished() {
if (!data.isEmpty()) {
finished = parseXML(data);
} else {
qCDebug(scriptengine) << "Error: Received no data when loading remote scripts";
qCDebug(scriptengine) << "Error: Received no data when loading default scripts";
}
} else {
qDebug() << "Error: when loading default scripts --" << reply->error();
}
reply->deleteLater();
@ -218,7 +238,11 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
xml.readNext();
lastKey = xml.text().toString();
if (jsRegex.exactMatch(xml.text().toString())) {
_treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), S3_URL + "/" + lastKey, SCRIPT_ORIGIN_REMOTE));
QString localPath = lastKey.split("/").mid(1).join("/");
QUrl fullPath = defaultScriptsLocation();
fullPath.setPath(fullPath.path() + "/" + lastKey);
const QString fullPathStr = normalizeScriptURL(fullPath).toString();
_treeNodes.append(new TreeNodeScript(localPath, fullPathStr, SCRIPT_ORIGIN_DEFAULT));
}
}
xml.readNext();
@ -231,12 +255,12 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
// Error handling
if (xml.hasError()) {
qCDebug(scriptengine) << "Error loading remote scripts: " << xml.errorString();
qCDebug(scriptengine) << "Error loading default scripts: " << xml.errorString();
return true;
}
if (truncated) {
requestRemoteFiles(lastKey);
requestDefaultFiles(lastKey);
}
// If this request was not truncated, we are done.
@ -261,7 +285,9 @@ void ScriptsModel::reloadLocalFiles() {
const QFileInfoList localFiles = _localDirectory.entryInfoList();
for (int i = 0; i < localFiles.size(); i++) {
QFileInfo file = localFiles[i];
_treeNodes.append(new TreeNodeScript(file.fileName(), file.absoluteFilePath(), SCRIPT_ORIGIN_LOCAL));
QString fileName = file.fileName();
QUrl absPath = normalizeScriptURL(QUrl::fromLocalFile(file.absoluteFilePath()));
_treeNodes.append(new TreeNodeScript(fileName, absPath.toString(), SCRIPT_ORIGIN_LOCAL));
}
rebuildTree();
endResetModel();

View file

@ -21,7 +21,7 @@ class TreeNodeFolder;
enum ScriptOrigin {
SCRIPT_ORIGIN_LOCAL,
SCRIPT_ORIGIN_REMOTE
SCRIPT_ORIGIN_DEFAULT
};
enum TreeNodeType {
@ -84,10 +84,10 @@ protected slots:
void updateScriptsLocation(const QString& newPath);
void downloadFinished();
void reloadLocalFiles();
void reloadRemoteFiles();
void reloadDefaultFiles();
protected:
void requestRemoteFiles(QString marker = QString());
void requestDefaultFiles(QString marker = QString());
bool parseXML(QByteArray xmlFile);
void rebuildTree();

View file

@ -15,6 +15,7 @@
#include <QDateTime>
#include <QFileInfo>
#include <QDir>
#include <QUrl>
#include "PathUtils.h"
@ -53,3 +54,14 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector<QSt
}
return newestFileName;
}
QUrl defaultScriptsLocation() {
#ifdef Q_OS_WIN
return QUrl(("file:///" + QCoreApplication::applicationDirPath()).toLower());
#elif defined(Q_OS_OSX)
return QUrl(("file://" + QCoreApplication::applicationDirPath() + "/../Resources").toLower());
#else
// return "http://s3.amazonaws.com/hifi-public";
return QUrl("file://" + QCoreApplication::applicationDirPath());
#endif
}

View file

@ -27,4 +27,6 @@ public:
QString fileNameWithoutExtension(const QString& fileName, const QVector<QString> possibleExtensions);
QString findMostRecentFileExtension(const QString& originalFileName, QVector<QString> possibleExtensions);
QUrl defaultScriptsLocation();
#endif // hifi_PathUtils_h

View file

@ -23,6 +23,7 @@
template <typename T>
class ThreadSafeValueCache {
public:
ThreadSafeValueCache() {}
ThreadSafeValueCache(const T& v) : _value { v } {}
// returns atomic copy of the cached value.

View file

@ -12,14 +12,19 @@
#include "OculusHelpers.h"
void OculusBaseDisplayPlugin::resetSensors() {
ovr_RecenterPose(_session);
ovr_RecenterTrackingOrigin(_session);
}
void OculusBaseDisplayPlugin::updateHeadPose(uint32_t frameIndex) {
auto displayTime = ovr_GetPredictedDisplayTime(_session, frameIndex);
auto trackingState = ovr_GetTrackingState(_session, displayTime, true);
mat4 headPose = toGlm(trackingState.HeadPose.ThePose);
_headPoseCache.set(headPose);
void OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
FrameInfo frame;
frame.sensorSampleTime = ovr_GetTimeInSeconds();;
frame.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex);
auto trackingState = ovr_GetTrackingState(_session, frame.predictedDisplayTime, ovrTrue);
frame.headPose = toGlm(trackingState.HeadPose.ThePose);
_currentRenderFrameInfo.set(frame);
Lock lock(_mutex);
_frameInfos[frameIndex] = frame;
}
bool OculusBaseDisplayPlugin::isSupported() const {
@ -42,36 +47,30 @@ bool OculusBaseDisplayPlugin::internalActivate() {
_hmdDesc = ovr_GetHmdDesc(_session);
_ipd = ovr_GetFloat(_session, OVR_KEY_IPD, _ipd);
glm::uvec2 eyeSizes[2];
_viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
_ipd = 0;
ovr_for_each_eye([&](ovrEyeType eye) {
_eyeFovs[eye] = _hmdDesc.DefaultEyeFov[eye];
ovrEyeRenderDesc& erd = _eyeRenderDescs[eye] = ovr_GetRenderDesc(_session, eye, _eyeFovs[eye]);
ovrMatrix4f ovrPerspectiveProjection =
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL);
_eyeProjections[eye] = toGlm(ovrPerspectiveProjection);
_eyeOffsets[eye] = glm::translate(mat4(), toGlm(erd.HmdToEyeViewOffset));
_eyeOffsets[eye] = glm::translate(mat4(), toGlm(erd.HmdToEyeOffset));
eyeSizes[eye] = toGlm(ovr_GetFovTextureSize(_session, eye, erd.Fov, 1.0f));
_viewScaleDesc.HmdToEyeViewOffset[eye] = erd.HmdToEyeViewOffset;
_viewScaleDesc.HmdToEyeOffset[eye] = erd.HmdToEyeOffset;
_ipd += glm::abs(glm::length(toGlm(erd.HmdToEyeOffset)));
});
auto combinedFov = _eyeFovs[0];
combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan);
_cullingProjection = toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
_cullingProjection = toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL));
_renderTargetSize = uvec2(
eyeSizes[0].x + eyeSizes[1].x,
std::max(eyeSizes[0].y, eyeSizes[1].y));
if (!OVR_SUCCESS(ovr_ConfigureTracking(_session,
ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) {
logWarning("Failed to attach to sensor device");
}
// Parent class relies on our _session intialization, so it must come after that.
memset(&_sceneLayer, 0, sizeof(ovrLayerEyeFov));
_sceneLayer.Header.Type = ovrLayerType_EyeFov;
_sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;

View file

@ -20,7 +20,8 @@ public:
// Stereo specific methods
virtual void resetSensors() override final;
virtual void updateHeadPose(uint32_t frameIndex) override;
virtual void beginFrameRender(uint32_t frameIndex) override;
protected:
void customizeContext() override;
@ -28,9 +29,8 @@ protected:
void internalDeactivate() override;
protected:
ovrSession _session;
ovrSession _session { nullptr };
ovrGraphicsLuid _luid;
float _ipd{ OVR_DEFAULT_IPD };
ovrEyeRenderDesc _eyeRenderDescs[2];
ovrFovPort _eyeFovs[2];
ovrHmdDesc _hmdDesc;

View file

@ -0,0 +1,219 @@
//
// OculusControllerManager.cpp
// input-plugins/src/input-plugins
//
// Created by Bradley Austin Davis 2016/03/04.
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OculusControllerManager.h"
#include <QtCore/QLoggingCategory>
#include <plugins/PluginContainer.h>
#include <controllers/UserInputMapper.h>
#include <controllers/StandardControls.h>
#include <PerfStat.h>
#include <PathUtils.h>
#include "OculusHelpers.h"
Q_DECLARE_LOGGING_CATEGORY(oculus)
static const QString MENU_PARENT = "Avatar";
static const QString MENU_NAME = "Oculus Touch Controllers";
static const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
const QString OculusControllerManager::NAME = "Oculus";
bool OculusControllerManager::isSupported() const {
return oculusAvailable();
}
bool OculusControllerManager::activate() {
InputPlugin::activate();
if (!_session) {
_session = acquireOculusSession();
}
Q_ASSERT(_session);
// register with UserInputMapper
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
if (_remote) {
userInputMapper->registerDevice(_remote);
}
if (_touch) {
userInputMapper->registerDevice(_touch);
}
return true;
}
void OculusControllerManager::deactivate() {
InputPlugin::deactivate();
if (_session) {
releaseOculusSession();
_session = nullptr;
}
// unregister with UserInputMapper
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
if (_touch) {
userInputMapper->removeDevice(_touch->getDeviceID());
}
if (_remote) {
userInputMapper->removeDevice(_remote->getDeviceID());
}
}
void OculusControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
PerformanceTimer perfTimer("OculusControllerManager::TouchDevice::update");
if (!OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) {
qCWarning(oculus) << "Unable to read oculus input state";
return;
}
if (_touch) {
_touch->update(deltaTime, inputCalibrationData, jointsCaptured);
}
if (_remote) {
_remote->update(deltaTime, inputCalibrationData, jointsCaptured);
}
}
void OculusControllerManager::pluginFocusOutEvent() {
if (_touch) {
_touch->focusOutEvent();
}
if (_remote) {
_remote->focusOutEvent();
}
}
using namespace controller;
static const std::vector<std::pair<ovrButton, StandardButtonChannel>> BUTTON_MAP { {
{ ovrButton_X, X },
{ ovrButton_Y, Y },
{ ovrButton_A, A },
{ ovrButton_B, B },
{ ovrButton_LThumb, LS },
{ ovrButton_RThumb, RS },
{ ovrButton_LShoulder, LB },
{ ovrButton_RShoulder, RB },
} };
static const std::vector<std::pair<ovrTouch, StandardButtonChannel>> TOUCH_MAP { {
{ ovrTouch_X, LEFT_SECONDARY_THUMB_TOUCH },
{ ovrTouch_Y, LEFT_SECONDARY_THUMB_TOUCH },
{ ovrTouch_A, RIGHT_SECONDARY_THUMB_TOUCH },
{ ovrTouch_B, RIGHT_SECONDARY_THUMB_TOUCH },
{ ovrTouch_LIndexTrigger, LEFT_PRIMARY_INDEX_TOUCH },
{ ovrTouch_RIndexTrigger, RIGHT_PRIMARY_INDEX_TOUCH },
{ ovrTouch_LThumb, LS_TOUCH },
{ ovrTouch_RThumb, RS_TOUCH },
{ ovrTouch_LThumbUp, LEFT_THUMB_UP },
{ ovrTouch_RThumbUp, RIGHT_THUMB_UP },
{ ovrTouch_LIndexPointing, LEFT_INDEX_POINT },
{ ovrTouch_RIndexPointing, RIGHT_INDEX_POINT },
} };
void OculusControllerManager::TouchDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
_poseStateMap.clear();
_buttonPressedMap.clear();
if (!jointsCaptured) {
int numTrackedControllers = 0;
static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked & ovrStatus_PositionTracked;
auto tracking = ovr_GetTrackingState(_parent._session, 0, false);
ovr_for_each_hand([&](ovrHandType hand) {
++numTrackedControllers;
if (REQUIRED_HAND_STATUS == (tracking.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) {
handlePose(deltaTime, inputCalibrationData, hand, tracking.HandPoses[hand]);
}
});
}
using namespace controller;
// Axes
const auto& inputState = _parent._inputState;
_axisStateMap[LX] = inputState.Thumbstick[ovrHand_Left].x;
_axisStateMap[LY] = inputState.Thumbstick[ovrHand_Left].y;
_axisStateMap[LT] = inputState.IndexTrigger[ovrHand_Left];
_axisStateMap[LG] = inputState.HandTrigger[ovrHand_Left];
_axisStateMap[RX] = inputState.Thumbstick[ovrHand_Right].x;
_axisStateMap[RY] = inputState.Thumbstick[ovrHand_Right].y;
_axisStateMap[RT] = inputState.IndexTrigger[ovrHand_Right];
_axisStateMap[RG] = inputState.HandTrigger[ovrHand_Right];
// Buttons
for (const auto& pair : BUTTON_MAP) {
if (inputState.Buttons & pair.first) {
_buttonPressedMap.insert(pair.second);
}
}
// Touches
for (const auto& pair : TOUCH_MAP) {
if (inputState.Touches & pair.first) {
_buttonPressedMap.insert(pair.second);
}
}
}
void OculusControllerManager::TouchDevice::focusOutEvent() {
_axisStateMap.clear();
_buttonPressedMap.clear();
};
void OculusControllerManager::TouchDevice::handlePose(float deltaTime,
const controller::InputCalibrationData& inputCalibrationData, ovrHandType hand,
const ovrPoseStatef& handPose) {
auto poseId = hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND;
auto& pose = _poseStateMap[poseId];
pose.translation = toGlm(handPose.ThePose.Position);
pose.rotation = toGlm(handPose.ThePose.Orientation);
pose.angularVelocity = toGlm(handPose.AngularVelocity);
pose.velocity = toGlm(handPose.LinearVelocity);
}
controller::Input::NamedVector OculusControllerManager::TouchDevice::getAvailableInputs() const {
using namespace controller;
QVector<Input::NamedPair> availableInputs{
// Trackpad analogs
makePair(LX, "LX"),
makePair(LY, "LY"),
makePair(RX, "RX"),
makePair(RY, "RY"),
// trigger analogs
makePair(LT, "LT"),
makePair(RT, "RT"),
makePair(LB, "LB"),
makePair(RB, "RB"),
makePair(LS, "LS"),
makePair(RS, "RS"),
makePair(LEFT_HAND, "LeftHand"),
makePair(RIGHT_HAND, "RightHand"),
makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"),
makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"),
makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"),
makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"),
};
return availableInputs;
}
QString OculusControllerManager::TouchDevice::getDefaultMappingConfig() const {
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/touch.json";
return MAPPING_JSON;
}

View file

@ -0,0 +1,81 @@
//
// Created by Bradley Austin Davis on 2016/03/04
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi__OculusControllerManager
#define hifi__OculusControllerManager
#include <QObject>
#include <unordered_set>
#include <GLMHelpers.h>
#include <controllers/InputDevice.h>
#include <plugins/InputPlugin.h>
#include <OVR_CAPI.h>
class OculusControllerManager : public InputPlugin {
Q_OBJECT
public:
// Plugin functions
bool isSupported() const override;
bool isJointController() const override { return true; }
const QString& getName() const override { return NAME; }
bool activate() override;
void deactivate() override;
void pluginFocusOutEvent() override;
void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
private:
class OculusInputDevice : public controller::InputDevice {
public:
OculusInputDevice(OculusControllerManager& parent, const QString& name) : controller::InputDevice(name), _parent(parent) {}
OculusControllerManager& _parent;
friend class OculusControllerManager;
};
class RemoteDevice : public OculusInputDevice {
public:
using Pointer = std::shared_ptr<RemoteDevice>;
RemoteDevice(OculusControllerManager& parent) : OculusInputDevice(parent, "Oculus Remote") {}
controller::Input::NamedVector getAvailableInputs() const override;
QString getDefaultMappingConfig() const override;
void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
void focusOutEvent() override;
friend class OculusControllerManager;
};
class TouchDevice : public OculusInputDevice {
public:
using Pointer = std::shared_ptr<TouchDevice>;
TouchDevice(OculusControllerManager& parent) : OculusInputDevice(parent, "Oculus Touch") {}
controller::Input::NamedVector getAvailableInputs() const override;
QString getDefaultMappingConfig() const override;
void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
void focusOutEvent() override;
private:
void handlePose(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, ovrHandType hand, const ovrPoseStatef& handPose);
int _trackedControllers { 0 };
friend class OculusControllerManager;
};
ovrSession _session { nullptr };
ovrInputState _inputState {};
RemoteDevice::Pointer _remote;
TouchDevice::Pointer _touch;
static const QString NAME;
};
#endif // hifi__OculusControllerManager

View file

@ -10,6 +10,23 @@
#include "OculusHelpers.h"
const QString OculusDisplayPlugin::NAME("Oculus Rift");
static ovrPerfHudMode currentDebugMode = ovrPerfHud_Off;
bool OculusDisplayPlugin::internalActivate() {
bool result = Parent::internalActivate();
currentDebugMode = ovrPerfHud_Off;
if (result && _session) {
ovr_SetInt(_session, OVR_PERF_HUD_MODE, currentDebugMode);
}
return result;
}
void OculusDisplayPlugin::cycleDebugOutput() {
if (_session) {
currentDebugMode = static_cast<ovrPerfHudMode>((currentDebugMode + 1) % ovrPerfHud_Count);
ovr_SetInt(_session, OVR_PERF_HUD_MODE, currentDebugMode);
}
}
void OculusDisplayPlugin::customizeContext() {
Parent::customizeContext();
@ -48,12 +65,6 @@ void blit(const SrcFbo& srcFbo, const DstFbo& dstFbo) {
});
}
void OculusDisplayPlugin::updateFrameData() {
Parent::updateFrameData();
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentRenderEyePoses[Left]);
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentRenderEyePoses[Right]);
}
void OculusDisplayPlugin::hmdPresent() {
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentRenderFrameIndex)
@ -63,12 +74,15 @@ void OculusDisplayPlugin::hmdPresent() {
}
blit(_compositeFramebuffer, _sceneFbo);
_sceneFbo->Commit();
{
_sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime;
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.headPose);
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.headPose);
ovrLayerHeader* layers = &_sceneLayer.Header;
ovrResult result = ovr_SubmitFrame(_session, _currentRenderFrameIndex, &_viewScaleDesc, &layers, 1);
if (!OVR_SUCCESS(result)) {
logWarning("Failed to present");
}
}
_sceneFbo->Increment();
}

View file

@ -22,12 +22,13 @@ public:
float getTargetFrameRate() override { return TARGET_RATE_Oculus; }
protected:
bool internalActivate() override;
void hmdPresent() override;
// FIXME update with Oculus API call once it's available in the SDK
bool isHmdMounted() const override { return true; }
void customizeContext() override;
void uncustomizeContext() override;
void updateFrameData() override;
void cycleDebugOutput() override;
private:
static const QString NAME;

View file

@ -9,7 +9,10 @@
#include "OculusHelpers.h"
#include <atomic>
#include <QtCore/QLoggingCategory>
#include <QtCore/QFile>
#include <QtCore/QDir>
using Mutex = std::mutex;
using Lock = std::unique_lock<Mutex>;
@ -38,9 +41,23 @@ void logFatal(const char* what) {
qFatal(error.c_str());
}
static const QString OCULUS_RUNTIME_PATH { "C:\\Program Files (x86)\\Oculus\\Support\\oculus-runtime" };
static const QString GOOD_OCULUS_RUNTIME_FILE { OCULUS_RUNTIME_PATH + "\\LibOVRRT64_1.dll" };
bool oculusAvailable() {
ovrDetectResult detect = ovr_Detect(0);
return (detect.IsOculusServiceRunning && detect.IsOculusHMDConnected);
if (!detect.IsOculusServiceRunning || !detect.IsOculusHMDConnected) {
return false;
}
// HACK Explicitly check for the presence of the 1.0 runtime DLL, and fail if it
// doesn't exist
if (!QFile(GOOD_OCULUS_RUNTIME_FILE).exists()) {
qCWarning(oculus) << "Oculus Runtime detected, but no 1.x DLL present: \"" + GOOD_OCULUS_RUNTIME_FILE + "\"";
return false;
}
return true;
}
ovrSession acquireOculusSession() {
@ -98,9 +115,9 @@ SwapFramebufferWrapper::~SwapFramebufferWrapper() {
destroyColor();
}
void SwapFramebufferWrapper::Increment() {
++color->CurrentIndex;
color->CurrentIndex %= color->TextureCount;
void SwapFramebufferWrapper::Commit() {
auto result = ovr_CommitTextureSwapChain(_session, color);
Q_ASSERT(OVR_SUCCESS(result));
}
void SwapFramebufferWrapper::Resize(const uvec2 & size) {
@ -114,7 +131,7 @@ void SwapFramebufferWrapper::Resize(const uvec2 & size) {
void SwapFramebufferWrapper::destroyColor() {
if (color) {
ovr_DestroySwapTextureSet(_session, color);
ovr_DestroyTextureSwapChain(_session, color);
color = nullptr;
}
}
@ -122,13 +139,30 @@ void SwapFramebufferWrapper::destroyColor() {
void SwapFramebufferWrapper::initColor() {
destroyColor();
if (!OVR_SUCCESS(ovr_CreateSwapTextureSetGL(_session, GL_SRGB8_ALPHA8, size.x, size.y, &color))) {
ovrTextureSwapChainDesc desc = {};
desc.Type = ovrTexture_2D;
desc.ArraySize = 1;
desc.Width = size.x;
desc.Height = size.y;
desc.MipLevels = 1;
desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
desc.SampleCount = 1;
desc.StaticImage = ovrFalse;
ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &color);
if (!OVR_SUCCESS(result)) {
logFatal("Failed to create swap textures");
}
for (int i = 0; i < color->TextureCount; ++i) {
ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i];
glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId);
int length = 0;
result = ovr_GetTextureSwapChainLength(_session, color, &length);
if (!OVR_SUCCESS(result) || !length) {
qFatal("Unable to count swap chain textures");
}
for (int i = 0; i < length; ++i) {
GLuint chainTexId;
ovr_GetTextureSwapChainBufferGL(_session, color, i, &chainTexId);
glBindTexture(GL_TEXTURE_2D, chainTexId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -141,8 +175,11 @@ void SwapFramebufferWrapper::initDone() {
}
void SwapFramebufferWrapper::onBind(oglplus::Framebuffer::Target target) {
ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]);
glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0);
int curIndex;
ovr_GetTextureSwapChainCurrentIndex(_session, color, &curIndex);
GLuint curTexId;
ovr_GetTextureSwapChainBufferGL(_session, color, curIndex, &curTexId);
glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0);
}
void SwapFramebufferWrapper::onUnbind(oglplus::Framebuffer::Target target) {

View file

@ -111,10 +111,10 @@ inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) {
// then submit it and increment to the next texture.
// The Oculus SDK manages the creation and destruction of
// the textures
struct SwapFramebufferWrapper : public FramebufferWrapper<ovrSwapTextureSet*, void*> {
struct SwapFramebufferWrapper : public FramebufferWrapper<ovrTextureSwapChain, void*> {
SwapFramebufferWrapper(const ovrSession& session);
~SwapFramebufferWrapper();
void Increment();
void Commit();
void Resize(const uvec2 & size);
protected:
void initColor() override final;

View file

@ -18,6 +18,7 @@
#include "OculusDisplayPlugin.h"
#include "OculusDebugDisplayPlugin.h"
#include "OculusControllerManager.h"
class OculusProvider : public QObject, public DisplayProvider, InputProvider
{
@ -51,8 +52,6 @@ public:
}
virtual InputPluginList getInputPlugins() override {
// FIXME pending full oculus input API and hardware
#if 0
static std::once_flag once;
std::call_once(once, [&] {
InputPluginPointer plugin(new OculusControllerManager());
@ -60,7 +59,6 @@ public:
_inputPlugins.push_back(plugin);
}
});
#endif
return _inputPlugins;
}

View file

@ -35,10 +35,14 @@ void OculusLegacyDisplayPlugin::resetSensors() {
ovrHmd_RecenterPose(_hmd);
}
void OculusLegacyDisplayPlugin::updateHeadPose(uint32_t frameIndex) {
void OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
FrameInfo frame;
frame.predictedDisplayTime = frame.sensorSampleTime = ovr_GetTimeInSeconds();
_trackingState = ovrHmd_GetTrackingState(_hmd, frame.predictedDisplayTime);
frame.headPose = toGlm(_trackingState.HeadPose.ThePose);
_currentRenderFrameInfo.set(frame);
Lock lock(_mutex);
_trackingState = ovrHmd_GetTrackingState(_hmd, ovr_GetTimeInSeconds());
_headPoseCache.set(toGlm(_trackingState.HeadPose.ThePose));
_frameInfos[frameIndex] = frame;
}
bool OculusLegacyDisplayPlugin::isSupported() const {

View file

@ -26,7 +26,7 @@ public:
// Stereo specific methods
virtual void resetSensors() override;
virtual void updateHeadPose(uint32_t frameIndex) override;
virtual void beginFrameRender(uint32_t frameIndex) override;
virtual float getTargetFrameRate() override;

View file

@ -121,22 +121,23 @@ void OpenVrDisplayPlugin::resetSensors() {
_sensorResetMat = glm::inverse(cancelOutRollAndPitch(m));
}
void OpenVrDisplayPlugin::updateHeadPose(uint32_t frameIndex) {
void OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
float displayFrequency = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
float frameDuration = 1.f / displayFrequency;
float vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);
double displayFrequency = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
double frameDuration = 1.f / displayFrequency;
double vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);
FrameInfo frame;
#if THREADED_PRESENT
// 3 frames of prediction + vsyncToPhotons = 44ms total
const float NUM_PREDICTION_FRAMES = 3.0f;
float predictedSecondsFromNow = NUM_PREDICTION_FRAMES * frameDuration + vsyncToPhotons;
const double NUM_PREDICTION_FRAMES = 3.0f;
frame.predictedDisplayTime = NUM_PREDICTION_FRAMES * frameDuration + vsyncToPhotons;
#else
float predictedSecondsFromNow = frameDuration + vsyncToPhotons;
frame.predictedDisplayTime = frameDuration + vsyncToPhotons;
#endif
vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, predictedSecondsFromNow, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount);
_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, frame.predictedDisplayTime, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount);
// copy and process predictedTrackedDevicePoses
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
@ -145,8 +146,11 @@ void OpenVrDisplayPlugin::updateHeadPose(uint32_t frameIndex) {
_trackedDeviceLinearVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vVelocity));
_trackedDeviceAngularVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vAngularVelocity));
}
frame.headPose = _trackedDevicePoseMat4[0];
_currentRenderFrameInfo.set(frame);
_headPoseCache.set(_trackedDevicePoseMat4[0]);
Lock lock(_mutex);
_frameInfos[frameIndex] = frame;
}
void OpenVrDisplayPlugin::hmdPresent() {

View file

@ -27,7 +27,7 @@ public:
// Stereo specific methods
virtual void resetSensors() override;
virtual void updateHeadPose(uint32_t frameIndex) override;
virtual void beginFrameRender(uint32_t frameIndex) override;
protected:
bool internalActivate() override;

View file

@ -1,5 +1,6 @@
Server\ Console-*/
server-console-*/
Sandbox-*/
electron-packager/
npm-debug.log
logs/

View file

@ -23,7 +23,7 @@ add_dependencies(${TARGET_NAME} assignment-client domain-server)
# set the packaged console folder depending on platform, so we can copy it
if (APPLE)
set(PACKAGED_CONSOLE_FOLDER "Server\\ Console-darwin-x64/${CONSOLE_EXEC_NAME}")
set(PACKAGED_CONSOLE_FOLDER "Sandbox-darwin-x64/${CONSOLE_EXEC_NAME}")
elseif (WIN32)
set(PACKAGED_CONSOLE_FOLDER "server-console-win32-x64")
elseif (UNIX)

View file

@ -23,12 +23,12 @@ var options = {
arch: "x64",
platform: platform,
icon: "resources/" + iconName,
ignore: "logs|(S|s)erver(\\s|-)(C|c)onsole-\\S+|electron-packager|README.md|CMakeLists.txt|packager.js|.gitignore"
ignore: "logs|(S|s)erver(\\s|-)(C|c)onsole-\\S+|(S|s)andbox-\\S+|electron-packager|README.md|CMakeLists.txt|packager.js|.gitignore"
}
const EXEC_NAME = "server-console";
const SHORT_NAME = "Server Console";
const FULL_NAME = "High Fidelity Server Console";
const SHORT_NAME = "Sandbox";
const FULL_NAME = "High Fidelity Sandbox";
// setup per OS options
if (osType == "Darwin") {

Binary file not shown.

Before

(image error) Size: 12 KiB

After

(image error) Size: 12 KiB

View file

@ -111,8 +111,8 @@ function shutdown() {
dialog.showMessageBox({
type: 'question',
buttons: ['Yes', 'No'],
title: 'Stopping Server Console',
message: 'Quitting will stop your Server Console and your Home domain will no longer be running.\nDo you wish to continue?'
title: 'Stopping High Fidelity Sandbox',
message: 'Quitting will stop your Sandbox and your Home domain will no longer be running.\nDo you wish to continue?'
}, shutdownCallback);
} else {
shutdownCallback(0);
@ -212,7 +212,7 @@ var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory)
});
if (shouldQuit) {
console.warn("Another instance of the Server Console is already running - this instance will quit.");
console.warn("Another instance of the Sandbox is already running - this instance will quit.");
app.quit();
return;
}
@ -237,7 +237,7 @@ function binaryMissingMessage(displayName, executableName, required) {
var message = "The " + displayName + " executable was not found.\n";
if (required) {
message += "It is required for the Server Console to run.\n\n";
message += "It is required for the High Fidelity Sandbox to run.\n\n";
} else {
message += "\n";
}
@ -250,7 +250,7 @@ function binaryMissingMessage(displayName, executableName, required) {
message += paths.join("\n");
} else {
message += "It is expected to be found beside this executable.\n";
message += "You may need to re-install the Server Console.";
message += "You may need to re-install the High Fidelity Sandbox.";
}
return message;
@ -347,134 +347,6 @@ function goHomeClicked() {
}
}
function stackManagerBasePath() {
var dataPath = 'High Fidelity/Stack Manager/resources';
if (process.platform == "win32") {
return path.resolve(osHomeDir(), 'AppData/Local', dataPath);
} else if (process.platform == "darwin") {
return path.resolve(osHomeDir(), 'Library/Application Support', dataPath);
} else {
return ""
}
}
function isStackManagerContentPresent() {
var modelsPath = path.resolve(stackManagerBasePath(), 'models.json.gz');
try {
var stats = fs.lstatSync(modelsPath);
if (stats.isFile()) {
console.log("Stack Manager entities file discovered at " + modelsPath)
// we found a content file
return true;
}
} catch (e) {
console.log("Stack Manager entities file not found at " + modelsPath);
}
}
function promptToMigrateContent() {
dialog.showMessageBox({
type: 'question',
buttons: ['Yes', 'No'],
title: 'Migrate Content',
message: 'Are you sure?\n\nThis will stop your home server and replace everything in your home with your content from Stack Manager.'
}, function(index) {
if (index == 0) {
if (homeServer.state != ProcessGroupStates.STOPPED) {
var stopThenMigrateCallback = function(processGroup) {
if (isShuttingDown) {
homeServer.removeListener('state-update', stopThenMigrateCallback);
} else if (processGroup.state == ProcessGroupStates.STOPPED) {
performContentMigration();
homeServer.removeListener('state-update', stopThenMigrateCallback);
}
};
homeServer.on('state-update', stopThenMigrateCallback);
homeServer.stop();
} else {
performContentMigration();
}
}
});
}
function performContentMigration() {
// check if there is a models file to migrate
var modelsPath = path.resolve(stackManagerBasePath(), 'models.json.gz');
try {
var stats = fs.lstatSync(modelsPath);
} catch (e) {
// no entities file
dialog.showMessageBox({
type: 'info',
buttons: ['OK'],
title: 'Models File Not Found',
message: 'There is no models file at ' + modelsPath + '\n\nStack Manager content migration can not proceed.'
}, null);
return;
}
function showMigrationCompletionDialog(copyError) {
if (!copyError) {
// show message for successful migration
dialog.showMessageBox({
type: 'info',
buttons: ['OK'],
title: 'Migration Complete',
message: 'Your Stack Manager content has been migrated.\n\nYour home server will now be restarted.'
}, null);
} else {
// show error message for copy fail
dialog.showMessageBox({
type: 'info',
buttons: ['OK'],
title: 'Migration Failed',
message: 'There was an error copying your Stack Manager content: ' + copyError + '\n\nPlease try again.'
}, null);
}
}
// we have a models file, try and copy it
var newModelsPath = path.resolve(getAssignmentClientResourcesDirectory(), 'entities/models.json.gz')
console.log("Copying Stack Manager entity file from " + modelsPath + " to " + newModelsPath);
try {
fs.copySync(modelsPath, newModelsPath);
// check if there are any assets to copy
var oldAssetsPath = path.resolve(stackManagerBasePath(), 'assets');
var assets = fs.readdirSync(oldAssetsPath);
if (assets.length > 0) {
// assume this means the directory is not empty
// and that we should copy it
var newAssetsPath = path.resolve(getAssignmentClientResourcesDirectory(), 'assets');
console.log("Copying Stack Manager assets from " + oldAssetsPath + " to " + newAssetsPath);
// attempt to copy the assets folder
fs.copySync(oldAssetsPath, newAssetsPath, {
preserveTimestamps: true
});
}
showMigrationCompletionDialog(null);
} catch (error) {
showMigrationCompletionDialog(error);
}
homeServer.start();
}
var logWindow = null;
var labels = {
@ -530,12 +402,6 @@ var labels = {
shell.openExternal('http://localhost:40100/settings/?action=share')
}
},
migrateContent: {
label: 'Migrate Stack Manager Content',
click: function() {
promptToMigrateContent();
}
},
shuttingDown: {
label: "Shutting down...",
enabled: false
@ -569,13 +435,6 @@ function buildMenuArray(serverState) {
menuArray.push(labels.share);
menuArray.push(separator);
menuArray.push(labels.quit);
var foundStackManagerContent = isStackManagerContentPresent();
if (foundStackManagerContent) {
// add a separator and the stack manager content migration option
menuArray.splice(menuArray.length - 1, 0, labels.migrateContent, separator);
}
}
@ -724,7 +583,7 @@ function maybeShowSplash() {
var window = new BrowserWindow({
icon: appIcon,
width: 1600 * zoomFactor,
height: 737 * zoomFactor,
height: 650 * zoomFactor,
center: true,
frame: true,
useContentSize: true,
@ -770,7 +629,7 @@ app.on('ready', function() {
// Create tray icon
tray = new Tray(trayIcons[ProcessGroupStates.STOPPED]);
tray.setToolTip('High Fidelity Server Console');
tray.setToolTip('High Fidelity Sandbox');
tray.on('click', function() {
tray.popUpContextMenu(tray.menu);

View file

@ -122,11 +122,6 @@ h2 {
#main-content {
height: 350px;
border-bottom: 2px solid #F5F6F6;
}
#existing-resources-area {
padding-top: 20px;
}
.footer {
@ -143,4 +138,4 @@ h2 {
input[type="checkbox"] {
-webkit-transform: scale(1.4);
display: inline-block;
}
}

View file

@ -23,7 +23,7 @@ High Fidelity is now installed and your Home domain is ready for you to explore.
</p>
<p>
You can make your home yours by uploading your own models and scripts, and adding items from the Market.
You can make your home yours by uploading your own models and scripts.
</p>
@ -67,12 +67,6 @@ You can make your home yours by uploading your own models and scripts, and addin
</script>
</div>
</div>
<div id="existing-resources-area">
<p>
<h2>Your existing Stack Manager content is safe.</h2>
Server Console comes with demo content but does not overwrite your data. <a target="_blank" href="https://docs.highfidelity.com/v1.0/docs/migrate-sm-to-sc">See our guide to importing content previously managed with Stack Manager</a>.
</p>
</div>
</div>
<div class="bottom">
<div class="content footer">

View file

@ -795,3 +795,35 @@ void OctreeTests::modelItemTests() {
#endif
}
void OctreeTests::elementAddChildTests() {
EntityTreePointer tree = std::make_shared<EntityTree>();
auto elem = tree->createNewElement();
QCOMPARE((bool)elem->getChildAtIndex(0), false);
elem->addChildAtIndex(0);
QCOMPARE((bool)elem->getChildAtIndex(0), true);
const int MAX_CHILD_INDEX = 8;
for (int i = 0; i < MAX_CHILD_INDEX; i++) {
for (int j = 0; j < MAX_CHILD_INDEX; j++) {
auto e = tree->createNewElement();
// add a single child.
auto firstChild = e->addChildAtIndex(i);
QCOMPARE(e->getChildAtIndex(i), firstChild);
if (i != j) {
// add a second child.
auto secondChild = e->addChildAtIndex(j);
QCOMPARE(e->getChildAtIndex(i), firstChild);
QCOMPARE(e->getChildAtIndex(j), secondChild);
// remove scecond child.
e->removeChildAtIndex(j);
QCOMPARE((bool)e->getChildAtIndex(j), false);
}
QCOMPARE(e->getChildAtIndex(i), firstChild);
}
}
}

View file

@ -25,6 +25,8 @@ private slots:
// This test is fine
void modelItemTests();
void elementAddChildTests();
// TODO: Break these into separate test functions
};