mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 08:33:29 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into dont-use-other-avatar-sounds
This commit is contained in:
commit
79f05c63e5
37 changed files with 520 additions and 137 deletions
assignment-client/src
cmake
examples
interface
libraries
animation/src
controllers/src/controllers
entities
input-plugins/src/input-plugins
physics/src
EntityMotionState.cppObjectAction.cppObjectAction.hObjectMotionState.cppObjectMotionState.hPhysicsEngine.cppThreadSafeDynamicsWorld.cppThreadSafeDynamicsWorld.h
procedural
shared/src
|
@ -74,7 +74,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
|
|||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||
|
||||
// make sure we output process IDs for a child AC otherwise it's insane to parse
|
||||
LogHandler::getInstance().setShouldOutputPID(true);
|
||||
LogHandler::getInstance().setShouldOutputProcessID(true);
|
||||
|
||||
// setup our _requestAssignment member variable from the passed arguments
|
||||
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
||||
|
|
|
@ -44,7 +44,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||
|
||||
// make sure we output process IDs for a monitor otherwise it's insane to parse
|
||||
LogHandler::getInstance().setShouldOutputPID(true);
|
||||
LogHandler::getInstance().setShouldOutputProcessID(true);
|
||||
|
||||
// create a NodeList so we can receive stats from children
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
|
|
42
cmake/externals/sdl2/CMakeLists.txt
vendored
42
cmake/externals/sdl2/CMakeLists.txt
vendored
|
@ -2,6 +2,8 @@ set(EXTERNAL_NAME sdl2)
|
|||
|
||||
include(ExternalProject)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
|
@ -13,15 +15,33 @@ if (WIN32)
|
|||
LOG_DOWNLOAD 1
|
||||
)
|
||||
elseif (APPLE)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/SDL2-2.0.3-OSX.tar.gz
|
||||
URL_MD5 64f888886268bdf1656ef1b4b7d7756d
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/SDL2-2.0.3.zip
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DVIDEO_OPENGL=OFF
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include/SDL2 CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY "${INSTALL_DIR}/lib/libSDL2-2.0.dylib" CACHE STRING "Path to SDL2 library")
|
||||
|
||||
set(_SDL2_LIB_DIR "${INSTALL_DIR}/lib")
|
||||
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name
|
||||
COMMENT "Calling install_name_tool on SDL2 libraries to fix install name for dylib linking"
|
||||
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SDL2_LIB_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
|
||||
DEPENDEES install
|
||||
WORKING_DIRECTORY <INSTALL_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
else ()
|
||||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
|
@ -41,12 +61,8 @@ endif ()
|
|||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (APPLE)
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/SDL2.framework/Headers CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/SDL2.framework/SDL2 CACHE STRING "Path to SDL2 library")
|
||||
elseif (WIN32)
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/include CACHE PATH "Location of SDL2 include directory")
|
||||
|
|
29
cmake/externals/sixense/CMakeLists.txt
vendored
29
cmake/externals/sixense/CMakeLists.txt
vendored
|
@ -30,17 +30,40 @@ if (WIN32)
|
|||
set(ARCH_SUFFIX "")
|
||||
endif()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${SOURCE_DIR}/lib/${ARCH_DIR}/VS2013/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE "${SOURCE_DIR}/lib/${ARCH_DIR}/VS2013/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
|
||||
add_paths_to_fixup_libs("${SOURCE_DIR}/bin/${ARCH_DIR}/VS2013/release_dll")
|
||||
|
||||
elseif(APPLE)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/lib/osx_x64/debug_dll/libsixensed_x64.dylib CACHE TYPE INTERNAL)
|
||||
|
||||
set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64")
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name-release
|
||||
COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
|
||||
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR}/release_dll -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
|
||||
DEPENDEES install
|
||||
WORKING_DIRECTORY <SOURCE_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64")
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name-debug
|
||||
COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
|
||||
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR}/debug_dll -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
|
||||
DEPENDEES install
|
||||
WORKING_DIRECTORY <SOURCE_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
elseif(NOT ANDROID)
|
||||
|
||||
# FIXME need to account for different architectures
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
|
||||
|
||||
endif()
|
||||
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(SIXENSE)
|
||||
|
||||
set(SIXENSE_REQUIREMENTS SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
|
||||
mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)
|
||||
|
|
|
@ -15,13 +15,11 @@
|
|||
Script.include("../libraries/utils.js");
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// add lines where the hand ray picking is happening
|
||||
//
|
||||
var WANT_DEBUG = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// these tune time-averaging and "on" value for analog trigger
|
||||
//
|
||||
|
@ -30,7 +28,6 @@ var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value
|
|||
var TRIGGER_ON_VALUE = 0.4;
|
||||
var TRIGGER_OFF_VALUE = 0.15;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// distant manipulation
|
||||
//
|
||||
|
@ -44,7 +41,6 @@ var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000,z: 1000};
|
|||
var LINE_LENGTH = 500;
|
||||
var PICK_MAX_DISTANCE = 500; // max length of pick-ray
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// near grabbing
|
||||
//
|
||||
|
@ -55,8 +51,8 @@ var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held
|
|||
var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected
|
||||
var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
|
||||
var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object
|
||||
var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// other constants
|
||||
//
|
||||
|
@ -79,6 +75,18 @@ var ACTION_TTL_REFRESH = 5;
|
|||
var PICKS_PER_SECOND_PER_HAND = 5;
|
||||
var MSECS_PER_SEC = 1000.0;
|
||||
|
||||
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
|
||||
var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
|
||||
|
||||
var DEFAULT_GRABBABLE_DATA = {
|
||||
grabbable: true,
|
||||
invertSolidWhileHeld: false
|
||||
};
|
||||
|
||||
var disabledHand ='none';
|
||||
|
||||
|
||||
// states for the state machine
|
||||
var STATE_OFF = 0;
|
||||
var STATE_SEARCHING = 1;
|
||||
|
@ -92,15 +100,35 @@ var STATE_FAR_GRABBING_NON_COLLIDING = 8;
|
|||
var STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING = 9;
|
||||
var STATE_RELEASE = 10;
|
||||
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
|
||||
var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
|
||||
|
||||
var DEFAULT_GRABBABLE_DATA = {
|
||||
grabbable: true,
|
||||
invertSolidWhileHeld: false
|
||||
};
|
||||
function stateToName(state) {
|
||||
switch (state) {
|
||||
case STATE_OFF:
|
||||
return "off";
|
||||
case STATE_SEARCHING:
|
||||
return "searching";
|
||||
case STATE_DISTANCE_HOLDING:
|
||||
return "distance_holding";
|
||||
case STATE_CONTINUE_DISTANCE_HOLDING:
|
||||
return "continue_distance_holding";
|
||||
case STATE_NEAR_GRABBING:
|
||||
return "near_grabbing";
|
||||
case STATE_CONTINUE_NEAR_GRABBING:
|
||||
return "continue_near_grabbing";
|
||||
case STATE_NEAR_GRABBING_NON_COLLIDING:
|
||||
return "near_grabbing_non_colliding";
|
||||
case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING:
|
||||
return "continue_near_grabbing_non_colliding";
|
||||
case STATE_FAR_GRABBING_NON_COLLIDING:
|
||||
return "far_grabbing_non_colliding";
|
||||
case STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING:
|
||||
return "continue_far_grabbing_non_colliding";
|
||||
case STATE_RELEASE:
|
||||
return "release";
|
||||
}
|
||||
|
||||
var disabledHand ='none';
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
function getTag() {
|
||||
return "grab-" + MyAvatar.sessionUUID;
|
||||
|
@ -196,7 +224,7 @@ function MyController(hand, triggerAction) {
|
|||
|
||||
this.setState = function(newState) {
|
||||
if (WANT_DEBUG) {
|
||||
print("STATE: " + this.state + " --> " + newState);
|
||||
print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand);
|
||||
}
|
||||
this.state = newState;
|
||||
}
|
||||
|
@ -353,10 +381,11 @@ function MyController(hand, triggerAction) {
|
|||
}
|
||||
if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) {
|
||||
// the hand is very close to the intersected object. go into close-grabbing mode.
|
||||
if (intersection.properties.collisionsWillMove === 1) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
} else {
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
if (grabbableData.wantsTrigger) {
|
||||
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
||||
} else {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
}
|
||||
} else {
|
||||
// don't allow two people to distance grab the same object
|
||||
|
@ -397,22 +426,22 @@ function MyController(hand, triggerAction) {
|
|||
}
|
||||
if (this.grabbedEntity === null) {
|
||||
return;
|
||||
} else if (props.locked === 0 && props.collisionsWillMove === 1) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
} else if (props.collisionsWillMove === 0 && grabbableData.wantsTrigger) {
|
||||
// We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event
|
||||
}
|
||||
if (grabbableData.wantsTrigger) {
|
||||
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
||||
} else if (props.locked === 0) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.distanceHolding = function() {
|
||||
|
||||
var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
|
||||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation);
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
|
||||
"gravity", "ignoreForCollisions"]);
|
||||
"gravity", "ignoreForCollisions",
|
||||
|
||||
var now = Date.now();
|
||||
|
||||
// add the action and initialize some variables
|
||||
|
@ -557,8 +586,14 @@ function MyController(hand, triggerAction) {
|
|||
this.lineOff();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
|
||||
["position", "rotation", "gravity", "ignoreForCollisions"]);
|
||||
["position", "rotation", "gravity",
|
||||
"ignoreForCollisions", "collisionsWillMove"]);
|
||||
this.activateEntity(this.grabbedEntity, grabbedProperties);
|
||||
if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) {
|
||||
Entities.editEntity(this.grabbedEntity, {
|
||||
collisionsWillMove: false
|
||||
});
|
||||
}
|
||||
|
||||
var handRotation = this.getHandRotation();
|
||||
var handPosition = this.getHandPosition();
|
||||
|
@ -587,7 +622,9 @@ function MyController(hand, triggerAction) {
|
|||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
ttl: ACTION_TTL
|
||||
ttl: ACTION_TTL,
|
||||
kinematic: NEAR_GRABBING_KINEMATIC,
|
||||
kinematicSetVelocity: true
|
||||
});
|
||||
if (this.actionID === NULL_ACTION_ID) {
|
||||
this.actionID = null;
|
||||
|
@ -639,7 +676,9 @@ function MyController(hand, triggerAction) {
|
|||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
ttl: ACTION_TTL
|
||||
ttl: ACTION_TTL,
|
||||
kinematic: NEAR_GRABBING_KINEMATIC,
|
||||
kinematicSetVelocity: true
|
||||
});
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
}
|
||||
|
@ -808,12 +847,13 @@ function MyController(hand, triggerAction) {
|
|||
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
|
||||
}
|
||||
|
||||
this.deactivateEntity(this.grabbedEntity);
|
||||
|
||||
// the action will tend to quickly bring an object's velocity to zero. now that
|
||||
// the action is gone, set the objects velocity to something the holder might expect.
|
||||
Entities.editEntity(this.grabbedEntity, {
|
||||
velocity: this.grabbedVelocity
|
||||
});
|
||||
this.deactivateEntity(this.grabbedEntity);
|
||||
|
||||
this.grabbedVelocity = ZERO_VEC;
|
||||
this.grabbedEntity = null;
|
||||
|
@ -836,6 +876,7 @@ function MyController(hand, triggerAction) {
|
|||
if (data["refCount"] == 1) {
|
||||
data["gravity"] = grabbedProperties.gravity;
|
||||
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
|
||||
data["collisionsWillMove"] = grabbedProperties.collisionsWillMove;
|
||||
var whileHeldProperties = {gravity: {x:0, y:0, z:0}};
|
||||
if (invertSolidWhileHeld) {
|
||||
whileHeldProperties["ignoreForCollisions"] = ! grabbedProperties.ignoreForCollisions;
|
||||
|
@ -853,7 +894,8 @@ function MyController(hand, triggerAction) {
|
|||
if (data["refCount"] < 1) {
|
||||
Entities.editEntity(entityID, {
|
||||
gravity: data["gravity"],
|
||||
ignoreForCollisions: data["ignoreForCollisions"]
|
||||
ignoreForCollisions: data["ignoreForCollisions"],
|
||||
collisionsWillMove: data["collisionsWillMove"]
|
||||
});
|
||||
data = null;
|
||||
}
|
||||
|
|
26
examples/example/lineExample.js
Normal file
26
examples/example/lineExample.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// lineExample.js
|
||||
// examples/example
|
||||
//
|
||||
// Created by Ryan Huffman on October 27, 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../libraries/line.js");
|
||||
|
||||
var basePosition = MyAvatar.position;
|
||||
var color = { red: 128, green: 220, blue: 190 };
|
||||
var strokeWidth = 0.01;
|
||||
var line = new InfiniteLine(basePosition, color, 20);
|
||||
|
||||
for (var i = 0; i < (16 * Math.PI); i += 0.05) {
|
||||
var x = 0
|
||||
var y = 0.25 * Math.sin(i);
|
||||
var z = i / 10;
|
||||
|
||||
var position = Vec3.sum(basePosition, { x: x, y: y, z: z });
|
||||
line.enqueuePoint(position, strokeWidth);
|
||||
}
|
161
examples/libraries/line.js
Normal file
161
examples/libraries/line.js
Normal file
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// line.js
|
||||
// examples/libraries
|
||||
//
|
||||
// Created by Ryan Huffman on October 27, 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
function error(message) {
|
||||
print("[ERROR] " + message);
|
||||
}
|
||||
|
||||
// PolyLine
|
||||
var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 };
|
||||
var MAX_LINE_LENGTH = 40; // This must be 2 or greater;
|
||||
var DEFAULT_STROKE_WIDTH = 0.1;
|
||||
var DEFAULT_LIFETIME = 20;
|
||||
var DEFAULT_COLOR = { red: 255, green: 255, blue: 255 };
|
||||
var PolyLine = function(position, color, lifetime) {
|
||||
this.position = position;
|
||||
this.color = color;
|
||||
this.lifetime = lifetime === undefined ? DEFAULT_LIFETIME : lifetime;
|
||||
this.points = [
|
||||
];
|
||||
this.strokeWidths = [
|
||||
];
|
||||
this.normals = [
|
||||
]
|
||||
this.entityID = Entities.addEntity({
|
||||
type: "PolyLine",
|
||||
position: position,
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths,
|
||||
dimensions: LINE_DIMENSIONS,
|
||||
color: color,
|
||||
lifetime: lifetime
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.enqueuePoint = function(position, strokeWidth) {
|
||||
if (this.isFull()) {
|
||||
error("Hit max PolyLine size");
|
||||
return;
|
||||
}
|
||||
|
||||
position = Vec3.subtract(position, this.position);
|
||||
this.points.push(position);
|
||||
this.normals.push({ x: 1, y: 0, z: 0 });
|
||||
this.strokeWidths.push(strokeWidth);
|
||||
Entities.editEntity(this.entityID, {
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.dequeuePoint = function() {
|
||||
if (this.points.length == 0) {
|
||||
error("Hit min PolyLine size");
|
||||
return;
|
||||
}
|
||||
|
||||
this.points = this.points.slice(1);
|
||||
this.normals = this.normals.slice(1);
|
||||
this.strokeWidths = this.strokeWidths.slice(1);
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.getFirstPoint = function() {
|
||||
return Vec3.sum(this.position, this.points[0]);
|
||||
};
|
||||
|
||||
PolyLine.prototype.getLastPoint = function() {
|
||||
return Vec3.sum(this.position, this.points[this.points.length - 1]);
|
||||
};
|
||||
|
||||
PolyLine.prototype.getSize = function() {
|
||||
return this.points.length;
|
||||
}
|
||||
|
||||
PolyLine.prototype.isFull = function() {
|
||||
return this.points.length >= MAX_LINE_LENGTH;
|
||||
};
|
||||
|
||||
PolyLine.prototype.destroy = function() {
|
||||
Entities.deleteEntity(this.entityID);
|
||||
this.points = [];
|
||||
};
|
||||
|
||||
|
||||
// InfiniteLine
|
||||
InfiniteLine = function(position, color, lifetime) {
|
||||
this.position = position;
|
||||
this.color = color;
|
||||
this.lifetime = lifetime === undefined ? DEFAULT_LIFETIME : lifetime;
|
||||
this.lines = [];
|
||||
this.size = 0;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.enqueuePoint = function(position, strokeWidth) {
|
||||
var currentLine;
|
||||
|
||||
if (this.lines.length == 0) {
|
||||
currentLine = new PolyLine(position, this.color, this.lifetime);
|
||||
this.lines.push(currentLine);
|
||||
} else {
|
||||
currentLine = this.lines[this.lines.length - 1];
|
||||
}
|
||||
|
||||
if (currentLine.isFull()) {
|
||||
var newLine = new PolyLine(currentLine.getLastPoint(), this.color, this.lifetime);
|
||||
newLine.enqueuePoint(currentLine.getLastPoint(), strokeWidth);
|
||||
this.lines.push(newLine);
|
||||
currentLine = newLine;
|
||||
}
|
||||
|
||||
currentLine.enqueuePoint(position, strokeWidth);
|
||||
|
||||
++this.size;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.dequeuePoint = function() {
|
||||
if (this.lines.length == 0) {
|
||||
error("Trying to dequeue from InfiniteLine when no points are left");
|
||||
return;
|
||||
}
|
||||
|
||||
var lastLine = this.lines[0];
|
||||
lastLine.dequeuePoint();
|
||||
|
||||
if (lastLine.getSize() <= 1) {
|
||||
this.lines = this.lines.slice(1);
|
||||
}
|
||||
|
||||
--this.size;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.getFirstPoint = function() {
|
||||
return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.getLastPoint = function() {
|
||||
return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.destroy = function() {
|
||||
for (var i = 0; i < this.lines.length; ++i) {
|
||||
this.lines[i].destroy();
|
||||
}
|
||||
|
||||
this.size = 0;
|
||||
};
|
|
@ -2,6 +2,15 @@
|
|||
"name": "Keyboard/Mouse to Actions",
|
||||
"channels": [
|
||||
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.E", "when": "Keyboard.Shift", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.05 } ] },
|
||||
{ "from": "Keyboard.C", "when": "Keyboard.Shift", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.05 } ] },
|
||||
{ "from": "Keyboard.S", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
|
||||
{ "from": "Keyboard.W", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
|
||||
|
||||
|
||||
{ "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
|
||||
"when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
|
||||
|
@ -41,15 +50,6 @@
|
|||
"to": "Actions.Yaw"
|
||||
},
|
||||
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.E", "when": "Keyboard.Shift", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.05 } ] },
|
||||
{ "from": "Keyboard.C", "when": "Keyboard.Shift", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.05 } ] },
|
||||
{ "from": "Keyboard.S", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
|
||||
{ "from": "Keyboard.W", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
|
||||
|
||||
{ "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
{ "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
|
||||
|
|
|
@ -119,6 +119,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
|||
worldTrans.setRotation(glmToBullet(_rotationalTarget));
|
||||
rigidBody->setWorldTransform(worldTrans);
|
||||
|
||||
motionState->dirtyInternalKinematicChanges();
|
||||
|
||||
_previousPositionalTarget = _positionalTarget;
|
||||
_previousRotationalTarget = _rotationalTarget;
|
||||
_previousSet = true;
|
||||
|
@ -224,6 +226,8 @@ QVariantMap AvatarActionHold::getArguments() {
|
|||
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
|
||||
arguments["timeScale"] = _linearTimeScale;
|
||||
arguments["hand"] = _hand;
|
||||
arguments["kinematic"] = _kinematic;
|
||||
arguments["kinematicSetVelocity"] = _kinematicSetVelocity;
|
||||
});
|
||||
return arguments;
|
||||
}
|
||||
|
|
|
@ -366,5 +366,10 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID)
|
|||
return std::static_pointer_cast<Avatar>(_myAvatar);
|
||||
}
|
||||
QReadLocker locker(&_hashLock);
|
||||
return _avatarHash[sessionID];
|
||||
auto iter = _avatarHash.find(sessionID);
|
||||
if (iter != _avatarHash.end()) {
|
||||
return iter.value();
|
||||
} else {
|
||||
return AvatarSharedPointer();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine,
|
|||
break;
|
||||
default:
|
||||
// Note that we don't do mat4 in Javascript currently, and there's not yet a reason to start now.
|
||||
assert("AnimVariant::Type" == "valid");
|
||||
assert(QString("AnimVariant::Type") == QString("valid"));
|
||||
}
|
||||
};
|
||||
if (useNames) { // copy only the requested names
|
||||
|
|
|
@ -74,7 +74,7 @@ void UserInputMapper::registerDevice(InputDevice::Pointer device) {
|
|||
}
|
||||
const auto& deviceID = device->_deviceID;
|
||||
|
||||
int numberOfType = recordDeviceOfType(device->getName());
|
||||
recordDeviceOfType(device->getName());
|
||||
|
||||
qCDebug(controllers) << "Registered input device <" << device->getName() << "> deviceID = " << deviceID;
|
||||
for (const auto& inputMapping : device->getAvailableInputs()) {
|
||||
|
@ -266,7 +266,7 @@ void UserInputMapper::update(float deltaTime) {
|
|||
}
|
||||
|
||||
auto standardInputs = getStandardInputs();
|
||||
if (_lastStandardStates.size() != standardInputs.size()) {
|
||||
if ((int)_lastStandardStates.size() != standardInputs.size()) {
|
||||
_lastStandardStates.resize(standardInputs.size());
|
||||
for (auto& lastValue : _lastStandardStates) {
|
||||
lastValue = 0;
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace controller {
|
|||
virtual void apply(float value, const Pointer& source) = 0;
|
||||
virtual Pose pose() { return Pose(); }
|
||||
virtual void apply(const Pose& value, const Pointer& source) {}
|
||||
virtual const bool isPose() { return _input.isPose(); }
|
||||
virtual bool isPose() { return _input.isPose(); }
|
||||
|
||||
virtual bool writeable() const { return true; }
|
||||
virtual bool readable() const { return true; }
|
||||
|
@ -54,6 +54,7 @@ namespace controller {
|
|||
|
||||
class LambdaEndpoint : public Endpoint {
|
||||
public:
|
||||
using Endpoint::apply;
|
||||
LambdaEndpoint(ReadLambda readLambda, WriteLambda writeLambda = [](float) {})
|
||||
: Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace controller {
|
|||
class EndpointConditional : public Conditional {
|
||||
public:
|
||||
EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
|
||||
virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
|
||||
virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0f; }
|
||||
private:
|
||||
Endpoint::Pointer _endpoint;
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace controller {
|
|||
class AnyEndpoint : public Endpoint {
|
||||
friend class UserInputMapper;
|
||||
public:
|
||||
using Endpoint::apply;
|
||||
AnyEndpoint(Endpoint::List children);
|
||||
virtual float value() override;
|
||||
virtual void apply(float newValue, const Endpoint::Pointer& source) override;
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace controller {
|
|||
class ArrayEndpoint : public Endpoint {
|
||||
friend class UserInputMapper;
|
||||
public:
|
||||
using Endpoint::apply;
|
||||
using Pointer = std::shared_ptr<ArrayEndpoint>;
|
||||
ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
namespace controller {
|
||||
class CompositeEndpoint : public Endpoint, Endpoint::Pair {
|
||||
public:
|
||||
using Endpoint::apply;
|
||||
CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second);
|
||||
|
||||
virtual float value() override;
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace controller {
|
|||
|
||||
class JSEndpoint : public Endpoint {
|
||||
public:
|
||||
using Endpoint::apply;
|
||||
JSEndpoint(const QJSValue& callable)
|
||||
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace controller {
|
|||
class ScriptEndpoint : public Endpoint {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
using Endpoint::apply;
|
||||
ScriptEndpoint(const QScriptValue& callable)
|
||||
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
|
||||
virtual void apply(float value, const Pointer& source) override {
|
||||
// For standard endpoints, the first NON-ZERO write counts.
|
||||
if (value != 0.0) {
|
||||
if (value != 0.0f) {
|
||||
_written = true;
|
||||
}
|
||||
VirtualEndpoint::apply(value, source);
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace controller {
|
|||
class InvertFilter : public ScaleFilter {
|
||||
REGISTER_FILTER_CLASS(InvertFilter);
|
||||
public:
|
||||
using ScaleFilter::parseParameters;
|
||||
InvertFilter() : ScaleFilter(-1.0f) {}
|
||||
|
||||
virtual bool parseParameters(const QJsonArray& parameters) { return true; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
set(TARGET_NAME entities)
|
||||
setup_hifi_library(Network Script)
|
||||
link_hifi_libraries(avatars shared octree gpu model fbx networking animation environment)
|
||||
link_hifi_libraries(avatars shared audio octree gpu model fbx networking animation environment)
|
||||
|
||||
target_bullet()
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ void SDL2Manager::activate() {
|
|||
emit joystickAdded(joystick.get());
|
||||
}
|
||||
#endif
|
||||
InputPlugin::activate();
|
||||
}
|
||||
|
||||
void SDL2Manager::deactivate() {
|
||||
|
@ -92,6 +93,7 @@ void SDL2Manager::deactivate() {
|
|||
emit joystickRemoved(joystick.get());
|
||||
}
|
||||
#endif
|
||||
InputPlugin::deactivate();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <vector>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtCore/QSysInfo>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
@ -74,7 +76,13 @@ SixenseManager::SixenseManager() :
|
|||
|
||||
bool SixenseManager::isSupported() const {
|
||||
#ifdef HAVE_SIXENSE
|
||||
|
||||
#if defined(Q_OS_OSX)
|
||||
return QSysInfo::macVersion() <= QSysInfo::MV_MAVERICKS;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
|
|
@ -254,7 +254,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) {
|
|||
}
|
||||
|
||||
numTrackedControllers++;
|
||||
bool left = numTrackedControllers == 1;
|
||||
bool left = numTrackedControllers == 2;
|
||||
|
||||
const mat4& mat = _trackedDevicePoseMat4[device];
|
||||
|
||||
|
@ -307,13 +307,13 @@ void ViveControllerManager::focusOutEvent() {
|
|||
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||
void ViveControllerManager::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
|
||||
#ifdef Q_OS_WIN
|
||||
//FIX ME? It enters here every frame: probably we want to enter only if an event occurs
|
||||
axis += vr::k_EButton_Axis0;
|
||||
using namespace controller;
|
||||
if (axis == vr::k_EButton_SteamVR_Touchpad) {
|
||||
_axisStateMap[left ? LX : RX] = x;
|
||||
_axisStateMap[left ? LY : RY] = y;
|
||||
} else if (axis == vr::k_EButton_SteamVR_Trigger) {
|
||||
//FIX ME: Seems that enters here everytime
|
||||
_axisStateMap[left ? LT : RT] = x;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -146,7 +146,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
|
|||
if (_entity->getCollisionsWillMove()) {
|
||||
return MOTION_TYPE_DYNAMIC;
|
||||
}
|
||||
return _entity->isMoving() ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
|
||||
return (_entity->isMoving() || _entity->hasActions()) ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
|
||||
}
|
||||
|
||||
bool EntityMotionState::isMoving() const {
|
||||
|
@ -184,6 +184,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
|||
if (!_entity) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(entityTreeIsLocked());
|
||||
measureBodyAcceleration();
|
||||
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
ObjectAction::ObjectAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) :
|
||||
btActionInterface(),
|
||||
EntityActionInterface(type, id),
|
||||
_active(false),
|
||||
_ownerEntity(ownerEntity) {
|
||||
}
|
||||
|
||||
|
@ -35,7 +34,9 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
|
|||
if (ownerEntityExpired) {
|
||||
qDebug() << "warning -- action with no entity removing self from btCollisionWorld.";
|
||||
btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld);
|
||||
dynamicsWorld->removeAction(this);
|
||||
if (dynamicsWorld) {
|
||||
dynamicsWorld->removeAction(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -120,6 +121,17 @@ QVariantMap ObjectAction::getArguments() {
|
|||
arguments["ttl"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
|
||||
}
|
||||
arguments["tag"] = _tag;
|
||||
|
||||
EntityItemPointer entity = _ownerEntity.lock();
|
||||
if (entity) {
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
|
||||
if (motionState) {
|
||||
arguments["::active"] = motionState->isActive();
|
||||
arguments["::motion-type"] = motionTypeToString(motionState->getMotionType());
|
||||
} else {
|
||||
arguments["::no-motion-state"] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
return arguments;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ public:
|
|||
virtual quint64 getExpires() { return _expires; }
|
||||
|
||||
protected:
|
||||
quint64 localTimeToServerTime(quint64 timeValue) const;
|
||||
quint64 serverTimeToLocalTime(quint64 timeValue) const;
|
||||
|
||||
virtual btRigidBody* getRigidBody();
|
||||
virtual glm::vec3 getPosition();
|
||||
|
@ -62,14 +64,10 @@ protected:
|
|||
virtual void setAngularVelocity(glm::vec3 angularVelocity);
|
||||
virtual void activateBody();
|
||||
|
||||
bool _active;
|
||||
EntityItemWeakPointer _ownerEntity;
|
||||
|
||||
quint64 _expires; // in seconds since epoch
|
||||
QString _tag;
|
||||
|
||||
quint64 localTimeToServerTime(quint64 timeValue) const;
|
||||
quint64 serverTimeToLocalTime(quint64 timeValue) const;
|
||||
quint64 _expires { 0 }; // in seconds since epoch
|
||||
bool _active { false };
|
||||
|
||||
private:
|
||||
int getEntityServerClockSkew() const;
|
||||
|
|
|
@ -20,17 +20,17 @@
|
|||
// origin of physics simulation in world-frame
|
||||
glm::vec3 _worldOffset(0.0f);
|
||||
|
||||
// static
|
||||
// static
|
||||
void ObjectMotionState::setWorldOffset(const glm::vec3& offset) {
|
||||
_worldOffset = offset;
|
||||
}
|
||||
|
||||
// static
|
||||
// static
|
||||
const glm::vec3& ObjectMotionState::getWorldOffset() {
|
||||
return _worldOffset;
|
||||
}
|
||||
|
||||
// static
|
||||
// static
|
||||
uint32_t worldSimulationStep = 0;
|
||||
void ObjectMotionState::setWorldSimulationStep(uint32_t step) {
|
||||
assert(step > worldSimulationStep);
|
||||
|
@ -41,7 +41,7 @@ uint32_t ObjectMotionState::getWorldSimulationStep() {
|
|||
return worldSimulationStep;
|
||||
}
|
||||
|
||||
// static
|
||||
// static
|
||||
ShapeManager* shapeManager = nullptr;
|
||||
void ObjectMotionState::setShapeManager(ShapeManager* manager) {
|
||||
assert(manager);
|
||||
|
@ -85,7 +85,7 @@ glm::vec3 ObjectMotionState::getBodyLinearVelocity() const {
|
|||
|
||||
glm::vec3 ObjectMotionState::getBodyLinearVelocityGTSigma() const {
|
||||
// NOTE: the threshold to use here relates to the linear displacement threshold (dX) for sending updates
|
||||
// to objects that are tracked server-side (e.g. entities which use dX = 2mm). Hence an object moving
|
||||
// to objects that are tracked server-side (e.g. entities which use dX = 2mm). Hence an object moving
|
||||
// just under this velocity threshold would trigger an update about V/dX times per second.
|
||||
const float MIN_LINEAR_SPEED_SQUARED = 0.0036f; // 6 mm/sec
|
||||
|
||||
|
|
|
@ -29,18 +29,27 @@ enum MotionType {
|
|||
MOTION_TYPE_KINEMATIC // keyframed motion
|
||||
};
|
||||
|
||||
inline QString motionTypeToString(MotionType motionType) {
|
||||
switch(motionType) {
|
||||
case MOTION_TYPE_STATIC: return QString("static");
|
||||
case MOTION_TYPE_DYNAMIC: return QString("dynamic");
|
||||
case MOTION_TYPE_KINEMATIC: return QString("kinematic");
|
||||
}
|
||||
return QString("unknown");
|
||||
}
|
||||
|
||||
enum MotionStateType {
|
||||
MOTIONSTATE_TYPE_INVALID,
|
||||
MOTIONSTATE_TYPE_ENTITY,
|
||||
MOTIONSTATE_TYPE_AVATAR
|
||||
};
|
||||
|
||||
// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
|
||||
// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
|
||||
// and re-added to the physics engine and "easy" which just updates the body properties.
|
||||
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_SHAPE |
|
||||
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_SHAPE |
|
||||
Simulation::DIRTY_COLLISION_GROUP);
|
||||
const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES |
|
||||
Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL |
|
||||
Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL |
|
||||
Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATOR_OWNERSHIP);
|
||||
|
||||
// These are the set of incoming flags that the PhysicsEngine needs to hear about:
|
||||
|
@ -57,7 +66,7 @@ class PhysicsEngine;
|
|||
class ObjectMotionState : public btMotionState {
|
||||
public:
|
||||
// These poroperties of the PhysicsEngine are "global" within the context of all ObjectMotionStates
|
||||
// (assuming just one PhysicsEngine). They are cached as statics for fast calculations in the
|
||||
// (assuming just one PhysicsEngine). They are cached as statics for fast calculations in the
|
||||
// ObjectMotionState context.
|
||||
static void setWorldOffset(const glm::vec3& offset);
|
||||
static const glm::vec3& getWorldOffset();
|
||||
|
@ -112,7 +121,7 @@ public:
|
|||
virtual float getObjectFriction() const = 0;
|
||||
virtual float getObjectLinearDamping() const = 0;
|
||||
virtual float getObjectAngularDamping() const = 0;
|
||||
|
||||
|
||||
virtual glm::vec3 getObjectPosition() const = 0;
|
||||
virtual glm::quat getObjectRotation() const = 0;
|
||||
virtual glm::vec3 getObjectLinearVelocity() const = 0;
|
||||
|
@ -131,6 +140,11 @@ public:
|
|||
|
||||
bool isActive() const { return _body ? _body->isActive() : false; }
|
||||
|
||||
bool hasInternalKinematicChanges() const { return _hasInternalKinematicChanges; }
|
||||
|
||||
void dirtyInternalKinematicChanges() { _hasInternalKinematicChanges = true; }
|
||||
void clearInternalKinematicChanges() { _hasInternalKinematicChanges = false; }
|
||||
|
||||
friend class PhysicsEngine;
|
||||
|
||||
protected:
|
||||
|
@ -151,6 +165,7 @@ protected:
|
|||
float _mass;
|
||||
|
||||
uint32_t _lastKinematicStep;
|
||||
bool _hasInternalKinematicChanges { false };
|
||||
};
|
||||
|
||||
typedef QSet<ObjectMotionState*> SetOfMotionStates;
|
||||
|
|
|
@ -82,12 +82,12 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
|
|||
btCollisionShape* shape = motionState->getShape();
|
||||
assert(shape);
|
||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||
motionState->setRigidBody(body);
|
||||
} else {
|
||||
body->setMassProps(mass, inertia);
|
||||
}
|
||||
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
body->updateInertiaTensor();
|
||||
motionState->setRigidBody(body);
|
||||
motionState->updateBodyVelocities();
|
||||
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
|
||||
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
|
||||
|
@ -101,12 +101,15 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
|
|||
shape->calculateLocalInertia(mass, inertia);
|
||||
if (!body) {
|
||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||
motionState->setRigidBody(body);
|
||||
} else {
|
||||
body->setMassProps(mass, inertia);
|
||||
}
|
||||
body->setCollisionFlags(body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT |
|
||||
btCollisionObject::CF_STATIC_OBJECT));
|
||||
body->updateInertiaTensor();
|
||||
motionState->setRigidBody(body);
|
||||
motionState->updateBodyVelocities();
|
||||
|
||||
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
||||
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
||||
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
||||
|
@ -123,12 +126,12 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
|
|||
if (!body) {
|
||||
assert(motionState->getShape());
|
||||
body = new btRigidBody(mass, motionState, motionState->getShape(), inertia);
|
||||
motionState->setRigidBody(body);
|
||||
} else {
|
||||
body->setMassProps(mass, inertia);
|
||||
}
|
||||
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||
body->updateInertiaTensor();
|
||||
motionState->setRigidBody(body);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it freely,
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it freely,
|
||||
* subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
|
@ -75,7 +75,7 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: We do NOT call synchronizeMotionState() after each substep (to avoid multiple locks on the
|
||||
// NOTE: We do NOT call synchronizeMotionStates() after each substep (to avoid multiple locks on the
|
||||
// object data outside of the physics engine). A consequence of this is that the transforms of the
|
||||
// external objects only ever update at the end of the full step.
|
||||
|
||||
|
@ -87,6 +87,33 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep
|
|||
return subSteps;
|
||||
}
|
||||
|
||||
// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
|
||||
void ThreadSafeDynamicsWorld::synchronizeMotionState(btRigidBody* body) {
|
||||
btAssert(body);
|
||||
if (body->getMotionState() && !body->isStaticObject()) {
|
||||
//we need to call the update at least once, even for sleeping objects
|
||||
//otherwise the 'graphics' transform never updates properly
|
||||
///@todo: add 'dirty' flag
|
||||
//if (body->getActivationState() != ISLAND_SLEEPING)
|
||||
{
|
||||
if (body->isKinematicObject()) {
|
||||
ObjectMotionState* objectMotionState = static_cast<ObjectMotionState*>(body->getMotionState());
|
||||
if (objectMotionState->hasInternalKinematicChanges()) {
|
||||
objectMotionState->clearInternalKinematicChanges();
|
||||
body->getMotionState()->setWorldTransform(body->getWorldTransform());
|
||||
}
|
||||
return;
|
||||
}
|
||||
btTransform interpolatedTransform;
|
||||
btTransformUtil::integrateTransform(body->getInterpolationWorldTransform(),
|
||||
body->getInterpolationLinearVelocity(),body->getInterpolationAngularVelocity(),
|
||||
(m_latencyMotionStateInterpolation && m_fixedTimeStep) ? m_localTime - m_fixedTimeStep : m_localTime*body->getHitFraction(),
|
||||
interpolatedTransform);
|
||||
body->getMotionState()->setWorldTransform(interpolatedTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
|
||||
_changedMotionStates.clear();
|
||||
BT_PROFILE("synchronizeMotionStates");
|
||||
|
@ -97,22 +124,22 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
|
|||
btRigidBody* body = btRigidBody::upcast(colObj);
|
||||
if (body) {
|
||||
if (body->getMotionState()) {
|
||||
synchronizeSingleMotionState(body);
|
||||
synchronizeMotionState(body);
|
||||
_changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
//iterate over all active rigid bodies
|
||||
for (int i=0;i<m_nonStaticRigidBodies.size();i++) {
|
||||
btRigidBody* body = m_nonStaticRigidBodies[i];
|
||||
if (body->isActive()) {
|
||||
if (body->getMotionState()) {
|
||||
synchronizeSingleMotionState(body);
|
||||
synchronizeMotionState(body);
|
||||
_changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it freely,
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it freely,
|
||||
* subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
|
@ -43,13 +43,16 @@ public:
|
|||
void synchronizeMotionStates();
|
||||
|
||||
// btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated
|
||||
// but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide
|
||||
// but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide
|
||||
// smoother rendering of objects when the physics simulation loop is ansynchronous to the render loop).
|
||||
float getLocalTimeAccumulation() const { return m_localTime; }
|
||||
|
||||
VectorOfMotionStates& getChangedMotionStates() { return _changedMotionStates; }
|
||||
|
||||
private:
|
||||
// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
|
||||
void synchronizeMotionState(btRigidBody* body);
|
||||
|
||||
VectorOfMotionStates _changedMotionStates;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
set(TARGET_NAME procedural)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared gpu model model-networking)
|
||||
link_hifi_libraries(shared gpu networking model model-networking)
|
||||
|
||||
|
|
|
@ -12,9 +12,12 @@
|
|||
|
||||
#include <qcoreapplication.h>
|
||||
|
||||
#include <qdatetime.h>
|
||||
#include <qdebug.h>
|
||||
#include <qtimer.h>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <QMutexLocker>
|
||||
#include <QRegExp>
|
||||
|
||||
#include "LogHandler.h"
|
||||
|
||||
|
@ -24,13 +27,14 @@ LogHandler& LogHandler::getInstance() {
|
|||
}
|
||||
|
||||
LogHandler::LogHandler() :
|
||||
_shouldOutputPID(false)
|
||||
_shouldOutputProcessID(false),
|
||||
_shouldOutputThreadID(false)
|
||||
{
|
||||
// setup our timer to flush the verbose logs every 5 seconds
|
||||
QTimer* logFlushTimer = new QTimer(this);
|
||||
connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages);
|
||||
logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000);
|
||||
|
||||
|
||||
// when the log handler is first setup we should print our timezone
|
||||
QString timezoneString = "Time zone: " + QDateTime::currentDateTime().toString("t");
|
||||
printf("%s\n", qPrintable(timezoneString));
|
||||
|
@ -57,51 +61,55 @@ const char* stringForLogType(LogMsgType msgType) {
|
|||
const QString DATE_STRING_FORMAT = "MM/dd hh:mm:ss";
|
||||
|
||||
void LogHandler::flushRepeatedMessages() {
|
||||
QMutexLocker locker(&_repeatedMessageLock);
|
||||
QHash<QString, int>::iterator message = _repeatMessageCountHash.begin();
|
||||
while (message != _repeatMessageCountHash.end()) {
|
||||
|
||||
|
||||
if (message.value() > 0) {
|
||||
QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"")
|
||||
.arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key()));
|
||||
|
||||
|
||||
QMessageLogContext emptyContext;
|
||||
printMessage(LogSuppressed, emptyContext, repeatMessage);
|
||||
}
|
||||
|
||||
|
||||
_lastRepeatedMessage.remove(message.key());
|
||||
message = _repeatMessageCountHash.erase(message);
|
||||
}
|
||||
}
|
||||
|
||||
QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
|
||||
|
||||
if (message.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
if (type == LogDebug) {
|
||||
// for debug messages, check if this matches any of our regexes for repeated log messages
|
||||
QMutexLocker locker(&_repeatedMessageLock);
|
||||
foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) {
|
||||
QRegExp repeatRegex(regexString);
|
||||
if (repeatRegex.indexIn(message) != -1) {
|
||||
|
||||
|
||||
if (!_repeatMessageCountHash.contains(regexString)) {
|
||||
// we have a match but didn't have this yet - output the first one
|
||||
_repeatMessageCountHash[regexString] = 0;
|
||||
|
||||
|
||||
// break the foreach so we output the first match
|
||||
break;
|
||||
} else {
|
||||
// we have a match - add 1 to the count of repeats for this message and set this as the last repeated message
|
||||
_repeatMessageCountHash[regexString] += 1;
|
||||
_lastRepeatedMessage[regexString] = message;
|
||||
|
||||
|
||||
// return out, we're not printing this one
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (type == LogDebug) {
|
||||
QMutexLocker locker(&_onlyOnceMessageLock);
|
||||
// see if this message is one we should only print once
|
||||
foreach(const QString& regexString, getInstance()._onlyOnceMessageRegexes) {
|
||||
QRegExp onlyOnceRegex(regexString);
|
||||
|
@ -118,23 +126,27 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// log prefix is in the following format
|
||||
// [TIMESTAMP] [DEBUG] [PID] [TARGET] logged string
|
||||
|
||||
// [TIMESTAMP] [DEBUG] [PID] [TID] [TARGET] logged string
|
||||
|
||||
QString prefixString = QString("[%1]").arg(QDateTime::currentDateTime().toString(DATE_STRING_FORMAT));
|
||||
|
||||
|
||||
prefixString.append(QString(" [%1]").arg(stringForLogType(type)));
|
||||
|
||||
if (_shouldOutputPID) {
|
||||
|
||||
if (_shouldOutputProcessID) {
|
||||
prefixString.append(QString(" [%1]").arg(QCoreApplication::instance()->applicationPid()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (_shouldOutputThreadID) {
|
||||
size_t threadID = (size_t)QThread::currentThreadId();
|
||||
prefixString.append(QString(" [%1]").arg(threadID));
|
||||
}
|
||||
|
||||
if (!_targetName.isEmpty()) {
|
||||
prefixString.append(QString(" [%1]").arg(_targetName));
|
||||
}
|
||||
|
||||
|
||||
QString logMessage = QString("%1 %2").arg(prefixString, message.split("\n").join("\n" + prefixString + " "));
|
||||
fprintf(stdout, "%s\n", qPrintable(logMessage));
|
||||
return logMessage;
|
||||
|
@ -143,3 +155,13 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
|
|||
void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
getInstance().printMessage((LogMsgType) type, context, message);
|
||||
}
|
||||
|
||||
const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) {
|
||||
QMutexLocker locker(&_repeatedMessageLock);
|
||||
return *_repeatedMessageRegexes.insert(regexString);
|
||||
}
|
||||
|
||||
const QString& LogHandler::addOnlyOnceMessageRegex(const QString& regexString) {
|
||||
QMutexLocker locker(&_onlyOnceMessageLock);
|
||||
return *_onlyOnceMessageRegexes.insert(regexString);
|
||||
}
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
#ifndef hifi_LogHandler_h
|
||||
#define hifi_LogHandler_h
|
||||
|
||||
#include <qhash.h>
|
||||
#include <qobject.h>
|
||||
#include <qregexp.h>
|
||||
#include <qset.h>
|
||||
#include <qstring.h>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QMutex>
|
||||
|
||||
const int VERBOSE_LOG_INTERVAL_SECONDS = 5;
|
||||
|
||||
|
@ -34,34 +34,38 @@ class LogHandler : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
static LogHandler& getInstance();
|
||||
|
||||
|
||||
/// sets the target name to output via the verboseMessageHandler, called once before logging begins
|
||||
/// \param targetName the desired target name to output in logs
|
||||
void setTargetName(const QString& targetName) { _targetName = targetName; }
|
||||
|
||||
void setShouldOutputPID(bool shouldOutputPID) { _shouldOutputPID = shouldOutputPID; }
|
||||
|
||||
|
||||
void setShouldOutputProcessID(bool shouldOutputProcessID) { _shouldOutputProcessID = shouldOutputProcessID; }
|
||||
void setShouldOutputThreadID(bool shouldOutputThreadID) { _shouldOutputThreadID = shouldOutputThreadID; }
|
||||
|
||||
QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message);
|
||||
|
||||
|
||||
/// a qtMessageHandler that can be hooked up to a target that links to Qt
|
||||
/// prints various process, message type, and time information
|
||||
static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message);
|
||||
|
||||
const QString& addRepeatedMessageRegex(const QString& regexString) { return *_repeatedMessageRegexes.insert(regexString); }
|
||||
const QString& addOnlyOnceMessageRegex(const QString& regexString) { return *_onlyOnceMessageRegexes.insert(regexString); }
|
||||
|
||||
const QString& addRepeatedMessageRegex(const QString& regexString);
|
||||
const QString& addOnlyOnceMessageRegex(const QString& regexString);
|
||||
private:
|
||||
LogHandler();
|
||||
|
||||
|
||||
void flushRepeatedMessages();
|
||||
|
||||
|
||||
QString _targetName;
|
||||
bool _shouldOutputPID;
|
||||
bool _shouldOutputProcessID;
|
||||
bool _shouldOutputThreadID;
|
||||
QSet<QString> _repeatedMessageRegexes;
|
||||
QHash<QString, int> _repeatMessageCountHash;
|
||||
QHash<QString, QString> _lastRepeatedMessage;
|
||||
QMutex _repeatedMessageLock;
|
||||
|
||||
QSet<QString> _onlyOnceMessageRegexes;
|
||||
QHash<QString, int> _onlyOnceMessageCountHash;
|
||||
QMutex _onlyOnceMessageLock;
|
||||
};
|
||||
|
||||
#endif // hifi_LogHandler_h
|
||||
|
|
Loading…
Reference in a new issue