mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 00:56:48 +02:00
Merge branch 'master' of https://github.com/worklist/hifi
This commit is contained in:
commit
c9312803bd
81 changed files with 2831 additions and 1977 deletions
|
@ -2,10 +2,6 @@ set(TARGET_NAME assignment-client)
|
|||
|
||||
setup_hifi_project(Core Gui Network Script Widgets WebSockets)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS})
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree environment gpu model fbx entities
|
||||
|
|
|
@ -16,7 +16,6 @@ macro(LINK_HIFI_LIBRARIES)
|
|||
foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
|
||||
if (NOT TARGET ${HIFI_LIBRARY})
|
||||
add_subdirectory("${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}" "${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}")
|
||||
set_target_properties(${HIFI_LIBRARY} PROPERTIES FOLDER "Libraries")
|
||||
endif ()
|
||||
|
||||
include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
|
||||
|
|
|
@ -36,5 +36,9 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
|
||||
# Don't make scribed shaders cumulative
|
||||
set(AUTOSCRIBE_SHADER_LIB_SRC "")
|
||||
|
||||
target_glm()
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Libraries")
|
||||
|
||||
endmacro(SETUP_HIFI_LIBRARY)
|
|
@ -34,4 +34,7 @@ macro(SETUP_HIFI_PROJECT)
|
|||
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
endforeach()
|
||||
|
||||
target_glm()
|
||||
|
||||
endmacro()
|
||||
|
|
|
@ -94,6 +94,7 @@ macro(SETUP_HIFI_TESTCASE)
|
|||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||
EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
|
||||
list (APPEND ${TEST_PROJ_NAME}_TARGETS ${TARGET_NAME})
|
||||
#list (APPEND ALL_TEST_TARGETS ${TARGET_NAME})
|
||||
|
||||
|
@ -111,8 +112,9 @@ macro(SETUP_HIFI_TESTCASE)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "hidden/test-executables")
|
||||
|
||||
# handle testcase-specific dependencies (this a macro that should be defined in the cmakelists.txt file in each tests subdir)
|
||||
|
||||
SETUP_TESTCASE_DEPENDENCIES ()
|
||||
SETUP_TESTCASE_DEPENDENCIES()
|
||||
target_glm()
|
||||
|
||||
endforeach ()
|
||||
|
||||
set(TEST_TARGET ${TEST_PROJ_NAME}-tests)
|
||||
|
|
18
cmake/macros/TargetBullet.cmake
Normal file
18
cmake/macros/TargetBullet.cmake
Normal file
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_BULLET)
|
||||
add_dependency_external_projects(bullet)
|
||||
find_package(Bullet REQUIRED)
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
else()
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
endif()
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
endmacro()
|
14
cmake/macros/TargetGlew.cmake
Normal file
14
cmake/macros/TargetGlew.cmake
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_GLEW)
|
||||
add_dependency_external_projects(glew)
|
||||
find_package(GLEW REQUIRED)
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY})
|
||||
endmacro()
|
12
cmake/macros/TargetGlm.cmake
Normal file
12
cmake/macros/TargetGlm.cmake
Normal file
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_GLM)
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
endmacro()
|
20
cmake/macros/TargetNsight.cmake
Normal file
20
cmake/macros/TargetNsight.cmake
Normal file
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_NSIGHT)
|
||||
if (WIN32)
|
||||
if (USE_NSIGHT)
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif ()
|
||||
endif()
|
||||
endif (WIN32)
|
||||
endmacro()
|
21
cmake/macros/TargetOglplus.cmake
Normal file
21
cmake/macros/TargetOglplus.cmake
Normal file
|
@ -0,0 +1,21 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_OGLPLUS)
|
||||
# our OGL plus setup requires glew
|
||||
target_glew()
|
||||
|
||||
# our OGL plus setup requires boostconfig
|
||||
add_dependency_external_projects(boostconfig)
|
||||
find_package(BoostConfig REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
|
||||
|
||||
|
||||
add_dependency_external_projects(oglplus)
|
||||
find_package(OGLPLUS REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
|
||||
endmacro()
|
|
@ -1,38 +1,24 @@
|
|||
|
||||
|
||||
macro(SETUP_HIFI_OPENGL)
|
||||
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_OPENGL)
|
||||
if (APPLE)
|
||||
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(OpenGL OpenGL)
|
||||
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
||||
|
||||
elseif (WIN32)
|
||||
|
||||
if (USE_NSIGHT)
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
elseif(ANDROID)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL")
|
||||
|
||||
else()
|
||||
|
||||
target_nsight()
|
||||
find_package(OpenGL REQUIRED)
|
||||
if (${OPENGL_INCLUDE_DIR})
|
||||
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
||||
endif()
|
||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||
|
||||
endif()
|
||||
|
||||
endmacro()
|
|
@ -176,7 +176,7 @@
|
|||
"type": "checkbox",
|
||||
"label": "Enabled",
|
||||
"help": "Assigns an asset-server in your domain to serve files to clients via the ATP protocol (over UDP)",
|
||||
"default": false,
|
||||
"default": true,
|
||||
"advanced": true
|
||||
}
|
||||
]
|
||||
|
|
|
@ -480,7 +480,7 @@ function MyController(hand, triggerAction) {
|
|||
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
|
||||
|
||||
this.actionID = NULL_ACTION_ID;
|
||||
this.actionID = Entities.addAction("kinematic-hold", this.grabbedEntity, {
|
||||
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: offsetPosition,
|
||||
|
|
593
examples/edit.js
593
examples/edit.js
File diff suppressed because it is too large
Load diff
|
@ -11,14 +11,19 @@
|
|||
|
||||
// Assumes you only have the default keyboard connected
|
||||
|
||||
|
||||
Object.keys(Controller.Standard).forEach(function (input) {
|
||||
print("Controller.Standard." + input + ":" + Controller.Standard[input]);
|
||||
});
|
||||
|
||||
Object.keys(Controller.Hardware).forEach(function (deviceName) {
|
||||
Object.keys(Controller.Hardware[deviceName]).forEach(function (input) {
|
||||
print(deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);
|
||||
print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);
|
||||
});
|
||||
});
|
||||
|
||||
Object.keys(Controller.Actions).forEach(function (actionName) {
|
||||
print(actionName + ":" + Controller.Actions[actionName]);
|
||||
print("Controller.Actions." + actionName + ":" + Controller.Actions[actionName]);
|
||||
});
|
||||
|
||||
// Resets every device to its default key bindings:
|
||||
|
|
|
@ -118,8 +118,16 @@ CameraManager = function() {
|
|||
that.targetYaw = 0;
|
||||
that.targetPitch = 0;
|
||||
|
||||
that.focalPoint = { x: 0, y: 0, z: 0 };
|
||||
that.targetFocalPoint = { x: 0, y: 0, z: 0 };
|
||||
that.focalPoint = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
that.targetFocalPoint = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
|
||||
easing = false;
|
||||
easingTime = 0;
|
||||
|
@ -127,13 +135,18 @@ CameraManager = function() {
|
|||
|
||||
that.previousCameraMode = null;
|
||||
|
||||
that.lastMousePosition = { x: 0, y: 0 };
|
||||
that.lastMousePosition = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
that.enable = function() {
|
||||
if (Camera.mode == "independent" || that.enabled) return;
|
||||
|
||||
for (var i = 0; i < CAPTURED_KEYS.length; i++) {
|
||||
Controller.captureKeyEvents({ text: CAPTURED_KEYS[i] });
|
||||
Controller.captureKeyEvents({
|
||||
text: CAPTURED_KEYS[i]
|
||||
});
|
||||
}
|
||||
|
||||
that.enabled = true;
|
||||
|
@ -143,7 +156,7 @@ CameraManager = function() {
|
|||
that.zoomDistance = INITIAL_ZOOM_DISTANCE;
|
||||
that.targetZoomDistance = that.zoomDistance + 3.0;
|
||||
var focalPoint = Vec3.sum(Camera.getPosition(),
|
||||
Vec3.multiply(that.zoomDistance, Quat.getFront(Camera.getOrientation())));
|
||||
Vec3.multiply(that.zoomDistance, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
// Determine the correct yaw and pitch to keep the camera in the same location
|
||||
var dPos = Vec3.subtract(focalPoint, Camera.getPosition());
|
||||
|
@ -169,7 +182,9 @@ CameraManager = function() {
|
|||
if (!that.enabled) return;
|
||||
|
||||
for (var i = 0; i < CAPTURED_KEYS.length; i++) {
|
||||
Controller.releaseKeyEvents({ text: CAPTURED_KEYS[i] });
|
||||
Controller.releaseKeyEvents({
|
||||
text: CAPTURED_KEYS[i]
|
||||
});
|
||||
}
|
||||
|
||||
that.enabled = false;
|
||||
|
@ -335,19 +350,27 @@ CameraManager = function() {
|
|||
|
||||
var hasDragged = false;
|
||||
that.mousePressEvent = function(event) {
|
||||
|
||||
if (cameraTool.mousePressEvent(event)) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (!that.enabled) return;
|
||||
|
||||
if (event.isRightButton || (event.isLeftButton && event.isControl && !event.isShifted)) {
|
||||
|
||||
that.mode = MODE_ORBIT;
|
||||
} else if (event.isMiddleButton || (event.isLeftButton && event.isControl && event.isShifted)) {
|
||||
|
||||
|
||||
that.mode = MODE_PAN;
|
||||
}
|
||||
|
||||
if (that.mode != MODE_INACTIVE) {
|
||||
if (that.mode !== MODE_INACTIVE) {
|
||||
|
||||
|
||||
hasDragged = false;
|
||||
|
||||
return true;
|
||||
|
@ -357,10 +380,12 @@ CameraManager = function() {
|
|||
}
|
||||
|
||||
that.mouseReleaseEvent = function(event) {
|
||||
|
||||
if (!that.enabled) return;
|
||||
|
||||
Window.setCursorVisible(true);
|
||||
that.mode = MODE_INACTIVE;
|
||||
Window.setCursorVisible(true);
|
||||
|
||||
}
|
||||
|
||||
that.keyPressEvent = function(event) {
|
||||
|
@ -396,15 +421,31 @@ CameraManager = function() {
|
|||
return;
|
||||
}
|
||||
|
||||
var yRot = Quat.angleAxis(that.yaw, { x: 0, y: 1, z: 0 });
|
||||
var xRot = Quat.angleAxis(that.pitch, { x: 1, y: 0, z: 0 });
|
||||
var yRot = Quat.angleAxis(that.yaw, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
var xRot = Quat.angleAxis(that.pitch, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
var q = Quat.multiply(yRot, xRot);
|
||||
|
||||
var pos = Vec3.multiply(Quat.getFront(q), that.zoomDistance);
|
||||
Camera.setPosition(Vec3.sum(that.focalPoint, pos));
|
||||
|
||||
yRot = Quat.angleAxis(that.yaw - 180, { x: 0, y: 1, z: 0 });
|
||||
xRot = Quat.angleAxis(-that.pitch, { x: 1, y: 0, z: 0 });
|
||||
yRot = Quat.angleAxis(that.yaw - 180, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
xRot = Quat.angleAxis(-that.pitch, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
q = Quat.multiply(yRot, xRot);
|
||||
|
||||
if (easing) {
|
||||
|
@ -483,7 +524,7 @@ CameraManager = function() {
|
|||
}
|
||||
});
|
||||
|
||||
Controller.keyReleaseEvent.connect(function (event) {
|
||||
Controller.keyReleaseEvent.connect(function(event) {
|
||||
if (event.text == "ESC" && that.enabled) {
|
||||
Camera.mode = lastAvatarCameraMode;
|
||||
cameraManager.disable(true);
|
||||
|
@ -503,9 +544,21 @@ CameraManager = function() {
|
|||
CameraTool = function(cameraManager) {
|
||||
var that = {};
|
||||
|
||||
var RED = { red: 191, green: 78, blue: 38 };
|
||||
var GREEN = { red: 26, green: 193, blue: 105 };
|
||||
var BLUE = { red: 0, green: 131, blue: 204 };
|
||||
var RED = {
|
||||
red: 191,
|
||||
green: 78,
|
||||
blue: 38
|
||||
};
|
||||
var GREEN = {
|
||||
red: 26,
|
||||
green: 193,
|
||||
blue: 105
|
||||
};
|
||||
var BLUE = {
|
||||
red: 0,
|
||||
green: 131,
|
||||
blue: 204
|
||||
};
|
||||
|
||||
var BORDER_WIDTH = 1;
|
||||
|
||||
|
@ -513,10 +566,10 @@ CameraTool = function(cameraManager) {
|
|||
var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2;
|
||||
var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5,
|
||||
|
||||
var ORIENTATION_OVERLAY_OFFSET = {
|
||||
x: 30,
|
||||
y: 30,
|
||||
}
|
||||
var ORIENTATION_OVERLAY_OFFSET = {
|
||||
x: 30,
|
||||
y: 30,
|
||||
}
|
||||
|
||||
var UI_WIDTH = 70;
|
||||
var UI_HEIGHT = 70;
|
||||
|
@ -536,7 +589,11 @@ CameraTool = function(cameraManager) {
|
|||
height: UI_HEIGHT + BORDER_WIDTH * 2,
|
||||
alpha: 0,
|
||||
text: "",
|
||||
backgroundColor: { red: 101, green: 101, blue: 101 },
|
||||
backgroundColor: {
|
||||
red: 101,
|
||||
green: 101,
|
||||
blue: 101
|
||||
},
|
||||
backgroundAlpha: 1.0,
|
||||
visible: false,
|
||||
});
|
||||
|
@ -548,7 +605,11 @@ CameraTool = function(cameraManager) {
|
|||
height: UI_HEIGHT,
|
||||
alpha: 0,
|
||||
text: "",
|
||||
backgroundColor: { red: 51, green: 51, blue: 51 },
|
||||
backgroundColor: {
|
||||
red: 51,
|
||||
green: 51,
|
||||
blue: 51
|
||||
},
|
||||
backgroundAlpha: 1.0,
|
||||
visible: false,
|
||||
});
|
||||
|
@ -556,7 +617,11 @@ CameraTool = function(cameraManager) {
|
|||
var defaultCubeProps = {
|
||||
size: ORIENTATION_OVERLAY_CUBE_SIZE,
|
||||
alpha: 1,
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
color: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
solid: true,
|
||||
visible: true,
|
||||
drawOnHUD: true,
|
||||
|
@ -564,10 +629,26 @@ CameraTool = function(cameraManager) {
|
|||
var defaultLineProps = {
|
||||
lineWidth: 1.5,
|
||||
alpha: 1,
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
start: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
end: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
color: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
visible: false,
|
||||
drawOnHUD: true,
|
||||
};
|
||||
|
@ -582,30 +663,66 @@ CameraTool = function(cameraManager) {
|
|||
|
||||
var OOHS = ORIENTATION_OVERLAY_HALF_SIZE;
|
||||
var cubeX = orientationOverlay.createOverlay("cube", mergeObjects(defaultCubeProps, {
|
||||
position: { x: -OOHS, y: OOHS, z: OOHS },
|
||||
position: {
|
||||
x: -OOHS,
|
||||
y: OOHS,
|
||||
z: OOHS
|
||||
},
|
||||
color: RED,
|
||||
}));
|
||||
var cubeY = orientationOverlay.createOverlay("cube", mergeObjects(defaultCubeProps, {
|
||||
position: { x: OOHS, y: -OOHS, z: OOHS },
|
||||
position: {
|
||||
x: OOHS,
|
||||
y: -OOHS,
|
||||
z: OOHS
|
||||
},
|
||||
color: GREEN,
|
||||
}));
|
||||
var cubeZ = orientationOverlay.createOverlay("cube", mergeObjects(defaultCubeProps, {
|
||||
position: { x: OOHS, y: OOHS, z: -OOHS },
|
||||
position: {
|
||||
x: OOHS,
|
||||
y: OOHS,
|
||||
z: -OOHS
|
||||
},
|
||||
color: BLUE,
|
||||
}));
|
||||
orientationOverlay.createOverlay("line3d", mergeObjects(defaultLineProps, {
|
||||
start: { x: -OOHS, y: OOHS, z: OOHS },
|
||||
end: { x: OOHS, y: OOHS, z: OOHS },
|
||||
start: {
|
||||
x: -OOHS,
|
||||
y: OOHS,
|
||||
z: OOHS
|
||||
},
|
||||
end: {
|
||||
x: OOHS,
|
||||
y: OOHS,
|
||||
z: OOHS
|
||||
},
|
||||
color: RED,
|
||||
}));
|
||||
orientationOverlay.createOverlay("line3d", mergeObjects(defaultLineProps, {
|
||||
start: { x: OOHS, y: -OOHS, z: OOHS },
|
||||
end: { x: OOHS, y: OOHS, z: OOHS },
|
||||
start: {
|
||||
x: OOHS,
|
||||
y: -OOHS,
|
||||
z: OOHS
|
||||
},
|
||||
end: {
|
||||
x: OOHS,
|
||||
y: OOHS,
|
||||
z: OOHS
|
||||
},
|
||||
color: GREEN,
|
||||
}));
|
||||
orientationOverlay.createOverlay("line3d", mergeObjects(defaultLineProps, {
|
||||
start: { x: OOHS, y: OOHS, z: -OOHS },
|
||||
end: { x: OOHS, y: OOHS, z: OOHS },
|
||||
start: {
|
||||
x: OOHS,
|
||||
y: OOHS,
|
||||
z: -OOHS
|
||||
},
|
||||
end: {
|
||||
x: OOHS,
|
||||
y: OOHS,
|
||||
z: OOHS
|
||||
},
|
||||
color: BLUE,
|
||||
}));
|
||||
|
||||
|
@ -645,7 +762,10 @@ CameraTool = function(cameraManager) {
|
|||
}
|
||||
|
||||
that.mousePressEvent = function(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
|
||||
if (clickedOverlay == cubeX) {
|
||||
targetPitch = 0;
|
||||
|
@ -666,12 +786,18 @@ CameraTool = function(cameraManager) {
|
|||
};
|
||||
|
||||
that.setVisible = function(visible) {
|
||||
orientationOverlay.setProperties({ visible: visible });
|
||||
Overlays.editOverlay(background, { visible: visible });
|
||||
Overlays.editOverlay(backgroundBorder, { visible: visible });
|
||||
orientationOverlay.setProperties({
|
||||
visible: visible
|
||||
});
|
||||
Overlays.editOverlay(background, {
|
||||
visible: visible
|
||||
});
|
||||
Overlays.editOverlay(backgroundBorder, {
|
||||
visible: visible
|
||||
});
|
||||
};
|
||||
|
||||
that.setVisible(false);
|
||||
|
||||
return that;
|
||||
};
|
||||
};
|
|
@ -2326,7 +2326,9 @@ SelectionDisplay = (function () {
|
|||
|
||||
that.checkMove = function() {
|
||||
if (SelectionManager.hasSelection()) {
|
||||
SelectionManager._update();
|
||||
|
||||
// FIXME - this cause problems with editing in the entity properties window
|
||||
//SelectionManager._update();
|
||||
|
||||
if (!Vec3.equal(Camera.getPosition(), lastCameraPosition) ||
|
||||
!Quat.equal(Camera.getOrientation(), lastCameraOrientation)) {
|
||||
|
|
|
@ -16,8 +16,9 @@ var scriptURL = Script.resolvePath('wallTarget.js');
|
|||
|
||||
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target.fbx';
|
||||
var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target_collision_hull.obj';
|
||||
var MINIMUM_MOVE_LENGTH = 0.05;
|
||||
var RESET_DISTANCE = 0.5;
|
||||
|
||||
var RESET_DISTANCE = 1;
|
||||
var TARGET_USER_DATA_KEY = 'hifi-ping_pong_target';
|
||||
var NUMBER_OF_TARGETS = 6;
|
||||
var TARGETS_PER_ROW = 3;
|
||||
|
@ -60,6 +61,8 @@ var targets = [];
|
|||
|
||||
var originalPositions = [];
|
||||
|
||||
var lastPositions = [];
|
||||
|
||||
function addTargets() {
|
||||
var i;
|
||||
var row = -1;
|
||||
|
@ -77,6 +80,7 @@ function addTargets() {
|
|||
position.y = startPosition.y - (row * VERTICAL_SPACING);
|
||||
|
||||
originalPositions.push(position);
|
||||
lastPositions.push(position);
|
||||
|
||||
var targetProperties = {
|
||||
name: 'Target',
|
||||
|
@ -103,7 +107,11 @@ function testTargetDistanceFromStart() {
|
|||
var distance = Vec3.subtract(originalPosition, currentPosition);
|
||||
var length = Vec3.length(distance);
|
||||
|
||||
if (length > RESET_DISTANCE) {
|
||||
var moving = Vec3.length(Vec3.subtract(currentPosition, lastPositions[index]));
|
||||
|
||||
lastPositions[index] = currentPosition;
|
||||
|
||||
if (length > RESET_DISTANCE && moving < MINIMUM_MOVE_LENGTH) {
|
||||
|
||||
Entities.deleteEntity(target);
|
||||
|
||||
|
@ -117,10 +125,16 @@ function testTargetDistanceFromStart() {
|
|||
compoundShapeURL: COLLISION_HULL_URL,
|
||||
position: originalPositions[index],
|
||||
rotation: rotation,
|
||||
script: scriptURL
|
||||
script: scriptURL,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
targets[index] = Entities.addEntity(targetProperties);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -142,7 +156,7 @@ function deleteTargets() {
|
|||
}
|
||||
|
||||
Entities.deletingEntity.connect(deleteEntity);
|
||||
var distanceCheckInterval = Script.setInterval(testTargetDistanceFromStart, 1000);
|
||||
var distanceCheckInterval = Script.setInterval(testTargetDistanceFromStart, 500);
|
||||
|
||||
addTargets();
|
||||
|
||||
|
|
|
@ -24,10 +24,6 @@ endif ()
|
|||
|
||||
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking audio-client avatars)
|
||||
|
||||
if (ANDROID)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
set(TARGET_NAME interface)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "Faceshift" "LeapMotion" "RtMidi" "RSSDK" "3DConnexionClient" "iViewHMD")
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
@ -97,29 +95,17 @@ else()
|
|||
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||
endif()
|
||||
|
||||
add_dependency_external_projects(glm bullet)
|
||||
|
||||
# set up the external glm library
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS})
|
||||
|
||||
find_package(Bullet REQUIRED)
|
||||
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
else()
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree environment gpu procedural model render fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
plugins display-plugins input-plugins)
|
||||
|
||||
target_bullet()
|
||||
target_glew()
|
||||
target_opengl()
|
||||
|
||||
|
||||
add_dependency_external_projects(sdl2)
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
|
|
|
@ -16,24 +16,38 @@
|
|||
{
|
||||
"jointName": "RightHand",
|
||||
"positionVar": "rightHandPosition",
|
||||
"rotationVar": "rightHandRotation"
|
||||
"rotationVar": "rightHandRotation",
|
||||
"typeVar": "rightHandType"
|
||||
},
|
||||
{
|
||||
"jointName": "LeftHand",
|
||||
"positionVar": "leftHandPosition",
|
||||
"rotationVar": "leftHandRotation"
|
||||
"rotationVar": "leftHandRotation",
|
||||
"typeVar": "leftHandType"
|
||||
},
|
||||
{
|
||||
"jointName": "RightFoot",
|
||||
"positionVar": "rightFootPosition",
|
||||
"rotationVar": "rightFootRotation",
|
||||
"typeVar": "rightFootType"
|
||||
},
|
||||
{
|
||||
"jointName": "LeftFoot",
|
||||
"positionVar": "leftFootPosition",
|
||||
"rotationVar": "leftFootRotation",
|
||||
"typeVar": "leftFootType"
|
||||
},
|
||||
{
|
||||
"jointName": "Neck",
|
||||
"positionVar": "neckPosition",
|
||||
"rotationVar": "neckRotation",
|
||||
"typeVar": "headAndNeckType"
|
||||
"typeVar": "neckType"
|
||||
},
|
||||
{
|
||||
"jointName": "Head",
|
||||
"positionVar": "headPosition",
|
||||
"rotationVar": "headRotation",
|
||||
"typeVar": "headAndNeckType"
|
||||
"typeVar": "headType"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -51,7 +65,7 @@
|
|||
"id": "spineLean",
|
||||
"type": "manipulator",
|
||||
"data": {
|
||||
"alpha": 1.0,
|
||||
"alpha": 0.0,
|
||||
"joints": [
|
||||
{ "var": "lean", "jointName": "Spine" }
|
||||
]
|
||||
|
|
|
@ -126,6 +126,7 @@
|
|||
#include "Stars.h"
|
||||
#include "ui/AddressBarDialog.h"
|
||||
#include "ui/AvatarInputs.h"
|
||||
#include "ui/AssetUploadDialogFactory.h"
|
||||
#include "ui/DataWebDialog.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
#include "ui/LoginDialog.h"
|
||||
|
@ -159,6 +160,7 @@ static const QString SVO_JSON_EXTENSION = ".svo.json";
|
|||
static const QString JS_EXTENSION = ".js";
|
||||
static const QString FST_EXTENSION = ".fst";
|
||||
static const QString FBX_EXTENSION = ".fbx";
|
||||
static const QString OBJ_EXTENSION = ".obj";
|
||||
|
||||
static const int MIRROR_VIEW_TOP_PADDING = 5;
|
||||
static const int MIRROR_VIEW_LEFT_PADDING = 10;
|
||||
|
@ -179,9 +181,6 @@ static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
|
|||
static const int TARGET_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / TARGET_SIM_FRAMERATE;
|
||||
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
|
||||
|
||||
const QString CHECK_VERSION_URL = "https://highfidelity.com/latestVersion.xml";
|
||||
const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
|
||||
|
||||
#ifndef __APPLE__
|
||||
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
#else
|
||||
|
@ -197,8 +196,7 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi
|
|||
{ SVO_EXTENSION, &Application::importSVOFromURL },
|
||||
{ SVO_JSON_EXTENSION, &Application::importSVOFromURL },
|
||||
{ JS_EXTENSION, &Application::askToLoadScript },
|
||||
{ FST_EXTENSION, &Application::askToSetAvatarUrl },
|
||||
{ FBX_EXTENSION, &Application::askToUploadAsset }
|
||||
{ FST_EXTENSION, &Application::askToSetAvatarUrl }
|
||||
};
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -1561,7 +1559,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
cursor->setIcon(Cursor::Icon::DEFAULT);
|
||||
}
|
||||
} else {
|
||||
resetSensors();
|
||||
resetSensors(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1892,16 +1890,6 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
computePickRay(mappedEvent.x(), mappedEvent.y()));
|
||||
sendEvent(this, &actionEvent);
|
||||
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
// "right click" on controllers to toggle the overlay
|
||||
if (deviceID > 0) {
|
||||
_overlayConductor.setEnabled(!_overlayConductor.getEnabled());
|
||||
}
|
||||
} else if (event->button() == Qt::MiddleButton) {
|
||||
// mouse middle click to toggle the overlay
|
||||
if (deviceID == 0) {
|
||||
_overlayConductor.setEnabled(!_overlayConductor.getEnabled());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2023,21 +2011,14 @@ void Application::dropEvent(QDropEvent *event) {
|
|||
const QMimeData* mimeData = event->mimeData();
|
||||
for (auto& url : mimeData->urls()) {
|
||||
QString urlString = url.toString();
|
||||
if (canAcceptURL(urlString) && acceptURL(urlString)) {
|
||||
if (acceptURL(urlString, true)) {
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::dragEnterEvent(QDragEnterEvent* event) {
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
for (auto& url : mimeData->urls()) {
|
||||
auto urlString = url.toString();
|
||||
if (canAcceptURL(urlString)) {
|
||||
event->acceptProposedAction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
bool Application::acceptSnapshot(const QString& urlString) {
|
||||
|
@ -2770,6 +2751,8 @@ void Application::update(float deltaTime) {
|
|||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||
|
||||
_avatarUpdate->synchronousProcess();
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("physics");
|
||||
myAvatar->relayDriveKeysToCharacterController();
|
||||
|
@ -2831,8 +2814,6 @@ void Application::update(float deltaTime) {
|
|||
_overlays.update(deltaTime);
|
||||
}
|
||||
|
||||
_avatarUpdate->synchronousProcess();
|
||||
|
||||
// Update _viewFrustum with latest camera and view frustum data...
|
||||
// NOTE: we get this from the view frustum, to make it simpler, since the
|
||||
// loadViewFrumstum() method will get the correct details from the camera
|
||||
|
@ -3600,7 +3581,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi
|
|||
renderArgs->_viewport = originalViewport;
|
||||
}
|
||||
|
||||
void Application::resetSensors() {
|
||||
void Application::resetSensors(bool andReload) {
|
||||
DependencyManager::get<Faceshift>()->reset();
|
||||
DependencyManager::get<DdeFaceTracker>()->reset();
|
||||
DependencyManager::get<EyeTracker>()->reset();
|
||||
|
@ -3612,7 +3593,7 @@ void Application::resetSensors() {
|
|||
QPoint windowCenter = mainWindow->geometry().center();
|
||||
_glWidget->cursor().setPos(currentScreen, windowCenter);
|
||||
|
||||
getMyAvatar()->reset();
|
||||
getMyAvatar()->reset(andReload);
|
||||
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "reset", Qt::QueuedConnection);
|
||||
}
|
||||
|
@ -3973,26 +3954,26 @@ bool Application::canAcceptURL(const QString& urlString) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Application::acceptURL(const QString& urlString) {
|
||||
bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
|
||||
if (urlString.startsWith(HIFI_URL_SCHEME)) {
|
||||
// this is a hifi URL - have the AddressManager handle it
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AddressManager>().data(), "handleLookupString",
|
||||
Qt::AutoConnection, Q_ARG(const QString&, urlString));
|
||||
return true;
|
||||
} else {
|
||||
QUrl url(urlString);
|
||||
QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions);
|
||||
QString lowerPath = url.path().toLower();
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (lowerPath.endsWith(i.key())) {
|
||||
AcceptURLMethod method = i.value();
|
||||
(this->*method)(urlString);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
QUrl url(urlString);
|
||||
QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions);
|
||||
QString lowerPath = url.path().toLower();
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (lowerPath.endsWith(i.key())) {
|
||||
AcceptURLMethod method = i.value();
|
||||
return (this->*method)(urlString);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return defaultUpload && askToUploadAsset(urlString);
|
||||
}
|
||||
|
||||
void Application::setSessionUUID(const QUuid& sessionUUID) {
|
||||
|
@ -4076,8 +4057,36 @@ bool Application::askToUploadAsset(const QString& filename) {
|
|||
|
||||
QUrl url { filename };
|
||||
if (auto upload = DependencyManager::get<AssetClient>()->createUpload(url.toLocalFile())) {
|
||||
|
||||
QMessageBox messageBox;
|
||||
messageBox.setWindowTitle("Asset upload");
|
||||
messageBox.setText("You are about to upload the following file to the asset server:\n" +
|
||||
url.toDisplayString());
|
||||
messageBox.setInformativeText("Do you want to continue?");
|
||||
messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||
messageBox.setDefaultButton(QMessageBox::Ok);
|
||||
|
||||
// Option to drop model in world for models
|
||||
if (filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION)) {
|
||||
auto checkBox = new QCheckBox(&messageBox);
|
||||
checkBox->setText("Add to scene");
|
||||
messageBox.setCheckBox(checkBox);
|
||||
}
|
||||
|
||||
if (messageBox.exec() != QMessageBox::Ok) {
|
||||
upload->deleteLater();
|
||||
return false;
|
||||
}
|
||||
|
||||
// connect to the finished signal so we know when the AssetUpload is done
|
||||
QObject::connect(upload, &AssetUpload::finished, this, &Application::assetUploadFinished);
|
||||
if (messageBox.checkBox() && (messageBox.checkBox()->checkState() == Qt::Checked)) {
|
||||
// Custom behavior for models
|
||||
QObject::connect(upload, &AssetUpload::finished, this, &Application::modelUploadFinished);
|
||||
} else {
|
||||
QObject::connect(upload, &AssetUpload::finished,
|
||||
&AssetUploadDialogFactory::getInstance(),
|
||||
&AssetUploadDialogFactory::handleUploadFinished);
|
||||
}
|
||||
|
||||
// start the upload now
|
||||
upload->start();
|
||||
|
@ -4089,47 +4098,26 @@ bool Application::askToUploadAsset(const QString& filename) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Application::assetUploadFinished(AssetUpload* upload, const QString& hash) {
|
||||
if (upload->getError() != AssetUpload::NoError) {
|
||||
// figure out the right error message for the message box
|
||||
QString additionalError;
|
||||
void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) {
|
||||
auto filename = QFileInfo(upload->getFilename()).fileName();
|
||||
|
||||
if ((upload->getError() == AssetUpload::NoError) &&
|
||||
(filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION))) {
|
||||
|
||||
switch (upload->getError()) {
|
||||
case AssetUpload::PermissionDenied:
|
||||
additionalError = "You do not have permission to upload content to this asset-server.";
|
||||
break;
|
||||
case AssetUpload::TooLarge:
|
||||
additionalError = "The uploaded content was too large and could not be stored in the asset-server.";
|
||||
break;
|
||||
case AssetUpload::FileOpenError:
|
||||
additionalError = "The file could not be opened. Please check your permissions and try again.";
|
||||
break;
|
||||
case AssetUpload::NetworkError:
|
||||
additionalError = "The file could not be opened. Please check your network connectivity.";
|
||||
break;
|
||||
default:
|
||||
// not handled, do not show a message box
|
||||
return;
|
||||
}
|
||||
auto entities = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
// display a message box with the error
|
||||
auto filename = QFileInfo(upload->getFilename()).fileName();
|
||||
QString errorMessage = QString("Failed to upload %1.\n\n%2").arg(filename, additionalError);
|
||||
QMessageBox::warning(_window, "Failed Upload", errorMessage);
|
||||
EntityItemProperties properties;
|
||||
properties.setType(EntityTypes::Model);
|
||||
properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(upload->getExtension()));
|
||||
properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f);
|
||||
properties.setName(QUrl(upload->getFilename()).fileName());
|
||||
|
||||
entities->addEntity(properties);
|
||||
|
||||
upload->deleteLater();
|
||||
} else {
|
||||
AssetUploadDialogFactory::getInstance().handleUploadFinished(upload, hash);
|
||||
}
|
||||
|
||||
auto entities = DependencyManager::get<EntityScriptingInterface>();
|
||||
auto myAvatar = getMyAvatar();
|
||||
|
||||
EntityItemProperties properties;
|
||||
properties.setType(EntityTypes::Model);
|
||||
properties.setModelURL(QString("%1:%2.%3").arg(ATP_SCHEME).arg(hash).arg(upload->getExtension()));
|
||||
properties.setPosition(myAvatar->getPosition() + myAvatar->getOrientation() * Vectors::FRONT * 2.0f);
|
||||
properties.setName(QUrl(upload->getFilename()).fileName());
|
||||
|
||||
entities->addEntity(properties);
|
||||
|
||||
upload->deleteLater();
|
||||
}
|
||||
|
||||
ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded,
|
||||
|
|
|
@ -211,7 +211,7 @@ public:
|
|||
void setScriptsLocation(const QString& scriptsLocation);
|
||||
|
||||
bool canAcceptURL(const QString& url);
|
||||
bool acceptURL(const QString& url);
|
||||
bool acceptURL(const QString& url, bool defaultUpload = false);
|
||||
|
||||
void setMaxOctreePacketsPerSecond(int maxOctreePPS);
|
||||
int getMaxOctreePacketsPerSecond();
|
||||
|
@ -274,7 +274,7 @@ public slots:
|
|||
void setRawAvatarUpdateThreading();
|
||||
void setRawAvatarUpdateThreading(bool isThreaded);
|
||||
|
||||
void resetSensors();
|
||||
void resetSensors(bool andReload = false);
|
||||
void setActiveFaceTracker();
|
||||
|
||||
#ifdef HAVE_IVIEWHMD
|
||||
|
@ -329,7 +329,7 @@ private slots:
|
|||
bool askToSetAvatarUrl(const QString& url);
|
||||
bool askToLoadScript(const QString& scriptFilenameOrURL);
|
||||
bool askToUploadAsset(const QString& asset);
|
||||
void assetUploadFinished(AssetUpload* upload, const QString& hash);
|
||||
void modelUploadFinished(AssetUpload* upload, const QString& hash);
|
||||
|
||||
void setSessionUUID(const QUuid& sessionUUID);
|
||||
void domainChanged(const QString& domainHostname);
|
||||
|
|
|
@ -461,6 +461,7 @@ Menu::Menu() {
|
|||
0, false,
|
||||
&ConnexionClient::getInstance(),
|
||||
SLOT(toggleConnexion(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true);
|
||||
|
||||
MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
|
||||
|
|
|
@ -159,6 +159,7 @@ namespace MenuOption {
|
|||
const QString CenterPlayerInView = "Center Player In View";
|
||||
const QString Chat = "Chat...";
|
||||
const QString Collisions = "Collisions";
|
||||
const QString ComfortMode = "Comfort Mode";
|
||||
const QString Connexion = "Activate 3D Connexion Devices";
|
||||
const QString Console = "Console...";
|
||||
const QString ControlWithSpeech = "Control With Speech";
|
||||
|
|
|
@ -144,7 +144,7 @@ void PluginContainerProxy::unsetFullscreen(const QScreen* avoid) {
|
|||
|
||||
void PluginContainerProxy::requestReset() {
|
||||
// We could signal qApp to sequence this, but it turns out that requestReset is only used from within the main thread anyway.
|
||||
qApp->resetSensors();
|
||||
qApp->resetSensors(true);
|
||||
}
|
||||
|
||||
void PluginContainerProxy::showDisplayPluginsTools() {
|
||||
|
|
|
@ -140,50 +140,54 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
return AvatarData::toByteArray(cullSmallChanges, sendAll);
|
||||
}
|
||||
|
||||
void MyAvatar::reset() {
|
||||
void MyAvatar::reset(bool andReload) {
|
||||
// Gather animation mode...
|
||||
// This should be simpler when we have only graph animations always on.
|
||||
bool isRig = _rig->getEnableRig();
|
||||
// seting rig animation to true, below, will clear the graph animation menu item, so grab it now.
|
||||
bool isGraph = _rig->getEnableAnimGraph() || Menu::getInstance()->isOptionChecked(MenuOption::EnableAnimGraph);
|
||||
// ... and get to sane configuration where other activity won't bother us.
|
||||
qApp->setRawAvatarUpdateThreading(false);
|
||||
_rig->disableHands = true;
|
||||
setEnableRigAnimations(true);
|
||||
if (andReload) {
|
||||
qApp->setRawAvatarUpdateThreading(false);
|
||||
_rig->disableHands = true;
|
||||
setEnableRigAnimations(true);
|
||||
}
|
||||
|
||||
// Reset dynamic state.
|
||||
_wasPushing = _isPushing = _isBraking = _billboardValid = _goToPending = _straighteningLean = false;
|
||||
_wasPushing = _isPushing = _isBraking = _billboardValid = _straighteningLean = false;
|
||||
_skeletonModel.reset();
|
||||
getHead()->reset();
|
||||
_targetVelocity = glm::vec3(0.0f);
|
||||
setThrust(glm::vec3(0.0f));
|
||||
|
||||
// Get fresh data, in case we're really slow and out of wack.
|
||||
_hmdSensorMatrix = qApp->getHMDSensorPose();
|
||||
_hmdSensorPosition = extractTranslation(_hmdSensorMatrix);
|
||||
_hmdSensorOrientation = glm::quat_cast(_hmdSensorMatrix);
|
||||
if (andReload) {
|
||||
// Get fresh data, in case we're really slow and out of wack.
|
||||
_hmdSensorMatrix = qApp->getHMDSensorPose();
|
||||
_hmdSensorPosition = extractTranslation(_hmdSensorMatrix);
|
||||
_hmdSensorOrientation = glm::quat_cast(_hmdSensorMatrix);
|
||||
|
||||
// Reset body position/orientation under the head.
|
||||
auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation..
|
||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||
glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||
glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
||||
// Reset body position/orientation under the head.
|
||||
auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation..
|
||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||
glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||
glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
||||
|
||||
// FIXME: Hack to retain the previous behavior wrt height.
|
||||
// I'd like to make the body match head height, but that will have to wait for separate PR.
|
||||
worldBodyPos.y = getPosition().y;
|
||||
// FIXME: Hack to retain the previous behavior wrt height.
|
||||
// I'd like to make the body match head height, but that will have to wait for separate PR.
|
||||
worldBodyPos.y = getPosition().y;
|
||||
|
||||
setPosition(worldBodyPos);
|
||||
setOrientation(worldBodyRot);
|
||||
// If there is any discrepency between positioning and the head (as there is in initial deriveBodyFromHMDSensor),
|
||||
// we can make that right by setting _bodySensorMatrix = newBodySensorMatrix.
|
||||
// However, doing so will make the head want to point to the previous body orientation, as cached above.
|
||||
//_bodySensorMatrix = newBodySensorMatrix;
|
||||
//updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes
|
||||
setPosition(worldBodyPos);
|
||||
setOrientation(worldBodyRot);
|
||||
// If there is any discrepency between positioning and the head (as there is in initial deriveBodyFromHMDSensor),
|
||||
// we can make that right by setting _bodySensorMatrix = newBodySensorMatrix.
|
||||
// However, doing so will make the head want to point to the previous body orientation, as cached above.
|
||||
//_bodySensorMatrix = newBodySensorMatrix;
|
||||
//updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes
|
||||
|
||||
_skeletonModel.simulate(0.1f); // non-zero
|
||||
setEnableRigAnimations(false);
|
||||
_skeletonModel.simulate(0.1f);
|
||||
_skeletonModel.simulate(0.1f); // non-zero
|
||||
setEnableRigAnimations(false);
|
||||
_skeletonModel.simulate(0.1f);
|
||||
}
|
||||
if (isRig) {
|
||||
setEnableRigAnimations(true);
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::EnableRigAnimations, true);
|
||||
|
@ -191,8 +195,10 @@ void MyAvatar::reset() {
|
|||
setEnableAnimGraph(true);
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::EnableAnimGraph, true);
|
||||
}
|
||||
_rig->disableHands = false;
|
||||
qApp->setRawAvatarUpdateThreading();
|
||||
if (andReload) {
|
||||
_rig->disableHands = false;
|
||||
qApp->setRawAvatarUpdateThreading();
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::update(float deltaTime) {
|
||||
|
@ -1514,33 +1520,69 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
|||
|
||||
void MyAvatar::updateOrientation(float deltaTime) {
|
||||
// Smoothly rotate body with arrow keys
|
||||
float targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED;
|
||||
if (targetSpeed != 0.0f) {
|
||||
const float ROTATION_RAMP_TIMESCALE = 0.1f;
|
||||
float blend = deltaTime / ROTATION_RAMP_TIMESCALE;
|
||||
if (blend > 1.0f) {
|
||||
blend = 1.0f;
|
||||
}
|
||||
_bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed;
|
||||
} else if (_bodyYawDelta != 0.0f) {
|
||||
// attenuate body rotation speed
|
||||
const float ROTATION_DECAY_TIMESCALE = 0.05f;
|
||||
float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE;
|
||||
if (attenuation < 0.0f) {
|
||||
attenuation = 0.0f;
|
||||
}
|
||||
_bodyYawDelta *= attenuation;
|
||||
float targetSpeed = 0.0f;
|
||||
|
||||
// FIXME - this comfort mode code is a total hack, remove it when we have new input mapping
|
||||
bool isComfortMode = Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode);
|
||||
bool isHMDMode = qApp->getAvatarUpdater()->isHMDMode();
|
||||
|
||||
if (!isHMDMode || !isComfortMode) {
|
||||
targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED;
|
||||
|
||||
if (targetSpeed != 0.0f) {
|
||||
const float ROTATION_RAMP_TIMESCALE = 0.1f;
|
||||
float blend = deltaTime / ROTATION_RAMP_TIMESCALE;
|
||||
if (blend > 1.0f) {
|
||||
blend = 1.0f;
|
||||
}
|
||||
_bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed;
|
||||
} else if (_bodyYawDelta != 0.0f) {
|
||||
// attenuate body rotation speed
|
||||
const float ROTATION_DECAY_TIMESCALE = 0.05f;
|
||||
float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE;
|
||||
if (attenuation < 0.0f) {
|
||||
attenuation = 0.0f;
|
||||
}
|
||||
_bodyYawDelta *= attenuation;
|
||||
|
||||
float MINIMUM_ROTATION_RATE = 2.0f;
|
||||
if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) {
|
||||
_bodyYawDelta = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// update body orientation by movement inputs
|
||||
setOrientation(getOrientation() *
|
||||
glm::quat(glm::radians(glm::vec3(0.0f, _bodyYawDelta * deltaTime, 0.0f))));
|
||||
|
||||
} else {
|
||||
// Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
|
||||
// get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
|
||||
// snap turn every half second.
|
||||
_bodyYawDelta = 0.0f;
|
||||
|
||||
static quint64 lastPulse = 0;
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second
|
||||
|
||||
float driveLeft = _driveKeys[ROT_LEFT];
|
||||
float driveRight= _driveKeys[ROT_RIGHT];
|
||||
|
||||
if ((driveLeft != 0.0f || driveRight != 0.0f) && (now - lastPulse > COMFORT_MODE_PULSE_TIMING)) {
|
||||
lastPulse = now;
|
||||
|
||||
const float SNAP_TURN_DELTA = 15.0f; // degrees
|
||||
float direction = (driveLeft - driveRight) < 0.0f ? -1.0f : 1.0f;
|
||||
float turnAmount = direction * SNAP_TURN_DELTA;
|
||||
|
||||
// update body orientation by movement inputs
|
||||
setOrientation(getOrientation() *
|
||||
glm::quat(glm::radians(glm::vec3(0.0f, turnAmount, 0.0f))));
|
||||
|
||||
float MINIMUM_ROTATION_RATE = 2.0f;
|
||||
if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) {
|
||||
_bodyYawDelta = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
getHead()->setBasePitch(getHead()->getBasePitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime);
|
||||
// update body orientation by movement inputs
|
||||
setOrientation(getOrientation() *
|
||||
glm::quat(glm::radians(glm::vec3(0.0f, _bodyYawDelta * deltaTime, 0.0f))));
|
||||
|
||||
if (qApp->getAvatarUpdater()->isHMDMode()) {
|
||||
glm::quat orientation = glm::quat_cast(getSensorToWorldMatrix()) * getHMDSensorOrientation();
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
AudioListenerMode getAudioListenerModeCamera() const { return FROM_CAMERA; }
|
||||
AudioListenerMode getAudioListenerModeCustom() const { return CUSTOM; }
|
||||
|
||||
void reset();
|
||||
void reset(bool andReload = false);
|
||||
void update(float deltaTime);
|
||||
void preRender(RenderArgs* renderArgs);
|
||||
|
||||
|
|
|
@ -391,6 +391,19 @@ QString ControllerScriptingInterface::sanatizeName(const QString& name) {
|
|||
|
||||
void ControllerScriptingInterface::wireUpControllers(ScriptEngine* engine) {
|
||||
|
||||
// Controller.Standard.*
|
||||
auto standardDevice = DependencyManager::get<UserInputMapper>()->getStandardDevice();
|
||||
if (standardDevice) {
|
||||
auto deviceName = sanatizeName(standardDevice->getName());
|
||||
auto deviceInputs = standardDevice->getAvailabeInputs();
|
||||
for (const auto& inputMapping : deviceInputs) {
|
||||
auto input = inputMapping.first;
|
||||
auto inputName = sanatizeName(inputMapping.second);
|
||||
QString deviceInputName{ "Controller." + deviceName + "." + inputName };
|
||||
engine->registerValue(deviceInputName, input.getID());
|
||||
}
|
||||
}
|
||||
|
||||
// Controller.Hardware.*
|
||||
auto devices = DependencyManager::get<UserInputMapper>()->getDevices();
|
||||
for(const auto& deviceMapping : devices) {
|
||||
|
|
|
@ -11,11 +11,6 @@
|
|||
|
||||
#include "AssetUploadDialogFactory.h"
|
||||
|
||||
#include <AssetClient.h>
|
||||
#include <AssetUpload.h>
|
||||
#include <AssetUtils.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtWidgets/QDialogButtonBox>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
|
@ -24,6 +19,12 @@
|
|||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
|
||||
#include <AssetClient.h>
|
||||
#include <AssetUpload.h>
|
||||
#include <AssetUtils.h>
|
||||
#include <NodeList.h>
|
||||
#include <ResourceManager.h>
|
||||
|
||||
AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() {
|
||||
static AssetUploadDialogFactory staticInstance;
|
||||
return staticInstance;
|
||||
|
@ -85,7 +86,7 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q
|
|||
// setup the line edit to hold the copiable text
|
||||
QLineEdit* lineEdit = new QLineEdit;
|
||||
|
||||
QString atpURL = QString("%1:%2.%3").arg(ATP_SCHEME).arg(hash).arg(upload->getExtension());
|
||||
QString atpURL = QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(upload->getExtension());
|
||||
|
||||
// set the ATP URL as the text value so it's copiable
|
||||
lineEdit->insert(atpURL);
|
||||
|
|
|
@ -30,7 +30,6 @@ public:
|
|||
|
||||
public slots:
|
||||
void showDialog();
|
||||
private slots:
|
||||
void handleUploadFinished(AssetUpload* upload, const QString& hash);
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
set(TARGET_NAME animation)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Script)
|
||||
|
||||
link_hifi_libraries(shared gpu model fbx)
|
||||
|
|
|
@ -56,9 +56,9 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con
|
|||
}
|
||||
|
||||
void AnimInverseKinematics::setTargetVars(
|
||||
const QString& jointName,
|
||||
const QString& positionVar,
|
||||
const QString& rotationVar,
|
||||
const QString& jointName,
|
||||
const QString& positionVar,
|
||||
const QString& rotationVar,
|
||||
const QString& typeVar) {
|
||||
// if there are dups, last one wins.
|
||||
bool found = false;
|
||||
|
@ -95,14 +95,20 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
|
|||
}
|
||||
} else {
|
||||
IKTarget target;
|
||||
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
||||
target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans);
|
||||
target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
|
||||
target.setType(animVars.lookup(targetVar.typeVar, QString("")));
|
||||
target.index = targetVar.jointIndex;
|
||||
targets.push_back(target);
|
||||
if (target.index > _maxTargetIndex) {
|
||||
_maxTargetIndex = target.index;
|
||||
target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition));
|
||||
if (target.getType() != IKTarget::Type::Unknown) {
|
||||
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
||||
glm::quat rotation = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
|
||||
glm::vec3 translation = animVars.lookup(targetVar.positionVar, defaultPose.trans);
|
||||
if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) {
|
||||
translation += _hipsOffset;
|
||||
}
|
||||
target.setPose(rotation, translation);
|
||||
target.setIndex(targetVar.jointIndex);
|
||||
targets.push_back(target);
|
||||
if (targetVar.jointIndex > _maxTargetIndex) {
|
||||
_maxTargetIndex = targetVar.jointIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,107 +147,116 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
|||
do {
|
||||
int lowestMovedIndex = _relativePoses.size();
|
||||
for (auto& target: targets) {
|
||||
if (target.type == IKTarget::Type::RotationOnly) {
|
||||
IKTarget::Type targetType = target.getType();
|
||||
if (targetType == IKTarget::Type::RotationOnly) {
|
||||
// the final rotation will be enforced after the iterations
|
||||
continue;
|
||||
}
|
||||
AnimPose targetPose = target.pose;
|
||||
|
||||
// cache tip absolute transform
|
||||
int tipIndex = target.index;
|
||||
int tipIndex = target.getIndex();
|
||||
int pivotIndex = _skeleton->getParentIndex(tipIndex);
|
||||
if (pivotIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
int pivotsParentIndex = _skeleton->getParentIndex(pivotIndex);
|
||||
if (pivotsParentIndex == -1) {
|
||||
// TODO?: handle case where tip's parent is root?
|
||||
continue;
|
||||
}
|
||||
|
||||
glm::vec3 tipPosition = absolutePoses[tipIndex].trans;
|
||||
glm::quat tipRotation = absolutePoses[tipIndex].rot;
|
||||
|
||||
// cache tip's parent's absolute rotation so we can recompute the tip's parent-relative
|
||||
// cache tip's parent's absolute rotation so we can recompute the tip's parent-relative
|
||||
// as we proceed walking down the joint chain
|
||||
int pivotIndex = _skeleton->getParentIndex(tipIndex);
|
||||
glm::quat tipParentRotation;
|
||||
if (pivotIndex != -1) {
|
||||
tipParentRotation = absolutePoses[pivotIndex].rot;
|
||||
}
|
||||
glm::quat tipParentRotation = absolutePoses[pivotIndex].rot;
|
||||
|
||||
// descend toward root, pivoting each joint to get tip closer to target
|
||||
int ancestorCount = 1;
|
||||
while (pivotIndex != -1) {
|
||||
while (pivotsParentIndex != -1) {
|
||||
// compute the two lines that should be aligned
|
||||
glm::vec3 jointPosition = absolutePoses[pivotIndex].trans;
|
||||
glm::vec3 leverArm = tipPosition - jointPosition;
|
||||
glm::vec3 targetLine = targetPose.trans - jointPosition;
|
||||
|
||||
// compute the swing that would get get tip closer
|
||||
glm::vec3 axis = glm::cross(leverArm, targetLine);
|
||||
float axisLength = glm::length(axis);
|
||||
glm::quat deltaRotation;
|
||||
const float MIN_AXIS_LENGTH = 1.0e-4f;
|
||||
if (axisLength > MIN_AXIS_LENGTH) {
|
||||
// compute deltaRotation for alignment (swings tip closer to target)
|
||||
axis /= axisLength;
|
||||
float angle = acosf(glm::dot(leverArm, targetLine) / (glm::length(leverArm) * glm::length(targetLine)));
|
||||
if (targetType == IKTarget::Type::RotationAndPosition ||
|
||||
targetType == IKTarget::Type::HipsRelativeRotationAndPosition) {
|
||||
// compute the swing that would get get tip closer
|
||||
glm::vec3 targetLine = target.getTranslation() - jointPosition;
|
||||
glm::vec3 axis = glm::cross(leverArm, targetLine);
|
||||
float axisLength = glm::length(axis);
|
||||
const float MIN_AXIS_LENGTH = 1.0e-4f;
|
||||
if (axisLength > MIN_AXIS_LENGTH) {
|
||||
// compute deltaRotation for alignment (swings tip closer to target)
|
||||
axis /= axisLength;
|
||||
float angle = acosf(glm::dot(leverArm, targetLine) / (glm::length(leverArm) * glm::length(targetLine)));
|
||||
|
||||
// NOTE: even when axisLength is not zero (e.g. lever-arm and pivot-arm are not quite aligned) it is
|
||||
// still possible for the angle to be zero so we also check that to avoid unnecessary calculations.
|
||||
const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f;
|
||||
if (angle > MIN_ADJUSTMENT_ANGLE) {
|
||||
// reduce angle by a fraction (reduces IK swing contribution of this joint)
|
||||
angle /= (float)ancestorCount;
|
||||
deltaRotation = glm::angleAxis(angle, axis);
|
||||
}
|
||||
// NOTE: even when axisLength is not zero (e.g. lever-arm and pivot-arm are not quite aligned) it is
|
||||
// still possible for the angle to be zero so we also check that to avoid unnecessary calculations.
|
||||
const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f;
|
||||
if (angle > MIN_ADJUSTMENT_ANGLE) {
|
||||
// reduce angle by a fraction (for stability)
|
||||
const float fraction = 0.5f;
|
||||
angle *= fraction;
|
||||
deltaRotation = glm::angleAxis(angle, axis);
|
||||
|
||||
// The swing will re-orient the tip but there will tend to be be a non-zero delta between the tip's
|
||||
// new rotation and its target. We compute that delta here and rotate the tipJoint accordingly.
|
||||
glm::quat tipRelativeRotation = glm::inverse(deltaRotation * tipParentRotation) * targetPose.rot;
|
||||
// The swing will re-orient the tip but there will tend to be be a non-zero delta between the tip's
|
||||
// new rotation and its target. This is the final parent-relative rotation that the tip joint have
|
||||
// make to achieve its target rotation.
|
||||
glm::quat tipRelativeRotation = glm::inverse(deltaRotation * tipParentRotation) * target.getRotation();
|
||||
|
||||
// enforce tip's constraint
|
||||
RotationConstraint* constraint = getConstraint(tipIndex);
|
||||
if (constraint) {
|
||||
bool constrained = constraint->apply(tipRelativeRotation);
|
||||
if (constrained) {
|
||||
// The tip's final parent-relative rotation violates its constraint
|
||||
// so we try to twist this pivot to compensate.
|
||||
glm::quat constrainedTipRotation = deltaRotation * tipParentRotation * tipRelativeRotation;
|
||||
glm::quat missingRotation = targetPose.rot * glm::inverse(constrainedTipRotation);
|
||||
glm::quat swingPart;
|
||||
glm::quat twistPart;
|
||||
glm::vec3 axis = glm::normalize(deltaRotation * leverArm);
|
||||
swingTwistDecomposition(missingRotation, axis, swingPart, twistPart);
|
||||
deltaRotation = twistPart * deltaRotation;
|
||||
}
|
||||
// we update the tip rotation here to rotate it as close to its target orientation as possible
|
||||
// before moving on to next pivot
|
||||
tipRotation = tipParentRotation * tipRelativeRotation;
|
||||
}
|
||||
}
|
||||
++ancestorCount;
|
||||
|
||||
int parentIndex = _skeleton->getParentIndex(pivotIndex);
|
||||
if (parentIndex == -1) {
|
||||
// TODO? apply constraints to root?
|
||||
// TODO? harvest the root's transform as movement of entire skeleton?
|
||||
} else {
|
||||
// compute joint's new parent-relative rotation after swing
|
||||
// Q' = dQ * Q and Q = Qp * q --> q' = Qp^ * dQ * Q
|
||||
glm::quat newRot = glm::normalize(glm::inverse(
|
||||
absolutePoses[parentIndex].rot) *
|
||||
deltaRotation *
|
||||
absolutePoses[pivotIndex].rot);
|
||||
|
||||
// enforce pivot's constraint
|
||||
RotationConstraint* constraint = getConstraint(pivotIndex);
|
||||
if (constraint) {
|
||||
bool constrained = constraint->apply(newRot);
|
||||
if (constrained) {
|
||||
// the constraint will modify the movement of the tip so we have to compute the modified
|
||||
// model-frame deltaRotation
|
||||
// Q' = Qp^ * dQ * Q --> dQ = Qp * Q' * Q^
|
||||
deltaRotation = absolutePoses[parentIndex].rot *
|
||||
newRot *
|
||||
glm::inverse(absolutePoses[pivotIndex].rot);
|
||||
// enforce tip's constraint
|
||||
RotationConstraint* constraint = getConstraint(tipIndex);
|
||||
if (constraint) {
|
||||
bool constrained = constraint->apply(tipRelativeRotation);
|
||||
if (constrained) {
|
||||
// The tip's final parent-relative rotation would violate its constraint
|
||||
// so we try to pre-twist this pivot to compensate.
|
||||
glm::quat constrainedTipRotation = deltaRotation * tipParentRotation * tipRelativeRotation;
|
||||
glm::quat missingRotation = target.getRotation() * glm::inverse(constrainedTipRotation);
|
||||
glm::quat swingPart;
|
||||
glm::quat twistPart;
|
||||
glm::vec3 axis = glm::normalize(deltaRotation * leverArm);
|
||||
swingTwistDecomposition(missingRotation, axis, swingPart, twistPart);
|
||||
float dotSign = copysignf(1.0f, twistPart.w);
|
||||
deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * twistPart, fraction)) * deltaRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// store the rotation change in the accumulator
|
||||
_accumulators[pivotIndex].add(newRot);
|
||||
} else if (targetType == IKTarget::Type::HmdHead) {
|
||||
// An HmdHead target slaves the orientation of the end-effector by distributing rotation
|
||||
// deltas up the hierarchy. Its target position is enforced later by shifting the hips.
|
||||
deltaRotation = target.getRotation() * glm::inverse(tipRotation);
|
||||
float dotSign = copysignf(1.0f, deltaRotation.w);
|
||||
const float ANGLE_DISTRIBUTION_FACTOR = 0.15f;
|
||||
deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * deltaRotation, ANGLE_DISTRIBUTION_FACTOR));
|
||||
}
|
||||
|
||||
// compute joint's new parent-relative rotation after swing
|
||||
// Q' = dQ * Q and Q = Qp * q --> q' = Qp^ * dQ * Q
|
||||
glm::quat newRot = glm::normalize(glm::inverse(
|
||||
absolutePoses[pivotsParentIndex].rot) *
|
||||
deltaRotation *
|
||||
absolutePoses[pivotIndex].rot);
|
||||
|
||||
// enforce pivot's constraint
|
||||
RotationConstraint* constraint = getConstraint(pivotIndex);
|
||||
if (constraint) {
|
||||
bool constrained = constraint->apply(newRot);
|
||||
if (constrained) {
|
||||
// the constraint will modify the movement of the tip so we have to compute the modified
|
||||
// model-frame deltaRotation
|
||||
// Q' = Qp^ * dQ * Q --> dQ = Qp * Q' * Q^
|
||||
deltaRotation = absolutePoses[pivotsParentIndex].rot *
|
||||
newRot *
|
||||
glm::inverse(absolutePoses[pivotIndex].rot);
|
||||
}
|
||||
}
|
||||
|
||||
// store the rotation change in the accumulator
|
||||
_accumulators[pivotIndex].add(newRot);
|
||||
|
||||
// this joint has been changed so we check to see if it has the lowest index
|
||||
if (pivotIndex < lowestMovedIndex) {
|
||||
lowestMovedIndex = pivotIndex;
|
||||
|
@ -252,7 +267,8 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
|||
tipRotation = glm::normalize(deltaRotation * tipRotation);
|
||||
tipParentRotation = glm::normalize(deltaRotation * tipParentRotation);
|
||||
|
||||
pivotIndex = _skeleton->getParentIndex(pivotIndex);
|
||||
pivotIndex = pivotsParentIndex;
|
||||
pivotsParentIndex = _skeleton->getParentIndex(pivotIndex);
|
||||
}
|
||||
}
|
||||
++numLoops;
|
||||
|
@ -275,26 +291,15 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
|||
}
|
||||
} while (numLoops < MAX_IK_LOOPS);
|
||||
|
||||
/* KEEP: example code for measuring endeffector error of IK solution
|
||||
for (uint32_t i = 0; i < targets.size(); ++i) {
|
||||
auto& target = targets[i];
|
||||
if (target.type == IKTarget::Type::RotationOnly) {
|
||||
continue;
|
||||
}
|
||||
glm::vec3 tipPosition = absolutePoses[target.index].trans;
|
||||
std::cout << i << " IK error = " << glm::distance(tipPosition, target.pose.trans) << std::endl;
|
||||
}
|
||||
*/
|
||||
|
||||
// finally set the relative rotation of each tip to agree with absolute target rotation
|
||||
for (auto& target: targets) {
|
||||
int tipIndex = target.index;
|
||||
int tipIndex = target.getIndex();
|
||||
int parentIndex = _skeleton->getParentIndex(tipIndex);
|
||||
if (parentIndex != -1) {
|
||||
AnimPose targetPose = target.pose;
|
||||
const glm::quat& targetRotation = target.getRotation();
|
||||
// compute tip's new parent-relative rotation
|
||||
// Q = Qp * q --> q' = Qp^ * Q
|
||||
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot;
|
||||
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetRotation;
|
||||
RotationConstraint* constraint = getConstraint(tipIndex);
|
||||
if (constraint) {
|
||||
constraint->apply(newRelativeRotation);
|
||||
|
@ -303,7 +308,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
|||
// to help this rotation target get met.
|
||||
}
|
||||
_relativePoses[tipIndex].rot = newRelativeRotation;
|
||||
absolutePoses[tipIndex].rot = targetPose.rot;
|
||||
absolutePoses[tipIndex].rot = targetRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +328,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
|||
// relax toward underpose
|
||||
// HACK: this relaxation needs to be constant per-frame rather than per-realtime
|
||||
// in order to prevent IK "flutter" for bad FPS. The bad news is that the good parts
|
||||
// of this relaxation will be FPS dependent (low FPS will make the limbs align slower
|
||||
// of this relaxation will be FPS dependent (low FPS will make the limbs align slower
|
||||
// in real-time), however most people will not notice this and this problem is less
|
||||
// annoying than the flutter.
|
||||
const float blend = (1.0f / 60.0f) / (0.25f); // effectively: dt / RELAXATION_TIMESCALE
|
||||
|
@ -343,7 +348,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
|||
// build a list of targets from _targetVarVec
|
||||
std::vector<IKTarget> targets;
|
||||
computeTargets(animVars, targets, underPoses);
|
||||
|
||||
|
||||
if (targets.empty()) {
|
||||
// no IK targets but still need to enforce constraints
|
||||
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
|
||||
|
@ -355,7 +360,50 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
|||
++constraintItr;
|
||||
}
|
||||
} else {
|
||||
// shift the hips according to the offset from the previous frame
|
||||
float offsetLength = glm::length(_hipsOffset);
|
||||
const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
|
||||
if (offsetLength > MIN_HIPS_OFFSET_LENGTH) {
|
||||
// but only if offset is long enough
|
||||
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
||||
_relativePoses[0].trans = underPoses[0].trans + scaleFactor * _hipsOffset;
|
||||
}
|
||||
|
||||
solveWithCyclicCoordinateDescent(targets);
|
||||
|
||||
// compute the new target hips offset (for next frame)
|
||||
// by looking for discrepancies between where a targeted endEffector is
|
||||
// and where it wants to be (after IK solutions are done)
|
||||
glm::vec3 newHipsOffset = Vectors::ZERO;
|
||||
for (auto& target: targets) {
|
||||
int targetIndex = target.getIndex();
|
||||
if (targetIndex == _headIndex && _headIndex != -1) {
|
||||
// special handling for headTarget
|
||||
if (target.getType() == IKTarget::Type::RotationOnly) {
|
||||
// we want to shift the hips to bring the underpose closer
|
||||
// to where the head happens to be (overpose)
|
||||
glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans;
|
||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans;
|
||||
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
|
||||
newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under);
|
||||
} else if (target.getType() == IKTarget::Type::HmdHead) {
|
||||
// we want to shift the hips to bring the head to its designated position
|
||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans;
|
||||
_hipsOffset += target.getTranslation() - actual;
|
||||
// and ignore all other targets
|
||||
newHipsOffset = _hipsOffset;
|
||||
break;
|
||||
}
|
||||
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans;
|
||||
glm::vec3 targetPosition = target.getTranslation();
|
||||
newHipsOffset += targetPosition - actualPosition;
|
||||
}
|
||||
}
|
||||
|
||||
// smooth transitions by relaxing _hipsOffset toward the new value
|
||||
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f;
|
||||
_hipsOffset += (newHipsOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE);
|
||||
}
|
||||
}
|
||||
return _relativePoses;
|
||||
|
@ -477,7 +525,7 @@ void AnimInverseKinematics::initConstraints() {
|
|||
stConstraint->setSwingLimits(minDots);
|
||||
|
||||
constraint = static_cast<RotationConstraint*>(stConstraint);
|
||||
} else if (0 == baseName.compare("UpLegXXX", Qt::CaseInsensitive)) {
|
||||
} else if (0 == baseName.compare("UpLeg", Qt::CaseInsensitive)) {
|
||||
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
||||
stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f);
|
||||
|
@ -581,7 +629,7 @@ void AnimInverseKinematics::initConstraints() {
|
|||
} else if (0 == baseName.compare("Neck", Qt::CaseInsensitive)) {
|
||||
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
||||
const float MAX_NECK_TWIST = PI / 2.0f;
|
||||
const float MAX_NECK_TWIST = PI / 4.0f;
|
||||
stConstraint->setTwistLimits(-MAX_NECK_TWIST, MAX_NECK_TWIST);
|
||||
|
||||
std::vector<float> minDots;
|
||||
|
@ -589,6 +637,18 @@ void AnimInverseKinematics::initConstraints() {
|
|||
minDots.push_back(cosf(MAX_NECK_SWING));
|
||||
stConstraint->setSwingLimits(minDots);
|
||||
|
||||
constraint = static_cast<RotationConstraint*>(stConstraint);
|
||||
} else if (0 == baseName.compare("Head", Qt::CaseInsensitive)) {
|
||||
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
||||
const float MAX_HEAD_TWIST = PI / 4.0f;
|
||||
stConstraint->setTwistLimits(-MAX_HEAD_TWIST, MAX_HEAD_TWIST);
|
||||
|
||||
std::vector<float> minDots;
|
||||
const float MAX_HEAD_SWING = PI / 4.0f;
|
||||
minDots.push_back(cosf(MAX_HEAD_SWING));
|
||||
stConstraint->setSwingLimits(minDots);
|
||||
|
||||
constraint = static_cast<RotationConstraint*>(stConstraint);
|
||||
} else if (0 == baseName.compare("ForeArm", Qt::CaseInsensitive)) {
|
||||
// The elbow joint rotates about the parent-frame's zAxis (-zAxis) for the Right (Left) arm.
|
||||
|
@ -621,7 +681,7 @@ void AnimInverseKinematics::initConstraints() {
|
|||
eConstraint->setAngleLimits(minAngle, maxAngle);
|
||||
|
||||
constraint = static_cast<RotationConstraint*>(eConstraint);
|
||||
} else if (0 == baseName.compare("LegXXX", Qt::CaseInsensitive)) {
|
||||
} else if (0 == baseName.compare("Leg", Qt::CaseInsensitive)) {
|
||||
// The knee joint rotates about the parent-frame's -xAxis.
|
||||
ElbowConstraint* eConstraint = new ElbowConstraint();
|
||||
glm::quat referenceRotation = _defaultRelativePoses[i].rot;
|
||||
|
@ -652,7 +712,7 @@ void AnimInverseKinematics::initConstraints() {
|
|||
eConstraint->setAngleLimits(minAngle, maxAngle);
|
||||
|
||||
constraint = static_cast<RotationConstraint*>(eConstraint);
|
||||
} else if (0 == baseName.compare("FootXXX", Qt::CaseInsensitive)) {
|
||||
} else if (0 == baseName.compare("Foot", Qt::CaseInsensitive)) {
|
||||
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
||||
stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f);
|
||||
|
@ -697,7 +757,9 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
|
|||
|
||||
if (skeleton) {
|
||||
initConstraints();
|
||||
_headIndex = _skeleton->nameToJointIndex("Head");
|
||||
} else {
|
||||
clearConstraints();
|
||||
_headIndex = -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "AnimNode.h"
|
||||
#include "IKTarget.h"
|
||||
|
||||
#include "RotationAccumulator.h"
|
||||
|
||||
|
@ -37,18 +38,6 @@ public:
|
|||
virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override;
|
||||
|
||||
protected:
|
||||
struct IKTarget {
|
||||
enum class Type {
|
||||
RotationAndPosition,
|
||||
RotationOnly
|
||||
};
|
||||
AnimPose pose;
|
||||
int index;
|
||||
Type type = Type::RotationAndPosition;
|
||||
|
||||
void setType(const QString& typeVar) { type = ((typeVar == "RotationOnly") ? Type::RotationOnly : Type::RotationAndPosition); }
|
||||
};
|
||||
|
||||
void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
|
||||
void solveWithCyclicCoordinateDescent(const std::vector<IKTarget>& targets);
|
||||
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
|
||||
|
@ -60,6 +49,10 @@ protected:
|
|||
void clearConstraints();
|
||||
void initConstraints();
|
||||
|
||||
// no copies
|
||||
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
||||
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
|
||||
|
||||
struct IKTargetVar {
|
||||
IKTargetVar(const QString& jointNameIn,
|
||||
const QString& positionVarIn,
|
||||
|
@ -85,9 +78,9 @@ protected:
|
|||
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
|
||||
AnimPoseVec _relativePoses; // current relative poses
|
||||
|
||||
// no copies
|
||||
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
||||
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
|
||||
// experimental data for moving hips during IK
|
||||
int _headIndex = -1;
|
||||
glm::vec3 _hipsOffset = Vectors::ZERO;
|
||||
|
||||
// _maxTargetIndex is tracked to help optimize the recalculation of absolute poses
|
||||
// during the the cyclic coordinate descent algorithm
|
||||
|
|
34
libraries/animation/src/IKTarget.cpp
Normal file
34
libraries/animation/src/IKTarget.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// IKTarget.cpp
|
||||
//
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "IKTarget.h"
|
||||
|
||||
void IKTarget::setPose(const glm::quat& rotation, const glm::vec3& translation) {
|
||||
_pose.rot = rotation;
|
||||
_pose.trans = translation;
|
||||
}
|
||||
|
||||
void IKTarget::setType(int type) {
|
||||
switch (type) {
|
||||
case (int)Type::RotationAndPosition:
|
||||
_type = Type::RotationAndPosition;
|
||||
break;
|
||||
case (int)Type::RotationOnly:
|
||||
_type = Type::RotationOnly;
|
||||
break;
|
||||
case (int)Type::HmdHead:
|
||||
_type = Type::HmdHead;
|
||||
break;
|
||||
case (int)Type::HipsRelativeRotationAndPosition:
|
||||
_type = Type::HipsRelativeRotationAndPosition;
|
||||
break;
|
||||
default:
|
||||
_type = Type::Unknown;
|
||||
}
|
||||
}
|
43
libraries/animation/src/IKTarget.h
Normal file
43
libraries/animation/src/IKTarget.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// IKTarget.h
|
||||
//
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_IKTarget_h
|
||||
#define hifi_IKTarget_h
|
||||
|
||||
#include "AnimSkeleton.h"
|
||||
|
||||
class IKTarget {
|
||||
public:
|
||||
enum class Type {
|
||||
RotationAndPosition,
|
||||
RotationOnly,
|
||||
HmdHead,
|
||||
HipsRelativeRotationAndPosition,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
IKTarget() {}
|
||||
|
||||
const glm::vec3& getTranslation() const { return _pose.trans; }
|
||||
const glm::quat& getRotation() const { return _pose.rot; }
|
||||
int getIndex() const { return _index; }
|
||||
Type getType() const { return _type; }
|
||||
|
||||
void setPose(const glm::quat& rotation, const glm::vec3& translation);
|
||||
void setIndex(int index) { _index = index; }
|
||||
void setType(int);
|
||||
|
||||
private:
|
||||
AnimPose _pose;
|
||||
int _index = -1;
|
||||
Type _type = Type::RotationAndPosition;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_IKTarget_h
|
|
@ -14,13 +14,14 @@
|
|||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <queue>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include <NumericalConstants.h>
|
||||
#include <DebugDraw.h>
|
||||
|
||||
#include "AnimationHandle.h"
|
||||
#include "AnimationLogging.h"
|
||||
#include "AnimSkeleton.h"
|
||||
#include "DebugDraw.h"
|
||||
#include "IKTarget.h"
|
||||
|
||||
#include "Rig.h"
|
||||
|
||||
void Rig::HeadParameters::dump() const {
|
||||
qCDebug(animation, "HeadParameters =");
|
||||
|
@ -1057,9 +1058,11 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
|
|||
|
||||
_animVars.set("headPosition", headPos);
|
||||
_animVars.set("headRotation", headRot);
|
||||
_animVars.set("headAndNeckType", QString("RotationAndPosition"));
|
||||
_animVars.set("headType", (int)IKTarget::Type::HmdHead);
|
||||
_animVars.set("neckPosition", neckPos);
|
||||
_animVars.set("neckRotation", neckRot);
|
||||
//_animVars.set("neckType", (int)IKTarget::Type::RotationOnly);
|
||||
_animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -1070,9 +1073,11 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
|
|||
|
||||
_animVars.unset("headPosition");
|
||||
_animVars.set("headRotation", realLocalHeadOrientation);
|
||||
_animVars.set("headAndNeckType", QString("RotationOnly"));
|
||||
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly);
|
||||
_animVars.set("headType", (int)IKTarget::Type::RotationOnly);
|
||||
_animVars.unset("neckPosition");
|
||||
_animVars.unset("neckRotation");
|
||||
_animVars.set("neckType", (int)IKTarget::Type::RotationOnly);
|
||||
}
|
||||
} else if (!_enableAnimGraph) {
|
||||
|
||||
|
@ -1130,16 +1135,20 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
|
|||
if (params.isLeftEnabled) {
|
||||
_animVars.set("leftHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.leftPosition);
|
||||
_animVars.set("leftHandRotation", rootBindPose.rot * yFlipHACK * params.leftOrientation);
|
||||
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||
} else {
|
||||
_animVars.unset("leftHandPosition");
|
||||
_animVars.unset("leftHandRotation");
|
||||
_animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
|
||||
}
|
||||
if (params.isRightEnabled) {
|
||||
_animVars.set("rightHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.rightPosition);
|
||||
_animVars.set("rightHandRotation", rootBindPose.rot * yFlipHACK * params.rightOrientation);
|
||||
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||
} else {
|
||||
_animVars.unset("rightHandPosition");
|
||||
_animVars.unset("rightHandRotation");
|
||||
_animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
|
||||
}
|
||||
|
||||
// set leftHand grab vars
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
set(TARGET_NAME audio-client)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Multimedia)
|
||||
|
||||
link_hifi_libraries(audio)
|
||||
|
||||
# append audio includes to our list of includes to bubble
|
||||
|
@ -10,9 +7,7 @@ target_include_directories(${TARGET_NAME} PUBLIC "${HIFI_LIBRARY_DIR}/audio/src"
|
|||
|
||||
# have CMake grab externals for us
|
||||
add_dependency_external_projects(gverb)
|
||||
|
||||
find_package(Gverb REQUIRED)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${GVERB_LIBRARIES})
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GVERB_INCLUDE_DIRS})
|
||||
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
set(TARGET_NAME audio)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(networking shared)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
set(TARGET_NAME auto-updater)
|
||||
|
||||
setup_hifi_library(Network)
|
||||
link_hifi_libraries(shared networking)
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
set(TARGET_NAME avatars)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Script)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(audio shared networking)
|
||||
|
|
|
@ -1,27 +1,12 @@
|
|||
set(TARGET_NAME display-plugins)
|
||||
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(OpenGL)
|
||||
|
||||
setup_hifi_opengl()
|
||||
|
||||
link_hifi_libraries(shared plugins gpu render-utils)
|
||||
|
||||
target_opengl()
|
||||
|
||||
GroupSources("src/display-plugins")
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(boostconfig)
|
||||
find_package(BoostConfig REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(oglplus)
|
||||
find_package(OGLPLUS REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
|
||||
target_oglplus()
|
||||
|
||||
add_dependency_external_projects(LibOVR)
|
||||
find_package(LibOVR REQUIRED)
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
set(TARGET_NAME embedded-webserver)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network)
|
||||
|
|
|
@ -1,29 +1,12 @@
|
|||
set(TARGET_NAME entities-renderer)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Widgets Network Script)
|
||||
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(bullet)
|
||||
find_package(Bullet REQUIRED)
|
||||
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
else()
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
target_bullet()
|
||||
|
||||
add_dependency_external_projects(polyvox)
|
||||
find_package(PolyVox REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
|
||||
|
||||
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
|
||||
|
|
|
@ -704,7 +704,9 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const
|
|||
if (_tree && !_shuttingDown) {
|
||||
EntityItemPointer entity = getTree()->findEntityByEntityItemID(entityID);
|
||||
if (entity && !entity->getScript().isEmpty()) {
|
||||
_entitiesScriptEngine->loadEntityScript(entityID, entity->getScript(), reload);
|
||||
QString scriptUrl = entity->getScript();
|
||||
scriptUrl = ResourceManager::normalizeURL(scriptUrl);
|
||||
_entitiesScriptEngine->loadEntityScript(entityID, scriptUrl, reload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
set(TARGET_NAME entities)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Script)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(bullet)
|
||||
|
||||
find_package(Bullet REQUIRED)
|
||||
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
else()
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
link_hifi_libraries(avatars shared octree gpu model fbx networking animation environment)
|
||||
|
||||
target_bullet()
|
||||
|
||||
include_hifi_library_headers(render)
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
set(TARGET_NAME environment)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking)
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
set(TARGET_NAME fbx)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu model networking octree)
|
||||
|
|
|
@ -1,48 +1,7 @@
|
|||
set(TARGET_NAME gpu)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(glew)
|
||||
find_package(GLEW REQUIRED)
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY})
|
||||
|
||||
if (APPLE)
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(OpenGL OpenGL)
|
||||
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
||||
elseif (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY} opengl32.lib)
|
||||
|
||||
if (USE_NSIGHT)
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
# note that this will also enable NSIGHT profilers in all the projects linking gpu
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${NSIGHT_INCLUDE_DIRS})
|
||||
target_compile_definitions(${TARGET_NAME} PUBLIC NSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif ()
|
||||
endif()
|
||||
elseif (ANDROID)
|
||||
target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL")
|
||||
else ()
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
if (${OPENGL_INCLUDE_DIR})
|
||||
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
||||
endif (APPLE)
|
||||
target_glew()
|
||||
target_opengl()
|
|
@ -1,26 +1,9 @@
|
|||
set(TARGET_NAME input-plugins)
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "SDL2" "Sixense")
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
|
||||
string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE)
|
||||
set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_SOURCE_DIR}/interface/external/${${EXTERNAL}_LOWERCASE}")
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
setup_hifi_library()
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
link_hifi_libraries(shared plugins gpu render-utils)
|
||||
|
||||
GroupSources("src/input-plugins")
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
add_dependency_external_projects(OpenVR)
|
||||
find_package(OpenVR REQUIRED)
|
||||
|
@ -33,6 +16,16 @@ endif()
|
|||
#target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS})
|
||||
#target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "SDL2" "Sixense")
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
|
||||
string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE)
|
||||
set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_SOURCE_DIR}/interface/external/${${EXTERNAL}_LOWERCASE}")
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
||||
|
|
160
libraries/input-plugins/src/input-plugins/StandardController.cpp
Normal file
160
libraries/input-plugins/src/input-plugins/StandardController.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
// StandardController.cpp
|
||||
// input-plugins/src/input-plugins
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2015-10-11.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "StandardController.h"
|
||||
|
||||
const float CONTROLLER_THRESHOLD = 0.3f;
|
||||
|
||||
StandardController::~StandardController() {
|
||||
}
|
||||
|
||||
void StandardController::update(float deltaTime, bool jointsCaptured) {
|
||||
for (auto axisState : _axisStateMap) {
|
||||
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
|
||||
_axisStateMap[axisState.first] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StandardController::focusOutEvent() {
|
||||
_axisStateMap.clear();
|
||||
_buttonPressedMap.clear();
|
||||
};
|
||||
|
||||
void StandardController::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getStandardDeviceID();
|
||||
|
||||
auto proxy = std::make_shared<UserInputMapper::DeviceProxy>(_name);
|
||||
proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this] () -> QVector<UserInputMapper::InputPair> {
|
||||
QVector<UserInputMapper::InputPair> availableInputs;
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_A), "Bottom Button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_B), "Right Button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_X), "Left Button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_Y), "Top Button"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_UP), "DPad Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_DOWN), "DPad Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_LEFT), "DPad Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_RIGHT), "DPad Right"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_LEFTSHOULDER), "L1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), "R1"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_SHOULDER), "L2"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_SHOULDER), "R2"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_Y_NEG), "Left Stick Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_Y_POS), "Left Stick Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_X_POS), "Left Stick Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_AXIS_X_NEG), "Left Stick Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_Y_NEG), "Right Stick Up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_Y_POS), "Right Stick Down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_X_POS), "Right Stick Right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_AXIS_X_NEG), "Right Stick Left"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_HAND), "Left Hand"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_HAND), "Right Hand"));
|
||||
|
||||
return availableInputs;
|
||||
};
|
||||
proxy->resetDeviceBindings = [this, &mapper] () -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
mapper.registerStandardDevice(proxy);
|
||||
}
|
||||
|
||||
void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
const float DPAD_MOVE_SPEED = 0.5f;
|
||||
const float JOYSTICK_YAW_SPEED = 0.5f;
|
||||
const float JOYSTICK_PITCH_SPEED = 0.25f;
|
||||
const float BOOM_SPEED = 0.1f;
|
||||
|
||||
// Y axes are flipped (up is negative)
|
||||
// Left StandardController: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(LEFT_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(LEFT_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(LEFT_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(LEFT_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
|
||||
|
||||
// Right StandardController: Camera orientation
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(RIGHT_AXIS_X_POS), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(RIGHT_AXIS_X_NEG), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(RIGHT_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(RIGHT_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
|
||||
|
||||
// Dpad movement
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_UP), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_DOWN), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_RIGHT), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_LEFT), DPAD_MOVE_SPEED);
|
||||
|
||||
// Button controls
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(STANDARD_CONTROLLER_BUTTON_Y), DPAD_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(STANDARD_CONTROLLER_BUTTON_X), DPAD_MOVE_SPEED);
|
||||
|
||||
// Zoom
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(RIGHT_SHOULDER), BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(LEFT_SHOULDER), BOOM_SPEED);
|
||||
|
||||
|
||||
// Hold front right shoulder button for precision controls
|
||||
// Left StandardController: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(LEFT_AXIS_Y_NEG), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(LEFT_AXIS_Y_POS), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(LEFT_AXIS_X_POS), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(LEFT_AXIS_X_NEG), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_MOVE_SPEED/2.0f);
|
||||
|
||||
// Right StandardController: Camera orientation
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(RIGHT_AXIS_X_POS), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_YAW_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(RIGHT_AXIS_X_NEG), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_YAW_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(RIGHT_AXIS_Y_NEG), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_PITCH_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(RIGHT_AXIS_Y_POS), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_PITCH_SPEED/2.0f);
|
||||
|
||||
// Dpad movement
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_UP), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_DOWN), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_RIGHT), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(STANDARD_CONTROLLER_BUTTON_DPAD_LEFT), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
|
||||
|
||||
// Button controls
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(STANDARD_CONTROLLER_BUTTON_Y), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(STANDARD_CONTROLLER_BUTTON_X), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
|
||||
|
||||
// Zoom
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(RIGHT_SHOULDER), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), BOOM_SPEED/2.0f);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(LEFT_SHOULDER), makeInput(STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER), BOOM_SPEED/2.0f);
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(STANDARD_CONTROLLER_BUTTON_LEFTSHOULDER));
|
||||
|
||||
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(STANDARD_CONTROLLER_BUTTON_B));
|
||||
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(STANDARD_CONTROLLER_BUTTON_A));
|
||||
}
|
||||
|
||||
UserInputMapper::Input StandardController::makeInput(StandardController::StandardControllerButtonChannel button) {
|
||||
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input StandardController::makeInput(StandardController::StandardControllerAxisChannel axis) {
|
||||
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
UserInputMapper::Input StandardController::makeInput(StandardController::StandardControllerPoseChannel pose) {
|
||||
return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE);
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// StandardController.h
|
||||
// input-plugins/src/input-plugins
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2015-10-11.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_StandardController_h
|
||||
#define hifi_StandardController_h
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qvector.h>
|
||||
|
||||
#include "InputDevice.h"
|
||||
|
||||
typedef std::shared_ptr<StandardController> StandardControllerPointer;
|
||||
|
||||
class StandardController : public QObject, public InputDevice {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
|
||||
public:
|
||||
enum StandardControllerAxisChannel {
|
||||
LEFT_AXIS_X_POS = 0,
|
||||
LEFT_AXIS_X_NEG,
|
||||
LEFT_AXIS_Y_POS,
|
||||
LEFT_AXIS_Y_NEG,
|
||||
RIGHT_AXIS_X_POS,
|
||||
RIGHT_AXIS_X_NEG,
|
||||
RIGHT_AXIS_Y_POS,
|
||||
RIGHT_AXIS_Y_NEG,
|
||||
RIGHT_SHOULDER,
|
||||
LEFT_SHOULDER,
|
||||
};
|
||||
enum StandardControllerButtonChannel {
|
||||
STANDARD_CONTROLLER_BUTTON_A = 0,
|
||||
STANDARD_CONTROLLER_BUTTON_B,
|
||||
STANDARD_CONTROLLER_BUTTON_X,
|
||||
STANDARD_CONTROLLER_BUTTON_Y,
|
||||
|
||||
STANDARD_CONTROLLER_BUTTON_DPAD_UP,
|
||||
STANDARD_CONTROLLER_BUTTON_DPAD_DOWN,
|
||||
STANDARD_CONTROLLER_BUTTON_DPAD_LEFT,
|
||||
STANDARD_CONTROLLER_BUTTON_DPAD_RIGHT,
|
||||
|
||||
STANDARD_CONTROLLER_BUTTON_LEFTSHOULDER,
|
||||
STANDARD_CONTROLLER_BUTTON_RIGHTSHOULDER,
|
||||
};
|
||||
|
||||
enum StandardControllerPoseChannel {
|
||||
LEFT_HAND = 0,
|
||||
RIGHT_HAND,
|
||||
};
|
||||
|
||||
const QString& getName() const { return _name; }
|
||||
|
||||
// Device functions
|
||||
virtual void registerToUserInputMapper(UserInputMapper& mapper) override;
|
||||
virtual void assignDefaultInputMapping(UserInputMapper& mapper) override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
StandardController() : InputDevice("Standard") {}
|
||||
~StandardController();
|
||||
|
||||
UserInputMapper::Input makeInput(StandardController::StandardControllerButtonChannel button);
|
||||
UserInputMapper::Input makeInput(StandardController::StandardControllerAxisChannel axis);
|
||||
UserInputMapper::Input makeInput(StandardController::StandardControllerPoseChannel pose);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // hifi_StandardController_h
|
|
@ -10,13 +10,19 @@
|
|||
//
|
||||
|
||||
#include "UserInputMapper.h"
|
||||
#include "StandardController.h"
|
||||
|
||||
// Default contruct allocate the poutput size with the current hardcoded action channels
|
||||
UserInputMapper::UserInputMapper() {
|
||||
registerStandardDevice();
|
||||
assignDefaulActionScales();
|
||||
createActionNames();
|
||||
}
|
||||
|
||||
UserInputMapper::~UserInputMapper() {
|
||||
}
|
||||
|
||||
|
||||
bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy){
|
||||
proxy->_name += " (" + QString::number(deviceID) + ")";
|
||||
_registeredDevices[deviceID] = proxy;
|
||||
|
@ -322,3 +328,8 @@ void UserInputMapper::createActionNames() {
|
|||
_actionNames[CONTEXT_MENU] = "CONTEXT_MENU";
|
||||
_actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE";
|
||||
}
|
||||
|
||||
void UserInputMapper::registerStandardDevice() {
|
||||
_standardController = std::make_shared<StandardController>();
|
||||
_standardController->registerToUserInputMapper(*this);
|
||||
}
|
|
@ -19,13 +19,17 @@
|
|||
#include <memory>
|
||||
#include <DependencyManager.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
|
||||
class StandardController;
|
||||
typedef std::shared_ptr<StandardController> StandardControllerPointer;
|
||||
|
||||
class UserInputMapper : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
Q_ENUMS(Action)
|
||||
public:
|
||||
~UserInputMapper();
|
||||
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
|
@ -123,6 +127,7 @@ public:
|
|||
// GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
|
||||
uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
|
||||
bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
|
||||
bool registerStandardDevice(const DeviceProxy::Pointer& device) { _standardDevice = device; return true; }
|
||||
DeviceProxy::Pointer getDeviceProxy(const Input& input);
|
||||
QString getDeviceName(uint16 deviceID);
|
||||
QVector<InputPair> getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); }
|
||||
|
@ -238,11 +243,19 @@ public:
|
|||
typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
|
||||
DevicesMap getDevices() { return _registeredDevices; }
|
||||
|
||||
uint16 getStandardDeviceID() const { return _standardDeviceID; }
|
||||
DeviceProxy::Pointer getStandardDevice() { return _standardDevice; }
|
||||
|
||||
signals:
|
||||
void actionEvent(int action, float state);
|
||||
|
||||
|
||||
protected:
|
||||
void registerStandardDevice();
|
||||
uint16 _standardDeviceID = 0;
|
||||
DeviceProxy::Pointer _standardDevice;
|
||||
StandardControllerPointer _standardController;
|
||||
|
||||
DevicesMap _registeredDevices;
|
||||
uint16 _nextFreeDeviceID = 1;
|
||||
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
set(TARGET_NAME model-networking)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking gpu model fbx)
|
||||
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
set(TARGET_NAME model)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu)
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
set(TARGET_NAME networking)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network)
|
||||
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
#include <QtNetwork/QAbstractNetworkCache>
|
||||
|
||||
#include "AssetClient.h"
|
||||
#include "NetworkAccessManager.h"
|
||||
#include "NetworkLogging.h"
|
||||
#include "NodeList.h"
|
||||
#include "ResourceCache.h"
|
||||
|
@ -41,14 +39,14 @@ void AssetRequest::start() {
|
|||
}
|
||||
|
||||
// Try to load from cache
|
||||
if (loadFromCache()) {
|
||||
_data = loadFromCache(getUrl());
|
||||
if (!_data.isNull()) {
|
||||
_info.hash = _hash;
|
||||
_info.size = _data.size();
|
||||
_error = NoError;
|
||||
|
||||
_state = Finished;
|
||||
emit finished(this);
|
||||
qCDebug(asset_client) << getUrl().toDisplayString() << "loaded from disk cache.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,9 +110,7 @@ void AssetRequest::start() {
|
|||
_totalReceived += data.size();
|
||||
emit progress(_totalReceived, _info.size);
|
||||
|
||||
if (saveToCache(data)) {
|
||||
qCDebug(asset_client) << getUrl().toDisplayString() << "saved to disk cache";
|
||||
}
|
||||
saveToCache(getUrl(), data);
|
||||
} else {
|
||||
// hash doesn't match - we have an error
|
||||
_error = HashVerificationFailed;
|
||||
|
@ -133,49 +129,6 @@ void AssetRequest::start() {
|
|||
}
|
||||
|
||||
QUrl AssetRequest::getUrl() const {
|
||||
if (!_extension.isEmpty()) {
|
||||
return QUrl(QString("%1:%2.%3").arg(URL_SCHEME_ATP, _hash, _extension));
|
||||
} else {
|
||||
return QUrl(QString("%1:%2").arg(URL_SCHEME_ATP, _hash));
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetRequest::loadFromCache() {
|
||||
if (auto cache = NetworkAccessManager::getInstance().cache()) {
|
||||
auto url = getUrl();
|
||||
if (auto ioDevice = cache->data(url)) {
|
||||
_data = ioDevice->readAll();
|
||||
return true;
|
||||
} else {
|
||||
qCDebug(asset_client) << url.toDisplayString() << "not in disk cache";
|
||||
}
|
||||
} else {
|
||||
qCWarning(asset_client) << "No disk cache to load assets from.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetRequest::saveToCache(const QByteArray& file) const {
|
||||
if (auto cache = NetworkAccessManager::getInstance().cache()) {
|
||||
auto url = getUrl();
|
||||
|
||||
if (!cache->metaData(url).isValid()) {
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
metaData.setSaveToDisk(true);
|
||||
metaData.setLastModified(QDateTime::currentDateTime());
|
||||
metaData.setExpirationDate(QDateTime()); // Never expires
|
||||
|
||||
if (auto ioDevice = cache->prepare(metaData)) {
|
||||
ioDevice->write(file);
|
||||
cache->insert(ioDevice);
|
||||
return true;
|
||||
}
|
||||
qCWarning(asset_client) << "Could not save" << url.toDisplayString() << "to disk cache.";
|
||||
}
|
||||
} else {
|
||||
qCWarning(asset_client) << "No disk cache to save assets to.";
|
||||
}
|
||||
return false;
|
||||
return ::getUrl(_hash, _extension);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,9 +53,6 @@ signals:
|
|||
void progress(qint64 totalReceived, qint64 total);
|
||||
|
||||
private:
|
||||
bool loadFromCache();
|
||||
bool saveToCache(const QByteArray& file) const;
|
||||
|
||||
State _state = NotStarted;
|
||||
Error _error = NoError;
|
||||
AssetInfo _info;
|
||||
|
|
|
@ -24,7 +24,7 @@ void AssetResourceRequest::doSend() {
|
|||
// Make request to atp
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
auto parts = _url.path().split(".", QString::SkipEmptyParts);
|
||||
auto hash = parts[0];
|
||||
auto hash = parts.length() > 0 ? parts[0] : "";
|
||||
auto extension = parts.length() > 1 ? parts[1] : "";
|
||||
|
||||
if (hash.length() != SHA256_HASH_HEX_LENGTH) {
|
||||
|
|
|
@ -25,7 +25,7 @@ AssetUpload::AssetUpload(QObject* object, const QString& filename) :
|
|||
|
||||
void AssetUpload::start() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "start", Qt::AutoConnection);
|
||||
QMetaObject::invokeMethod(this, "start");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -37,14 +37,15 @@ void AssetUpload::start() {
|
|||
// file opened, read the data and grab the extension
|
||||
_extension = QFileInfo(_filename).suffix();
|
||||
|
||||
auto data = file.readAll();
|
||||
_data = file.readAll();
|
||||
|
||||
// ask the AssetClient to upload the asset and emit the proper signals from the passed callback
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
|
||||
qCDebug(asset_client) << "Attempting to upload" << _filename << "to asset-server.";
|
||||
|
||||
assetClient->uploadAsset(data, _extension, [this](bool responseReceived, AssetServerError error, const QString& hash){
|
||||
assetClient->uploadAsset(_data, _extension, [this](bool responseReceived, AssetServerError error,
|
||||
const QString& hash){
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
|
@ -63,6 +64,11 @@ void AssetUpload::start() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_error == NoError && hash == hashData(_data).toHex()) {
|
||||
saveToCache(getUrl(hash, _extension), _data);
|
||||
}
|
||||
|
||||
emit finished(this, hash);
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -50,6 +50,7 @@ signals:
|
|||
private:
|
||||
QString _filename;
|
||||
QString _extension;
|
||||
QByteArray _data;
|
||||
Error _error;
|
||||
};
|
||||
|
||||
|
|
69
libraries/networking/src/AssetUtils.cpp
Normal file
69
libraries/networking/src/AssetUtils.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// AssetUtils.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Clément Brisset on 10/12/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AssetUtils.h"
|
||||
|
||||
#include <QtCore/QCryptographicHash>
|
||||
#include <QtNetwork/QAbstractNetworkCache>
|
||||
|
||||
#include "NetworkAccessManager.h"
|
||||
#include "NetworkLogging.h"
|
||||
|
||||
#include "ResourceManager.h"
|
||||
|
||||
QUrl getUrl(const QString& hash, const QString& extension) {
|
||||
if (!extension.isEmpty()) {
|
||||
return QUrl(QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, extension));
|
||||
} else {
|
||||
return QUrl(QString("%1:%2").arg(URL_SCHEME_ATP, hash));
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray hashData(const QByteArray& data) {
|
||||
return QCryptographicHash::hash(data, QCryptographicHash::Sha256);
|
||||
}
|
||||
|
||||
QByteArray loadFromCache(const QUrl& url) {
|
||||
if (auto cache = NetworkAccessManager::getInstance().cache()) {
|
||||
if (auto ioDevice = cache->data(url)) {
|
||||
qCDebug(asset_client) << url.toDisplayString() << "loaded from disk cache.";
|
||||
return ioDevice->readAll();
|
||||
} else {
|
||||
qCDebug(asset_client) << url.toDisplayString() << "not in disk cache";
|
||||
}
|
||||
} else {
|
||||
qCWarning(asset_client) << "No disk cache to load assets from.";
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool saveToCache(const QUrl& url, const QByteArray& file) {
|
||||
if (auto cache = NetworkAccessManager::getInstance().cache()) {
|
||||
if (!cache->metaData(url).isValid()) {
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
metaData.setSaveToDisk(true);
|
||||
metaData.setLastModified(QDateTime::currentDateTime());
|
||||
metaData.setExpirationDate(QDateTime()); // Never expires
|
||||
|
||||
if (auto ioDevice = cache->prepare(metaData)) {
|
||||
ioDevice->write(file);
|
||||
cache->insert(ioDevice);
|
||||
qCDebug(asset_client) << url.toDisplayString() << "saved to disk cache";
|
||||
return true;
|
||||
}
|
||||
qCWarning(asset_client) << "Could not save" << url.toDisplayString() << "to disk cache.";
|
||||
}
|
||||
} else {
|
||||
qCWarning(asset_client) << "No disk cache to save assets to.";
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -12,10 +12,11 @@
|
|||
#ifndef hifi_AssetUtils_h
|
||||
#define hifi_AssetUtils_h
|
||||
|
||||
#include <QtCore/QCryptographicHash>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
using MessageID = uint32_t;
|
||||
using DataOffset = int64_t;
|
||||
|
||||
|
@ -31,8 +32,11 @@ enum AssetServerError : uint8_t {
|
|||
PermissionDenied
|
||||
};
|
||||
|
||||
const QString ATP_SCHEME = "atp";
|
||||
QUrl getUrl(const QString& hash, const QString& extension = QString());
|
||||
|
||||
inline QByteArray hashData(const QByteArray& data) { return QCryptographicHash::hash(data, QCryptographicHash::Sha256); }
|
||||
QByteArray hashData(const QByteArray& data);
|
||||
|
||||
QByteArray loadFromCache(const QUrl& url);
|
||||
bool saveToCache(const QUrl& url, const QByteArray& file);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -319,10 +319,10 @@ void Resource::attemptRequest() {
|
|||
|
||||
void Resource::finishedLoading(bool success) {
|
||||
if (success) {
|
||||
qDebug() << "Finished loading:" << _url;
|
||||
qDebug().noquote() << "Finished loading:" << _url.toDisplayString();
|
||||
_loaded = true;
|
||||
} else {
|
||||
qDebug() << "Failed to load:" << _url;
|
||||
qDebug().noquote() << "Failed to load:" << _url.toDisplayString();
|
||||
_failedToLoad = true;
|
||||
}
|
||||
_loadPriorities.clear();
|
||||
|
@ -339,13 +339,13 @@ void Resource::makeRequest() {
|
|||
_request = ResourceManager::createResourceRequest(this, _activeUrl);
|
||||
|
||||
if (!_request) {
|
||||
qDebug() << "Failed to get request for " << _url;
|
||||
qDebug().noquote() << "Failed to get request for" << _url.toDisplayString();
|
||||
ResourceCache::requestCompleted(this);
|
||||
finishedLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Starting request for: " << _url;
|
||||
qDebug().noquote() << "Starting request for:" << _url.toDisplayString();
|
||||
|
||||
connect(_request, &ResourceRequest::progress, this, &Resource::handleDownloadProgress);
|
||||
connect(_request, &ResourceRequest::finished, this, &Resource::handleReplyFinished);
|
||||
|
@ -368,7 +368,8 @@ void Resource::handleReplyFinished() {
|
|||
auto result = _request->getResult();
|
||||
if (result == ResourceRequest::Success) {
|
||||
_data = _request->getData();
|
||||
qDebug() << "Request finished for " << _url << ", " << _activeUrl;
|
||||
auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString());
|
||||
qDebug().noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo);
|
||||
|
||||
finishedLoading(true);
|
||||
emit loaded(_data);
|
||||
|
|
|
@ -17,7 +17,30 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
QUrl ResourceManager::normalizeURL(const QUrl& url) {
|
||||
ResourceManager::PrefixMap ResourceManager::_prefixMap;
|
||||
QMutex ResourceManager::_prefixMapLock;
|
||||
|
||||
|
||||
void ResourceManager::setUrlPrefixOverride(const QString& prefix, const QString& replacement) {
|
||||
QMutexLocker locker(&_prefixMapLock);
|
||||
_prefixMap[prefix] = replacement;
|
||||
}
|
||||
|
||||
QString ResourceManager::normalizeURL(const QString& urlString) {
|
||||
QString result = urlString;
|
||||
QMutexLocker locker(&_prefixMapLock);
|
||||
foreach(const auto& entry, _prefixMap) {
|
||||
const auto& prefix = entry.first;
|
||||
const auto& replacement = entry.second;
|
||||
if (result.startsWith(prefix)) {
|
||||
result.replace(0, prefix.size(), replacement);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QUrl ResourceManager::normalizeURL(const QUrl& originalUrl) {
|
||||
QUrl url = QUrl(normalizeURL(originalUrl.toString()));
|
||||
auto scheme = url.scheme();
|
||||
if (!(scheme == URL_SCHEME_FILE ||
|
||||
scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP ||
|
||||
|
@ -37,11 +60,11 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q
|
|||
auto normalizedURL = normalizeURL(url);
|
||||
auto scheme = normalizedURL.scheme();
|
||||
if (scheme == URL_SCHEME_FILE) {
|
||||
return new FileResourceRequest(parent, url);
|
||||
return new FileResourceRequest(parent, normalizedURL);
|
||||
} else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) {
|
||||
return new HTTPResourceRequest(parent, url);
|
||||
return new HTTPResourceRequest(parent, normalizedURL);
|
||||
} else if (scheme == URL_SCHEME_ATP) {
|
||||
return new AssetResourceRequest(parent, url);
|
||||
return new AssetResourceRequest(parent, normalizedURL);
|
||||
}
|
||||
|
||||
qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url();
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
#include <QtCore/QMutex>
|
||||
|
||||
#include "ResourceRequest.h"
|
||||
|
||||
const QString URL_SCHEME_FILE = "file";
|
||||
|
@ -24,8 +26,15 @@ const QString URL_SCHEME_ATP = "atp";
|
|||
|
||||
class ResourceManager {
|
||||
public:
|
||||
static void setUrlPrefixOverride(const QString& prefix, const QString& replacement);
|
||||
static QString normalizeURL(const QString& urlString);
|
||||
static QUrl normalizeURL(const QUrl& url);
|
||||
static ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url);
|
||||
private:
|
||||
using PrefixMap = std::map<QString, QString>;
|
||||
|
||||
static PrefixMap _prefixMap;
|
||||
static QMutex _prefixMapLock;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
set(TARGET_NAME octree)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking)
|
||||
|
|
|
@ -1,24 +1,5 @@
|
|||
set(TARGET_NAME physics)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(bullet)
|
||||
|
||||
find_package(Bullet REQUIRED)
|
||||
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
else()
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
link_hifi_libraries(shared fbx entities)
|
||||
include_hifi_library_headers(fbx)
|
||||
|
||||
target_bullet()
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
set(TARGET_NAME plugins)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(OpenGL)
|
||||
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
set(TARGET_NAME procedural)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu model model-networking)
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ void Procedural::parse(const QJsonObject& proceduralData) {
|
|||
// Get the path to the shader
|
||||
{
|
||||
QString shaderUrl = proceduralData[URL_KEY].toString();
|
||||
shaderUrl = ResourceManager::normalizeURL(shaderUrl);
|
||||
_shaderUrl = QUrl(shaderUrl);
|
||||
if (!_shaderUrl.isValid()) {
|
||||
qWarning() << "Invalid shader URL: " << shaderUrl;
|
||||
|
|
|
@ -1,45 +1,9 @@
|
|||
set(TARGET_NAME render-utils)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model render)
|
||||
|
||||
# pull in the resources.qrc file
|
||||
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(boostconfig)
|
||||
find_package(BoostConfig REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(oglplus)
|
||||
find_package(OGLPLUS REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
|
||||
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
if (WIN32)
|
||||
if (USE_NSIGHT)
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif ()
|
||||
endif()
|
||||
endif (WIN32)
|
||||
|
||||
add_dependency_external_projects(boostconfig)
|
||||
find_package(BoostConfig REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(oglplus)
|
||||
find_package(OGLPLUS REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu procedural model model-networking render environment animation fbx)
|
||||
|
||||
target_nsight()
|
||||
target_oglplus()
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
set(TARGET_NAME render)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu model)
|
||||
|
||||
if (WIN32)
|
||||
if (USE_NSIGHT)
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif ()
|
||||
endif()
|
||||
endif (WIN32)
|
||||
|
||||
target_nsight()
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
set(TARGET_NAME script-engine)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Gui Network Script WebSockets Widgets)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities animation audio physics)
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
set(TARGET_NAME shared)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
# TODO: there isn't really a good reason to have Script linked here - let's get what is requiring it out (RegisteredMetaTypes.cpp)
|
||||
setup_hifi_library(Gui Network Script Widgets)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS})
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
# Birarda will fix this when he finds it.
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
set(TARGET_NAME ui)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(OpenGL Network Qml Quick Script XmlPatterns)
|
||||
|
||||
link_hifi_libraries(render-utils shared)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
|
||||
set(TARGET_NAME gpu-test)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model render-utils)
|
||||
|
||||
# This is not a testcase -- just set it up as a regular hifi project
|
||||
setup_hifi_project(Quick Gui OpenGL Script Widgets)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
#include_oglplus()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(networking gpu procedural shared fbx model model-networking animation script-engine render-utils )
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
|
@ -1,22 +1,7 @@
|
|||
|
||||
# Declare dependencies
|
||||
macro (SETUP_TESTCASE_DEPENDENCIES)
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(bullet)
|
||||
|
||||
find_package(Bullet REQUIRED)
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
else()
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_bullet()
|
||||
link_hifi_libraries(shared physics)
|
||||
copy_dlls_beside_windows_executable()
|
||||
endmacro ()
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
};
|
||||
|
||||
|
||||
|
||||
MasterReset = function() {
|
||||
var resetKey = "resetMe";
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey";
|
||||
|
@ -320,6 +319,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -379,7 +381,8 @@
|
|||
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target.fbx';
|
||||
var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target_collision_hull.obj';
|
||||
|
||||
var RESET_DISTANCE = 1;
|
||||
var MINIMUM_MOVE_LENGTH = 0.05;
|
||||
var RESET_DISTANCE = 0.5;
|
||||
var TARGET_USER_DATA_KEY = 'hifi-ping_pong_target';
|
||||
var NUMBER_OF_TARGETS = 6;
|
||||
var TARGETS_PER_ROW = 3;
|
||||
|
@ -393,7 +396,6 @@
|
|||
var VERTICAL_SPACING = TARGET_DIMENSIONS.y + 0.5;
|
||||
var HORIZONTAL_SPACING = TARGET_DIMENSIONS.z + 0.5;
|
||||
|
||||
|
||||
var startPosition = {
|
||||
x: 548.68,
|
||||
y: 497.30,
|
||||
|
@ -407,11 +409,6 @@
|
|||
type: 'Box',
|
||||
position: startPosition,
|
||||
dimensions: TARGET_DIMENSIONS,
|
||||
color: {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
},
|
||||
rotation: rotation,
|
||||
visible: false,
|
||||
collisionsWillMove: false,
|
||||
|
@ -419,6 +416,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -427,6 +427,8 @@
|
|||
|
||||
var originalPositions = [];
|
||||
|
||||
var lastPositions = [];
|
||||
|
||||
function addTargets() {
|
||||
var i;
|
||||
var row = -1;
|
||||
|
@ -443,6 +445,7 @@
|
|||
position.y = startPosition.y - (row * VERTICAL_SPACING);
|
||||
|
||||
originalPositions.push(position);
|
||||
lastPositions.push(position);
|
||||
|
||||
var targetProperties = {
|
||||
name: 'Target',
|
||||
|
@ -458,6 +461,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
@ -474,7 +480,11 @@
|
|||
var distance = Vec3.subtract(originalPosition, currentPosition);
|
||||
var length = Vec3.length(distance);
|
||||
|
||||
if (length > RESET_DISTANCE) {
|
||||
var moving = Vec3.length(Vec3.subtract(currentPosition, lastPositions[index]));
|
||||
|
||||
lastPositions[index] = currentPosition;
|
||||
|
||||
if (length > RESET_DISTANCE && moving < MINIMUM_MOVE_LENGTH) {
|
||||
|
||||
Entities.deleteEntity(target);
|
||||
|
||||
|
@ -492,11 +502,14 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
};
|
||||
var target = Entities.addEntity(targetProperties);
|
||||
targets[index] = target;
|
||||
|
||||
targets[index] = Entities.addEntity(targetProperties);
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -554,6 +567,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -589,7 +605,11 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -658,6 +678,7 @@
|
|||
green: 146,
|
||||
blue: 24
|
||||
},
|
||||
isSpotlight: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
|
@ -685,6 +706,7 @@
|
|||
green: 146,
|
||||
blue: 24
|
||||
},
|
||||
isSpotlight: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
|
@ -734,7 +756,6 @@
|
|||
|
||||
|
||||
|
||||
|
||||
var sconceLight3 = Entities.addEntity({
|
||||
type: "Light",
|
||||
position: {
|
||||
|
@ -755,6 +776,7 @@
|
|||
green: 146,
|
||||
blue: 24
|
||||
},
|
||||
isSpotlight: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
|
@ -783,6 +805,7 @@
|
|||
green: 146,
|
||||
blue: 24
|
||||
},
|
||||
isSpotlight: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
|
@ -810,6 +833,7 @@
|
|||
green: 146,
|
||||
blue: 24
|
||||
},
|
||||
isSpotlight: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
|
@ -853,6 +877,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
};
|
||||
|
@ -888,7 +915,7 @@
|
|||
y: 1.13,
|
||||
z: 0.2
|
||||
},
|
||||
rotation: rotation2,
|
||||
rotation: rotation,
|
||||
collisionsWillMove: true,
|
||||
gravity: {
|
||||
x: 0,
|
||||
|
@ -942,6 +969,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -1016,6 +1046,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -1055,6 +1088,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -1092,6 +1128,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -1128,6 +1167,9 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true,
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -1256,7 +1298,7 @@
|
|||
y: 0.05,
|
||||
z: 0.25
|
||||
}
|
||||
},];
|
||||
}, ];
|
||||
|
||||
var modelURL, entity;
|
||||
for (i = 0; i < blockTypes.length; i++) {
|
||||
|
@ -1305,7 +1347,6 @@
|
|||
Script.scriptEnding.connect(cleanup);
|
||||
}
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new ResetSwitch();
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue