mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 16:55:07 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into HMDLightingBug
This commit is contained in:
commit
9f8d6a78cc
28 changed files with 716 additions and 179 deletions
|
@ -15,16 +15,22 @@
|
|||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("connexionclient")
|
||||
hifi_library_search_hints("3dconnexionclient")
|
||||
|
||||
if (APPLE)
|
||||
find_library(3DCONNEXIONCLIENT_LIBRARIES NAMES 3DConnexionClient HINTS 3DCONNEXIONCLIENT_SEARCH_DIRS)
|
||||
if(EXISTS ${3DConnexionClient})
|
||||
set(3DCONNEXIONCLIENT_FOUND true)
|
||||
set(3DCONNEXIONCLIENT_INCLUDE_DIRS ${3DConnexionClient})
|
||||
set(3DCONNEXIONCLIENT_LIBRARY ${3DConnexionClient})
|
||||
message(STATUS "Found 3DConnexion at " ${3DConnexionClient})
|
||||
mark_as_advanced(3DCONNEXIONCLIENT_INCLUDE_DIR 3DCONNEXIONCLIENT_LIBRARY)
|
||||
find_library(3DCONNEXIONCLIENT 3DconnexionClient)
|
||||
if(EXISTS ${3DCONNEXIONCLIENT})
|
||||
find_path(3DCONNEXIONCLIENT_INCLUDE_DIR2 ConnexionClient.h PATH_SUFFIXES include HINTS ${3DCONNEXIONCLIENT_SEARCH_DIRS})
|
||||
include_directories(${3DCONNEXIONCLIENT_INCLUDE_DIR2})
|
||||
|
||||
get_filename_component( 3DCONNEXIONCLIENT_FRAMEWORK_DIR ${3DCONNEXIONCLIENT} PATH )
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "-weak_framework 3DconnexionClient")
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FRAMEWORK_SEARCH_PATHS 3DCONNEXIONCLIENT_FRAMEWORK_DIR)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(3DCONNEXIONCLIENT DEFAULT_MSG 3DCONNEXIONCLIENT_INCLUDE_DIR2)
|
||||
mark_as_advanced(3DCONNEXIONCLIENT_INCLUDE_DIR2)
|
||||
message(STATUS "Found 3DConnexion")
|
||||
else ()
|
||||
message(STATUS "Could NOT find 3DConnexionClient")
|
||||
endif()
|
||||
|
@ -32,7 +38,7 @@ elseif (WIN32)
|
|||
find_path(3DCONNEXIONCLIENT_INCLUDE_DIRS I3dMouseParams.h PATH_SUFFIXES include HINTS ${3DCONNEXIONCLIENT_SEARCH_DIRS})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(3DConnexionClient DEFAULT_MSG 3DCONNEXIONCLIENT_INCLUDE_DIRS)
|
||||
find_package_handle_standard_args(3DCONNEXIONCLIENT DEFAULT_MSG 3DCONNEXIONCLIENT_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(3DCONNEXIONCLIENT_INCLUDE_DIRS 3DCONNEXIONCLIENT_SEARCH_DIRS)
|
||||
endif()
|
||||
endif()
|
||||
|
|
237
interface/external/3dconnexionclient/include/ConnexionClient.h
vendored
Normal file
237
interface/external/3dconnexionclient/include/ConnexionClient.h
vendored
Normal file
|
@ -0,0 +1,237 @@
|
|||
//==============================================================================
|
||||
|
||||
#ifndef _H_connexionclient
|
||||
#define _H_connexionclient
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//==============================================================================
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
//==============================================================================
|
||||
#pragma pack(push,2)
|
||||
//==============================================================================
|
||||
// Client registration modes
|
||||
|
||||
// Use kConnexionClientWildcard ('****') as the application signature in the
|
||||
// RegisterConnexionClient API to take over the device system-wide in all
|
||||
// applications:
|
||||
|
||||
#define kConnexionClientWildcard 0x2A2A2A2A
|
||||
|
||||
// There are two plugin operating modes: one takes over the device
|
||||
// and disables all built-in driver assignments, the other complements
|
||||
// the driver by only executing commands that are meant for plugins:
|
||||
|
||||
enum {
|
||||
kConnexionClientModeTakeOver = 1, // take over device completely, driver no longer executes assignments
|
||||
kConnexionClientModePlugin = 2 // receive plugin assignments only, let driver take care of its own
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Client commands
|
||||
|
||||
// The following assignments must be executed by the client:
|
||||
|
||||
enum {
|
||||
kConnexionCmdNone = 0,
|
||||
kConnexionCmdHandleRawData = 1,
|
||||
kConnexionCmdHandleButtons = 2,
|
||||
kConnexionCmdHandleAxis = 3,
|
||||
|
||||
kConnexionCmdAppSpecific = 10
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Messages
|
||||
|
||||
// The following messages are forwarded to user space clients:
|
||||
|
||||
#define kConnexionMsgDeviceState '3dSR' // forwarded device state data
|
||||
#define kConnexionMsgPrefsChanged '3dPC' // notify clients that the current app prefs have changed
|
||||
#define kConnexionMsgCalibrateDevice '3dSC' // device state data to be used for calibration
|
||||
|
||||
// Control messages for the driver sent via the ConnexionControl API:
|
||||
|
||||
#define kConnexionCtlSetLEDState '3dsl' // set the LED state, param = (uint8_t)ledState
|
||||
#define kConnexionCtlGetDeviceID '3did' // get vendorID and productID in the high and low words of the result
|
||||
#define kConnexionCtlCalibrate '3dca' // calibrate the device with the current axes values (same as executing the calibrate assignment)
|
||||
#define kConnexionCtlUncalibrate '3dde' // uncalibrate the device (i.e. reset calibration to 0,0,0,0,0,0)
|
||||
#define kConnexionCtlOpenPrefPane '3dop' // open the 3dconnexion preference pane in System Preferences
|
||||
#define kConnexionCtlSetSwitches '3dss' // set the current state of the client-controlled feature switches (bitmap, see masks below)
|
||||
|
||||
// Client capability mask constants (this mask defines which buttons and controls should be sent to clients, the others are handled by the driver)
|
||||
|
||||
#define kConnexionMaskButton1 0x0001
|
||||
#define kConnexionMaskButton2 0x0002
|
||||
#define kConnexionMaskButton3 0x0004
|
||||
#define kConnexionMaskButton4 0x0008
|
||||
#define kConnexionMaskButton5 0x0010
|
||||
#define kConnexionMaskButton6 0x0020
|
||||
#define kConnexionMaskButton7 0x0040
|
||||
#define kConnexionMaskButton8 0x0080
|
||||
|
||||
#define kConnexionMaskAxis1 0x0100
|
||||
#define kConnexionMaskAxis2 0x0200
|
||||
#define kConnexionMaskAxis3 0x0400
|
||||
#define kConnexionMaskAxis4 0x0800
|
||||
#define kConnexionMaskAxis5 0x1000
|
||||
#define kConnexionMaskAxis6 0x2000
|
||||
|
||||
#define kConnexionMaskButtons 0x00FF // note: this only specifies the first 8 buttons, kept for backwards compatibility
|
||||
#define kConnexionMaskAxisTrans 0x0700
|
||||
#define kConnexionMaskAxisRot 0x3800
|
||||
#define kConnexionMaskAxis 0x3F00
|
||||
#define kConnexionMaskAll 0x3FFF
|
||||
|
||||
// Added in version 10:0 to support all 32 buttons on the SpacePilot Pro, use with the new SetConnexionClientButtonMask API
|
||||
|
||||
#define kConnexionMaskButton9 0x00000100
|
||||
#define kConnexionMaskButton10 0x00000200
|
||||
#define kConnexionMaskButton11 0x00000400
|
||||
#define kConnexionMaskButton12 0x00000800
|
||||
#define kConnexionMaskButton13 0x00001000
|
||||
#define kConnexionMaskButton14 0x00002000
|
||||
#define kConnexionMaskButton15 0x00004000
|
||||
#define kConnexionMaskButton16 0x00008000
|
||||
|
||||
#define kConnexionMaskButton17 0x00010000
|
||||
#define kConnexionMaskButton18 0x00020000
|
||||
#define kConnexionMaskButton19 0x00040000
|
||||
#define kConnexionMaskButton20 0x00080000
|
||||
#define kConnexionMaskButton21 0x00100000
|
||||
#define kConnexionMaskButton22 0x00200000
|
||||
#define kConnexionMaskButton23 0x00400000
|
||||
#define kConnexionMaskButton24 0x00800000
|
||||
|
||||
#define kConnexionMaskButton25 0x01000000
|
||||
#define kConnexionMaskButton26 0x02000000
|
||||
#define kConnexionMaskButton27 0x04000000
|
||||
#define kConnexionMaskButton28 0x08000000
|
||||
#define kConnexionMaskButton29 0x10000000
|
||||
#define kConnexionMaskButton30 0x20000000
|
||||
#define kConnexionMaskButton31 0x40000000
|
||||
#define kConnexionMaskButton32 0x80000000
|
||||
|
||||
#define kConnexionMaskAllButtons 0xFFFFFFFF
|
||||
|
||||
// Masks for client-controlled feature switches
|
||||
|
||||
#define kConnexionSwitchDominant 0x0002
|
||||
#define kConnexionSwitchEnableAxis1 0x0004
|
||||
#define kConnexionSwitchEnableAxis2 0x0008
|
||||
#define kConnexionSwitchEnableAxis3 0x0010
|
||||
#define kConnexionSwitchEnableAxis4 0x0020
|
||||
#define kConnexionSwitchEnableAxis5 0x0040
|
||||
#define kConnexionSwitchEnableAxis6 0x0080
|
||||
|
||||
#define kConnexionSwitchEnableTrans 0x001C
|
||||
#define kConnexionSwitchEnableRot 0x00E0
|
||||
#define kConnexionSwitchEnableAll 0x00FC
|
||||
|
||||
#define kConnexionSwitchZoomOnY 0x0001 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseAxis1 0x0100 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseAxis2 0x0200 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseAxis3 0x0400 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseAxis4 0x0800 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseAxis5 0x1000 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseAxis6 0x2000 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseTrans 0x0700 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseRot 0x3800 // no longer applies, no effect on new driver
|
||||
#define kConnexionSwitchReverseAll 0x3F00 // no longer applies, no effect on new driver
|
||||
|
||||
#define kConnexionSwitchesDisabled 0x80000000 // use driver defaults instead of client-controlled switches
|
||||
|
||||
//==============================================================================
|
||||
// Device state record
|
||||
|
||||
// Structure type and current version:
|
||||
|
||||
#define kConnexionDeviceStateType 0x4D53 // 'MS' (Connexion State)
|
||||
#define kConnexionDeviceStateVers 0x6D33 // 'm3' (version 3 includes 32-bit button data in previously unused field, binary compatible with version 2)
|
||||
|
||||
// This structure is used to forward device data and commands from the kext to the client:
|
||||
|
||||
typedef struct {
|
||||
// header
|
||||
uint16_t version; // kConnexionDeviceStateVers
|
||||
uint16_t client; // identifier of the target client when sending a state message to all user clients
|
||||
// command
|
||||
uint16_t command; // command for the user-space client
|
||||
int16_t param; // optional parameter for the specified command
|
||||
int32_t value; // optional value for the specified command
|
||||
uint64_t time; // timestamp for this message (clock_get_uptime)
|
||||
// raw report
|
||||
uint8_t report[8]; // raw USB report from the device
|
||||
// processed data
|
||||
uint16_t buttons8; // buttons (first 8 buttons only, for backwards binary compatibility- use "buttons" field instead)
|
||||
int16_t axis[6]; // x, y, z, rx, ry, rz
|
||||
uint16_t address; // USB device address, used to tell one device from the other
|
||||
uint32_t buttons; // buttons
|
||||
} ConnexionDeviceState, *ConnexionDeviceStatePtr;
|
||||
|
||||
// Size of the above structure:
|
||||
|
||||
#define kConnexionDeviceStateSize (sizeof(ConnexionDeviceState))
|
||||
|
||||
//==============================================================================
|
||||
// Device IDs for 3Dconnexion devices with separate and different preferences.
|
||||
// NOTE: These IDs are no longer internally used by the driver, and the
|
||||
// ConnexionGetCurrentDevicePrefs API always returns kDevID_AnyDevice in the
|
||||
// deviceID field. The definitions are kept here for backwards compatibility only.
|
||||
|
||||
#define kDevID_AnyDevice 0x7FFF // wildcard used to specify any available device
|
||||
|
||||
//==============================================================================
|
||||
// Device prefs record
|
||||
|
||||
// Structure type and current version:
|
||||
|
||||
#define kConnexionDevicePrefsType 0x4D50 // 'MP' (Connexion Prefs)
|
||||
#define kConnexionDevicePrefsVers 0x7031 // 'p1' (version 1)
|
||||
|
||||
// This structure is used to retrieve the current device prefs from the helper:
|
||||
|
||||
typedef struct {
|
||||
// header
|
||||
uint16_t type; // kConnexionDevicePrefsType
|
||||
uint16_t version; // kConnexionDevicePrefsVers
|
||||
uint16_t deviceID; // device ID (SpaceNavigator, SpaceNavigatorNB, SpaceExplorer...)
|
||||
uint16_t reserved1; // set to 0
|
||||
// target application
|
||||
uint32_t appSignature; // target application signature
|
||||
uint32_t reserved2; // set to 0
|
||||
uint8_t appName[64]; // target application name (Pascal string with length byte at the beginning)
|
||||
// device preferences
|
||||
uint8_t mainSpeed; // overall speed
|
||||
uint8_t zoomOnY; // use Y axis for zoom, Z axis for un/down pan
|
||||
uint8_t dominant; // only respond to the largest one of all 6 axes values at any given time
|
||||
uint8_t reserved3; // set to 0
|
||||
int8_t mapV[6]; // axes mapping when Zoom direction is on vertical axis (zoomOnY = 0)
|
||||
int8_t mapH[6]; // axes mapping when Zoom direction is on horizontal axis (zoomOnY != 0)
|
||||
uint8_t enabled[6]; // enable or disable individual axes
|
||||
uint8_t reversed[6]; // reverse individual axes
|
||||
uint8_t speed[6]; // speed for individual axes (min 0, max 200, reserved 201-255)
|
||||
uint8_t sensitivity[6]; // sensitivity for individual axes (min 0, max 200, reserved 201-255)
|
||||
int32_t scale[6]; // 10000 * scale and "natural" reverse state for individual axes
|
||||
// added in version 10.0 (build 136)
|
||||
uint32_t gamma; // 1000 * gamma value used to compute nonlinear axis response, use 1000 (1.0) for linear response
|
||||
uint32_t intersect; // intersect value used for gamma computations
|
||||
} ConnexionDevicePrefs, *ConnexionDevicePrefsPtr;
|
||||
|
||||
// Size of the above structure:
|
||||
|
||||
#define kConnexionDevicePrefsSize (sizeof(ConnexionDevicePrefs))
|
||||
|
||||
//==============================================================================
|
||||
#pragma pack(pop)
|
||||
//==============================================================================
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
//==============================================================================
|
||||
|
||||
#endif // _H_connexionclient
|
||||
|
||||
//==============================================================================
|
88
interface/external/3dconnexionclient/include/ConnexionClientAPI.h
vendored
Normal file
88
interface/external/3dconnexionclient/include/ConnexionClientAPI.h
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
//==============================================================================
|
||||
|
||||
#ifndef _H_connexionclientapi
|
||||
#define _H_connexionclientapi
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "ConnexionClient.h"
|
||||
|
||||
//==============================================================================
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
//==============================================================================
|
||||
// Callback procedure types
|
||||
|
||||
typedef void (*ConnexionAddedHandlerProc) (unsigned int productID);
|
||||
typedef void (*ConnexionRemovedHandlerProc) (unsigned int productID);
|
||||
typedef void (*ConnexionMessageHandlerProc) (unsigned int productID, unsigned int messageType, void *messageArgument);
|
||||
|
||||
// NOTE for ConnexionMessageHandlerProc:
|
||||
// when messageType == kConnexionMsgDeviceState, messageArgument points to ConnexionDeviceState with size kConnexionDeviceStateSize
|
||||
// when messageType == kConnexionMsgPrefsChanged, messageArgument points to the target application signature with size sizeof(uint32_t)
|
||||
|
||||
//==============================================================================
|
||||
// Public APIs to be called once when the application starts up or shuts down
|
||||
|
||||
int16_t SetConnexionHandlers (ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler, bool useSeparateThread);
|
||||
void CleanupConnexionHandlers (void);
|
||||
|
||||
// Obsolete API replaced by SetConnexionHandlers, will be removed in the future
|
||||
|
||||
int16_t InstallConnexionHandlers (ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler);
|
||||
|
||||
//==============================================================================
|
||||
// Public APIs to be called whenever the app wants to start/stop receiving data
|
||||
// the mask parameter (client capabilities mask) specifies which controls must be forwarded to the client
|
||||
// buttonMask (previously part of the client capabilities mask) specifies which buttons must be forwarded to the client
|
||||
|
||||
uint16_t RegisterConnexionClient (uint32_t signature, uint8_t *name, uint16_t mode, uint32_t mask);
|
||||
void SetConnexionClientMask (uint16_t clientID, uint32_t mask);
|
||||
void SetConnexionClientButtonMask (uint16_t clientID, uint32_t buttonMask);
|
||||
void UnregisterConnexionClient (uint16_t clientID);
|
||||
|
||||
//==============================================================================
|
||||
// Public API to send control commands to the driver and retrieve a result value
|
||||
// Note: the new ConnexionClientControl variant is strictly required for
|
||||
// kConnexionCtlSetSwitches and kConnexionCtlClearSwitches but also works for
|
||||
// all other Control calls. The old variant remains for backwards compatibility.
|
||||
|
||||
int16_t ConnexionControl (uint32_t message, int32_t param, int32_t *result);
|
||||
int16_t ConnexionClientControl (uint16_t clientID, uint32_t message, int32_t param, int32_t *result);
|
||||
|
||||
//==============================================================================
|
||||
// Public API to fetch the current device preferences for either the first connected device or a specific device type (kDevID_Xxx)
|
||||
|
||||
int16_t ConnexionGetCurrentDevicePrefs (uint32_t deviceID, ConnexionDevicePrefs *prefs);
|
||||
|
||||
//==============================================================================
|
||||
// Public API to set all button labels in the iOS/Android "virtual device" apps
|
||||
|
||||
int16_t ConnexionSetButtonLabels (uint8_t *labels, uint16_t size);
|
||||
|
||||
// Labels data is a series of 32 variable-length null-terminated UTF8-encoded strings.
|
||||
// The sequence of strings follows the SpacePilot Pro button numbering.
|
||||
// Empty strings revert the button label to its default value.
|
||||
// As an example, this data would set the label for button Top to "Top" and
|
||||
// revert all other button labels to their default values:
|
||||
//
|
||||
// 0x00, // empty string for Menu
|
||||
// 0x00, // empty string for Fit
|
||||
// 0x54, 0x6F, 0x70, 0x00, // utf-8 encoded "Top" string for Top
|
||||
// 0x00, // empty string for Left
|
||||
// 0x00, 0x00, 0x00, 0x00, // empty strings for Right, Front, etc...
|
||||
// 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00
|
||||
//==============================================================================
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
//==============================================================================
|
||||
|
||||
#endif // _H_connexionclientapi
|
||||
|
||||
//==============================================================================
|
|
@ -1,3 +1,4 @@
|
|||
The Mac version does not require any files. The 3D Connexion driver should be installed from http://www.3dconnexion.eu/service/drivers.html
|
||||
You can copy the header files to the include dir, so that they get compiled in by xcode
|
||||
|
||||
For Windows the provided header file is required: include/I3dMouseParams.h
|
||||
For Windows the provided header file is required: include/I3dMouseParams.h
|
||||
|
|
|
@ -158,7 +158,7 @@ private:
|
|||
#else
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include "3DconnexionClient/ConnexionClientAPI.h"
|
||||
#include "ConnexionClientAPI.h"
|
||||
|
||||
class ConnexionClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -239,4 +239,4 @@ protected:
|
|||
AxisStateMap _axisStateMap;
|
||||
};
|
||||
|
||||
#endif // defined(hifi_3DConnexionClient_h)
|
||||
#endif // defined(hifi_3DConnexionClient_h)
|
||||
|
|
|
@ -134,6 +134,9 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q
|
|||
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;
|
||||
|
|
|
@ -149,28 +149,6 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
|
|||
|
||||
glm::vec3 tip = absolutePoses[tipIndex].trans;
|
||||
float error = glm::length(targetPose.trans - tip);
|
||||
if (error < ACCEPTABLE_RELATIVE_ERROR) {
|
||||
if (largestError < error) {
|
||||
largestError = error;
|
||||
}
|
||||
// this targetPose has been met
|
||||
// finally set the relative rotation of the tip to agree with absolute target rotation
|
||||
int parentIndex = _skeleton->getParentIndex(tipIndex);
|
||||
if (parentIndex != -1) {
|
||||
// compute tip's new parent-relative rotation
|
||||
// Q = Qp * q --> q' = Qp^ * Q
|
||||
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot;
|
||||
RotationConstraint* constraint = getConstraint(tipIndex);
|
||||
if (constraint) {
|
||||
constraint->apply(newRelativeRotation);
|
||||
// TODO: ATM the final rotation target may fails but we need to provide
|
||||
// feedback to the IK system so that it can adjust the bones up the skeleton
|
||||
// to help this rotation target get met.
|
||||
}
|
||||
_relativePoses[tipIndex].rot = newRelativeRotation;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// descend toward root, rotating each joint to get tip closer to target
|
||||
int index = _skeleton->getParentIndex(tipIndex);
|
||||
|
@ -191,6 +169,8 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
|
|||
// 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.
|
||||
if (angle > EPSILON) {
|
||||
// reduce angle by half: slows convergence but adds stability to IK solution
|
||||
angle = 0.5f * angle;
|
||||
glm::quat deltaRotation = glm::angleAxis(angle, axis);
|
||||
|
||||
int parentIndex = _skeleton->getParentIndex(index);
|
||||
|
@ -268,7 +248,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
|||
loadPoses(underPoses);
|
||||
} else {
|
||||
// relax toward underpose
|
||||
const float RELAXATION_TIMESCALE = 0.25f;
|
||||
const float RELAXATION_TIMESCALE = 0.125f;
|
||||
const float alpha = glm::clamp(dt / RELAXATION_TIMESCALE, 0.0f, 1.0f);
|
||||
int numJoints = (int)_relativePoses.size();
|
||||
for (int i = 0; i < numJoints; ++i) {
|
||||
|
@ -342,7 +322,7 @@ void AnimInverseKinematics::initConstraints() {
|
|||
// compute corresponding absolute poses
|
||||
int numJoints = (int)_defaultRelativePoses.size();
|
||||
AnimPoseVec absolutePoses;
|
||||
absolutePoses.reserve(numJoints);
|
||||
absolutePoses.resize(numJoints);
|
||||
for (int i = 0; i < numJoints; ++i) {
|
||||
int parentIndex = _skeleton->getParentIndex(i);
|
||||
if (parentIndex < 0) {
|
||||
|
@ -467,11 +447,11 @@ void AnimInverseKinematics::initConstraints() {
|
|||
} else if (baseName.startsWith("Shoulder", Qt::CaseInsensitive)) {
|
||||
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
||||
const float MAX_SHOULDER_TWIST = PI / 8.0f;
|
||||
const float MAX_SHOULDER_TWIST = PI / 20.0f;
|
||||
stConstraint->setTwistLimits(-MAX_SHOULDER_TWIST, MAX_SHOULDER_TWIST);
|
||||
|
||||
std::vector<float> minDots;
|
||||
const float MAX_SHOULDER_SWING = PI / 14.0f;
|
||||
const float MAX_SHOULDER_SWING = PI / 20.0f;
|
||||
minDots.push_back(cosf(MAX_SHOULDER_SWING));
|
||||
stConstraint->setSwingLimits(minDots);
|
||||
|
||||
|
@ -509,7 +489,7 @@ void AnimInverseKinematics::initConstraints() {
|
|||
// we determine the max/min angles by rotating the swing limit lines from parent- to child-frame
|
||||
// then measure the angles to swing the yAxis into alignment
|
||||
glm::vec3 hingeAxis = - mirror * zAxis;
|
||||
const float MIN_ELBOW_ANGLE = 0.0f;
|
||||
const float MIN_ELBOW_ANGLE = 0.05f;
|
||||
const float MAX_ELBOW_ANGLE = 11.0f * PI / 12.0f;
|
||||
glm::quat invReferenceRotation = glm::inverse(referenceRotation);
|
||||
glm::vec3 minSwingAxis = invReferenceRotation * glm::angleAxis(MIN_ELBOW_ANGLE, hingeAxis) * yAxis;
|
||||
|
|
|
@ -418,9 +418,17 @@ soxr_error_t possibleResampling(soxr_t resampler,
|
|||
numSourceSamples,
|
||||
sourceAudioFormat, destinationAudioFormat);
|
||||
|
||||
size_t numDestinationSamplesActual = 0;
|
||||
resampleError = soxr_process(resampler,
|
||||
channelConversionSamples, numChannelCoversionSamples, NULL,
|
||||
destinationSamples, numDestinationSamples, NULL);
|
||||
destinationSamples, numDestinationSamples, &numDestinationSamplesActual);
|
||||
|
||||
// return silence instead of playing garbage samples
|
||||
if (numDestinationSamplesActual < numDestinationSamples) {
|
||||
unsigned int nBytes = (numDestinationSamples - numDestinationSamplesActual) * destinationAudioFormat.channelCount() * sizeof(int16_t);
|
||||
memset(&destinationSamples[numDestinationSamplesActual * destinationAudioFormat.channelCount()], 0, nBytes);
|
||||
qCDebug(audioclient) << "SOXR: padded with" << nBytes << "bytes of silence";
|
||||
}
|
||||
|
||||
delete[] channelConversionSamples;
|
||||
} else {
|
||||
|
@ -433,9 +441,17 @@ soxr_error_t possibleResampling(soxr_t resampler,
|
|||
numAdjustedDestinationSamples /= 2;
|
||||
}
|
||||
|
||||
size_t numAdjustedDestinationSamplesActual = 0;
|
||||
resampleError = soxr_process(resampler,
|
||||
sourceSamples, numAdjustedSourceSamples, NULL,
|
||||
destinationSamples, numAdjustedDestinationSamples, NULL);
|
||||
destinationSamples, numAdjustedDestinationSamples, &numAdjustedDestinationSamplesActual);
|
||||
|
||||
// return silence instead of playing garbage samples
|
||||
if (numAdjustedDestinationSamplesActual < numAdjustedDestinationSamples) {
|
||||
unsigned int nBytes = (numAdjustedDestinationSamples - numAdjustedDestinationSamplesActual) * destinationAudioFormat.channelCount() * sizeof(int16_t);
|
||||
memset(&destinationSamples[numAdjustedDestinationSamplesActual * destinationAudioFormat.channelCount()], 0, nBytes);
|
||||
qCDebug(audioclient) << "SOXR: padded with" << nBytes << "bytes of silence";
|
||||
}
|
||||
}
|
||||
|
||||
return resampleError;
|
||||
|
|
|
@ -31,23 +31,16 @@ AssetClient::AssetClient() {
|
|||
static_cast<AssetClient*>(dependency)->deleteLater();
|
||||
});
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply");
|
||||
packetReceiver.registerMessageListener(PacketType::AssetGetReply, this, "handleAssetGetReply");
|
||||
packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply");
|
||||
|
||||
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &AssetClient::handleNodeKilled);
|
||||
}
|
||||
|
||||
AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
AssetRequest* req;
|
||||
QMetaObject::invokeMethod(this, "createRequest",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(AssetRequest*, req),
|
||||
Q_ARG(QString, hash),
|
||||
Q_ARG(QString, extension));
|
||||
return req;
|
||||
}
|
||||
|
||||
if (hash.length() != SHA256_HASH_HEX_LENGTH) {
|
||||
qDebug() << "Invalid hash size";
|
||||
return nullptr;
|
||||
|
@ -62,19 +55,15 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return new AssetRequest(this, hash, extension);
|
||||
auto request = new AssetRequest(hash, extension);
|
||||
|
||||
// Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case)
|
||||
request->moveToThread(thread());
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
AssetUpload* AssetClient::createUpload(const QString& filename) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
AssetUpload* upload;
|
||||
QMetaObject::invokeMethod(this, "createUpload",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(AssetUpload*, upload),
|
||||
Q_ARG(QString, filename));
|
||||
return upload;
|
||||
}
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
|
@ -83,7 +72,11 @@ AssetUpload* AssetClient::createUpload(const QString& filename) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return new AssetUpload(this, filename);
|
||||
auto upload = new AssetUpload(this, filename);
|
||||
|
||||
upload->moveToThread(thread());
|
||||
|
||||
return upload;
|
||||
}
|
||||
|
||||
bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end,
|
||||
|
@ -118,7 +111,7 @@ bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOf
|
|||
|
||||
nodeList->sendPacket(std::move(packet), *assetServer);
|
||||
|
||||
_pendingRequests[messageID] = callback;
|
||||
_pendingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -143,7 +136,7 @@ bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, Ge
|
|||
|
||||
nodeList->sendPacket(std::move(packet), *assetServer);
|
||||
|
||||
_pendingInfoRequests[messageID] = callback;
|
||||
_pendingInfoRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -165,9 +158,23 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer<NLPacket> packet, Share
|
|||
packet->readPrimitive(&info.size);
|
||||
}
|
||||
|
||||
if (_pendingInfoRequests.contains(messageID)) {
|
||||
auto callback = _pendingInfoRequests.take(messageID);
|
||||
callback(error, info);
|
||||
// Check if we have any pending requests for this node
|
||||
auto messageMapIt = _pendingInfoRequests.find(senderNode);
|
||||
if (messageMapIt != _pendingInfoRequests.end()) {
|
||||
|
||||
// Found the node, get the MessageID -> Callback map
|
||||
auto& messageCallbackMap = messageMapIt->second;
|
||||
|
||||
// Check if we have this pending request
|
||||
auto requestIt = messageCallbackMap.find(messageID);
|
||||
if (requestIt != messageCallbackMap.end()) {
|
||||
auto callback = requestIt->second;
|
||||
callback(true, error, info);
|
||||
messageCallbackMap.erase(requestIt);
|
||||
}
|
||||
|
||||
// Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from
|
||||
// it to avoid constantly creating/deleting the map on subsequent requests.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,9 +201,23 @@ void AssetClient::handleAssetGetReply(QSharedPointer<NLPacketList> packetList, S
|
|||
qDebug() << "Failure getting asset: " << error;
|
||||
}
|
||||
|
||||
if (_pendingRequests.contains(messageID)) {
|
||||
auto callback = _pendingRequests.take(messageID);
|
||||
callback(error, data);
|
||||
// Check if we have any pending requests for this node
|
||||
auto messageMapIt = _pendingRequests.find(senderNode);
|
||||
if (messageMapIt != _pendingRequests.end()) {
|
||||
|
||||
// Found the node, get the MessageID -> Callback map
|
||||
auto& messageCallbackMap = messageMapIt->second;
|
||||
|
||||
// Check if we have this pending request
|
||||
auto requestIt = messageCallbackMap.find(messageID);
|
||||
if (requestIt != messageCallbackMap.end()) {
|
||||
auto callback = requestIt->second;
|
||||
callback(true, error, data);
|
||||
messageCallbackMap.erase(requestIt);
|
||||
}
|
||||
|
||||
// Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from
|
||||
// it to avoid constantly creating/deleting the map on subsequent requests.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +240,7 @@ bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension,
|
|||
|
||||
nodeList->sendPacketList(std::move(packetList), *assetServer);
|
||||
|
||||
_pendingUploads[messageID] = callback;
|
||||
_pendingUploads[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -244,8 +265,59 @@ void AssetClient::handleAssetUploadReply(QSharedPointer<NLPacket> packet, Shared
|
|||
qDebug() << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString;
|
||||
}
|
||||
|
||||
if (_pendingUploads.contains(messageID)) {
|
||||
auto callback = _pendingUploads.take(messageID);
|
||||
callback(error, hashString);
|
||||
// Check if we have any pending requests for this node
|
||||
auto messageMapIt = _pendingUploads.find(senderNode);
|
||||
if (messageMapIt != _pendingUploads.end()) {
|
||||
|
||||
// Found the node, get the MessageID -> Callback map
|
||||
auto& messageCallbackMap = messageMapIt->second;
|
||||
|
||||
// Check if we have this pending request
|
||||
auto requestIt = messageCallbackMap.find(messageID);
|
||||
if (requestIt != messageCallbackMap.end()) {
|
||||
auto callback = requestIt->second;
|
||||
callback(true, error, hashString);
|
||||
messageCallbackMap.erase(requestIt);
|
||||
}
|
||||
|
||||
// Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from
|
||||
// it to avoid constantly creating/deleting the map on subsequent requests.
|
||||
}
|
||||
}
|
||||
|
||||
void AssetClient::handleNodeKilled(SharedNodePointer node) {
|
||||
if (node->getType() != NodeType::AssetServer) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto messageMapIt = _pendingRequests.find(node);
|
||||
if (messageMapIt != _pendingRequests.end()) {
|
||||
for (const auto& value : messageMapIt->second) {
|
||||
value.second(false, AssetServerError::NoError, QByteArray());
|
||||
}
|
||||
messageMapIt->second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto messageMapIt = _pendingInfoRequests.find(node);
|
||||
if (messageMapIt != _pendingInfoRequests.end()) {
|
||||
AssetInfo info { "", 0 };
|
||||
for (const auto& value : messageMapIt->second) {
|
||||
value.second(false, AssetServerError::NoError, info);
|
||||
}
|
||||
messageMapIt->second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto messageMapIt = _pendingUploads.find(node);
|
||||
if (messageMapIt != _pendingUploads.end()) {
|
||||
for (const auto& value : messageMapIt->second) {
|
||||
value.second(false, AssetServerError::NoError, "");
|
||||
}
|
||||
messageMapIt->second.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "AssetUtils.h"
|
||||
#include "LimitedNodeList.h"
|
||||
#include "NLPacket.h"
|
||||
#include "Node.h"
|
||||
|
||||
class AssetRequest;
|
||||
class AssetUpload;
|
||||
|
@ -29,9 +30,11 @@ struct AssetInfo {
|
|||
int64_t size;
|
||||
};
|
||||
|
||||
using ReceivedAssetCallback = std::function<void(AssetServerError serverError, const QByteArray& data)>;
|
||||
using GetInfoCallback = std::function<void(AssetServerError serverError, AssetInfo info)>;
|
||||
using UploadResultCallback = std::function<void(AssetServerError serverError, const QString& hash)>;
|
||||
using ReceivedAssetCallback = std::function<void(bool responseReceived, AssetServerError serverError, const QByteArray& data)>;
|
||||
using GetInfoCallback = std::function<void(bool responseReceived, AssetServerError serverError, AssetInfo info)>;
|
||||
using UploadResultCallback = std::function<void(bool responseReceived, AssetServerError serverError, const QString& hash)>;
|
||||
|
||||
|
||||
|
||||
class AssetClient : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -46,15 +49,17 @@ private slots:
|
|||
void handleAssetGetReply(QSharedPointer<NLPacketList> packetList, SharedNodePointer senderNode);
|
||||
void handleAssetUploadReply(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
|
||||
void handleNodeKilled(SharedNodePointer node);
|
||||
|
||||
private:
|
||||
bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback);
|
||||
bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback);
|
||||
bool uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback);
|
||||
|
||||
static MessageID _currentID;
|
||||
QHash<MessageID, ReceivedAssetCallback> _pendingRequests;
|
||||
QHash<MessageID, GetInfoCallback> _pendingInfoRequests;
|
||||
QHash<MessageID, UploadResultCallback> _pendingUploads;
|
||||
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, ReceivedAssetCallback>> _pendingRequests;
|
||||
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, GetInfoCallback>> _pendingInfoRequests;
|
||||
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, UploadResultCallback>> _pendingUploads;
|
||||
|
||||
friend class AssetRequest;
|
||||
friend class AssetUpload;
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include "NetworkLogging.h"
|
||||
#include "NodeList.h"
|
||||
|
||||
AssetRequest::AssetRequest(QObject* parent, const QString& hash, const QString& extension) :
|
||||
QObject(parent),
|
||||
AssetRequest::AssetRequest(const QString& hash, const QString& extension) :
|
||||
QObject(),
|
||||
_hash(hash),
|
||||
_extension(extension)
|
||||
{
|
||||
|
@ -33,29 +33,40 @@ void AssetRequest::start() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (_state != NOT_STARTED) {
|
||||
if (_state != NotStarted) {
|
||||
qCWarning(networking) << "AssetRequest already started.";
|
||||
return;
|
||||
}
|
||||
|
||||
_state = WAITING_FOR_INFO;
|
||||
_state = WaitingForInfo;
|
||||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->getAssetInfo(_hash, _extension, [this](AssetServerError serverError, AssetInfo info) {
|
||||
assetClient->getAssetInfo(_hash, _extension, [this](bool responseReceived, AssetServerError serverError, AssetInfo info) {
|
||||
_info = info;
|
||||
|
||||
if (serverError != AssetServerError::NoError) {
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else if (serverError != AssetServerError::NoError) {
|
||||
switch(serverError) {
|
||||
case AssetServerError::AssetNotFound:
|
||||
_error = NotFound;
|
||||
break;
|
||||
default:
|
||||
_error = UnknownError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_error != NoError) {
|
||||
qCDebug(networking) << "Got error retrieving asset info for" << _hash;
|
||||
|
||||
_state = FINISHED;
|
||||
|
||||
_state = Finished;
|
||||
emit finished(this);
|
||||
|
||||
_error = (serverError == AssetServerError::AssetNotFound) ? NotFound : UnknownError;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_state = WAITING_FOR_DATA;
|
||||
_state = WaitingForData;
|
||||
_data.resize(info.size);
|
||||
|
||||
qCDebug(networking) << "Got size of " << _hash << " : " << info.size << " bytes";
|
||||
|
@ -63,23 +74,11 @@ void AssetRequest::start() {
|
|||
int start = 0, end = _info.size;
|
||||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->getAsset(_hash, _extension, start, end, [this, start, end](AssetServerError serverError,
|
||||
assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool responseReceived, AssetServerError serverError,
|
||||
const QByteArray& data) {
|
||||
Q_ASSERT(data.size() == (end - start));
|
||||
|
||||
if (serverError == AssetServerError::NoError) {
|
||||
|
||||
// we need to check the hash of the received data to make sure it matches what we expect
|
||||
if (hashData(data).toHex() == _hash) {
|
||||
memcpy(_data.data() + start, data.constData(), data.size());
|
||||
_totalReceived += data.size();
|
||||
emit progress(_totalReceived, _info.size);
|
||||
} else {
|
||||
// hash doesn't match - we have an error
|
||||
_error = HashVerificationFailed;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else if (serverError != AssetServerError::NoError) {
|
||||
switch (serverError) {
|
||||
case AssetServerError::AssetNotFound:
|
||||
_error = NotFound;
|
||||
|
@ -91,13 +90,26 @@ void AssetRequest::start() {
|
|||
_error = UnknownError;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Q_ASSERT(data.size() == (end - start));
|
||||
|
||||
// we need to check the hash of the received data to make sure it matches what we expect
|
||||
if (hashData(data).toHex() == _hash) {
|
||||
memcpy(_data.data() + start, data.constData(), data.size());
|
||||
_totalReceived += data.size();
|
||||
emit progress(_totalReceived, _info.size);
|
||||
} else {
|
||||
// hash doesn't match - we have an error
|
||||
_error = HashVerificationFailed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (_error != NoError) {
|
||||
qCDebug(networking) << "Got error retrieving asset" << _hash << "- error code" << _error;
|
||||
}
|
||||
|
||||
_state = FINISHED;
|
||||
_state = Finished;
|
||||
emit finished(this);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,10 +24,10 @@ class AssetRequest : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
enum State {
|
||||
NOT_STARTED = 0,
|
||||
WAITING_FOR_INFO,
|
||||
WAITING_FOR_DATA,
|
||||
FINISHED
|
||||
NotStarted = 0,
|
||||
WaitingForInfo,
|
||||
WaitingForData,
|
||||
Finished
|
||||
};
|
||||
|
||||
enum Error {
|
||||
|
@ -35,10 +35,11 @@ public:
|
|||
NotFound,
|
||||
InvalidByteRange,
|
||||
HashVerificationFailed,
|
||||
NetworkError,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
AssetRequest(QObject* parent, const QString& hash, const QString& extension);
|
||||
AssetRequest(const QString& hash, const QString& extension);
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
|
@ -51,7 +52,7 @@ signals:
|
|||
void progress(qint64 totalReceived, qint64 total);
|
||||
|
||||
private:
|
||||
State _state = NOT_STARTED;
|
||||
State _state = NotStarted;
|
||||
Error _error = NoError;
|
||||
AssetInfo _info;
|
||||
uint64_t _totalReceived { 0 };
|
||||
|
|
|
@ -12,9 +12,14 @@
|
|||
#include "AssetResourceRequest.h"
|
||||
|
||||
#include "AssetClient.h"
|
||||
#include "AssetRequest.h"
|
||||
#include "AssetUtils.h"
|
||||
|
||||
AssetResourceRequest::~AssetResourceRequest() {
|
||||
if (_assetRequest) {
|
||||
_assetRequest->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void AssetResourceRequest::doSend() {
|
||||
// Make request to atp
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
|
@ -31,9 +36,9 @@ void AssetResourceRequest::doSend() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto request = assetClient->createRequest(hash, extension);
|
||||
_assetRequest = assetClient->createRequest(hash, extension);
|
||||
|
||||
if (!request) {
|
||||
if (!_assetRequest) {
|
||||
_result = ServerUnavailable;
|
||||
_state = Finished;
|
||||
|
||||
|
@ -42,10 +47,11 @@ void AssetResourceRequest::doSend() {
|
|||
return;
|
||||
}
|
||||
|
||||
connect(request, &AssetRequest::progress, this, &AssetResourceRequest::progress);
|
||||
QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable {
|
||||
connect(_assetRequest, &AssetRequest::progress, this, &AssetResourceRequest::progress);
|
||||
QObject::connect(_assetRequest, &AssetRequest::finished, [this](AssetRequest* req) mutable {
|
||||
Q_ASSERT(_state == InProgress);
|
||||
Q_ASSERT(req->getState() == AssetRequest::FINISHED);
|
||||
Q_ASSERT(req == _assetRequest);
|
||||
Q_ASSERT(req->getState() == AssetRequest::Finished);
|
||||
|
||||
switch (req->getError()) {
|
||||
case AssetRequest::Error::NoError:
|
||||
|
@ -55,6 +61,9 @@ void AssetResourceRequest::doSend() {
|
|||
case AssetRequest::Error::NotFound:
|
||||
_result = NotFound;
|
||||
break;
|
||||
case AssetRequest::Error::NetworkError:
|
||||
_result = ServerUnavailable;
|
||||
break;
|
||||
default:
|
||||
_result = Error;
|
||||
break;
|
||||
|
@ -62,9 +71,12 @@ void AssetResourceRequest::doSend() {
|
|||
|
||||
_state = Finished;
|
||||
emit finished();
|
||||
|
||||
_assetRequest->deleteLater();
|
||||
_assetRequest = nullptr;
|
||||
});
|
||||
|
||||
request->start();
|
||||
_assetRequest->start();
|
||||
}
|
||||
|
||||
void AssetResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
|
||||
|
|
|
@ -14,18 +14,23 @@
|
|||
|
||||
#include <QUrl>
|
||||
|
||||
#include "AssetRequest.h"
|
||||
#include "ResourceRequest.h"
|
||||
|
||||
class AssetResourceRequest : public ResourceRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssetResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { }
|
||||
~AssetResourceRequest();
|
||||
|
||||
protected:
|
||||
virtual void doSend() override;
|
||||
|
||||
private slots:
|
||||
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
||||
|
||||
private:
|
||||
AssetRequest* _assetRequest;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,20 +43,24 @@ void AssetUpload::start() {
|
|||
|
||||
qDebug() << "Attempting to upload" << _filename << "to asset-server.";
|
||||
|
||||
assetClient->uploadAsset(data, _extension, [this](AssetServerError error, const QString& hash){
|
||||
switch (error) {
|
||||
case AssetServerError::NoError:
|
||||
_error = NoError;
|
||||
break;
|
||||
case AssetServerError::AssetTooLarge:
|
||||
_error = TooLarge;
|
||||
break;
|
||||
case AssetServerError::PermissionDenied:
|
||||
_error = PermissionDenied;
|
||||
break;
|
||||
default:
|
||||
_error = FileOpenError;
|
||||
break;
|
||||
assetClient->uploadAsset(data, _extension, [this](bool responseReceived, AssetServerError error, const QString& hash){
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
switch (error) {
|
||||
case AssetServerError::NoError:
|
||||
_error = NoError;
|
||||
break;
|
||||
case AssetServerError::AssetTooLarge:
|
||||
_error = TooLarge;
|
||||
break;
|
||||
case AssetServerError::PermissionDenied:
|
||||
_error = PermissionDenied;
|
||||
break;
|
||||
default:
|
||||
_error = FileOpenError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit finished(this, hash);
|
||||
});
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
|
||||
enum Error {
|
||||
NoError = 0,
|
||||
NetworkError,
|
||||
Timeout,
|
||||
TooLarge,
|
||||
PermissionDenied,
|
||||
|
|
|
@ -24,7 +24,7 @@ const size_t SHA256_HASH_HEX_LENGTH = 64;
|
|||
const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB
|
||||
|
||||
enum AssetServerError : uint8_t {
|
||||
NoError,
|
||||
NoError = 0,
|
||||
AssetNotFound,
|
||||
InvalidByteRange,
|
||||
AssetTooLarge,
|
||||
|
|
|
@ -88,6 +88,16 @@ private:
|
|||
typedef QSharedPointer<Node> SharedNodePointer;
|
||||
Q_DECLARE_METATYPE(SharedNodePointer)
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<SharedNodePointer> {
|
||||
size_t operator()(const SharedNodePointer& p) const {
|
||||
// Return the hash of the pointer
|
||||
return hash<Node*>()(p.data());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const Node& node);
|
||||
|
||||
#endif // hifi_Node_h
|
||||
|
|
|
@ -34,7 +34,7 @@ void CongestionControl::setPacketSendPeriod(double newSendPeriod) {
|
|||
}
|
||||
|
||||
DefaultCC::DefaultCC() :
|
||||
_lastRCTime(high_resolution_clock::now()),
|
||||
_lastRCTime(p_high_resolution_clock::now()),
|
||||
_slowStartLastAck(_sendCurrSeqNum),
|
||||
_lastDecreaseMaxSeq(SequenceNumber {SequenceNumber::MAX })
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) {
|
|||
const double minimumIncrease = 0.01;
|
||||
|
||||
// we will only adjust once per sync interval so check that it has been at least that long now
|
||||
auto now = high_resolution_clock::now();
|
||||
auto now = p_high_resolution_clock::now();
|
||||
if (duration_cast<microseconds>(now - _lastRCTime).count() < synInterval()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,11 +12,12 @@
|
|||
#ifndef hifi_CongestionControl_h
|
||||
#define hifi_CongestionControl_h
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#include "LossList.h"
|
||||
#include "SequenceNumber.h"
|
||||
|
||||
|
@ -107,7 +108,7 @@ public:
|
|||
private:
|
||||
void stopSlowStart(); // stops the slow start on loss or timeout
|
||||
|
||||
std::chrono::high_resolution_clock::time_point _lastRCTime; // last rate increase time
|
||||
p_high_resolution_clock::time_point _lastRCTime; // last rate increase time
|
||||
bool _slowStart { true }; // if in slow start phase
|
||||
SequenceNumber _slowStartLastAck; // last ACKed seq num
|
||||
bool _loss { false }; // if loss happened since last rate increase
|
||||
|
|
|
@ -28,7 +28,7 @@ using namespace udt;
|
|||
using namespace std::chrono;
|
||||
|
||||
Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr<CongestionControl> congestionControl) :
|
||||
_connectionStart(high_resolution_clock::now()),
|
||||
_connectionStart(p_high_resolution_clock::now()),
|
||||
_parentSocket(parentSocket),
|
||||
_destination(destination),
|
||||
_congestionControl(move(congestionControl))
|
||||
|
@ -154,7 +154,7 @@ void Connection::sync() {
|
|||
static const int NUM_TIMEOUTS_BEFORE_EXPIRY = 16;
|
||||
static const int MIN_SECONDS_BEFORE_EXPIRY = 5;
|
||||
|
||||
auto now = high_resolution_clock::now();
|
||||
auto now = p_high_resolution_clock::now();
|
||||
|
||||
auto sincePacketReceive = now - _lastReceiveTime;
|
||||
|
||||
|
@ -185,7 +185,7 @@ void Connection::sync() {
|
|||
if (_lossList.getLength() > 0) {
|
||||
// check if we need to re-transmit a loss list
|
||||
// we do this if it has been longer than the current nakInterval since we last sent
|
||||
auto now = high_resolution_clock::now();
|
||||
auto now = p_high_resolution_clock::now();
|
||||
|
||||
if (duration_cast<microseconds>(now - _lastNAKTime).count() >= _nakInterval) {
|
||||
// Send a timeout NAK packet
|
||||
|
@ -197,7 +197,7 @@ void Connection::sync() {
|
|||
// this most likely means we were started erroneously
|
||||
// check the start time for this connection and auto expire it after 5 seconds of not receiving or sending any data
|
||||
static const int CONNECTION_NOT_USED_EXPIRY_SECONDS = 5;
|
||||
auto secondsSinceStart = duration_cast<seconds>(high_resolution_clock::now() - _connectionStart).count();
|
||||
auto secondsSinceStart = duration_cast<seconds>(p_high_resolution_clock::now() - _connectionStart).count();
|
||||
|
||||
if (secondsSinceStart >= CONNECTION_NOT_USED_EXPIRY_SECONDS) {
|
||||
// it's been CONNECTION_NOT_USED_EXPIRY_SECONDS and nothing has actually happened with this connection
|
||||
|
@ -222,8 +222,8 @@ void Connection::recordRetransmission() {
|
|||
}
|
||||
|
||||
void Connection::sendACK(bool wasCausedBySyncTimeout) {
|
||||
static high_resolution_clock::time_point lastACKSendTime;
|
||||
auto currentTime = high_resolution_clock::now();
|
||||
static p_high_resolution_clock::time_point lastACKSendTime;
|
||||
auto currentTime = p_high_resolution_clock::now();
|
||||
|
||||
SequenceNumber nextACKNumber = nextACK();
|
||||
Q_ASSERT_X(nextACKNumber >= _lastSentACK, "Connection::sendACK", "Sending lower ACK, something is wrong");
|
||||
|
@ -280,7 +280,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) {
|
|||
ackPacket->writePrimitive(estimatedBandwidth);
|
||||
|
||||
// record this as the last ACK send time
|
||||
lastACKSendTime = high_resolution_clock::now();
|
||||
lastACKSendTime = p_high_resolution_clock::now();
|
||||
}
|
||||
|
||||
// have the socket send off our packet
|
||||
|
@ -290,7 +290,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) {
|
|||
"Connection::sendACK", "Adding an invalid ACK to _sentACKs");
|
||||
|
||||
// write this ACK to the map of sent ACKs
|
||||
_sentACKs.push_back({ _currentACKSubSequenceNumber, { nextACKNumber, high_resolution_clock::now() }});
|
||||
_sentACKs.push_back({ _currentACKSubSequenceNumber, { nextACKNumber, p_high_resolution_clock::now() }});
|
||||
|
||||
// reset the number of data packets received since last ACK
|
||||
_packetsSinceACK = 0;
|
||||
|
@ -358,7 +358,7 @@ void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) {
|
|||
_parentSocket->writeBasePacket(*lossReport, _destination);
|
||||
|
||||
// record our last NAK time
|
||||
_lastNAKTime = high_resolution_clock::now();
|
||||
_lastNAKTime = p_high_resolution_clock::now();
|
||||
|
||||
_stats.record(ConnectionStats::Stats::SentNAK);
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ void Connection::sendTimeoutNAK() {
|
|||
_parentSocket->writeBasePacket(*lossListPacket, _destination);
|
||||
|
||||
// record this as the last NAK time
|
||||
_lastNAKTime = high_resolution_clock::now();
|
||||
_lastNAKTime = p_high_resolution_clock::now();
|
||||
|
||||
_stats.record(ConnectionStats::Stats::SentTimeoutNAK);
|
||||
}
|
||||
|
@ -403,7 +403,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in
|
|||
_isReceivingData = true;
|
||||
|
||||
// mark our last receive time as now (to push the potential expiry farther)
|
||||
_lastReceiveTime = high_resolution_clock::now();
|
||||
_lastReceiveTime = p_high_resolution_clock::now();
|
||||
|
||||
// check if this is a packet pair we should estimate bandwidth from, or just a regular packet
|
||||
if (((uint32_t) sequenceNumber & 0xF) == 0) {
|
||||
|
@ -533,8 +533,8 @@ void Connection::processACK(std::unique_ptr<ControlPacket> controlPacket) {
|
|||
// Check if we need send an ACK2 for this ACK
|
||||
// This will be the case if it has been longer than the sync interval OR
|
||||
// it looks like they haven't received our ACK2 for this ACK
|
||||
auto currentTime = high_resolution_clock::now();
|
||||
static high_resolution_clock::time_point lastACK2SendTime;
|
||||
auto currentTime = p_high_resolution_clock::now();
|
||||
static p_high_resolution_clock::time_point lastACK2SendTime;
|
||||
|
||||
microseconds sinceLastACK2 = duration_cast<microseconds>(currentTime - lastACK2SendTime);
|
||||
|
||||
|
@ -542,7 +542,7 @@ void Connection::processACK(std::unique_ptr<ControlPacket> controlPacket) {
|
|||
// Send ACK2 packet
|
||||
sendACK2(currentACKSubSequenceNumber);
|
||||
|
||||
lastACK2SendTime = high_resolution_clock::now();
|
||||
lastACK2SendTime = p_high_resolution_clock::now();
|
||||
}
|
||||
|
||||
// read the ACKed sequence number
|
||||
|
@ -664,7 +664,7 @@ void Connection::processACK2(std::unique_ptr<ControlPacket> controlPacket) {
|
|||
// update the RTT using the ACK window
|
||||
|
||||
// calculate the RTT (time now - time ACK sent)
|
||||
auto now = high_resolution_clock::now();
|
||||
auto now = p_high_resolution_clock::now();
|
||||
int rtt = duration_cast<microseconds>(now - it->second.second).count();
|
||||
|
||||
updateRTT(rtt);
|
||||
|
@ -779,13 +779,13 @@ void Connection::resetReceiveState() {
|
|||
|
||||
// clear the loss list and _lastNAKTime
|
||||
_lossList.clear();
|
||||
_lastNAKTime = high_resolution_clock::time_point();
|
||||
_lastNAKTime = p_high_resolution_clock::time_point();
|
||||
|
||||
// the _nakInterval need not be reset, that will happen on loss
|
||||
|
||||
// clear sync variables
|
||||
_isReceivingData = false;
|
||||
_connectionStart = high_resolution_clock::now();
|
||||
_connectionStart = p_high_resolution_clock::now();
|
||||
|
||||
_acksDuringSYN = 1;
|
||||
_lightACKsDuringSYN = 1;
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
#ifndef hifi_Connection_h
|
||||
#define hifi_Connection_h
|
||||
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#include "ConnectionStats.h"
|
||||
#include "Constants.h"
|
||||
#include "LossList.h"
|
||||
|
@ -51,7 +52,7 @@ private:
|
|||
class Connection : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using SequenceNumberTimePair = std::pair<SequenceNumber, std::chrono::high_resolution_clock::time_point>;
|
||||
using SequenceNumberTimePair = std::pair<SequenceNumber, p_high_resolution_clock::time_point>;
|
||||
using ACKListPair = std::pair<SequenceNumber, SequenceNumberTimePair>;
|
||||
using SentACKList = std::list<ACKListPair>;
|
||||
|
||||
|
@ -113,13 +114,13 @@ private:
|
|||
|
||||
int _nakInterval { -1 }; // NAK timeout interval, in microseconds, set on loss
|
||||
int _minNAKInterval { 100000 }; // NAK timeout interval lower bound, default of 100ms
|
||||
std::chrono::high_resolution_clock::time_point _lastNAKTime;
|
||||
p_high_resolution_clock::time_point _lastNAKTime;
|
||||
|
||||
bool _hasReceivedHandshake { false }; // flag for receipt of handshake from server
|
||||
bool _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client
|
||||
|
||||
std::chrono::high_resolution_clock::time_point _connectionStart; // holds the time_point for creation of this connection
|
||||
std::chrono::high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender
|
||||
p_high_resolution_clock::time_point _connectionStart; // holds the time_point for creation of this connection
|
||||
p_high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender
|
||||
bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection
|
||||
|
||||
LossList _lossList; // List of all missing packets
|
||||
|
|
|
@ -94,7 +94,7 @@ int32_t PacketTimeWindow::getEstimatedBandwidth() const {
|
|||
|
||||
void PacketTimeWindow::onPacketArrival() {
|
||||
// take the current time
|
||||
auto now = high_resolution_clock::now();
|
||||
auto now = p_high_resolution_clock::now();
|
||||
|
||||
// record the interval between this packet and the last one
|
||||
_packetIntervals[_currentPacketInterval++] = duration_cast<microseconds>(now - _lastPacketTime).count();
|
||||
|
@ -110,12 +110,12 @@ void PacketTimeWindow::onPacketArrival() {
|
|||
|
||||
void PacketTimeWindow::onProbePair1Arrival() {
|
||||
// take the current time as the first probe time
|
||||
_firstProbeTime = high_resolution_clock::now();
|
||||
_firstProbeTime = p_high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void PacketTimeWindow::onProbePair2Arrival() {
|
||||
// store the interval between the two probes
|
||||
auto now = high_resolution_clock::now();
|
||||
auto now = p_high_resolution_clock::now();
|
||||
|
||||
_probeIntervals[_currentProbeInterval++] = duration_cast<microseconds>(now - _firstProbeTime).count();
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
#ifndef hifi_PacketTimeWindow_h
|
||||
#define hifi_PacketTimeWindow_h
|
||||
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
namespace udt {
|
||||
|
||||
class PacketTimeWindow {
|
||||
|
@ -41,8 +42,8 @@ private:
|
|||
std::vector<int> _packetIntervals; // vector of microsecond intervals between packet arrivals
|
||||
std::vector<int> _probeIntervals; // vector of microsecond intervals between probe pair arrivals
|
||||
|
||||
std::chrono::high_resolution_clock::time_point _lastPacketTime; // the time_point when last packet arrived
|
||||
std::chrono::high_resolution_clock::time_point _firstProbeTime; // the time_point when first probe in pair arrived
|
||||
p_high_resolution_clock::time_point _lastPacketTime; // the time_point when last packet arrived
|
||||
p_high_resolution_clock::time_point _firstProbeTime; // the time_point when first probe in pair arrived
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -272,7 +272,7 @@ void SendQueue::run() {
|
|||
|
||||
while (_isRunning) {
|
||||
// Record how long the loop takes to execute
|
||||
auto loopStartTimestamp = high_resolution_clock::now();
|
||||
auto loopStartTimestamp = p_high_resolution_clock::now();
|
||||
|
||||
std::unique_lock<std::mutex> handshakeLock { _handshakeMutex };
|
||||
|
||||
|
@ -281,12 +281,12 @@ void SendQueue::run() {
|
|||
// if it has been at least 100ms since we last sent a handshake, send another now
|
||||
|
||||
// hold the time of last send in a static
|
||||
static auto lastSendHandshake = high_resolution_clock::time_point();
|
||||
static auto lastSendHandshake = p_high_resolution_clock::time_point();
|
||||
|
||||
static const auto HANDSHAKE_RESEND_INTERVAL_MS = std::chrono::milliseconds(100);
|
||||
|
||||
// calculation the duration since the last handshake send
|
||||
auto sinceLastHandshake = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now()
|
||||
auto sinceLastHandshake = std::chrono::duration_cast<std::chrono::milliseconds>(p_high_resolution_clock::now()
|
||||
- lastSendHandshake);
|
||||
|
||||
if (sinceLastHandshake >= HANDSHAKE_RESEND_INTERVAL_MS) {
|
||||
|
@ -295,12 +295,12 @@ void SendQueue::run() {
|
|||
static auto handshakePacket = ControlPacket::create(ControlPacket::Handshake, 0);
|
||||
_socket->writeBasePacket(*handshakePacket, _destination);
|
||||
|
||||
lastSendHandshake = high_resolution_clock::now();
|
||||
lastSendHandshake = p_high_resolution_clock::now();
|
||||
}
|
||||
|
||||
// we wait for the ACK or the re-send interval to expire
|
||||
_handshakeACKCondition.wait_until(handshakeLock,
|
||||
high_resolution_clock::now()
|
||||
p_high_resolution_clock::now()
|
||||
+ HANDSHAKE_RESEND_INTERVAL_MS);
|
||||
|
||||
// Once we're here we've either received the handshake ACK or it's going to be time to re-send a handshake.
|
||||
|
@ -420,7 +420,7 @@ void SendQueue::run() {
|
|||
}
|
||||
}
|
||||
|
||||
auto loopEndTimestamp = high_resolution_clock::now();
|
||||
auto loopEndTimestamp = p_high_resolution_clock::now();
|
||||
|
||||
// sleep as long as we need until next packet send, if we can
|
||||
auto timeToSleep = (loopStartTimestamp + std::chrono::microseconds(_packetSendPeriod)) - loopEndTimestamp;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#define hifi_SendQueue_h
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
|
@ -24,6 +23,8 @@
|
|||
#include <QtCore/QObject>
|
||||
#include <QtCore/QReadWriteLock>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#include "../HifiSockAddr.h"
|
||||
|
||||
#include "Constants.h"
|
||||
|
@ -44,8 +45,7 @@ class SendQueue : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using high_resolution_clock = std::chrono::high_resolution_clock;
|
||||
using time_point = high_resolution_clock::time_point;
|
||||
using time_point = p_high_resolution_clock::time_point;
|
||||
|
||||
static std::unique_ptr<SendQueue> create(Socket* socket, HifiSockAddr destination);
|
||||
|
||||
|
|
30
libraries/shared/src/PortableHighResolutionClock.cpp
Normal file
30
libraries/shared/src/PortableHighResolutionClock.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// PortableHighResolutionClock.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2015-09-14.
|
||||
// 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
|
||||
//
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
|
||||
#include "PortableHighResolutionClock.h"
|
||||
|
||||
namespace {
|
||||
const long long g_Frequency = []() -> long long {
|
||||
LARGE_INTEGER frequency;
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
return frequency.QuadPart;
|
||||
}();
|
||||
}
|
||||
|
||||
win_high_resolution_clock::time_point win_high_resolution_clock::now() {
|
||||
LARGE_INTEGER count;
|
||||
QueryPerformanceCounter(&count);
|
||||
return time_point(duration(count.QuadPart * static_cast<rep>(period::den) / g_Frequency));
|
||||
}
|
||||
|
||||
#endif
|
51
libraries/shared/src/PortableHighResolutionClock.h
Normal file
51
libraries/shared/src/PortableHighResolutionClock.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// PortableHighResolutionClock.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2015-09-14.
|
||||
// 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
|
||||
//
|
||||
|
||||
// I discovered the low-resolution nature of the VC2012 implementation of std::chrono::high_resolution_clock
|
||||
// while debugging a UDT issue with packet receive speeds. That lead to
|
||||
// http://stackoverflow.com/questions/16299029/resolution-of-stdchronohigh-resolution-clock-doesnt-correspond-to-measureme
|
||||
// which is where the implementation of this class is from.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef hifi_PortableHighResolutionClock_h
|
||||
#define hifi_PortableHighResolutionClock_h
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// The following struct is not compliant with the HF coding standard, but uses underscores to match the classes
|
||||
// in std::chrono
|
||||
|
||||
struct win_high_resolution_clock {
|
||||
typedef long long rep;
|
||||
typedef std::nano period;
|
||||
typedef std::chrono::duration<rep, period> duration;
|
||||
typedef std::chrono::time_point<win_high_resolution_clock> time_point;
|
||||
static const bool is_steady = true;
|
||||
|
||||
static time_point now();
|
||||
};
|
||||
|
||||
using p_high_resolution_clock = win_high_resolution_clock;
|
||||
|
||||
#else
|
||||
|
||||
using p_high_resolution_clock = std::chrono::high_resolution_clock;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // hifi_PortableHighResolutionClock_h
|
Loading…
Reference in a new issue