Merge branch 'master' of https://github.com/highfidelity/hifi into skin

This commit is contained in:
samcake 2016-06-09 14:36:28 -07:00
commit 75a2864845
148 changed files with 6289 additions and 2267 deletions

View file

@ -24,6 +24,16 @@ macro(SETUP_HIFI_LIBRARY)
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx) set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx)
endif() endif()
endforeach() endforeach()
# add compiler flags to AVX2 source files
file(GLOB_RECURSE AVX2_SRCS "src/avx2/*.cpp" "src/avx2/*.c")
foreach(SRC ${AVX2_SRCS})
if (WIN32)
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX2)
elseif (APPLE OR UNIX)
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mavx2 -mfma")
endif()
endforeach()
setup_memory_debugger() setup_memory_debugger()

View file

@ -1,5 +1,5 @@
{ {
"version": 1.2, "version": 1.3,
"settings": [ "settings": [
{ {
"name": "metaverse", "name": "metaverse",
@ -71,6 +71,76 @@
} }
] ]
}, },
{
"name": "descriptors",
"label": "Description",
"help": "This data will be queryable from your server. It may be collected by High Fidelity and used to share your domain with others.",
"settings": [
{
"name": "description",
"label": "Description",
"help": "A description of your domain (256 character limit)."
},
{
"name": "maturity",
"label": "Maturity",
"help": "A maturity rating, available as a guideline for content on your domain.",
"default": "unrated",
"type": "select",
"options": [
{
"value": "unrated",
"label": "Unrated"
},
{
"value": "everyone",
"label": "Everyone"
},
{
"value": "teen",
"label": "Teen (13+)"
},
{
"value": "mature",
"label": "Mature (17+)"
},
{
"value": "adult",
"label": "Adult (18+)"
}
]
},
{
"name": "hosts",
"label": "Hosts",
"type": "table",
"help": "Usernames of hosts who can reliably show your domain to new visitors.",
"numbered": false,
"columns": [
{
"name": "host",
"label": "Username",
"can_set": true
}
]
},
{
"name": "tags",
"label": "Tags",
"type": "table",
"help": "Common categories under which your domain falls.",
"numbered": false,
"columns": [
{
"name": "tag",
"label": "Tag",
"can_set": true
}
]
}
]
},
{ {
"name": "security", "name": "security",
"label": "Security", "label": "Security",

View file

@ -0,0 +1,132 @@
//
// DomainMetadata.cpp
// domain-server/src
//
// Created by Zach Pomerantz on 5/25/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#include "DomainMetadata.h"
#include <HifiConfigVariantMap.h>
#include <DependencyManager.h>
#include <LimitedNodeList.h>
#include "DomainServerNodeData.h"
const QString DomainMetadata::USERS = "users";
const QString DomainMetadata::USERS_NUM_TOTAL = "num_users";
const QString DomainMetadata::USERS_NUM_ANON = "num_anon_users";
const QString DomainMetadata::USERS_HOSTNAMES = "user_hostnames";
// users metadata will appear as (JSON):
// { "num_users": Number,
// "num_anon_users": Number,
// "user_hostnames": { <HOSTNAME>: Number }
// }
const QString DomainMetadata::DESCRIPTORS = "descriptors";
const QString DomainMetadata::DESCRIPTORS_DESCRIPTION = "description";
const QString DomainMetadata::DESCRIPTORS_CAPACITY = "capacity"; // parsed from security
const QString DomainMetadata::DESCRIPTORS_RESTRICTION = "restriction"; // parsed from ACL
const QString DomainMetadata::DESCRIPTORS_MATURITY = "maturity";
const QString DomainMetadata::DESCRIPTORS_HOSTS = "hosts";
const QString DomainMetadata::DESCRIPTORS_TAGS = "tags";
// descriptors metadata will appear as (JSON):
// { "capacity": Number,
// TODO: "hours": String, // UTF-8 representation of the week, split into 15" segments
// "restriction": String, // enum of either open, hifi, or acl
// "maturity": String, // enum corresponding to ESRB ratings
// "hosts": [ String ], // capped list of usernames
// "description": String, // capped description
// TODO: "img": {
// "src": String,
// "type": String,
// "size": Number,
// "updated_at": Number,
// },
// "tags": [ String ], // capped list of tags
// }
// metadata will appear as (JSON):
// { users: <USERS>, descriptors: <DESCRIPTORS> }
//
// it is meant to be sent to and consumed by an external API
DomainMetadata::DomainMetadata() {
_metadata[USERS] = {};
_metadata[DESCRIPTORS] = {};
}
void DomainMetadata::setDescriptors(QVariantMap& settings) {
const QString CAPACITY = "security.maximum_user_capacity";
const QVariant* capacityVariant = valueForKeyPath(settings, CAPACITY);
unsigned int capacity = capacityVariant ? capacityVariant->toUInt() : 0;
// TODO: Keep parity with ACL development.
const QString RESTRICTION = "security.restricted_access";
const QString RESTRICTION_OPEN = "open";
// const QString RESTRICTION_HIFI = "hifi";
const QString RESTRICTION_ACL = "acl";
const QVariant* isRestrictedVariant = valueForKeyPath(settings, RESTRICTION);
bool isRestricted = isRestrictedVariant ? isRestrictedVariant->toBool() : false;
QString restriction = isRestricted ? RESTRICTION_ACL : RESTRICTION_OPEN;
QVariantMap descriptors = settings[DESCRIPTORS].toMap();
descriptors[DESCRIPTORS_CAPACITY] = capacity;
descriptors[DESCRIPTORS_RESTRICTION] = restriction;
_metadata[DESCRIPTORS] = descriptors;
#if DEV_BUILD || PR_BUILD
qDebug() << "Domain metadata descriptors set:" << descriptors;
#endif
}
void DomainMetadata::updateUsers() {
static const QString DEFAULT_HOSTNAME = "*";
auto nodeList = DependencyManager::get<LimitedNodeList>();
int numConnected = 0;
int numConnectedAnonymously = 0;
QVariantMap userHostnames;
// figure out the breakdown of currently connected interface clients
nodeList->eachNode([&numConnected, &numConnectedAnonymously, &userHostnames](const SharedNodePointer& node) {
auto linkedData = node->getLinkedData();
if (linkedData) {
auto nodeData = static_cast<DomainServerNodeData*>(linkedData);
if (!nodeData->wasAssigned()) {
++numConnected;
if (nodeData->getUsername().isEmpty()) {
++numConnectedAnonymously;
}
// increment the count for this hostname (or the default if we don't have one)
auto placeName = nodeData->getPlaceName();
auto hostname = placeName.isEmpty() ? DEFAULT_HOSTNAME : placeName;
userHostnames[hostname] = userHostnames[hostname].toInt() + 1;
}
}
});
QVariantMap users = {
{ USERS_NUM_TOTAL, numConnected },
{ USERS_NUM_ANON, numConnectedAnonymously },
{ USERS_HOSTNAMES, userHostnames }};
_metadata[USERS] = users;
#if DEV_BUILD || PR_BUILD
qDebug() << "Domain metadata users updated:" << users;
#endif
}
void DomainMetadata::usersChanged() {
++_tic;
#if DEV_BUILD || PR_BUILD
qDebug() << "Domain metadata users change detected";
#endif
}

View file

@ -0,0 +1,65 @@
//
// DomainMetadata.h
// domain-server/src
//
// Created by Zach Pomerantz on 5/25/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#ifndef hifi_DomainMetadata_h
#define hifi_DomainMetadata_h
#include <stdint.h>
#include <QVariantMap>
#include <QJsonObject>
class DomainMetadata : public QObject {
Q_OBJECT
static const QString USERS;
static const QString USERS_NUM_TOTAL;
static const QString USERS_NUM_ANON;
static const QString USERS_HOSTNAMES;
static const QString DESCRIPTORS;
static const QString DESCRIPTORS_DESCRIPTION;
static const QString DESCRIPTORS_CAPACITY;
static const QString DESCRIPTORS_HOURS;
static const QString DESCRIPTORS_RESTRICTION;
static const QString DESCRIPTORS_MATURITY;
static const QString DESCRIPTORS_HOSTS;
static const QString DESCRIPTORS_TAGS;
static const QString DESCRIPTORS_IMG;
static const QString DESCRIPTORS_IMG_SRC;
static const QString DESCRIPTORS_IMG_TYPE;
static const QString DESCRIPTORS_IMG_SIZE;
static const QString DESCRIPTORS_IMG_UPDATED_AT;
public:
DomainMetadata();
// Returns the last set metadata
// If connected users have changed, metadata may need to be updated
// this should be checked by storing tic = getTic() between calls
// and testing it for equality before the next get (tic == getTic())
QJsonObject get() { return QJsonObject::fromVariantMap(_metadata); }
QJsonObject getUsers() { return QJsonObject::fromVariantMap(_metadata[USERS].toMap()); }
QJsonObject getDescriptors() { return QJsonObject::fromVariantMap(_metadata[DESCRIPTORS].toMap()); }
uint32_t getTic() { return _tic; }
void setDescriptors(QVariantMap& settings);
void updateUsers();
public slots:
void usersChanged();
protected:
QVariantMap _metadata;
uint32_t _tic{ 0 };
};
#endif // hifi_DomainMetadata_h

View file

@ -94,6 +94,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
qRegisterMetaType<DomainServerWebSessionData>("DomainServerWebSessionData"); qRegisterMetaType<DomainServerWebSessionData>("DomainServerWebSessionData");
qRegisterMetaTypeStreamOperators<DomainServerWebSessionData>("DomainServerWebSessionData"); qRegisterMetaTypeStreamOperators<DomainServerWebSessionData>("DomainServerWebSessionData");
// update the metadata when a user (dis)connects
connect(this, &DomainServer::userConnected, &_metadata, &DomainMetadata::usersChanged);
connect(this, &DomainServer::userDisconnected, &_metadata, &DomainMetadata::usersChanged);
// make sure we hear about newly connected nodes from our gatekeeper // make sure we hear about newly connected nodes from our gatekeeper
connect(&_gatekeeper, &DomainGatekeeper::connectedNode, this, &DomainServer::handleConnectedNode); connect(&_gatekeeper, &DomainGatekeeper::connectedNode, this, &DomainServer::handleConnectedNode);
@ -112,6 +116,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
optionallyGetTemporaryName(args); optionallyGetTemporaryName(args);
} }
// update the metadata with current descriptors
_metadata.setDescriptors(_settingsManager.getSettingsMap());
} }
DomainServer::~DomainServer() { DomainServer::~DomainServer() {
@ -767,12 +774,16 @@ QUrl DomainServer::oauthAuthorizationURL(const QUuid& stateUUID) {
} }
void DomainServer::handleConnectedNode(SharedNodePointer newNode) { void DomainServer::handleConnectedNode(SharedNodePointer newNode) {
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(newNode->getLinkedData());
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(newNode->getLinkedData());
// reply back to the user with a PacketType::DomainList // reply back to the user with a PacketType::DomainList
sendDomainListToNode(newNode, nodeData->getSendingSockAddr()); sendDomainListToNode(newNode, nodeData->getSendingSockAddr());
// if this node is a user (unassigned Agent), signal
if (newNode->getType() == NodeType::Agent && !nodeData->wasAssigned()) {
emit userConnected();
}
// send out this node to our other connected nodes // send out this node to our other connected nodes
broadcastNewNode(newNode); broadcastNewNode(newNode);
} }
@ -1067,62 +1078,39 @@ void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr)
sendHeartbeatToMetaverse(newPublicSockAddr.getAddress().toString()); sendHeartbeatToMetaverse(newPublicSockAddr.getAddress().toString());
} }
void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
auto nodeList = DependencyManager::get<LimitedNodeList>(); auto nodeList = DependencyManager::get<LimitedNodeList>();
const QUuid& domainID = nodeList->getSessionUUID(); const QUuid& domainID = nodeList->getSessionUUID();
// setup the domain object to send to the data server // Setup the domain object to send to the data server
const QString PUBLIC_NETWORK_ADDRESS_KEY = "network_address";
const QString AUTOMATIC_NETWORKING_KEY = "automatic_networking";
QJsonObject domainObject; QJsonObject domainObject;
if (!networkAddress.isEmpty()) { if (!networkAddress.isEmpty()) {
static const QString PUBLIC_NETWORK_ADDRESS_KEY = "network_address";
domainObject[PUBLIC_NETWORK_ADDRESS_KEY] = networkAddress; domainObject[PUBLIC_NETWORK_ADDRESS_KEY] = networkAddress;
} }
static const QString AUTOMATIC_NETWORKING_KEY = "automatic_networking";
domainObject[AUTOMATIC_NETWORKING_KEY] = _automaticNetworkingSetting; domainObject[AUTOMATIC_NETWORKING_KEY] = _automaticNetworkingSetting;
// add a flag to indicate if this domain uses restricted access - for now that will exclude it from listings // Add a flag to indicate if this domain uses restricted access -
const QString RESTRICTED_ACCESS_FLAG = "restricted"; // for now that will exclude it from listings
static const QString RESTRICTED_ACCESS_FLAG = "restricted";
domainObject[RESTRICTED_ACCESS_FLAG] = domainObject[RESTRICTED_ACCESS_FLAG] =
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool(); _settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
// figure out the breakdown of currently connected interface clients // Add the metadata to the heartbeat
int numConnectedUnassigned = 0;
QJsonObject userHostnames;
static const QString DEFAULT_HOSTNAME = "*";
nodeList->eachNode([&numConnectedUnassigned, &userHostnames](const SharedNodePointer& node) {
if (node->getLinkedData()) {
auto nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
if (!nodeData->wasAssigned()) {
++numConnectedUnassigned;
// increment the count for this hostname (or the default if we don't have one)
auto hostname = nodeData->getPlaceName().isEmpty() ? DEFAULT_HOSTNAME : nodeData->getPlaceName();
userHostnames[hostname] = userHostnames[hostname].toInt() + 1;
}
}
});
static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat"; static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat";
static const QString HEARTBEAT_NUM_USERS_KEY = "num_users"; auto tic = _metadata.getTic();
static const QString HEARTBEAT_USER_HOSTNAMES_KEY = "user_hostnames"; if (_metadataTic != tic) {
_metadataTic = tic;
_metadata.updateUsers();
}
domainObject[DOMAIN_HEARTBEAT_KEY] = _metadata.getUsers();
QJsonObject heartbeatObject; QString domainUpdateJSON = QString("{\"domain\":%1}").arg(QString(QJsonDocument(domainObject).toJson(QJsonDocument::Compact)));
heartbeatObject[HEARTBEAT_NUM_USERS_KEY] = numConnectedUnassigned;
heartbeatObject[HEARTBEAT_USER_HOSTNAMES_KEY] = userHostnames;
domainObject[DOMAIN_HEARTBEAT_KEY] = heartbeatObject;
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
static const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
AccountManagerAuth::Required, AccountManagerAuth::Required,
QNetworkAccessManager::PutOperation, QNetworkAccessManager::PutOperation,
@ -1918,11 +1906,10 @@ void DomainServer::nodeAdded(SharedNodePointer node) {
} }
void DomainServer::nodeKilled(SharedNodePointer node) { void DomainServer::nodeKilled(SharedNodePointer node) {
// if this peer connected via ICE then remove them from our ICE peers hash // if this peer connected via ICE then remove them from our ICE peers hash
_gatekeeper.removeICEPeer(node->getUUID()); _gatekeeper.removeICEPeer(node->getUUID());
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData()); DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
if (nodeData) { if (nodeData) {
// if this node's UUID matches a static assignment we need to throw it back in the assignment queue // if this node's UUID matches a static assignment we need to throw it back in the assignment queue
@ -1934,15 +1921,22 @@ void DomainServer::nodeKilled(SharedNodePointer node) {
} }
} }
// If this node was an Agent ask DomainServerNodeData to potentially remove the interpolation we stored
nodeData->removeOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
uuidStringWithoutCurlyBraces(node->getUUID()));
// cleanup the connection secrets that we set up for this node (on the other nodes) // cleanup the connection secrets that we set up for this node (on the other nodes)
foreach (const QUuid& otherNodeSessionUUID, nodeData->getSessionSecretHash().keys()) { foreach (const QUuid& otherNodeSessionUUID, nodeData->getSessionSecretHash().keys()) {
SharedNodePointer otherNode = DependencyManager::get<LimitedNodeList>()->nodeWithUUID(otherNodeSessionUUID); SharedNodePointer otherNode = DependencyManager::get<LimitedNodeList>()->nodeWithUUID(otherNodeSessionUUID);
if (otherNode) { if (otherNode) {
reinterpret_cast<DomainServerNodeData*>(otherNode->getLinkedData())->getSessionSecretHash().remove(node->getUUID()); static_cast<DomainServerNodeData*>(otherNode->getLinkedData())->getSessionSecretHash().remove(node->getUUID());
}
}
if (node->getType() == NodeType::Agent) {
// if this node was an Agent ask DomainServerNodeData to remove the interpolation we potentially stored
nodeData->removeOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
uuidStringWithoutCurlyBraces(node->getUUID()));
// if this node is a user (unassigned Agent), signal
if (!nodeData->wasAssigned()) {
emit userDisconnected();
} }
} }
} }

View file

@ -26,6 +26,7 @@
#include <LimitedNodeList.h> #include <LimitedNodeList.h>
#include "DomainGatekeeper.h" #include "DomainGatekeeper.h"
#include "DomainMetadata.h"
#include "DomainServerSettingsManager.h" #include "DomainServerSettingsManager.h"
#include "DomainServerWebSessionData.h" #include "DomainServerWebSessionData.h"
#include "WalletTransaction.h" #include "WalletTransaction.h"
@ -91,6 +92,8 @@ private slots:
signals: signals:
void iceServerChanged(); void iceServerChanged();
void userConnected();
void userDisconnected();
private: private:
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
@ -167,6 +170,9 @@ private:
DomainServerSettingsManager _settingsManager; DomainServerSettingsManager _settingsManager;
DomainMetadata _metadata;
uint32_t _metadataTic{ 0 };
HifiSockAddr _iceServerSocket; HifiSockAddr _iceServerSocket;
std::unique_ptr<NLPacket> _iceServerHeartbeatPacket; std::unique_ptr<NLPacket> _iceServerHeartbeatPacket;

View file

@ -1,22 +1,40 @@
{ {
"name": "Oculus Touch to Standard", "name": "Oculus Touch to Standard",
"channels": [ "channels": [
{ "from": "OculusTouch.LY", "filters": "invert", "to": "Standard.LY" }, { "from": "OculusTouch.A", "to": "Standard.A" },
{ "from": "OculusTouch.LX", "to": "Standard.LX" }, { "from": "OculusTouch.B", "to": "Standard.B" },
{ "from": "OculusTouch.X", "to": "Standard.X" },
{ "from": "OculusTouch.Y", "to": "Standard.Y" },
{ "from": "OculusTouch.LY", "filters": "invert", "to": "Standard.LY" },
{ "from": "OculusTouch.LX", "to": "Standard.LX" },
{ "from": "OculusTouch.LT", "to": "Standard.LT" }, { "from": "OculusTouch.LT", "to": "Standard.LT" },
{ "from": "OculusTouch.LS", "to": "Standard.LS" },
{ "from": "OculusTouch.LeftGrip", "to": "Standard.LeftGrip" },
{ "from": "OculusTouch.LeftHand", "to": "Standard.LeftHand" },
{ "from": "OculusTouch.RY", "filters": "invert", "to": "Standard.RY" }, { "from": "OculusTouch.RY", "filters": "invert", "to": "Standard.RY" },
{ "from": "OculusTouch.RX", "to": "Standard.RX" }, { "from": "OculusTouch.RX", "to": "Standard.RX" },
{ "from": "OculusTouch.RT", "to": "Standard.RT" }, { "from": "OculusTouch.RT", "to": "Standard.RT" },
{ "from": "OculusTouch.RB", "to": "Standard.RB" },
{ "from": "OculusTouch.RS", "to": "Standard.RS" }, { "from": "OculusTouch.RS", "to": "Standard.RS" },
{ "from": "OculusTouch.RightGrip", "to": "Standard.RightGrip" },
{ "from": "OculusTouch.RightHand", "to": "Standard.RightHand" },
{ "from": "OculusTouch.LeftApplicationMenu", "to": "Standard.Back" }, { "from": "OculusTouch.LeftApplicationMenu", "to": "Standard.Back" },
{ "from": "OculusTouch.RightApplicationMenu", "to": "Standard.Start" }, { "from": "OculusTouch.RightApplicationMenu", "to": "Standard.Start" },
{ "from": "OculusTouch.LeftHand", "to": "Standard.LeftHand" }, { "from": "OculusTouch.LeftPrimaryThumbTouch", "to": "Standard.LeftPrimaryThumbTouch" },
{ "from": "OculusTouch.RightHand", "to": "Standard.RightHand" } { "from": "OculusTouch.LeftSecondaryThumbTouch", "to": "Standard.LeftSecondaryThumbTouch" },
{ "from": "OculusTouch.RightPrimaryThumbTouch", "to": "Standard.RightPrimaryThumbTouch" },
{ "from": "OculusTouch.RightSecondaryThumbTouch", "to": "Standard.RightSecondaryThumbTouch" },
{ "from": "OculusTouch.LeftPrimaryIndexTouch", "to": "Standard.LeftPrimaryIndexTouch" },
{ "from": "OculusTouch.RightPrimaryIndexTouch", "to": "Standard.RightPrimaryIndexTouch" },
{ "from": "OculusTouch.LSTouch", "to": "Standard.LSTouch" },
{ "from": "OculusTouch.RSTouch", "to": "Standard.RSTouch" },
{ "from": "OculusTouch.LeftThumbUp", "to": "Standard.LeftThumbUp" },
{ "from": "OculusTouch.RightThumbUp", "to": "Standard.RightThumbUp" },
{ "from": "OculusTouch.LeftIndexPoint", "to": "Standard.LeftIndexPoint" },
{ "from": "OculusTouch.RightIndexPoint", "to": "Standard.RightIndexPoint" }
] ]
} }

View file

@ -9,6 +9,8 @@
"to": "Actions.StepYaw", "to": "Actions.StepYaw",
"filters": "filters":
[ [
{ "type": "deadZone", "min": 0.15 },
"constrainToInteger",
{ "type": "pulse", "interval": 0.5 }, { "type": "pulse", "interval": 0.5 },
{ "type": "scale", "scale": 22.5 } { "type": "scale", "scale": 22.5 }
] ]

View file

@ -5,7 +5,7 @@
{ "from": "Vive.LX", "when": "Vive.LSOuter", "to": "Standard.LX" }, { "from": "Vive.LX", "when": "Vive.LSOuter", "to": "Standard.LX" },
{ "from": "Vive.LT", "to": "Standard.LT" }, { "from": "Vive.LT", "to": "Standard.LT" },
{ "from": "Vive.LeftGrip", "to": "Standard.LB" }, { "from": "Vive.LeftGrip", "to": "Standard.LeftGrip" },
{ "from": "Vive.LS", "to": "Standard.LS" }, { "from": "Vive.LS", "to": "Standard.LS" },
{ "from": "Vive.LSTouch", "to": "Standard.LSTouch" }, { "from": "Vive.LSTouch", "to": "Standard.LSTouch" },
@ -13,7 +13,7 @@
{ "from": "Vive.RX", "when": "Vive.RSOuter", "to": "Standard.RX" }, { "from": "Vive.RX", "when": "Vive.RSOuter", "to": "Standard.RX" },
{ "from": "Vive.RT", "to": "Standard.RT" }, { "from": "Vive.RT", "to": "Standard.RT" },
{ "from": "Vive.RightGrip", "to": "Standard.RB" }, { "from": "Vive.RightGrip", "to": "Standard.RightGrip" },
{ "from": "Vive.RS", "to": "Standard.RS" }, { "from": "Vive.RS", "to": "Standard.RS" },
{ "from": "Vive.RSTouch", "to": "Standard.RSTouch" }, { "from": "Vive.RSTouch", "to": "Standard.RSTouch" },

View file

@ -1,14 +1,14 @@
{ {
"name": "XBox to Standard", "name": "XBox to Standard",
"channels": [ "channels": [
{ "from": "GamePad.LY", "to": "Standard.LY" }, { "from": "GamePad.LY", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.LY" },
{ "from": "GamePad.LX", "to": "Standard.LX" }, { "from": "GamePad.LX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.LX" },
{ "from": "GamePad.LT", "to": "Standard.LT" }, { "from": "GamePad.LT", "to": "Standard.LT" },
{ "from": "GamePad.LB", "to": "Standard.LB" }, { "from": "GamePad.LB", "to": "Standard.LB" },
{ "from": "GamePad.LS", "to": "Standard.LS" }, { "from": "GamePad.LS", "to": "Standard.LS" },
{ "from": "GamePad.RY", "to": "Standard.RY" }, { "from": "GamePad.RY", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.RY" },
{ "from": "GamePad.RX", "to": "Standard.RX" }, { "from": "GamePad.RX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.RX" },
{ "from": "GamePad.RT", "to": "Standard.RT" }, { "from": "GamePad.RT", "to": "Standard.RT" },
{ "from": "GamePad.RB", "to": "Standard.RB" }, { "from": "GamePad.RB", "to": "Standard.RB" },
{ "from": "GamePad.RS", "to": "Standard.RS" }, { "from": "GamePad.RS", "to": "Standard.RS" },

View file

@ -341,7 +341,7 @@ Window {
HifiControls.GlyphButton { HifiControls.GlyphButton {
glyph: hifi.glyphs.reload glyph: hifi.glyphs.reload
color: hifi.buttons.white color: hifi.buttons.black
colorScheme: root.colorScheme colorScheme: root.colorScheme
width: hifi.dimensions.controlLineHeight width: hifi.dimensions.controlLineHeight
@ -349,8 +349,8 @@ Window {
} }
HifiControls.Button { HifiControls.Button {
text: "ADD TO WORLD" text: "Add To World"
color: hifi.buttons.white color: hifi.buttons.black
colorScheme: root.colorScheme colorScheme: root.colorScheme
width: 120 width: 120
@ -360,8 +360,8 @@ Window {
} }
HifiControls.Button { HifiControls.Button {
text: "RENAME" text: "Rename"
color: hifi.buttons.white color: hifi.buttons.black
colorScheme: root.colorScheme colorScheme: root.colorScheme
width: 80 width: 80
@ -372,7 +372,7 @@ Window {
HifiControls.Button { HifiControls.Button {
id: deleteButton id: deleteButton
text: "DELETE" text: "Delete"
color: hifi.buttons.red color: hifi.buttons.red
colorScheme: root.colorScheme colorScheme: root.colorScheme
width: 80 width: 80

View file

@ -23,9 +23,9 @@ Window {
title: "Running Scripts" title: "Running Scripts"
resizable: true resizable: true
destroyOnInvisible: true destroyOnInvisible: true
implicitWidth: 400 implicitWidth: 424
implicitHeight: isHMD ? 695 : 728 implicitHeight: isHMD ? 695 : 728
minSize: Qt.vector2d(200, 300) minSize: Qt.vector2d(424, 300)
HifiConstants { id: hifi } HifiConstants { id: hifi }
@ -83,6 +83,11 @@ Window {
scripts.reloadAllScripts(); scripts.reloadAllScripts();
} }
function loadDefaults() {
console.log("Load default scripts");
scripts.loadOneScript(scripts.defaultScriptsPath + "/defaultScripts.js");
}
function stopAll() { function stopAll() {
console.log("Stop all scripts"); console.log("Stop all scripts");
scripts.stopAllScripts(); scripts.stopAllScripts();
@ -101,13 +106,13 @@ Window {
spacing: hifi.dimensions.contentSpacing.x spacing: hifi.dimensions.contentSpacing.x
HifiControls.Button { HifiControls.Button {
text: "Reload all" text: "Reload All"
color: hifi.buttons.black color: hifi.buttons.black
onClicked: reloadAll() onClicked: reloadAll()
} }
HifiControls.Button { HifiControls.Button {
text: "Stop all" text: "Remove All"
color: hifi.buttons.red color: hifi.buttons.red
onClicked: stopAll() onClicked: stopAll()
} }
@ -215,7 +220,6 @@ Window {
Row { Row {
spacing: hifi.dimensions.contentSpacing.x spacing: hifi.dimensions.contentSpacing.x
anchors.right: parent.right
HifiControls.Button { HifiControls.Button {
text: "from URL" text: "from URL"
@ -253,6 +257,13 @@ Window {
onTriggered: ApplicationInterface.loadDialog(); onTriggered: ApplicationInterface.loadDialog();
} }
} }
HifiControls.Button {
text: "Load Defaults"
color: hifi.buttons.black
height: 26
onClicked: loadDefaults()
}
} }
HifiControls.VerticalSpacer {} HifiControls.VerticalSpacer {}

View file

@ -19,6 +19,7 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <QtCore/QAbstractNativeEventFilter> #include <QtCore/QAbstractNativeEventFilter>
#include <QtCore/QCommandLineParser>
#include <QtCore/QMimeData> #include <QtCore/QMimeData>
#include <QtCore/QThreadPool> #include <QtCore/QThreadPool>
@ -197,7 +198,6 @@ static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check f
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
static const QString INPUT_DEVICE_MENU_PREFIX = "Device: ";
Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions { const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
@ -994,12 +994,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
if (_keyboardFocusedItem != entityItemID) { if (_keyboardFocusedItem != entityItemID) {
_keyboardFocusedItem = UNKNOWN_ENTITY_ID; _keyboardFocusedItem = UNKNOWN_ENTITY_ID;
auto properties = entityScriptingInterface->getEntityProperties(entityItemID); auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
if (EntityTypes::Web == properties.getType() && !properties.getLocked()) { if (EntityTypes::Web == properties.getType() && !properties.getLocked() && properties.getVisible()) {
auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID); auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID);
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get()); RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
if (webEntity) { if (webEntity) {
webEntity->setProxyWindow(_window->windowHandle()); webEntity->setProxyWindow(_window->windowHandle());
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent(); _keyboardMouseDevice->pluginFocusOutEvent();
} }
_keyboardFocusedItem = entityItemID; _keyboardFocusedItem = entityItemID;
@ -1049,6 +1049,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
} }
}); });
connect(this, &Application::aboutToQuit, [=]() {
_keyboardFocusedItem = UNKNOWN_ENTITY_ID;
if (_keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
});
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
updateHeartbeat(); updateHeartbeat();
@ -1145,9 +1152,7 @@ void Application::aboutToQuit() {
emit beforeAboutToQuit(); emit beforeAboutToQuit();
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); if (inputPlugin->isActive()) {
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action->isChecked()) {
inputPlugin->deactivate(); inputPlugin->deactivate();
} }
} }
@ -1469,7 +1474,6 @@ void Application::initializeUi() {
} }
} }
_window->setMenuBar(new Menu()); _window->setMenuBar(new Menu());
updateInputModes();
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();
connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] { connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] {
@ -1503,7 +1507,13 @@ void Application::paintGL() {
// FIXME not needed anymore? // FIXME not needed anymore?
_offscreenContext->makeCurrent(); _offscreenContext->makeCurrent();
displayPlugin->beginFrameRender(_frameCount); // If a display plugin loses it's underlying support, it
// needs to be able to signal us to not use it
if (!displayPlugin->beginFrameRender(_frameCount)) {
_inPaint = false;
updateDisplayMode();
return;
}
// update the avatar with a fresh HMD pose // update the avatar with a fresh HMD pose
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose()); getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
@ -2011,7 +2021,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
} }
if (hasFocus()) { if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->keyPressEvent(event); _keyboardMouseDevice->keyPressEvent(event);
} }
@ -2345,7 +2355,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->keyReleaseEvent(event); _keyboardMouseDevice->keyReleaseEvent(event);
} }
@ -2377,9 +2387,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
void Application::focusOutEvent(QFocusEvent* event) { void Application::focusOutEvent(QFocusEvent* event) {
auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
foreach(auto inputPlugin, inputPlugins) { foreach(auto inputPlugin, inputPlugins) {
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); if (inputPlugin->isActive()) {
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action && action->isChecked()) {
inputPlugin->pluginFocusOutEvent(); inputPlugin->pluginFocusOutEvent();
} }
} }
@ -2464,7 +2472,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mouseMoveEvent(event); _keyboardMouseDevice->mouseMoveEvent(event);
} }
@ -2501,7 +2509,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
if (hasFocus()) { if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mousePressEvent(event); _keyboardMouseDevice->mousePressEvent(event);
} }
@ -2546,7 +2554,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
} }
if (hasFocus()) { if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mouseReleaseEvent(event); _keyboardMouseDevice->mouseReleaseEvent(event);
} }
@ -2573,7 +2581,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchUpdateEvent(event); _keyboardMouseDevice->touchUpdateEvent(event);
} }
} }
@ -2591,7 +2599,7 @@ void Application::touchBeginEvent(QTouchEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchBeginEvent(event); _keyboardMouseDevice->touchBeginEvent(event);
} }
@ -2608,7 +2616,7 @@ void Application::touchEndEvent(QTouchEvent* event) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchEndEvent(event); _keyboardMouseDevice->touchEndEvent(event);
} }
@ -2624,7 +2632,7 @@ void Application::wheelEvent(QWheelEvent* event) const {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->wheelEvent(event); _keyboardMouseDevice->wheelEvent(event);
} }
} }
@ -2757,9 +2765,7 @@ void Application::idle(float nsecsElapsed) {
getActiveDisplayPlugin()->idle(); getActiveDisplayPlugin()->idle();
auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
foreach(auto inputPlugin, inputPlugins) { foreach(auto inputPlugin, inputPlugins) {
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); if (inputPlugin->isActive()) {
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action && action->isChecked()) {
inputPlugin->idle(); inputPlugin->idle();
} }
} }
@ -2943,6 +2949,27 @@ void Application::loadSettings() {
//DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false); //DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);
Menu::getInstance()->loadSettings(); Menu::getInstance()->loadSettings();
// If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
auto pluginManager = PluginManager::getInstance();
auto plugins = pluginManager->getPreferredDisplayPlugins();
for (auto plugin : plugins) {
auto menu = Menu::getInstance();
if (auto action = menu->getActionForOption(plugin->getName())) {
action->setChecked(true);
action->trigger();
// Find and activated highest priority plugin, bail for the rest
break;
}
}
auto inputs = pluginManager->getInputPlugins();
for (auto plugin : inputs) {
if (!plugin->isActive()) {
plugin->activate();
}
}
getMyAvatar()->loadData(); getMyAvatar()->loadData();
_settingsLoaded = true; _settingsLoaded = true;
@ -4923,7 +4950,34 @@ void Application::postLambdaEvent(std::function<void()> f) {
} }
} }
void Application::initPlugins() { void Application::initPlugins(const QStringList& arguments) {
QCommandLineOption display("display", "Preferred displays", "displays");
QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays");
QCommandLineOption disableInputs("disable-inputs", "Inputs to disable", "inputs");
QCommandLineParser parser;
parser.addOption(display);
parser.addOption(disableDisplays);
parser.addOption(disableInputs);
parser.parse(arguments);
if (parser.isSet(display)) {
auto preferredDisplays = parser.value(display).split(',', QString::SkipEmptyParts);
qInfo() << "Setting prefered display plugins:" << preferredDisplays;
PluginManager::getInstance()->setPreferredDisplayPlugins(preferredDisplays);
}
if (parser.isSet(disableDisplays)) {
auto disabledDisplays = parser.value(disableDisplays).split(',', QString::SkipEmptyParts);
qInfo() << "Disabling following display plugins:" << disabledDisplays;
PluginManager::getInstance()->disableDisplays(disabledDisplays);
}
if (parser.isSet(disableInputs)) {
auto disabledInputs = parser.value(disableInputs).split(',', QString::SkipEmptyParts);
qInfo() << "Disabling following input plugins:" << disabledInputs;
PluginManager::getInstance()->disableInputs(disabledInputs);
}
} }
void Application::shutdownPlugins() { void Application::shutdownPlugins() {
@ -5098,9 +5152,17 @@ void Application::updateDisplayMode() {
foreach(auto displayPlugin, standard) { foreach(auto displayPlugin, standard) {
addDisplayPluginToMenu(displayPlugin, first); addDisplayPluginToMenu(displayPlugin, first);
auto displayPluginName = displayPlugin->getName();
QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) { QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) {
resizeGL(); resizeGL();
}); });
QObject::connect(displayPlugin.get(), &DisplayPlugin::outputDeviceLost, [this, displayPluginName] {
PluginManager::getInstance()->disableDisplayPlugin(displayPluginName);
auto menu = Menu::getInstance();
if (menu->menuItemExists(MenuOption::OutputMenu, displayPluginName)) {
menu->removeMenuItem(MenuOption::OutputMenu, displayPluginName);
}
});
first = false; first = false;
} }
@ -5116,6 +5178,10 @@ void Application::updateDisplayMode() {
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
QString name = displayPlugin->getName(); QString name = displayPlugin->getName();
QAction* action = menu->getActionForOption(name); QAction* action = menu->getActionForOption(name);
// Menu might have been removed if the display plugin lost
if (!action) {
continue;
}
if (action->isChecked()) { if (action->isChecked()) {
newDisplayPlugin = displayPlugin; newDisplayPlugin = displayPlugin;
break; break;
@ -5181,81 +5247,6 @@ void Application::updateDisplayMode() {
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
} }
static void addInputPluginToMenu(InputPluginPointer inputPlugin) {
auto menu = Menu::getInstance();
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
Q_ASSERT(!menu->menuItemExists(MenuOption::InputMenu, name));
static QActionGroup* inputPluginGroup = nullptr;
if (!inputPluginGroup) {
inputPluginGroup = new QActionGroup(menu);
inputPluginGroup->setExclusive(false);
}
auto parent = menu->getMenu(MenuOption::InputMenu);
auto action = menu->addCheckableActionToQMenuAndActionHash(parent,
name, 0, true, qApp,
SLOT(updateInputModes()));
inputPluginGroup->addAction(action);
Q_ASSERT(menu->menuItemExists(MenuOption::InputMenu, name));
}
void Application::updateInputModes() {
auto menu = Menu::getInstance();
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
static std::once_flag once;
std::call_once(once, [&] {
foreach(auto inputPlugin, inputPlugins) {
addInputPluginToMenu(inputPlugin);
}
});
auto offscreenUi = DependencyManager::get<OffscreenUi>();
InputPluginList newInputPlugins;
InputPluginList removedInputPlugins;
foreach(auto inputPlugin, inputPlugins) {
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
QAction* action = menu->getActionForOption(name);
auto it = std::find(std::begin(_activeInputPlugins), std::end(_activeInputPlugins), inputPlugin);
if (action->isChecked() && it == std::end(_activeInputPlugins)) {
_activeInputPlugins.push_back(inputPlugin);
newInputPlugins.push_back(inputPlugin);
} else if (!action->isChecked() && it != std::end(_activeInputPlugins)) {
_activeInputPlugins.erase(it);
removedInputPlugins.push_back(inputPlugin);
}
}
// A plugin was checked
if (newInputPlugins.size() > 0) {
foreach(auto newInputPlugin, newInputPlugins) {
newInputPlugin->activate();
//newInputPlugin->installEventFilter(qApp);
//newInputPlugin->installEventFilter(offscreenUi.data());
}
}
if (removedInputPlugins.size() > 0) { // A plugin was unchecked
foreach(auto removedInputPlugin, removedInputPlugins) {
removedInputPlugin->deactivate();
//removedInputPlugin->removeEventFilter(qApp);
//removedInputPlugin->removeEventFilter(offscreenUi.data());
}
}
//if (newInputPlugins.size() > 0 || removedInputPlugins.size() > 0) {
// if (!_currentInputPluginActions.isEmpty()) {
// auto menu = Menu::getInstance();
// foreach(auto itemInfo, _currentInputPluginActions) {
// menu->removeMenuItem(itemInfo.first, itemInfo.second);
// }
// _currentInputPluginActions.clear();
// }
//}
}
mat4 Application::getEyeProjection(int eye) const { mat4 Application::getEyeProjection(int eye) const {
QMutexLocker viewLocker(&_viewMutex); QMutexLocker viewLocker(&_viewMutex);
if (isHMDMode()) { if (isHMDMode()) {

View file

@ -101,7 +101,7 @@ public:
}; };
// FIXME? Empty methods, do we still need them? // FIXME? Empty methods, do we still need them?
static void initPlugins(); static void initPlugins(const QStringList& arguments);
static void shutdownPlugins(); static void shutdownPlugins();
Application(int& argc, char** argv, QElapsedTimer& startup_time); Application(int& argc, char** argv, QElapsedTimer& startup_time);
@ -327,7 +327,6 @@ private slots:
void nodeKilled(SharedNodePointer node); void nodeKilled(SharedNodePointer node);
static void packetSent(quint64 length); static void packetSent(quint64 length);
void updateDisplayMode(); void updateDisplayMode();
void updateInputModes();
void domainConnectionRefused(const QString& reasonMessage, int reason); void domainConnectionRefused(const QString& reasonMessage, int reason);
private: private:

View file

@ -403,12 +403,6 @@ Menu::Menu() {
// Developer > Avatar >>> // Developer > Avatar >>>
MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar");
// Settings > Input Devices
MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced");
QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu);
inputModeGroup->setExclusive(false);
// Developer > Avatar > Face Tracking // Developer > Avatar > Face Tracking
MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking"); MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
{ {

View file

@ -113,7 +113,6 @@ namespace MenuOption {
const QString Help = "Help..."; const QString Help = "Help...";
const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode"; const QString IndependentMode = "Independent Mode";
const QString InputMenu = "Developer>Avatar>Input Devices";
const QString ActionMotorControl = "Enable Default Motor Control"; const QString ActionMotorControl = "Enable Default Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File..."; const QString LoadScript = "Open and Run Script File...";

View file

@ -84,7 +84,6 @@ Avatar::Avatar(RigPointer rig) :
_acceleration(0.0f), _acceleration(0.0f),
_lastAngularVelocity(0.0f), _lastAngularVelocity(0.0f),
_lastOrientation(), _lastOrientation(),
_leanScale(0.5f),
_worldUpDirection(DEFAULT_UP_DIRECTION), _worldUpDirection(DEFAULT_UP_DIRECTION),
_moving(false), _moving(false),
_initialized(false), _initialized(false),

View file

@ -210,7 +210,6 @@ protected:
glm::vec3 _angularAcceleration; glm::vec3 _angularAcceleration;
glm::quat _lastOrientation; glm::quat _lastOrientation;
float _leanScale;
glm::vec3 _worldUpDirection; glm::vec3 _worldUpDirection;
float _stringLength; float _stringLength;
bool _moving; ///< set when position is changing bool _moving; ///< set when position is changing

View file

@ -54,8 +54,6 @@ Head::Head(Avatar* owningAvatar) :
_deltaPitch(0.0f), _deltaPitch(0.0f),
_deltaYaw(0.0f), _deltaYaw(0.0f),
_deltaRoll(0.0f), _deltaRoll(0.0f),
_deltaLeanSideways(0.0f),
_deltaLeanForward(0.0f),
_isCameraMoving(false), _isCameraMoving(false),
_isLookingAtMe(false), _isLookingAtMe(false),
_lookingAtMeStarted(0), _lookingAtMeStarted(0),
@ -70,7 +68,6 @@ void Head::init() {
void Head::reset() { void Head::reset() {
_baseYaw = _basePitch = _baseRoll = 0.0f; _baseYaw = _basePitch = _baseRoll = 0.0f;
_leanForward = _leanSideways = 0.0f;
} }
void Head::simulate(float deltaTime, bool isMine, bool billboard) { void Head::simulate(float deltaTime, bool isMine, bool billboard) {
@ -118,13 +115,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
auto eyeTracker = DependencyManager::get<EyeTracker>(); auto eyeTracker = DependencyManager::get<EyeTracker>();
_isEyeTrackerConnected = eyeTracker->isTracking(); _isEyeTrackerConnected = eyeTracker->isTracking();
} }
// Twist the upper body to follow the rotation of the head, but only do this with my avatar,
// since everyone else will see the full joint rotations for other people.
const float BODY_FOLLOW_HEAD_YAW_RATE = 0.1f;
const float BODY_FOLLOW_HEAD_FACTOR = 0.66f;
float currentTwist = getTorsoTwist();
setTorsoTwist(currentTwist + (getFinalYaw() * BODY_FOLLOW_HEAD_FACTOR - currentTwist) * BODY_FOLLOW_HEAD_YAW_RATE);
} }
if (!(_isFaceTrackerConnected || billboard)) { if (!(_isFaceTrackerConnected || billboard)) {
@ -301,17 +291,13 @@ void Head::applyEyelidOffset(glm::quat headOrientation) {
} }
} }
void Head::relaxLean(float deltaTime) { void Head::relax(float deltaTime) {
// restore rotation, lean to neutral positions // restore rotation, lean to neutral positions
const float LEAN_RELAXATION_PERIOD = 0.25f; // seconds const float LEAN_RELAXATION_PERIOD = 0.25f; // seconds
float relaxationFactor = 1.0f - glm::min(deltaTime / LEAN_RELAXATION_PERIOD, 1.0f); float relaxationFactor = 1.0f - glm::min(deltaTime / LEAN_RELAXATION_PERIOD, 1.0f);
_deltaYaw *= relaxationFactor; _deltaYaw *= relaxationFactor;
_deltaPitch *= relaxationFactor; _deltaPitch *= relaxationFactor;
_deltaRoll *= relaxationFactor; _deltaRoll *= relaxationFactor;
_leanSideways *= relaxationFactor;
_leanForward *= relaxationFactor;
_deltaLeanSideways *= relaxationFactor;
_deltaLeanForward *= relaxationFactor;
} }
void Head::setScale (float scale) { void Head::setScale (float scale) {
@ -419,8 +405,3 @@ float Head::getFinalPitch() const {
float Head::getFinalRoll() const { float Head::getFinalRoll() const {
return glm::clamp(_baseRoll + _deltaRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); return glm::clamp(_baseRoll + _deltaRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL);
} }
void Head::addLeanDeltas(float sideways, float forward) {
_deltaLeanSideways += sideways;
_deltaLeanForward += forward;
}

View file

@ -59,8 +59,6 @@ public:
glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; }
glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
float getFinalLeanSideways() const { return _leanSideways + _deltaLeanSideways; }
float getFinalLeanForward() const { return _leanForward + _deltaLeanForward; }
glm::quat getEyeRotation(const glm::vec3& eyePosition) const; glm::quat getEyeRotation(const glm::vec3& eyePosition) const;
@ -91,8 +89,7 @@ public:
virtual float getFinalYaw() const; virtual float getFinalYaw() const;
virtual float getFinalRoll() const; virtual float getFinalRoll() const;
void relaxLean(float deltaTime); void relax(float deltaTime);
void addLeanDeltas(float sideways, float forward);
float getTimeWithoutTalking() const { return _timeWithoutTalking; } float getTimeWithoutTalking() const { return _timeWithoutTalking; }
@ -132,10 +129,6 @@ private:
float _deltaYaw; float _deltaYaw;
float _deltaRoll; float _deltaRoll;
// delta lean angles for lean perturbations (driven by collisions)
float _deltaLeanSideways;
float _deltaLeanForward;
bool _isCameraMoving; bool _isCameraMoving;
bool _isLookingAtMe; bool _isLookingAtMe;
quint64 _lookingAtMeStarted; quint64 _lookingAtMeStarted;

View file

@ -190,9 +190,6 @@ MyAvatar::MyAvatar(RigPointer rig) :
if (!headData->getBlendshapeCoefficients().isEmpty()) { if (!headData->getBlendshapeCoefficients().isEmpty()) {
_headData->setBlendshapeCoefficients(headData->getBlendshapeCoefficients()); _headData->setBlendshapeCoefficients(headData->getBlendshapeCoefficients());
} }
// head lean
_headData->setLeanForward(headData->getLeanForward());
_headData->setLeanSideways(headData->getLeanSideways());
// head orientation // head orientation
_headData->setLookAtPosition(headData->getLookAtPosition()); _headData->setLookAtPosition(headData->getLookAtPosition());
} }
@ -237,7 +234,7 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "reset", Q_ARG(bool, andRecenter)); QMetaObject::invokeMethod(this, "reset", Q_ARG(bool, andRecenter), Q_ARG(bool, andReload), Q_ARG(bool, andHead));
return; return;
} }
@ -306,7 +303,7 @@ void MyAvatar::update(float deltaTime) {
} }
Head* head = getHead(); Head* head = getHead();
head->relaxLean(deltaTime); head->relax(deltaTime);
updateFromTrackers(deltaTime); updateFromTrackers(deltaTime);
// Get audio loudness data from audio input device // Get audio loudness data from audio input device
@ -574,16 +571,6 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
head->setDeltaYaw(estimatedRotation.y * magnifyFieldOfView); head->setDeltaYaw(estimatedRotation.y * magnifyFieldOfView);
head->setDeltaRoll(estimatedRotation.z); head->setDeltaRoll(estimatedRotation.z);
} }
// Update torso lean distance based on accelerometer data
const float TORSO_LENGTH = 0.5f;
glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f);
const float MAX_LEAN = 45.0f;
head->setLeanSideways(glm::clamp(glm::degrees(atanf(relativePosition.x * _leanScale / TORSO_LENGTH)),
-MAX_LEAN, MAX_LEAN));
head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)),
-MAX_LEAN, MAX_LEAN));
} }
glm::vec3 MyAvatar::getLeftHandPosition() const { glm::vec3 MyAvatar::getLeftHandPosition() const {
@ -692,7 +679,6 @@ void MyAvatar::saveData() {
settings.setValue("headPitch", getHead()->getBasePitch()); settings.setValue("headPitch", getHead()->getBasePitch());
settings.setValue("leanScale", _leanScale);
settings.setValue("scale", _targetScale); settings.setValue("scale", _targetScale);
settings.setValue("fullAvatarURL", settings.setValue("fullAvatarURL",
@ -739,7 +725,7 @@ void MyAvatar::saveData() {
settings.endGroup(); settings.endGroup();
} }
float loadSetting(QSettings& settings, const char* name, float defaultValue) { float loadSetting(Settings& settings, const QString& name, float defaultValue) {
float value = settings.value(name, defaultValue).toFloat(); float value = settings.value(name, defaultValue).toFloat();
if (glm::isnan(value)) { if (glm::isnan(value)) {
value = defaultValue; value = defaultValue;
@ -809,7 +795,6 @@ void MyAvatar::loadData() {
getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f)); getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f));
_leanScale = loadSetting(settings, "leanScale", 0.05f);
_targetScale = loadSetting(settings, "scale", 1.0f); _targetScale = loadSetting(settings, "scale", 1.0f);
setScale(glm::vec3(_targetScale)); setScale(glm::vec3(_targetScale));
@ -1214,7 +1199,10 @@ void MyAvatar::updateMotors() {
if (_characterController.getState() == CharacterController::State::Hover) { if (_characterController.getState() == CharacterController::State::Hover) {
motorRotation = getHead()->getCameraOrientation(); motorRotation = getHead()->getCameraOrientation();
} else { } else {
motorRotation = getOrientation(); // non-hovering = walking: follow camera twist about vertical but not lift
// so we decompose camera's rotation and store the twist part in motorRotation
glm::quat liftRotation;
swingTwistDecomposition(getHead()->getCameraOrientation(), _worldUpDirection, liftRotation, motorRotation);
} }
const float DEFAULT_MOTOR_TIMESCALE = 0.2f; const float DEFAULT_MOTOR_TIMESCALE = 0.2f;
const float INVALID_MOTOR_TIMESCALE = 1.0e6f; const float INVALID_MOTOR_TIMESCALE = 1.0e6f;
@ -1268,13 +1256,13 @@ void MyAvatar::prepareForPhysicsSimulation() {
void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) {
glm::vec3 position = getPosition(); glm::vec3 position = getPosition();
glm::quat orientation = getOrientation(); glm::quat orientation = getOrientation();
if (_characterController.isEnabled()) { if (_characterController.isEnabledAndReady()) {
_characterController.getPositionAndOrientation(position, orientation); _characterController.getPositionAndOrientation(position, orientation);
} }
nextAttitude(position, orientation); nextAttitude(position, orientation);
_bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix); _bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix);
if (_characterController.isEnabled()) { if (_characterController.isEnabledAndReady()) {
setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity()); setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity());
} else { } else {
setVelocity(getVelocity() + _characterController.getFollowVelocity()); setVelocity(getVelocity() + _characterController.getFollowVelocity());
@ -1657,7 +1645,7 @@ void MyAvatar::updatePosition(float deltaTime) {
vec3 velocity = getVelocity(); vec3 velocity = getVelocity();
const float MOVING_SPEED_THRESHOLD_SQUARED = 0.0001f; // 0.01 m/s const float MOVING_SPEED_THRESHOLD_SQUARED = 0.0001f; // 0.01 m/s
if (!_characterController.isEnabled()) { if (!_characterController.isEnabledAndReady()) {
// _characterController is not in physics simulation but it can still compute its target velocity // _characterController is not in physics simulation but it can still compute its target velocity
updateMotors(); updateMotors();
_characterController.computeNewVelocity(deltaTime, velocity); _characterController.computeNewVelocity(deltaTime, velocity);
@ -1831,6 +1819,16 @@ void MyAvatar::updateMotionBehaviorFromMenu() {
_motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; _motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
} }
setCharacterControllerEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController));
}
void MyAvatar::setCharacterControllerEnabled(bool enabled) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setCharacterControllerEnabled", Q_ARG(bool, enabled));
return;
}
bool ghostingAllowed = true; bool ghostingAllowed = true;
EntityTreeRenderer* entityTreeRenderer = qApp->getEntities(); EntityTreeRenderer* entityTreeRenderer = qApp->getEntities();
if (entityTreeRenderer) { if (entityTreeRenderer) {
@ -1839,12 +1837,11 @@ void MyAvatar::updateMotionBehaviorFromMenu() {
ghostingAllowed = zone->getGhostingAllowed(); ghostingAllowed = zone->getGhostingAllowed();
} }
} }
bool checked = menu->isOptionChecked(MenuOption::EnableCharacterController); _characterController.setEnabled(ghostingAllowed ? enabled : true);
if (!ghostingAllowed) { }
checked = true;
}
_characterController.setEnabled(checked); bool MyAvatar::getCharacterControllerEnabled() {
return _characterController.isEnabled();
} }
void MyAvatar::clearDriveKeys() { void MyAvatar::clearDriveKeys() {
@ -2052,14 +2049,17 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) {
_desiredBodyMatrix = desiredBodyMatrix; _desiredBodyMatrix = desiredBodyMatrix;
if (!isActive(Rotation) && shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {
activate(Rotation); if (myAvatar.getHMDLeanRecenterEnabled()) {
} if (!isActive(Rotation) && shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {
if (!isActive(Horizontal) && shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { activate(Rotation);
activate(Horizontal); }
} if (!isActive(Horizontal) && shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {
if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Horizontal);
activate(Vertical); }
if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
activate(Vertical);
}
} }
glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * _desiredBodyMatrix; glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * _desiredBodyMatrix;

View file

@ -69,7 +69,6 @@ class MyAvatar : public Avatar {
Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom) Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom)
//TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition) Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition)
Q_PROPERTY(glm::vec3 rightHandPosition READ getRightHandPosition) Q_PROPERTY(glm::vec3 rightHandPosition READ getRightHandPosition)
Q_PROPERTY(glm::vec3 leftHandTipPosition READ getLeftHandTipPosition) Q_PROPERTY(glm::vec3 leftHandTipPosition READ getLeftHandTipPosition)
@ -84,6 +83,9 @@ class MyAvatar : public Avatar {
Q_PROPERTY(float energy READ getEnergy WRITE setEnergy) Q_PROPERTY(float energy READ getEnergy WRITE setEnergy)
Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled)
Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled)
public: public:
explicit MyAvatar(RigPointer rig); explicit MyAvatar(RigPointer rig);
~MyAvatar(); ~MyAvatar();
@ -123,9 +125,6 @@ public:
void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); } void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); }
void setLeanScale(float scale) { _leanScale = scale; }
float getLeanScale() const { return _leanScale; }
Q_INVOKABLE glm::vec3 getDefaultEyePosition() const; Q_INVOKABLE glm::vec3 getDefaultEyePosition() const;
float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); } float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); }
@ -163,6 +162,9 @@ public:
Q_INVOKABLE bool getClearOverlayWhenDriving() const { return _clearOverlayWhenDriving; } Q_INVOKABLE bool getClearOverlayWhenDriving() const { return _clearOverlayWhenDriving; }
Q_INVOKABLE void setClearOverlayWhenDriving(bool on) { _clearOverlayWhenDriving = on; } Q_INVOKABLE void setClearOverlayWhenDriving(bool on) { _clearOverlayWhenDriving = on; }
Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; }
Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; }
// get/set avatar data // get/set avatar data
void saveData(); void saveData();
void loadData(); void loadData();
@ -264,6 +266,9 @@ public:
controller::Pose getLeftHandControllerPoseInAvatarFrame() const; controller::Pose getLeftHandControllerPoseInAvatarFrame() const;
controller::Pose getRightHandControllerPoseInAvatarFrame() const; controller::Pose getRightHandControllerPoseInAvatarFrame() const;
Q_INVOKABLE void setCharacterControllerEnabled(bool enabled);
Q_INVOKABLE bool getCharacterControllerEnabled();
public slots: public slots:
void increaseSize(); void increaseSize();
void decreaseSize(); void decreaseSize();
@ -470,6 +475,8 @@ private:
ThreadSafeValueCache<controller::Pose> _leftHandControllerPoseInSensorFrameCache { controller::Pose() }; ThreadSafeValueCache<controller::Pose> _leftHandControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _rightHandControllerPoseInSensorFrameCache { controller::Pose() }; ThreadSafeValueCache<controller::Pose> _rightHandControllerPoseInSensorFrameCache { controller::Pose() };
bool _hmdLeanRecenterEnabled = true;
float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f }; float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f };
float AUDIO_ENERGY_CONSTANT { 0.000001f }; float AUDIO_ENERGY_CONSTANT { 0.000001f };
float MAX_AVATAR_MOVEMENT_PER_FRAME { 30.0f }; float MAX_AVATAR_MOVEMENT_PER_FRAME { 30.0f };

View file

@ -106,10 +106,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar); MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
Rig::HeadParameters headParams; Rig::HeadParameters headParams;
headParams.enableLean = qApp->isHMDMode();
headParams.leanSideways = head->getFinalLeanSideways();
headParams.leanForward = head->getFinalLeanForward();
headParams.torsoTwist = head->getTorsoTwist();
if (qApp->isHMDMode()) { if (qApp->isHMDMode()) {
headParams.isInHMD = true; headParams.isInHMD = true;
@ -131,7 +127,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
headParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame(); headParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
} }
headParams.leanJointIndex = geometry.leanJointIndex;
headParams.neckJointIndex = geometry.neckJointIndex; headParams.neckJointIndex = geometry.neckJointIndex;
headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f; headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f;

View file

@ -46,6 +46,12 @@ int main(int argc, const char* argv[]) {
bool instanceMightBeRunning = true; bool instanceMightBeRunning = true;
QStringList arguments;
for (int i = 0; i < argc; ++i) {
arguments << argv[i];
}
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// Try to create a shared memory block - if it can't be created, there is an instance of // Try to create a shared memory block - if it can't be created, there is an instance of
// interface already running. We only do this on Windows for now because of the potential // interface already running. We only do this on Windows for now because of the potential
@ -64,12 +70,6 @@ int main(int argc, const char* argv[]) {
// Try to connect - if we can't connect, interface has probably just gone down // Try to connect - if we can't connect, interface has probably just gone down
if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) { if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) {
QStringList arguments;
for (int i = 0; i < argc; ++i) {
arguments << argv[i];
}
QCommandLineParser parser; QCommandLineParser parser;
QCommandLineOption urlOption("url", "", "value"); QCommandLineOption urlOption("url", "", "value");
parser.addOption(urlOption); parser.addOption(urlOption);
@ -135,7 +135,7 @@ int main(int argc, const char* argv[]) {
// Oculus initialization MUST PRECEDE OpenGL context creation. // Oculus initialization MUST PRECEDE OpenGL context creation.
// The nature of the Application constructor means this has to be either here, // The nature of the Application constructor means this has to be either here,
// or in the main window ctor, before GL startup. // or in the main window ctor, before GL startup.
Application::initPlugins(); Application::initPlugins(arguments);
int exitCode; int exitCode;
{ {

View file

@ -14,6 +14,10 @@
ClipboardScriptingInterface::ClipboardScriptingInterface() { ClipboardScriptingInterface::ClipboardScriptingInterface() {
} }
glm::vec3 ClipboardScriptingInterface::getContentsDimensions() {
return qApp->getEntityClipboard()->getContentsDimensions();
}
float ClipboardScriptingInterface::getClipboardContentsLargestDimension() { float ClipboardScriptingInterface::getClipboardContentsLargestDimension() {
return qApp->getEntityClipboard()->getContentsLargestDimension(); return qApp->getEntityClipboard()->getContentsLargestDimension();
} }

View file

@ -22,6 +22,7 @@ signals:
void readyToImport(); void readyToImport();
public slots: public slots:
glm::vec3 getContentsDimensions(); /// returns the overall dimensions of everything on the blipboard
float getClipboardContentsLargestDimension(); /// returns the largest dimension of everything on the clipboard float getClipboardContentsLargestDimension(); /// returns the largest dimension of everything on the clipboard
bool importEntities(const QString& filename); bool importEntities(const QString& filename);
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs); bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs);

View file

@ -129,16 +129,6 @@ void setupPreferences() {
preference->setStep(1); preference->setStep(1);
preferences->addPreference(preference); preferences->addPreference(preference);
} }
{
auto getter = [=]()->float { return myAvatar->getLeanScale(); };
auto setter = [=](float value) { myAvatar->setLeanScale(value); };
auto preference = new SpinnerPreference(AVATAR_TUNING, "Lean scale (applies to Faceshift users)", getter, setter);
preference->setMin(0);
preference->setMax(99.9f);
preference->setDecimals(2);
preference->setStep(1);
preferences->addPreference(preference);
}
{ {
auto getter = [=]()->float { return myAvatar->getUniformScale(); }; auto getter = [=]()->float { return myAvatar->getUniformScale(); };
auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell? auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell?

View file

@ -931,11 +931,6 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) {
} }
void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) { void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
if (params.enableLean) {
updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist);
} else {
_animVars.unset("lean");
}
updateNeckJoint(params.neckJointIndex, params); updateNeckJoint(params.neckJointIndex, params);
_animVars.set("isTalking", params.isTalking); _animVars.set("isTalking", params.isTalking);
@ -953,15 +948,6 @@ static const glm::vec3 X_AXIS(1.0f, 0.0f, 0.0f);
static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f); static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f);
static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f); static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f);
void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) {
if (isIndexValid(index)) {
glm::quat absRot = (glm::angleAxis(-RADIANS_PER_DEGREE * leanSideways, Z_AXIS) *
glm::angleAxis(-RADIANS_PER_DEGREE * leanForward, X_AXIS) *
glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, Y_AXIS));
_animVars.set("lean", absRot);
}
}
void Rig::computeHeadNeckAnimVars(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut, void Rig::computeHeadNeckAnimVars(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut,
glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) const { glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) const {

View file

@ -42,15 +42,10 @@ public:
}; };
struct HeadParameters { struct HeadParameters {
float leanSideways = 0.0f; // degrees
float leanForward = 0.0f; // degrees
float torsoTwist = 0.0f; // degrees
bool enableLean = false;
glm::quat worldHeadOrientation = glm::quat(); // world space (-z forward) glm::quat worldHeadOrientation = glm::quat(); // world space (-z forward)
glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward) glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward)
glm::vec3 rigHeadPosition = glm::vec3(); // rig space glm::vec3 rigHeadPosition = glm::vec3(); // rig space
bool isInHMD = false; bool isInHMD = false;
int leanJointIndex = -1;
int neckJointIndex = -1; int neckJointIndex = -1;
bool isTalking = false; bool isTalking = false;
}; };
@ -222,7 +217,6 @@ protected:
void applyOverridePoses(); void applyOverridePoses();
void buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut); void buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut);
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
void updateNeckJoint(int index, const HeadParameters& params); void updateNeckJoint(int index, const HeadParameters& params);
void computeHeadNeckAnimVars(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut, void computeHeadNeckAnimVars(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut,
glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) const; glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) const;

View file

@ -14,552 +14,11 @@
#include <algorithm> #include <algorithm>
#include "AudioSRC.h" #include "AudioSRC.h"
#include "AudioSRCData.h"
// // high/low part of int64_t
// prototype lowpass filter #define LO32(a) ((uint32_t)(a))
// #define HI32(a) ((int32_t)((a) >> 32))
// Minimum-phase equiripple FIR
// taps = 96, oversampling = 32
//
// passband = 0.918
// stopband = 1.010
// passband ripple = +-0.01dB
// stopband attn = -125dB (-70dB at 1.000)
//
static const int PROTOTYPE_TAPS = 96; // filter taps per phase
static const int PROTOTYPE_PHASES = 32; // oversampling factor
static const float prototypeFilter[PROTOTYPE_TAPS * PROTOTYPE_PHASES] = {
0.00000000e+00f, 1.55021703e-05f, 1.46054865e-05f, 2.07057160e-05f, 2.91335519e-05f, 4.00091078e-05f,
5.33544450e-05f, 7.03618468e-05f, 9.10821639e-05f, 1.16484613e-04f, 1.47165999e-04f, 1.84168304e-04f,
2.28429617e-04f, 2.80913884e-04f, 3.42940399e-04f, 4.15773039e-04f, 5.01023255e-04f, 6.00234953e-04f,
7.15133271e-04f, 8.47838855e-04f, 1.00032516e-03f, 1.17508881e-03f, 1.37452550e-03f, 1.60147614e-03f,
1.85886458e-03f, 2.14985024e-03f, 2.47783071e-03f, 2.84666764e-03f, 3.26016878e-03f, 3.72252797e-03f,
4.23825900e-03f, 4.81207874e-03f, 5.44904143e-03f, 6.15447208e-03f, 6.93399929e-03f, 7.79337059e-03f,
8.73903392e-03f, 9.77729117e-03f, 1.09149561e-02f, 1.21591316e-02f, 1.35171164e-02f, 1.49965439e-02f,
1.66053136e-02f, 1.83515384e-02f, 2.02435362e-02f, 2.22899141e-02f, 2.44995340e-02f, 2.68813362e-02f,
2.94443254e-02f, 3.21979928e-02f, 3.51514690e-02f, 3.83143719e-02f, 4.16960560e-02f, 4.53060504e-02f,
4.91538115e-02f, 5.32486197e-02f, 5.75998650e-02f, 6.22164253e-02f, 6.71072811e-02f, 7.22809789e-02f,
7.77457552e-02f, 8.35095233e-02f, 8.95796944e-02f, 9.59631768e-02f, 1.02666457e-01f, 1.09695215e-01f,
1.17054591e-01f, 1.24748885e-01f, 1.32781656e-01f, 1.41155521e-01f, 1.49872243e-01f, 1.58932534e-01f,
1.68335961e-01f, 1.78081143e-01f, 1.88165339e-01f, 1.98584621e-01f, 2.09333789e-01f, 2.20406193e-01f,
2.31793899e-01f, 2.43487398e-01f, 2.55475740e-01f, 2.67746404e-01f, 2.80285305e-01f, 2.93076743e-01f,
3.06103423e-01f, 3.19346351e-01f, 3.32784916e-01f, 3.46396772e-01f, 3.60158039e-01f, 3.74043042e-01f,
3.88024564e-01f, 4.02073759e-01f, 4.16160177e-01f, 4.30251886e-01f, 4.44315429e-01f, 4.58315954e-01f,
4.72217175e-01f, 4.85981675e-01f, 4.99570709e-01f, 5.12944586e-01f, 5.26062401e-01f, 5.38882630e-01f,
5.51362766e-01f, 5.63459860e-01f, 5.75130384e-01f, 5.86330458e-01f, 5.97016050e-01f, 6.07143161e-01f,
6.16667840e-01f, 6.25546499e-01f, 6.33735979e-01f, 6.41193959e-01f, 6.47878856e-01f, 6.53750084e-01f,
6.58768549e-01f, 6.62896349e-01f, 6.66097381e-01f, 6.68337353e-01f, 6.69583869e-01f, 6.69807061e-01f,
6.68979117e-01f, 6.67075139e-01f, 6.64072812e-01f, 6.59952827e-01f, 6.54699116e-01f, 6.48298688e-01f,
6.40742160e-01f, 6.32023668e-01f, 6.22141039e-01f, 6.11095903e-01f, 5.98893921e-01f, 5.85544600e-01f,
5.71061707e-01f, 5.55463040e-01f, 5.38770639e-01f, 5.21010762e-01f, 5.02213839e-01f, 4.82414572e-01f,
4.61651859e-01f, 4.39968628e-01f, 4.17412000e-01f, 3.94032951e-01f, 3.69886464e-01f, 3.45031084e-01f,
3.19529091e-01f, 2.93446187e-01f, 2.66851164e-01f, 2.39815999e-01f, 2.12415399e-01f, 1.84726660e-01f,
1.56829293e-01f, 1.28804933e-01f, 1.00736965e-01f, 7.27100355e-02f, 4.48100810e-02f, 1.71237415e-02f,
-1.02620228e-02f, -3.72599591e-02f, -6.37832871e-02f, -8.97457733e-02f, -1.15062201e-01f, -1.39648782e-01f,
-1.63423488e-01f, -1.86306368e-01f, -2.08220103e-01f, -2.29090072e-01f, -2.48845046e-01f, -2.67417270e-01f,
-2.84742946e-01f, -3.00762597e-01f, -3.15421127e-01f, -3.28668542e-01f, -3.40459849e-01f, -3.50755400e-01f,
-3.59521402e-01f, -3.66729768e-01f, -3.72358475e-01f, -3.76391839e-01f, -3.78820421e-01f, -3.79641287e-01f,
-3.78858203e-01f, -3.76481336e-01f, -3.72527677e-01f, -3.67020780e-01f, -3.59990760e-01f, -3.51474372e-01f,
-3.41514630e-01f, -3.30160971e-01f, -3.17468898e-01f, -3.03499788e-01f, -2.88320749e-01f, -2.72004315e-01f,
-2.54628056e-01f, -2.36274454e-01f, -2.17030464e-01f, -1.96986952e-01f, -1.76238733e-01f, -1.54883647e-01f,
-1.33022496e-01f, -1.10758449e-01f, -8.81964466e-02f, -6.54430504e-02f, -4.26055475e-02f, -1.97916415e-02f,
2.89108184e-03f, 2.53355868e-02f, 4.74362201e-02f, 6.90887518e-02f, 9.01914308e-02f, 1.10644978e-01f,
1.30353494e-01f, 1.49224772e-01f, 1.67170735e-01f, 1.84107975e-01f, 1.99958067e-01f, 2.14648181e-01f,
2.28111323e-01f, 2.40286622e-01f, 2.51119890e-01f, 2.60563701e-01f, 2.68577740e-01f, 2.75129027e-01f,
2.80192144e-01f, 2.83749177e-01f, 2.85790223e-01f, 2.86312986e-01f, 2.85323221e-01f, 2.82834421e-01f,
2.78867915e-01f, 2.73452721e-01f, 2.66625431e-01f, 2.58429983e-01f, 2.48917457e-01f, 2.38145826e-01f,
2.26179680e-01f, 2.13089734e-01f, 1.98952740e-01f, 1.83850758e-01f, 1.67870897e-01f, 1.51104879e-01f,
1.33648388e-01f, 1.15600665e-01f, 9.70639763e-02f, 7.81429119e-02f, 5.89439889e-02f, 3.95749746e-02f,
2.01442353e-02f, 7.60241152e-04f, -1.84690990e-02f, -3.74370397e-02f, -5.60385970e-02f, -7.41711039e-02f,
-9.17348686e-02f, -1.08633632e-01f, -1.24775254e-01f, -1.40071993e-01f, -1.54441372e-01f, -1.67806284e-01f,
-1.80095654e-01f, -1.91244732e-01f, -2.01195605e-01f, -2.09897310e-01f, -2.17306320e-01f, -2.23386736e-01f,
-2.28110407e-01f, -2.31457193e-01f, -2.33415044e-01f, -2.33980051e-01f, -2.33156463e-01f, -2.30956673e-01f,
-2.27401097e-01f, -2.22518148e-01f, -2.16343899e-01f, -2.08921985e-01f, -2.00303365e-01f, -1.90545790e-01f,
-1.79713804e-01f, -1.67877977e-01f, -1.55114789e-01f, -1.41505907e-01f, -1.27137921e-01f, -1.12101628e-01f,
-9.64915640e-02f, -8.04054232e-02f, -6.39434707e-02f, -4.72078814e-02f, -3.03021635e-02f, -1.33305082e-02f,
3.60284977e-03f, 2.03942507e-02f, 3.69413014e-02f, 5.31433810e-02f, 6.89024656e-02f, 8.41234679e-02f,
9.87150268e-02f, 1.12589969e-01f, 1.25665865e-01f, 1.37865538e-01f, 1.49117506e-01f, 1.59356490e-01f,
1.68523664e-01f, 1.76567229e-01f, 1.83442499e-01f, 1.89112308e-01f, 1.93547212e-01f, 1.96725586e-01f,
1.98633878e-01f, 1.99266486e-01f, 1.98625999e-01f, 1.96723008e-01f, 1.93576075e-01f, 1.89211557e-01f,
1.83663562e-01f, 1.76973516e-01f, 1.69190033e-01f, 1.60368490e-01f, 1.50570805e-01f, 1.39864815e-01f,
1.28324021e-01f, 1.16026978e-01f, 1.03056879e-01f, 8.95008829e-02f, 7.54496798e-02f, 6.09968238e-02f,
4.62380664e-02f, 3.12708901e-02f, 1.61936956e-02f, 1.10531988e-03f, -1.38957653e-02f, -2.87119784e-02f,
-4.32472742e-02f, -5.74078385e-02f, -7.11026311e-02f, -8.42439713e-02f, -9.67481917e-02f, -1.08536049e-01f,
-1.19533350e-01f, -1.29671345e-01f, -1.38887238e-01f, -1.47124498e-01f, -1.54333373e-01f, -1.60470968e-01f,
-1.65501755e-01f, -1.69397631e-01f, -1.72138140e-01f, -1.73710602e-01f, -1.74110159e-01f, -1.73339798e-01f,
-1.71410274e-01f, -1.68340111e-01f, -1.64155335e-01f, -1.58889414e-01f, -1.52582850e-01f, -1.45283122e-01f,
-1.37044042e-01f, -1.27925722e-01f, -1.17993860e-01f, -1.07319421e-01f, -9.59781808e-02f, -8.40500777e-02f,
-7.16188049e-02f, -5.87710561e-02f, -4.55961475e-02f, -3.21851919e-02f, -1.86306406e-02f, -5.02554942e-03f,
8.53698384e-03f, 2.19645467e-02f, 3.51659468e-02f, 4.80518693e-02f, 6.05355056e-02f, 7.25330700e-02f,
8.39645094e-02f, 9.47537898e-02f, 1.04829753e-01f, 1.14126254e-01f, 1.22582788e-01f, 1.30144907e-01f,
1.36764459e-01f, 1.42400029e-01f, 1.47017076e-01f, 1.50588312e-01f, 1.53093700e-01f, 1.54520736e-01f,
1.54864367e-01f, 1.54127119e-01f, 1.52318991e-01f, 1.49457408e-01f, 1.45567062e-01f, 1.40679709e-01f,
1.34833933e-01f, 1.28074855e-01f, 1.20453893e-01f, 1.12028129e-01f, 1.02860307e-01f, 9.30178765e-02f,
8.25730032e-02f, 7.16016450e-02f, 6.01833134e-02f, 4.84002546e-02f, 3.63370724e-02f, 2.40800037e-02f,
1.17163168e-02f, -6.66217400e-04f, -1.29801121e-02f, -2.51385315e-02f, -3.70562030e-02f, -4.86497748e-02f,
-5.98384928e-02f, -7.05447859e-02f, -8.06947592e-02f, -9.02187441e-02f, -9.90517313e-02f, -1.07133911e-01f,
-1.14410951e-01f, -1.20834483e-01f, -1.26362422e-01f, -1.30959116e-01f, -1.34595787e-01f, -1.37250547e-01f,
-1.38908600e-01f, -1.39562374e-01f, -1.39211442e-01f, -1.37862602e-01f, -1.35529795e-01f, -1.32233909e-01f,
-1.28002721e-01f, -1.22870611e-01f, -1.16878278e-01f, -1.10072477e-01f, -1.02505698e-01f, -9.42356124e-02f,
-8.53248753e-02f, -7.58404912e-02f, -6.58532924e-02f, -5.54376360e-02f, -4.46705953e-02f, -3.36315414e-02f,
-2.24015972e-02f, -1.10628991e-02f, 3.01894735e-04f, 1.16101918e-02f, 2.27801642e-02f, 3.37311642e-02f,
4.43845430e-02f, 5.46640016e-02f, 6.44962637e-02f, 7.38115400e-02f, 8.25440784e-02f, 9.06325572e-02f,
9.80206066e-02f, 1.04657146e-01f, 1.10496723e-01f, 1.15499920e-01f, 1.19633523e-01f, 1.22870824e-01f,
1.25191729e-01f, 1.26582959e-01f, 1.27038061e-01f, 1.26557494e-01f, 1.25148528e-01f, 1.22825305e-01f,
1.19608512e-01f, 1.15525479e-01f, 1.10609643e-01f, 1.04900592e-01f, 9.84435537e-02f, 9.12890948e-02f,
8.34927732e-02f, 7.51146973e-02f, 6.62190194e-02f, 5.68735547e-02f, 4.71491262e-02f, 3.71191855e-02f,
2.68591932e-02f, 1.64459573e-02f, 5.95731808e-03f, -4.52874940e-03f, -1.49344723e-02f, -2.51829130e-02f,
-3.51986373e-02f, -4.49081427e-02f, -5.42404654e-02f, -6.31276969e-02f, -7.15054163e-02f, -7.93132713e-02f,
-8.64953327e-02f, -9.30005042e-02f, -9.87829011e-02f, -1.03802223e-01f, -1.08023943e-01f, -1.11419636e-01f,
-1.13967111e-01f, -1.15650603e-01f, -1.16460855e-01f, -1.16395152e-01f, -1.15457368e-01f, -1.13657871e-01f,
-1.11013433e-01f, -1.07547117e-01f, -1.03288073e-01f, -9.82712708e-02f, -9.25372646e-02f, -8.61318657e-02f,
-7.91057486e-02f, -7.15141053e-02f, -6.34161588e-02f, -5.48747791e-02f, -4.59559696e-02f, -3.67282941e-02f,
-2.72624874e-02f, -1.76307914e-02f, -7.90648674e-03f, 1.83670340e-03f, 1.15251424e-02f, 2.10858716e-02f,
3.04471304e-02f, 3.95388944e-02f, 4.82933904e-02f, 5.66456655e-02f, 6.45340054e-02f, 7.19003487e-02f,
7.86908695e-02f, 8.48562395e-02f, 9.03519908e-02f, 9.51389501e-02f, 9.91834077e-02f, 1.02457361e-01f,
1.04938834e-01f, 1.06611872e-01f, 1.07466724e-01f, 1.07499917e-01f, 1.06714213e-01f, 1.05118588e-01f,
1.02728167e-01f, 9.95640680e-02f, 9.56532488e-02f, 9.10282406e-02f, 8.57269309e-02f, 7.97922261e-02f,
7.32717395e-02f, 6.62174249e-02f, 5.86850536e-02f, 5.07339959e-02f, 4.24265058e-02f, 3.38274345e-02f,
2.50036502e-02f, 1.60234844e-02f, 6.95628026e-03f, -2.12820655e-03f, -1.11602438e-02f, -2.00708281e-02f,
-2.87920337e-02f, -3.72576320e-02f, -4.54035426e-02f, -5.31684173e-02f, -6.04938939e-02f, -6.73253212e-02f,
-7.36119310e-02f, -7.93072981e-02f, -8.43697556e-02f, -8.87625537e-02f, -9.24542939e-02f, -9.54189981e-02f,
-9.76364402e-02f, -9.90921435e-02f, -9.97776003e-02f, -9.96902366e-02f, -9.88334463e-02f, -9.72165780e-02f,
-9.48547668e-02f, -9.17688999e-02f, -8.79853312e-02f, -8.35357688e-02f, -7.84569594e-02f, -7.27903677e-02f,
-6.65818940e-02f, -5.98814932e-02f, -5.27427333e-02f, -4.52224733e-02f, -3.73802459e-02f, -2.92780037e-02f,
-2.09794209e-02f, -1.25495498e-02f, -4.05425988e-03f, 4.44034349e-03f, 1.28682571e-02f, 2.11643361e-02f,
2.92645357e-02f, 3.71066200e-02f, 4.46305203e-02f, 5.17788267e-02f, 5.84972389e-02f, 6.47349496e-02f,
7.04450836e-02f, 7.55849928e-02f, 8.01165748e-02f, 8.40066506e-02f, 8.72270848e-02f, 8.97550618e-02f,
9.15732179e-02f, 9.26698315e-02f, 9.30387881e-02f, 9.26796720e-02f, 9.15978025e-02f, 8.98040443e-02f,
8.73148489e-02f, 8.41520461e-02f, 8.03426093e-02f, 7.59185468e-02f, 7.09165136e-02f, 6.53776255e-02f,
5.93470480e-02f, 5.28736293e-02f, 4.60095655e-02f, 3.88099545e-02f, 3.13323302e-02f, 2.36362162e-02f,
1.57827398e-02f, 7.83395091e-03f, -1.47413782e-04f, -8.09864153e-03f, -1.59574406e-02f, -2.36623595e-02f,
-3.11534717e-02f, -3.83725840e-02f, -4.52638947e-02f, -5.17743411e-02f, -5.78539729e-02f, -6.34564348e-02f,
-6.85392092e-02f, -7.30640654e-02f, -7.69971954e-02f, -8.03096220e-02f, -8.29772975e-02f, -8.49813524e-02f,
-8.63081836e-02f, -8.69495746e-02f, -8.69027157e-02f, -8.61702687e-02f, -8.47602668e-02f, -8.26860569e-02f,
-7.99661981e-02f, -7.66242997e-02f, -7.26887788e-02f, -6.81926752e-02f, -6.31733712e-02f, -5.76722279e-02f,
-5.17343061e-02f, -4.54080069e-02f, -3.87446321e-02f, -3.17980032e-02f, -2.46239897e-02f, -1.72801497e-02f,
-9.82518156e-03f, -2.31845300e-03f, 5.18037510e-03f, 1.26119044e-02f, 1.99174857e-02f, 2.70395921e-02f,
3.39223499e-02f, 4.05119404e-02f, 4.67570465e-02f, 5.26092142e-02f, 5.80232695e-02f, 6.29576539e-02f,
6.73747113e-02f, 7.12410320e-02f, 7.45276905e-02f, 7.72104218e-02f, 7.92698394e-02f, 8.06915952e-02f,
8.14664004e-02f, 8.15901977e-02f, 8.10640907e-02f, 7.98943315e-02f, 7.80922975e-02f, 7.56743792e-02f,
7.26617861e-02f, 6.90804346e-02f, 6.49606433e-02f, 6.03370049e-02f, 5.52479503e-02f, 4.97355660e-02f,
4.38451300e-02f, 3.76248662e-02f, 3.11254263e-02f, 2.43995757e-02f, 1.75017105e-02f, 1.04874823e-02f,
3.41321948e-03f, -3.66433362e-03f, -1.06886566e-02f, -1.76037566e-02f, -2.43547422e-02f, -3.08881238e-02f,
-3.71523818e-02f, -4.30982377e-02f, -4.86791529e-02f, -5.38515978e-02f, -5.85754991e-02f, -6.28144137e-02f,
-6.65359631e-02f, -6.97119559e-02f, -7.23186409e-02f, -7.43369897e-02f, -7.57526047e-02f, -7.65560812e-02f,
-7.67428560e-02f, -7.63134051e-02f, -7.52730583e-02f, -7.36321241e-02f, -7.14055927e-02f, -6.86132027e-02f,
-6.52791213e-02f, -6.14318004e-02f, -5.71037475e-02f, -5.23312158e-02f, -4.71539306e-02f, -4.16147519e-02f,
-3.57593331e-02f, -2.96357023e-02f, -2.32939478e-02f, -1.67857228e-02f, -1.01639251e-02f, -3.48213128e-03f,
3.20566951e-03f, 9.84566549e-03f, 1.63845318e-02f, 2.27699627e-02f, 2.89509937e-02f, 3.48784838e-02f,
4.05054571e-02f, 4.57875191e-02f, 5.06831561e-02f, 5.51541055e-02f, 5.91656321e-02f, 6.26867948e-02f,
6.56907214e-02f, 6.81547545e-02f, 7.00607045e-02f, 7.13948753e-02f, 7.21482790e-02f, 7.23165894e-02f,
7.19002973e-02f, 7.09044846e-02f, 6.93390331e-02f, 6.72183039e-02f, 6.45611568e-02f, 6.13906537e-02f,
5.77340810e-02f, 5.36223917e-02f, 4.90902973e-02f, 4.41756853e-02f, 3.89195025e-02f, 3.33653266e-02f,
2.75589553e-02f, 2.15482187e-02f, 1.53823433e-02f, 9.11173206e-03f, 2.78750380e-03f, -3.53899736e-03f,
-9.81648845e-03f, -1.59942887e-02f, -2.20226002e-02f, -2.78530676e-02f, -3.34389835e-02f, -3.87358558e-02f,
-4.37015752e-02f, -4.82968641e-02f, -5.24856104e-02f, -5.62350079e-02f, -5.95160314e-02f, -6.23034090e-02f,
-6.45760369e-02f, -6.63170246e-02f, -6.75138263e-02f, -6.81583864e-02f, -6.82471093e-02f, -6.77809819e-02f,
-6.67654439e-02f, -6.52104027e-02f, -6.31301405e-02f, -6.05431381e-02f, -5.74719510e-02f, -5.39430121e-02f,
-4.99864152e-02f, -4.56356108e-02f, -4.09271785e-02f, -3.59005358e-02f, -3.05975021e-02f, -2.50620982e-02f,
-1.93400931e-02f, -1.34786109e-02f, -7.52582921e-03f, -1.53047296e-03f, 4.45846396e-03f, 1.03922252e-02f,
1.62226043e-02f, 2.19024111e-02f, 2.73857927e-02f, 3.26286453e-02f, 3.75889120e-02f, 4.22270162e-02f,
4.65060678e-02f, 5.03922602e-02f, 5.38550360e-02f, 5.68673912e-02f, 5.94061299e-02f, 6.14518959e-02f,
6.29894927e-02f, 6.40078422e-02f, 6.45002081e-02f, 6.44641312e-02f, 6.39014463e-02f, 6.28183549e-02f,
6.12252434e-02f, 5.91366226e-02f, 5.65710713e-02f, 5.35509478e-02f, 5.01023211e-02f, 4.62546289e-02f,
4.20405644e-02f, 3.74956324e-02f, 3.26580309e-02f, 2.75681921e-02f, 2.22685138e-02f, 1.68029869e-02f,
1.12168479e-02f, 5.55616360e-03f, -1.32475496e-04f, -5.80242145e-03f, -1.14072870e-02f, -1.69013632e-02f,
-2.22399629e-02f, -2.73798231e-02f, -3.22793559e-02f, -3.68992177e-02f, -4.12022700e-02f, -4.51542301e-02f,
-4.87237130e-02f, -5.18825743e-02f, -5.46061242e-02f, -5.68733215e-02f, -5.86668721e-02f, -5.99735198e-02f,
-6.07838952e-02f, -6.10928895e-02f, -6.08993923e-02f, -6.02064781e-02f, -5.90213291e-02f, -5.73550887e-02f,
-5.52228853e-02f, -5.26435817e-02f, -4.96396897e-02f, -4.62371294e-02f, -4.24650256e-02f, -3.83554628e-02f,
-3.39432096e-02f, -2.92654225e-02f, -2.43613233e-02f, -1.92718970e-02f, -1.40395616e-02f, -8.70771728e-03f,
-3.32056777e-03f, 2.07744785e-03f, 7.44190391e-03f, 1.27287222e-02f, 1.78946228e-02f, 2.28975002e-02f,
2.76965843e-02f, 3.22530140e-02f, 3.65299534e-02f, 4.04930363e-02f, 4.41105069e-02f, 4.73536159e-02f,
5.01967201e-02f, 5.26175750e-02f, 5.45974724e-02f, 5.61213729e-02f, 5.71780843e-02f, 5.77601946e-02f,
5.78643759e-02f, 5.74910914e-02f, 5.66448597e-02f, 5.53340158e-02f, 5.35707338e-02f, 5.13708843e-02f,
4.87538683e-02f, 4.57425137e-02f, 4.23627999e-02f, 3.86437075e-02f, 3.46169024e-02f, 3.03165387e-02f,
2.57788894e-02f, 2.10421222e-02f, 1.61459251e-02f, 1.11311994e-02f, 6.03970466e-03f, 9.13695817e-04f,
-4.20433431e-03f, -9.27218149e-03f, -1.42480682e-02f, -1.90911878e-02f, -2.37618648e-02f, -2.82220093e-02f,
-3.24353766e-02f, -3.63678336e-02f, -3.99876924e-02f, -4.32659237e-02f, -4.61764207e-02f, -4.86961602e-02f,
-5.08054551e-02f, -5.24880386e-02f, -5.37312181e-02f, -5.45260166e-02f, -5.48671104e-02f, -5.47530531e-02f,
-5.41860463e-02f, -5.31721475e-02f, -5.17210363e-02f, -4.98459868e-02f, -4.75637647e-02f, -4.48944406e-02f,
-4.18612746e-02f, -3.84904206e-02f, -3.48107925e-02f, -3.08537797e-02f, -2.66529685e-02f, -2.22438695e-02f,
-1.76636682e-02f, -1.29507560e-02f, -8.14466071e-03f, -3.28544776e-03f, 1.58643018e-03f, 6.43050440e-03f,
1.12067405e-02f, 1.58756642e-02f, 2.03989020e-02f, 2.47393345e-02f, 2.88614617e-02f, 3.27317634e-02f,
3.63187992e-02f, 3.95936470e-02f, 4.25300387e-02f, 4.51045672e-02f, 4.72968940e-02f, 4.90899703e-02f,
5.04700047e-02f, 5.14267809e-02f, 5.19535643e-02f, 5.20472034e-02f, 5.17082287e-02f, 5.09406434e-02f,
4.97521048e-02f, 4.81537188e-02f, 4.61599131e-02f, 4.37884262e-02f, 4.10600706e-02f, 3.79985488e-02f,
3.46302622e-02f, 3.09841217e-02f, 2.70912412e-02f, 2.29847199e-02f, 1.86992847e-02f, 1.42711599e-02f,
9.73752669e-03f, 5.13643650e-03f, 5.06379454e-04f, -4.11408166e-03f, -8.68649476e-03f, -1.31729621e-02f,
-1.75363807e-02f, -2.17408089e-02f, -2.57516979e-02f, -2.95362143e-02f, -3.30635093e-02f, -3.63049622e-02f,
-3.92344048e-02f, -4.18283298e-02f, -4.40661418e-02f, -4.59301913e-02f, -4.74060505e-02f, -4.84825511e-02f,
-4.91518827e-02f, -4.94096235e-02f, -4.92548579e-02f, -4.86900251e-02f, -4.77210458e-02f, -4.63571741e-02f,
-4.46108878e-02f, -4.24979107e-02f, -4.00368564e-02f, -3.72492987e-02f, -3.41594108e-02f, -3.07938448e-02f,
-2.71814552e-02f, -2.33531198e-02f, -1.93413598e-02f, -1.51802063e-02f, -1.09048013e-02f, -6.55114338e-03f,
-2.15581014e-03f, 2.24443555e-03f, 6.61280814e-03f, 1.09129453e-02f, 1.51091980e-02f, 1.91667630e-02f,
2.30522168e-02f, 2.67335907e-02f, 3.01807365e-02f, 3.33655579e-02f, 3.62622051e-02f, 3.88473226e-02f,
4.11002204e-02f, 4.30030300e-02f, 4.45408790e-02f, 4.57019705e-02f, 4.64777109e-02f, 4.68627135e-02f,
4.68549093e-02f, 4.64554958e-02f, 4.56689373e-02f, 4.45029599e-02f, 4.29683919e-02f, 4.10791386e-02f,
3.88520159e-02f, 3.63066475e-02f, 3.34652385e-02f, 3.03523892e-02f, 2.69949681e-02f, 2.34217263e-02f,
1.96632025e-02f, 1.57513974e-02f, 1.17194459e-02f, 7.60145677e-03f, 3.43215481e-03f, -7.53454950e-04f,
-4.92025229e-03f, -9.03345904e-03f, -1.30587503e-02f, -1.69627406e-02f, -2.07130441e-02f, -2.42787472e-02f,
-2.76304969e-02f, -3.07408842e-02f, -3.35845310e-02f, -3.61384026e-02f, -3.83819804e-02f, -4.02973364e-02f,
-4.18693911e-02f, -4.30859849e-02f, -4.39379525e-02f, -4.44192202e-02f, -4.45268207e-02f, -4.42609489e-02f,
-4.36249417e-02f, -4.26251693e-02f, -4.12710965e-02f, -3.95751119e-02f, -3.75524034e-02f, -3.52209020e-02f,
-3.26010732e-02f, -2.97156826e-02f, -2.65897306e-02f, -2.32501339e-02f, -1.97255230e-02f, -1.60459906e-02f,
-1.22428645e-02f, -8.34840613e-03f, -4.39555788e-03f, -4.17641093e-04f, 3.55186529e-03f, 7.47969548e-03f,
1.13330289e-02f, 1.50796895e-02f, 1.86886063e-02f, 2.21298440e-02f, 2.53750227e-02f, 2.83974776e-02f,
3.11724713e-02f, 3.36774564e-02f, 3.58921485e-02f, 3.77988281e-02f, 3.93823848e-02f, 4.06304645e-02f,
4.15335460e-02f, 4.20850895e-02f, 4.22814530e-02f, 4.21220657e-02f, 4.16092724e-02f, 4.07484568e-02f,
3.95478256e-02f, 3.80185099e-02f, 3.61742882e-02f, 3.40316228e-02f, 3.16093467e-02f, 2.89286854e-02f,
2.60129143e-02f, 2.28872072e-02f, 1.95785162e-02f, 1.61151429e-02f, 1.25266872e-02f, 8.84367289e-03f,
5.09737541e-03f, 1.31946573e-03f, -2.45819207e-03f, -6.20382907e-03f, -9.88599514e-03f, -1.34739714e-02f,
-1.69377975e-02f, -2.02487225e-02f, -2.33793144e-02f, -2.63038233e-02f, -2.89981802e-02f, -3.14404213e-02f,
-3.36107546e-02f, -3.54916723e-02f, -3.70682427e-02f, -3.83280672e-02f, -3.92614736e-02f, -3.98615776e-02f,
-4.01243243e-02f, -4.00484517e-02f, -3.96356708e-02f, -3.88903731e-02f, -3.78198781e-02f, -3.64341365e-02f,
-3.47457457e-02f, -3.27698392e-02f, -3.05238882e-02f, -2.80276282e-02f, -2.53028218e-02f, -2.23730957e-02f,
-1.92637467e-02f, -1.60015029e-02f, -1.26142882e-02f, -9.13104283e-03f, -5.58138981e-03f, -1.99542434e-03f,
1.59649307e-03f, 5.16408174e-03f, 8.67737144e-03f, 1.21068581e-02f, 1.54239205e-02f, 1.86009100e-02f,
2.16114772e-02f, 2.44306994e-02f, 2.70354163e-02f, 2.94042665e-02f, 3.15179985e-02f, 3.33595356e-02f,
3.49141593e-02f, 3.61696229e-02f, 3.71161871e-02f, 3.77468512e-02f, 3.80571878e-02f, 3.80455485e-02f,
3.77129900e-02f, 3.70632810e-02f, 3.61028508e-02f, 3.48407199e-02f, 3.32884428e-02f, 3.14600053e-02f,
2.93716228e-02f, 2.70417408e-02f, 2.44907277e-02f, 2.17407576e-02f, 1.88156734e-02f, 1.57406803e-02f,
1.25421761e-02f, 9.24754692e-03f, 5.88488640e-03f, 2.48280587e-03f, -9.29864758e-04f, -4.32426314e-03f,
-7.67179184e-03f, -1.09442952e-02f, -1.41143886e-02f, -1.71555974e-02f, -2.00425787e-02f, -2.27514891e-02f,
-2.52599054e-02f, -2.75472706e-02f, -2.95949315e-02f, -3.13863062e-02f, -3.29069832e-02f, -3.41450096e-02f,
-3.50907101e-02f, -3.57369992e-02f, -3.60793163e-02f, -3.61156751e-02f, -3.58467080e-02f, -3.52755740e-02f,
-3.44080617e-02f, -3.32523628e-02f, -3.18191314e-02f, -3.01213186e-02f, -2.81740846e-02f, -2.59946393e-02f,
-2.36021125e-02f, -2.10173975e-02f, -1.82629132e-02f, -1.53624700e-02f, -1.23410560e-02f, -9.22456599e-03f,
-6.03967755e-03f, -2.81350877e-03f, 4.26514319e-04f, 3.65292660e-03f, 6.83848944e-03f, 9.95638508e-03f,
1.29804234e-02f, 1.58853076e-02f, 1.86468203e-02f, 2.12420277e-02f, 2.36494909e-02f, 2.58493792e-02f,
2.78237450e-02f, 2.95565060e-02f, 3.10338053e-02f, 3.22438572e-02f, 3.31772716e-02f, 3.38269627e-02f,
3.41883176e-02f, 3.42591610e-02f, 3.40397435e-02f, 3.35328606e-02f, 3.27436351e-02f, 3.16796573e-02f,
3.03507246e-02f, 2.87689689e-02f, 2.69484839e-02f, 2.49054827e-02f, 2.26579086e-02f, 2.02254442e-02f,
1.76292617e-02f, 1.48918382e-02f, 1.20368159e-02f, 9.08872468e-03f, 6.07283273e-03f, 3.01489838e-03f,
-5.90212194e-05f, -3.12287666e-03f, -6.15069532e-03f, -9.11695091e-03f, -1.19967033e-02f, -1.47657868e-02f,
-1.74011004e-02f, -1.98807214e-02f, -2.21841025e-02f, -2.42922632e-02f, -2.61879368e-02f, -2.78557311e-02f,
-2.92821801e-02f, -3.04559562e-02f, -3.13678907e-02f, -3.20110632e-02f, -3.23808087e-02f, -3.24749193e-02f,
-3.22933847e-02f, -3.18386269e-02f, -3.11153366e-02f, -3.01304804e-02f, -2.88932552e-02f, -2.74148734e-02f,
-2.57086673e-02f, -2.37898314e-02f, -2.16752343e-02f, -1.93835013e-02f, -1.69345799e-02f, -1.43497284e-02f,
-1.16513243e-02f, -8.86259097e-03f, -6.00748525e-03f, -3.11044903e-03f, -1.96143386e-04f, 2.71056658e-03f,
5.58512222e-03f, 8.40318833e-03f, 1.11410160e-02f, 1.37756382e-02f, 1.62850338e-02f, 1.86482666e-02f,
2.08457445e-02f, 2.28593437e-02f, 2.46725329e-02f, 2.62705694e-02f, 2.76405329e-02f, 2.87715470e-02f,
2.96547092e-02f, 3.02833419e-02f, 3.06529059e-02f, 3.07610441e-02f, 3.06076742e-02f, 3.01949567e-02f,
2.95271502e-02f, 2.86107876e-02f, 2.74543883e-02f, 2.60685701e-02f, 2.44657863e-02f, 2.26603655e-02f,
2.06682557e-02f, 1.85070033e-02f, 1.61954603e-02f, 1.37537720e-02f, 1.12030588e-02f, 8.56537064e-03f,
5.86336215e-03f, 3.12021752e-03f, 3.59345288e-04f, -2.39571357e-03f, -5.12158252e-03f, -7.79518527e-03f,
-1.03939536e-02f, -1.28961026e-02f, -1.52805838e-02f, -1.75275761e-02f, -1.96183935e-02f, -2.15357712e-02f,
-2.32639542e-02f, -2.47888545e-02f, -2.60981899e-02f, -2.71814567e-02f, -2.80302370e-02f, -2.86380088e-02f,
-2.90003996e-02f, -2.91151172e-02f, -2.89819544e-02f, -2.86028697e-02f, -2.79818317e-02f, -2.71249297e-02f,
-2.60401957e-02f, -2.47375751e-02f, -2.32288414e-02f, -2.15275091e-02f, -1.96486443e-02f, -1.76087964e-02f,
-1.54258426e-02f, -1.31187994e-02f, -1.07076937e-02f, -8.21335282e-03f, -5.65730582e-03f, -3.06143405e-03f,
-4.47990175e-04f, 2.16074548e-03f, 4.74260737e-03f, 7.27569124e-03f, 9.73864733e-03f, 1.21106824e-02f,
1.43719841e-02f, 1.65036001e-02f, 1.84878471e-02f, 2.03083286e-02f, 2.19500531e-02f, 2.33996493e-02f,
2.46453861e-02f, 2.56773512e-02f, 2.64874345e-02f, 2.70694463e-02f, 2.74192279e-02f, 2.75344951e-02f,
2.74150667e-02f, 2.70627089e-02f, 2.64811913e-02f, 2.56761950e-02f, 2.46553112e-02f, 2.34279326e-02f,
2.20051823e-02f, 2.03998041e-02f, 1.86260730e-02f, 1.66996483e-02f, 1.46373888e-02f, 1.24573628e-02f,
1.01784699e-02f, 7.82046099e-03f, 5.40366356e-03f, 2.94886537e-03f, 4.77074685e-04f, -1.99056008e-03f,
-4.43309957e-03f, -6.82975366e-03f, -9.16032780e-03f, -1.14051392e-02f, -1.35453571e-02f, -1.55631186e-02f,
-1.74416221e-02f, -1.91653203e-02f, -2.07200521e-02f, -2.20931290e-02f, -2.32734389e-02f, -2.42515770e-02f,
-2.50198790e-02f, -2.55724740e-02f, -2.59053977e-02f, -2.60165073e-02f, -2.59056121e-02f, -2.55744100e-02f,
-2.50263861e-02f, -2.42670139e-02f, -2.33034172e-02f, -2.21444752e-02f, -2.08007704e-02f, -1.92843016e-02f,
-1.76086143e-02f, -1.57885066e-02f, -1.38399632e-02f, -1.17800468e-02f, -9.62665505e-03f, -7.39846180e-03f,
-5.11473979e-03f, -2.79509520e-03f, -4.59475153e-04f, 1.87219411e-03f, 4.18004886e-03f, 6.44446028e-03f,
8.64630036e-03f, 1.07670050e-02f, 1.27887263e-02f, 1.46946183e-02f, 1.64687696e-02f, 1.80965074e-02f,
1.95644657e-02f, 2.08606409e-02f, 2.19745569e-02f, 2.28973400e-02f, 2.36217678e-02f, 2.41423032e-02f,
2.44552329e-02f, 2.45585559e-02f, 2.44521268e-02f, 2.41375247e-02f, 2.36181843e-02f, 2.28991883e-02f,
2.19873596e-02f, 2.08911372e-02f, 1.96204854e-02f, 1.81868423e-02f, 1.66029686e-02f, 1.48829260e-02f,
1.30418196e-02f, 1.10957823e-02f, 9.06176569e-03f, 6.95742371e-03f, 4.80095797e-03f, 2.61094572e-03f,
4.06163422e-04f, -1.79448120e-03f, -3.97227507e-03f, -6.10867089e-03f, -8.18559133e-03f, -1.01855447e-02f,
-1.20916775e-02f, -1.38880736e-02f, -1.55597947e-02f, -1.70929424e-02f, -1.84749792e-02f, -1.96945768e-02f,
-2.07419008e-02f, -2.16086011e-02f, -2.22879060e-02f, -2.27746496e-02f, -2.30653527e-02f, -2.31582122e-02f,
-2.30530853e-02f, -2.27516002e-02f, -2.22569518e-02f, -2.15740851e-02f, -2.07094459e-02f, -1.96710504e-02f,
-1.84683607e-02f, -1.71122258e-02f, -1.56147530e-02f, -1.39891960e-02f, -1.22499260e-02f, -1.04121226e-02f,
-8.49187069e-03f, -6.50583812e-03f, -4.47121574e-03f, -2.40553061e-03f, -3.26560349e-04f, 1.74792849e-03f,
3.80020986e-03f, 5.81284812e-03f, 7.76878436e-03f, 9.65152189e-03f, 1.14452321e-02f, 1.31348903e-02f,
1.47064602e-02f, 1.61469015e-02f, 1.74443880e-02f, 1.85883329e-02f, 1.95694960e-02f, 2.03800747e-02f,
2.10137416e-02f, 2.14657028e-02f, 2.17327470e-02f, 2.18132189e-02f, 2.17071096e-02f, 2.14159688e-02f,
2.09429396e-02f, 2.02927056e-02f, 1.94714591e-02f, 1.84867806e-02f, 1.73476996e-02f, 1.60644888e-02f,
1.46486021e-02f, 1.31126305e-02f, 1.14700918e-02f, 9.73543186e-03f, 7.92379251e-03f, 6.05090462e-03f,
4.13301608e-03f, 2.18669055e-03f, 2.28581333e-04f, -1.72441072e-03f, -3.65572200e-03f, -5.54887990e-03f,
-7.38782061e-03f, -9.15706782e-03f, -1.08417082e-02f, -1.24276657e-02f, -1.39017311e-02f, -1.52516970e-02f,
-1.64664949e-02f, -1.75361817e-02f, -1.84521823e-02f, -1.92071599e-02f, -1.97953056e-02f, -2.02121243e-02f,
-2.04547147e-02f, -2.05216098e-02f, -2.04128534e-02f, -2.01300439e-02f, -1.96761990e-02f, -1.90558123e-02f,
-1.82748056e-02f, -1.73404276e-02f, -1.62612067e-02f, -1.50469098e-02f, -1.37084115e-02f, -1.22575769e-02f,
-1.07072432e-02f, -9.07102930e-03f, -7.36320826e-03f, -5.59869147e-03f, -3.79270806e-03f, -1.96092013e-03f,
-1.19027325e-04f, 1.71713152e-03f, 3.53191747e-03f, 5.30986343e-03f, 7.03590331e-03f, 8.69547560e-03f,
1.02746006e-02f, 1.17601122e-02f, 1.31396009e-02f, 1.44016653e-02f, 1.55359973e-02f, 1.65332483e-02f,
1.73855033e-02f, 1.80859434e-02f, 1.86291305e-02f, 1.90110277e-02f, 1.92289384e-02f, 1.92815880e-02f,
1.91691688e-02f, 1.88932135e-02f, 1.84567183e-02f, 1.78639790e-02f, 1.71206377e-02f, 1.62336473e-02f,
1.52110920e-02f, 1.40622274e-02f, 1.27973510e-02f, 1.14277163e-02f, 9.96541843e-03f, 8.42333112e-03f,
6.81491991e-03f, 5.15420944e-03f, 3.45559138e-03f, 1.73374462e-03f, 3.49154958e-06f, -1.72033182e-03f,
-3.42300908e-03f, -5.09002877e-03f, -6.70728983e-03f, -8.26110592e-03f, -9.73843101e-03f, -1.11269177e-02f,
-1.24149972e-02f, -1.35920411e-02f, -1.46483675e-02f, -1.55754162e-02f, -1.63657097e-02f, -1.70130158e-02f,
-1.75123254e-02f, -1.78599156e-02f, -1.80533642e-02f, -1.80916471e-02f, -1.79749596e-02f, -1.77049199e-02f,
-1.72844059e-02f, -1.67175734e-02f, -1.60098348e-02f, -1.51677846e-02f, -1.41991369e-02f, -1.31126308e-02f,
-1.19180614e-02f, -1.06260158e-02f, -9.24795820e-03f, -7.79599691e-03f, -6.28282689e-03f, -4.72166017e-03f,
-3.12602130e-03f, -1.50971188e-03f, 1.13358008e-04f, 1.72924640e-03f, 3.32419869e-03f, 4.88457483e-03f,
6.39719332e-03f, 7.84928507e-03f, 9.22860374e-03f, 1.05236737e-02f, 1.17237027e-02f, 1.28187631e-02f,
1.37999219e-02f, 1.46591627e-02f, 1.53896448e-02f, 1.59855771e-02f, 1.64423748e-02f, 1.67566705e-02f,
1.69263151e-02f, 1.69504088e-02f, 1.68293192e-02f, 1.65646048e-02f, 1.61591292e-02f, 1.56168830e-02f,
1.49430466e-02f, 1.41438870e-02f, 1.32267343e-02f, 1.21999194e-02f, 1.10726150e-02f, 9.85491162e-03f,
8.55755480e-03f, 7.19198626e-03f, 5.77013714e-03f, 4.30443841e-03f, 2.80758857e-03f, 1.29252809e-03f,
-2.27683018e-04f, -1.74000213e-03f, -3.23153173e-03f, -4.68956247e-03f, -6.10171563e-03f, -7.45612506e-03f,
-8.74136426e-03f, -9.94672023e-03f, -1.10621909e-02f, -1.20785406e-02f, -1.29874795e-02f, -1.37816456e-02f,
-1.44546479e-02f, -1.50012468e-02f, -1.54172106e-02f, -1.56995155e-02f, -1.58462779e-02f, -1.58567437e-02f,
-1.57313825e-02f, -1.54717967e-02f, -1.50807184e-02f, -1.45620705e-02f, -1.39207297e-02f, -1.31627253e-02f,
-1.22950111e-02f, -1.13254027e-02f, -1.02626834e-02f, -9.11627932e-03f, -7.89634415e-03f, -6.61364765e-03f,
-5.27939952e-03f, -3.90525708e-03f, -2.50314317e-03f, -1.08517576e-03f, 3.36418391e-04f, 1.74945190e-03f,
3.14186033e-03f, 4.50178261e-03f, 5.81769448e-03f, 7.07851939e-03f, 8.27365386e-03f, 9.39310326e-03f,
1.04276320e-02f, 1.13686527e-02f, 1.22085379e-02f, 1.29404450e-02f, 1.35585678e-02f, 1.40580446e-02f,
1.44350939e-02f, 1.46869568e-02f, 1.48120098e-02f, 1.48096348e-02f, 1.46804295e-02f, 1.44259781e-02f,
1.40489668e-02f, 1.35531325e-02f, 1.29432014e-02f, 1.22248563e-02f, 1.14046959e-02f, 1.04901687e-02f,
9.48948107e-03f, 8.41156632e-03f, 7.26596347e-03f, 6.06280447e-03f, 4.81257444e-03f, 3.52622627e-03f,
2.21492506e-03f, 8.89983592e-04f, -4.37153812e-04f, -1.75513167e-03f, -3.05265494e-03f, -4.31872834e-03f,
-5.54261874e-03f, -6.71396264e-03f, -7.82302244e-03f, -8.86045250e-03f, -9.81773278e-03f, -1.06869351e-02f,
-1.14610023e-02f, -1.21336754e-02f, -1.26995953e-02f, -1.31543908e-02f, -1.34945718e-02f, -1.37177266e-02f,
-1.38224110e-02f, -1.38082286e-02f, -1.36757739e-02f, -1.34266887e-02f, -1.30635886e-02f, -1.25900369e-02f,
-1.20105709e-02f, -1.13305978e-02f, -1.05563538e-02f, -9.69485926e-03f, -8.75389081e-03f, -7.74181164e-03f,
-6.66761679e-03f, -5.54076187e-03f, -4.37111830e-03f, -3.16893052e-03f, -1.94457115e-03f, -7.08705149e-04f,
5.28079290e-04f, 1.75515870e-03f, 2.96204304e-03f, 4.13848585e-03f, 5.27451557e-03f, 6.36060039e-03f,
7.38755863e-03f, 8.34692530e-03f, 9.23070802e-03f, 1.00316534e-02f, 1.07432528e-02f, 1.13597680e-02f,
1.18763350e-02f, 1.22889283e-02f, 1.25944631e-02f, 1.27907515e-02f, 1.28765994e-02f, 1.28517102e-02f,
1.27167966e-02f, 1.24734480e-02f, 1.21242371e-02f, 1.16725839e-02f, 1.11228281e-02f, 1.04800592e-02f,
9.75022575e-03f, 8.93990424e-03f, 8.05644990e-03f, 7.10768601e-03f, 6.10205625e-03f, 5.04843878e-03f,
3.95605458e-03f, 2.83441418e-03f, 1.69331277e-03f, 5.42568186e-04f, -6.07877124e-04f, -1.74818575e-03f,
-2.86860405e-03f, -3.95962685e-03f, -5.01201657e-03f, -6.01690058e-03f, -6.96589716e-03f, -7.85110424e-03f,
-8.66518231e-03f, -9.40145619e-03f, -1.00540095e-02f, -1.06175123e-02f, -1.10876024e-02f, -1.14606062e-02f,
-1.17337519e-02f, -1.19051415e-02f, -1.19737311e-02f, -1.19393909e-02f, -1.18028751e-02f, -1.15657387e-02f,
-1.12305357e-02f, -1.08005049e-02f, -1.02797519e-02f, -9.67318729e-03f, -8.98632838e-03f, -8.22543877e-03f,
-7.39737215e-03f, -6.50950785e-03f, -5.56975395e-03f, -4.58632875e-03f, -3.56792674e-03f, -2.52340823e-03f,
-1.46183597e-03f, -3.92391156e-04f, 6.75701684e-04f, 1.73331709e-03f, 2.77141530e-03f, 3.78118353e-03f,
4.75407672e-03f, 5.68193005e-03f, 6.55698994e-03f, 7.37195674e-03f, 8.12013345e-03f, 8.79539509e-03f,
9.39225030e-03f, 9.90597190e-03f, 1.03324819e-02f, 1.06685242e-02f, 1.09116177e-02f, 1.10600973e-02f,
1.11130936e-02f, 1.10705983e-02f, 1.09333788e-02f, 1.07030445e-02f, 1.03819949e-02f, 9.97335332e-03f,
9.48107464e-03f, 8.90968434e-03f, 8.26449756e-03f, 7.55132972e-03f, 6.77664458e-03f, 5.94731079e-03f,
5.07073939e-03f, 4.15462520e-03f, 3.20700306e-03f, 2.23616222e-03f, 1.25050340e-03f, 2.58592562e-04f,
-7.31105992e-04f, -1.71003848e-03f, -2.66991104e-03f, -3.60254805e-03f, -4.50009626e-03f, -5.35500152e-03f,
-6.16013372e-03f, -6.90880302e-03f, -7.59484887e-03f, -8.21267759e-03f, -8.75730297e-03f, -9.22437062e-03f,
-9.61022818e-03f, -9.91196266e-03f, -1.01273334e-02f, -1.02549146e-02f, -1.02939949e-02f, -1.02446487e-02f,
-1.01077102e-02f, -9.88473930e-03f, -9.57804506e-03f, -9.19065219e-03f, -8.72623997e-03f, -8.18914967e-03f,
-7.58431711e-03f, -6.91725624e-03f, -6.19393169e-03f, -5.42085678e-03f, -4.60486090e-03f, -3.75314479e-03f,
-2.87318400e-03f, -1.97263669e-03f, -1.05936420e-03f, -1.41184633e-04f, 7.73935206e-04f, 1.67818033e-03f,
2.56387121e-03f, 3.42348245e-03f, 4.24972968e-03f, 5.03575853e-03f, 5.77493594e-03f, 6.46117800e-03f,
7.08885263e-03f, 7.65282423e-03f, 8.14856911e-03f, 8.57214716e-03f, 8.92027019e-03f, 9.19029194e-03f,
9.38027470e-03f, 9.48895025e-03f, 9.51578399e-03f, 9.46091429e-03f, 9.32518284e-03f, 9.11016180e-03f,
8.81806173e-03f, 8.45171440e-03f, 8.01466407e-03f, 7.51094572e-03f, 6.94521826e-03f, 6.32261691e-03f,
5.64875255e-03f, 4.92963671e-03f, 4.17165548e-03f, 3.38149573e-03f, 2.56610069e-03f, 1.73253154e-03f,
8.88083719e-04f, 4.00140997e-05f, -8.04377007e-04f, -1.63786496e-03f, -2.45336348e-03f, -3.24394120e-03f,
-4.00297149e-03f, -4.72406012e-03f, -5.40122825e-03f, -6.02886353e-03f, -6.60184564e-03f, -7.11547043e-03f,
-7.56567204e-03f, -7.94886879e-03f, -8.26207948e-03f, -8.50298133e-03f, -8.66984745e-03f, -8.76158174e-03f,
-8.77778600e-03f, -8.71866903e-03f, -8.58510255e-03f, -8.37858953e-03f, -8.10125332e-03f, -7.75580633e-03f,
-7.34555568e-03f, -6.87431135e-03f, -6.34642360e-03f, -5.76669768e-03f, -5.14031767e-03f, -4.47294897e-03f,
-3.77043291e-03f, -3.03903272e-03f, -2.28511456e-03f, -1.51527024e-03f, -7.36178447e-04f, 4.54225562e-05f,
8.22859022e-04f, 1.58943109e-03f, 2.33866278e-03f, 3.06420334e-03f, 3.75990680e-03f, 4.42002538e-03f,
5.03901750e-03f, 5.61180111e-03f, 6.13366220e-03f, 6.60043272e-03f, 7.00831931e-03f, 7.35414500e-03f,
7.63524392e-03f, 7.84953557e-03f, 7.99547645e-03f, 8.07218955e-03f, 8.07933095e-03f, 8.01721906e-03f,
7.88666864e-03f, 7.68919343e-03f, 7.42679720e-03f, 7.10202788e-03f, 6.71802523e-03f, 6.27832934e-03f,
5.78702253e-03f, 5.24853339e-03f, 4.66776048e-03f, 4.04985033e-03f, 3.40032055e-03f, 2.72486114e-03f,
2.02943382e-03f, 1.32005555e-03f, 6.02922229e-04f, -1.15810889e-04f, -8.29962401e-04f, -1.53344695e-03f,
-2.22024937e-03f, -2.88460828e-03f, -3.52090915e-03f, -4.12386103e-03f, -4.68844782e-03f, -5.21000854e-03f,
-5.68433641e-03f, -6.10753890e-03f, -6.47629357e-03f, -6.78770430e-03f, -7.03936807e-03f, -7.22944790e-03f,
-7.35662441e-03f, -7.42012069e-03f, -7.41971164e-03f, -7.35573757e-03f, -7.22905724e-03f, -7.04107429e-03f,
-6.79370122e-03f, -6.48940038e-03f, -6.13102314e-03f, -5.72192873e-03f, -5.26590521e-03f, -4.76707464e-03f,
-4.22993214e-03f, -3.65930825e-03f, -3.06022345e-03f, -2.43797793e-03f, -1.79803310e-03f, -1.14594988e-03f,
-4.87389180e-04f, 1.71985886e-04f, 8.26505744e-04f, 1.47057292e-03f, 2.09875564e-03f, 2.70572827e-03f,
3.28638788e-03f, 3.83592350e-03f, 4.34975506e-03f, 4.82368759e-03f, 5.25383132e-03f, 5.63677359e-03f,
5.96942535e-03f, 6.24924092e-03f, 6.47405650e-03f, 6.64226721e-03f, 6.75269253e-03f, 6.80469430e-03f,
6.79815717e-03f, 6.73340631e-03f, 6.61130455e-03f, 6.43322863e-03f, 6.20094526e-03f, 5.91677710e-03f,
5.58340169e-03f, 5.20393196e-03f, 4.78187614e-03f, 4.32106320e-03f, 3.82565711e-03f, 3.30005613e-03f,
2.74895362e-03f, 2.17719303e-03f, 1.58978015e-03f, 9.91844057e-04f, 3.88540330e-04f, -2.14916878e-04f,
-8.13361192e-04f, -1.40168257e-03f, -1.97489740e-03f, -2.52818059e-03f, -3.05688539e-03f, -3.55662656e-03f,
-4.02326574e-03f, -4.45296958e-03f, -4.84228652e-03f, -5.18803438e-03f, -5.48755315e-03f, -5.73848611e-03f,
-5.93891991e-03f, -6.08745626e-03f, -6.18305471e-03f, -6.22520840e-03f, -6.21382472e-03f, -6.14928419e-03f,
-6.03244633e-03f, -5.86455879e-03f, -5.64736180e-03f, -5.38296537e-03f, -5.07389363e-03f, -4.72301916e-03f,
-4.33361321e-03f, -3.90915761e-03f, -3.45353173e-03f, -2.97077347e-03f, -2.46516689e-03f, -1.94119584e-03f,
-1.40340595e-03f, -8.56512644e-04f, -3.05232133e-04f, 2.45691031e-04f, 7.91538060e-04f, 1.32763724e-03f,
1.84949345e-03f, 2.35267547e-03f, 2.83299113e-03f, 3.28645035e-03f, 3.70931698e-03f, 4.09812665e-03f,
4.44973511e-03f, 4.76135341e-03f, 5.03050354e-03f, 5.25513155e-03f, 5.43353323e-03f, 5.56447821e-03f,
5.64705544e-03f, 5.68083601e-03f, 5.66583437e-03f, 5.60238431e-03f, 5.49135375e-03f, 5.33391723e-03f,
5.13169207e-03f, 4.88664671e-03f, 4.60113202e-03f, 4.27780860e-03f, 3.91964875e-03f, 3.52989866e-03f,
3.11212090e-03f, 2.66999053e-03f, 2.20744344e-03f, 1.72859110e-03f, 1.23756351e-03f, 7.38678150e-04f,
2.36236760e-04f, -2.65462378e-04f, -7.62072815e-04f, -1.24943395e-03f, -1.72337956e-03f, -2.17993754e-03f,
-2.61530935e-03f, -3.02588421e-03f, -3.40825196e-03f, -3.75935360e-03f, -4.07630652e-03f, -4.35660760e-03f,
-4.59808398e-03f, -4.79883718e-03f, -4.95743843e-03f, -5.07271280e-03f, -5.14393833e-03f, -5.17077608e-03f,
-5.15318763e-03f, -5.09164480e-03f, -4.98686807e-03f, -4.84002285e-03f, -4.65260103e-03f, -4.42642977e-03f,
-4.16366446e-03f, -3.86678300e-03f, -3.53847751e-03f, -3.18177292e-03f, -2.79986847e-03f, -2.39618401e-03f,
-1.97429017e-03f, -1.53788782e-03f, -1.09083664e-03f, -6.36973406e-04f, -1.80264329e-04f, 2.75399352e-04f,
7.26104424e-04f, 1.16802598e-03f, 1.59744046e-03f, 2.01073128e-03f, 2.40446819e-03f, 2.77538562e-03f,
3.12044615e-03f, 3.43683203e-03f, 3.72202393e-03f, 3.97374850e-03f, 4.19002854e-03f, 4.36925418e-03f,
4.51006070e-03f, 4.61152219e-03f, 4.67293053e-03f, 4.69404975e-03f, 4.67490366e-03f, 4.61589307e-03f,
4.51775252e-03f, 4.38154991e-03f, 4.20868532e-03f, 4.00082377e-03f, 3.75997274e-03f, 3.48836415e-03f,
3.18851504e-03f, 2.86314343e-03f, 2.51519536e-03f, 2.14776743e-03f, 1.76411750e-03f, 1.36763070e-03f,
9.61751835e-04f, 5.50052405e-04f, 1.36015058e-04f, -2.76720943e-04f, -6.84698152e-04f, -1.08442387e-03f,
-1.47253691e-03f, -1.84578853e-03f, -2.20105818e-03f, -2.53544188e-03f, -2.84616998e-03f, -3.13076058e-03f,
-3.38689733e-03f, -3.61260297e-03f, -3.80606518e-03f, -3.96589267e-03f, -4.09087232e-03f, -4.18013173e-03f,
-4.23315965e-03f, -4.24970953e-03f, -4.22981560e-03f, -4.17392494e-03f, -4.08267808e-03f, -3.95709577e-03f,
-3.79845153e-03f, -3.60829670e-03f, -3.38844338e-03f, -3.14094669e-03f, -2.86809742e-03f, -2.57237442e-03f,
-2.25643831e-03f, -1.92312165e-03f, -1.57535841e-03f, -1.21624129e-03f, -8.48868370e-04f, -4.76457354e-04f,
-1.02227062e-04f, 2.70659894e-04f, 6.38948957e-04f, 9.99596773e-04f, 1.34950884e-03f, 1.68579412e-03f,
2.00565112e-03f, 2.30644176e-03f, 2.58570970e-03f, 2.84121989e-03f, 3.07087670e-03f, 3.27296771e-03f,
3.44584695e-03f, 3.58825627e-03f, 3.69915439e-03f, 3.77779535e-03f, 3.82369144e-03f, 3.83666312e-03f,
3.81678507e-03f, 3.76444486e-03f, 3.68027755e-03f, 3.56519883e-03f, 3.42038694e-03f, 3.24725992e-03f,
3.04745181e-03f, 2.82287635e-03f, 2.57555610e-03f, 2.30778342e-03f, 2.02193938e-03f, 1.72060684e-03f,
1.40642226e-03f, 1.08218540e-03f, 7.50708128e-04f, 4.14852040e-04f, 7.75468400e-05f, -2.58336678e-04f,
-5.89954675e-04f, -9.14464553e-04f, -1.22917409e-03f, -1.53142096e-03f, -1.81874942e-03f, -2.08875765e-03f,
-2.33925204e-03f, -2.56824046e-03f, -2.77387464e-03f, -2.95457151e-03f, -3.10891286e-03f, -3.23576957e-03f,
-3.33422309e-03f, -3.40361730e-03f, -3.44352432e-03f, -3.45380945e-03f, -3.43454926e-03f, -3.38612359e-03f,
-3.30910238e-03f, -3.20434413e-03f, -3.07289782e-03f, -2.91605448e-03f, -2.73534798e-03f, -2.53242439e-03f,
-2.30918427e-03f, -2.06766744e-03f, -1.81002532e-03f, -1.53857461e-03f, -1.25572213e-03f, -9.63956082e-04f,
-6.65804929e-04f, -3.63875198e-04f, -6.07622519e-05f, 2.40955893e-04f, 5.38685581e-04f, 8.29936911e-04f,
1.11224977e-03f, 1.38328230e-03f, 1.64080028e-03f, 1.88265574e-03f, 2.10694670e-03f, 2.31181334e-03f,
2.49567938e-03f, 2.65707799e-03f, 2.79477329e-03f, 2.90778929e-03f, 2.99526804e-03f, 3.05666792e-03f,
3.09159989e-03f, 3.09996074e-03f, 3.08183486e-03f, 3.03757314e-03f, 2.96768997e-03f, 2.87296391e-03f,
2.75438271e-03f, 2.61305979e-03f, 2.45041225e-03f, 2.26792371e-03f, 2.06728115e-03f, 1.85034398e-03f,
1.61901728e-03f, 1.37543970e-03f, 1.12168235e-03f, 8.60048928e-04f, 5.92781787e-04f, 3.22217129e-04f,
5.06437951e-05f, -2.19547817e-04f, -4.86132510e-04f, -7.46817210e-04f, -9.99443627e-04f, -1.24188233e-03f,
-1.47217245e-03f, -1.68839648e-03f, -1.88883105e-03f, -2.07184785e-03f, -2.23601745e-03f, -2.38006048e-03f,
-2.50288118e-03f, -2.60358292e-03f, -2.68144174e-03f, -2.73595307e-03f, -2.76679595e-03f, -2.77388624e-03f,
-2.75729794e-03f, -2.71735188e-03f, -2.65451985e-03f, -2.56952130e-03f, -2.46319204e-03f, -2.33660956e-03f,
-2.19096493e-03f, -2.02765268e-03f, -1.84815939e-03f, -1.65412932e-03f, -1.44731483e-03f, -1.22956426e-03f,
-1.00280075e-03f, -7.69022668e-04f, -5.30268510e-04f, -2.88586883e-04f, -4.60956253e-05f, 1.95186584e-04f,
4.33161045e-04f, 6.65873263e-04f, 8.91328897e-04f, 1.10770620e-03f, 1.31316296e-03f, 1.50610067e-03f,
1.68489795e-03f, 1.84814923e-03f, 1.99458512e-03f, 2.12304250e-03f, 2.23258384e-03f, 2.32237953e-03f,
2.39181962e-03f, 2.44043032e-03f, 2.46796938e-03f, 2.47430968e-03f, 2.45957831e-03f, 2.42401283e-03f,
2.36808884e-03f, 2.29238471e-03f, 2.19773378e-03f, 2.08501666e-03f, 1.95534528e-03f, 1.80993801e-03f,
1.65014053e-03f, 1.47739854e-03f, 1.29329221e-03f, 1.09944593e-03f, 8.97596290e-04f, 6.89486470e-04f,
4.76967544e-04f, 2.61847472e-04f, 4.59979030e-05f, -1.68770369e-04f, -3.80612759e-04f, -5.87744421e-04f,
-7.88452414e-04f, -9.81081718e-04f, -1.16402219e-03f, -1.33580811e-03f, -1.49504859e-03f, -1.64047131e-03f,
-1.77095587e-03f, -1.88548340e-03f, -1.98318254e-03f, -2.06335667e-03f, -2.12544333e-03f, -2.16903096e-03f,
-2.19389731e-03f, -2.19994674e-03f, -2.18726700e-03f, -2.15609170e-03f, -2.10683457e-03f, -2.04002290e-03f,
-1.95633800e-03f, -1.85665258e-03f, -1.74189023e-03f, -1.61313165e-03f, -1.47159921e-03f, -1.31856217e-03f,
-1.15541374e-03f, -9.83590913e-04f, -8.04645529e-04f, -6.20138811e-04f, -4.31664744e-04f, -2.40859759e-04f,
-4.93718861e-05f, 1.41183920e-04f, 3.29184443e-04f, 5.13049545e-04f, 6.91252710e-04f, 8.62329668e-04f,
1.02486089e-03f, 1.17753306e-03f, 1.31912530e-03f, 1.44851584e-03f, 1.56468190e-03f, 1.66675270e-03f,
1.75393226e-03f, 1.82562545e-03f, 1.88129935e-03f, 1.92062935e-03f, 1.94336360e-03f, 1.94946381e-03f,
1.93898469e-03f, 1.91211060e-03f, 1.86925265e-03f, 1.81081128e-03f, 1.73745800e-03f, 1.64989979e-03f,
1.54896085e-03f, 1.43565148e-03f, 1.31095906e-03f, 1.17607031e-03f, 1.03219054e-03f, 8.80596006e-04f,
7.22634695e-04f, 5.59715925e-04f, 3.93223384e-04f, 2.24602808e-04f, 5.53223372e-05f, -1.13204206e-04f,
-2.79527886e-04f, -4.42273875e-04f, -6.00090187e-04f, -7.51646708e-04f, -8.95738714e-04f, -1.03117771e-03f,
-1.15687770e-03f, -1.27187587e-03f, -1.37523688e-03f, -1.46618576e-03f, -1.54403989e-03f, -1.60825931e-03f,
-1.65836399e-03f, -1.69405240e-03f, -1.71514183e-03f, -1.72154028e-03f, -1.71331327e-03f, -1.69063272e-03f,
-1.65381037e-03f, -1.60326168e-03f, -1.53948863e-03f, -1.46318779e-03f, -1.37503217e-03f, -1.27591969e-03f,
-1.16672308e-03f, -1.04846883e-03f, -9.22232848e-04f, -7.89108246e-04f, -6.50329911e-04f, -5.07057241e-04f,
-3.60579584e-04f, -2.12138548e-04f, -6.30166060e-05f, 8.55107333e-05f, 2.32212191e-04f, 3.75851456e-04f,
5.15213418e-04f, 6.49182851e-04f, 7.76642588e-04f, 8.96585347e-04f, 1.00803198e-03f, 1.11010987e-03f,
1.20203475e-03f, 1.28308439e-03f, 1.35268783e-03f, 1.41030687e-03f, 1.45558664e-03f, 1.48819124e-03f,
1.50798717e-03f, 1.51486502e-03f, 1.50888467e-03f, 1.49022209e-03f, 1.45906012e-03f, 1.41583581e-03f,
1.36095722e-03f, 1.29499749e-03f, 1.21859138e-03f, 1.13249419e-03f, 1.03745344e-03f, 9.34384957e-04f,
8.24209226e-04f, 7.07921644e-04f, 5.86535461e-04f, 4.61118668e-04f, 3.32797940e-04f, 2.02615430e-04f,
7.17560319e-05f, -5.87215139e-05f, -1.87700771e-04f, -3.14093799e-04f, -4.36855019e-04f, -5.54982470e-04f,
-6.67514567e-04f, -7.73539543e-04f, -8.72216549e-04f, -9.62754726e-04f, -1.04446836e-03f, -1.11673823e-03f,
-1.17901020e-03f, -1.23084835e-03f, -1.27191263e-03f, -1.30189831e-03f, -1.32066941e-03f, -1.32816613e-03f,
-1.32437715e-03f, -1.30944714e-03f, -1.28360668e-03f, -1.24710492e-03f, -1.20038313e-03f, -1.14391116e-03f,
-1.07822250e-03f, -1.00394823e-03f, -9.21799577e-04f, -8.32520513e-04f, -7.36916195e-04f, -6.35853312e-04f,
-5.30218398e-04f, -4.20950684e-04f, -3.08981087e-04f, -1.95310152e-04f, -8.08721649e-05f, 3.33481785e-05f,
1.46369769e-04f, 2.57271691e-04f, 3.65123878e-04f, 4.69053422e-04f, 5.68205019e-04f, 6.61777482e-04f,
7.49035427e-04f, 8.29295760e-04f, 9.01919035e-04f, 9.66370937e-04f, 1.02218113e-03f, 1.06892877e-03f,
1.10630552e-03f, 1.13406370e-03f, 1.15204451e-03f, 1.16019052e-03f, 1.15848806e-03f, 1.14706630e-03f,
1.12606449e-03f, 1.09574589e-03f, 1.05645362e-03f, 1.00859266e-03f, 9.52601766e-04f, 8.89057609e-04f,
8.18535938e-04f, 7.41697389e-04f, 6.59241262e-04f, 5.71884368e-04f, 4.80414698e-04f, 3.85677252e-04f,
2.88406796e-04f, 1.89536836e-04f, 8.98491837e-05f, -9.79888746e-06f, -1.08531507e-04f, -2.05575498e-04f,
-3.00092231e-04f, -3.91327952e-04f, -4.78537671e-04f, -5.61003964e-04f, -6.38090388e-04f, -7.09209697e-04f,
-7.73747838e-04f, -8.31297964e-04f, -8.81364804e-04f, -9.23641236e-04f, -9.57793553e-04f, -9.83624619e-04f,
-1.00098424e-03f, -1.00979404e-03f, -1.01003977e-03f, -1.00180772e-03f, -9.85219816e-04f, -9.60506778e-04f,
-9.27905874e-04f, -8.87790902e-04f, -8.40553609e-04f, -7.86632276e-04f, -7.26559669e-04f, -6.60872173e-04f,
-5.90177860e-04f, -5.15099219e-04f, -4.36341554e-04f, -3.54526447e-04f, -2.70436804e-04f, -1.84757234e-04f,
-9.82406108e-05f, -1.16228429e-05f, 7.44116225e-05f, 1.59099493e-04f, 2.41739119e-04f, 3.21707034e-04f,
3.98276352e-04f, 4.70887555e-04f, 5.38973046e-04f, 6.01940918e-04f, 6.59368174e-04f, 7.10783030e-04f,
7.55802336e-04f, 7.94127086e-04f, 8.25478803e-04f, 8.49639386e-04f, 8.66487952e-04f, 8.75935969e-04f,
8.77948893e-04f, 8.72611584e-04f, 8.59994515e-04f, 8.40271458e-04f, 8.13696181e-04f, 7.80491851e-04f,
7.41053306e-04f, 6.95727202e-04f, 6.44936090e-04f, 5.89181503e-04f, 5.28946796e-04f, 4.64790448e-04f,
3.97272420e-04f, 3.27000597e-04f, 2.54559578e-04f, 1.80597276e-04f, 1.05760446e-04f, 3.06209047e-05f,
-4.41172003e-05f, -1.17884760e-04f, -1.90032814e-04f, -2.60000039e-04f, -3.27213235e-04f, -3.91110007e-04f,
-4.51226928e-04f, -5.07042112e-04f, -5.58194586e-04f, -6.04189222e-04f, -6.44816381e-04f, -6.79653847e-04f,
-7.08557315e-04f, -7.31282579e-04f, -7.47702169e-04f, -7.57731688e-04f, -7.61359812e-04f, -7.58589885e-04f,
-7.49503361e-04f, -7.34226582e-04f, -7.12935677e-04f, -6.85882645e-04f, -6.53307567e-04f, -6.15569562e-04f,
-5.72978650e-04f, -5.25977418e-04f, -4.74963705e-04f, -4.20426590e-04f, -3.62819514e-04f, -3.02647353e-04f,
-2.40497241e-04f, -1.76810216e-04f, -1.12210871e-04f, -4.71976690e-05f, 1.76624641e-05f, 8.18440593e-05f,
1.44804207e-04f, 2.06021410e-04f, 2.65025446e-04f, 3.21327783e-04f, 3.74487008e-04f, 4.24062432e-04f,
4.69715655e-04f, 5.11042943e-04f, 5.47794530e-04f, 5.79655168e-04f, 6.06446384e-04f, 6.27934546e-04f,
6.44010762e-04f, 6.54614698e-04f, 6.59636425e-04f, 6.59157826e-04f, 6.53158826e-04f, 6.41794049e-04f,
6.25154916e-04f, 6.03470855e-04f, 5.76917242e-04f, 5.45789736e-04f, 5.10368292e-04f, 4.70998661e-04f,
4.28021656e-04f, 3.81834126e-04f, 3.32863326e-04f, 2.81489629e-04f, 2.28231239e-04f, 1.73484261e-04f,
1.17756607e-04f, 6.14881351e-05f, 5.17778269e-06f, -5.07352374e-05f, -1.05745987e-04f, -1.59454662e-04f,
-2.11394268e-04f, -2.61151905e-04f, -3.08351703e-04f, -3.52598590e-04f, -3.93545002e-04f, -4.30916147e-04f,
-4.64387406e-04f, -4.93756593e-04f, -5.18755281e-04f, -5.39265493e-04f, -5.55137934e-04f, -5.66259303e-04f,
-5.72606783e-04f, -5.74140344e-04f, -5.70903292e-04f, -5.62934741e-04f, -5.50388898e-04f, -5.33351962e-04f,
-5.12028510e-04f, -4.86612455e-04f, -4.57392981e-04f, -4.24578939e-04f, -3.88503808e-04f, -3.49487518e-04f,
-3.07895836e-04f, -2.64036522e-04f, -2.18356445e-04f, -1.71198300e-04f, -1.22998901e-04f, -7.41392080e-05f,
-2.50280393e-05f, 2.38852047e-05f, 7.22663332e-05f, 1.19659647e-04f, 1.65718806e-04f, 2.10055385e-04f,
2.52324173e-04f, 2.92190427e-04f, 3.29337577e-04f, 3.63510150e-04f, 3.94385715e-04f, 4.21803288e-04f,
4.45519433e-04f, 4.65391876e-04f, 4.81270460e-04f, 4.93057625e-04f, 5.00688030e-04f, 5.04121708e-04f,
5.03379627e-04f, 4.98485604e-04f, 4.89499566e-04f, 4.76539317e-04f, 4.59760023e-04f, 4.39274612e-04f,
4.15334876e-04f, 3.88103885e-04f, 3.57902146e-04f, 3.24908089e-04f, 2.89490480e-04f, 2.51922687e-04f,
2.12512220e-04f, 1.71637404e-04f, 1.29609890e-04f, 8.67866183e-05f, 4.35312276e-05f, 1.98808307e-07f,
-4.28589070e-05f, -8.52865394e-05f, -1.26765698e-04f, -1.66922292e-04f, -2.05456466e-04f, -2.42095652e-04f,
-2.76487494e-04f, -3.08425602e-04f, -3.37638832e-04f, -3.63923042e-04f, -3.87022898e-04f, -4.06875144e-04f,
-4.23245129e-04f, -4.36071615e-04f, -4.45236993e-04f, -4.50724682e-04f, -4.52491230e-04f, -4.50548104e-04f,
-4.44936790e-04f, -4.35725612e-04f, -4.22987381e-04f, -4.06882738e-04f, -3.87548587e-04f, -3.65123104e-04f,
-3.39860288e-04f, -3.11947486e-04f, -2.81618569e-04f, -2.49166817e-04f, -2.14824344e-04f, -1.78876370e-04f,
-1.41684861e-04f, -1.03466427e-04f, -6.45996088e-05f, -2.53738050e-05f, 1.39035721e-05f, 5.28977578e-05f,
9.13010773e-05f, 1.28809554e-04f, 1.65139924e-04f, 2.00005346e-04f, 2.33095696e-04f, 2.64232233e-04f,
2.93070034e-04f, 3.19508024e-04f, 3.43252648e-04f, 3.64165224e-04f, 3.82074036e-04f, 3.96868082e-04f,
4.08408250e-04f, 4.16671952e-04f, 4.21556517e-04f, 4.23035822e-04f, 4.21172111e-04f, 4.15928838e-04f,
4.07377025e-04f, 3.95568598e-04f, 3.80628038e-04f, 3.62729177e-04f, 3.41921136e-04f, 3.18489958e-04f,
2.92497406e-04f, 2.64266550e-04f, 2.33955571e-04f, 2.01809261e-04f, 1.68092145e-04f, 1.33141461e-04f,
9.71043460e-05f, 6.03452880e-05f, 2.31264055e-05f, -1.43105089e-05f, -5.15607083e-05f, -8.84833364e-05f,
-1.24679461e-04f, -1.59910519e-04f, -1.93952723e-04f, -2.26496145e-04f, -2.57307566e-04f, -2.86175538e-04f,
-3.12853472e-04f, -3.37140613e-04f, -3.58914997e-04f, -3.77932329e-04f, -3.94117065e-04f, -4.07317063e-04f,
-4.17422308e-04f, -4.24419479e-04f, -4.28161231e-04f, -4.28700484e-04f, -4.26016659e-04f, -4.20088126e-04f,
-4.11009185e-04f, -3.98835037e-04f, -3.83585114e-04f, -3.65493072e-04f, -3.44616197e-04f, -3.21064387e-04f,
-2.95119418e-04f, -2.66863117e-04f, -2.36549174e-04f, -2.04391686e-04f, -1.70585806e-04f, -1.35432614e-04f,
-9.91006984e-05f, -6.19152828e-05f, -2.41012311e-05f, 1.40621144e-05f, 5.22867497e-05f, 9.03199843e-05f,
1.27917614e-04f, 1.64740292e-04f, 2.00634478e-04f, 2.35261402e-04f, 2.68377430e-04f, 2.99818019e-04f,
3.29273634e-04f, 3.56562766e-04f, 3.81532332e-04f, 4.03948113e-04f, 4.23655375e-04f, 4.40488930e-04f,
4.54376777e-04f, 4.65137195e-04f, 4.72679704e-04f, 4.77014073e-04f, 4.77982201e-04f, 4.75625277e-04f,
4.69878507e-04f, 4.60802987e-04f, 4.48367418e-04f, 4.32641679e-04f, 4.13709630e-04f, 3.91634147e-04f,
3.66512902e-04f, 3.38481392e-04f, 3.07634938e-04f, 2.74189182e-04f, 2.38229594e-04f, 1.99985879e-04f,
1.59632210e-04f, 1.17351364e-04f, 7.33404728e-05f, 2.78844831e-05f, -1.89099461e-05f, -6.67343638e-05f,
-1.15367449e-04f, -1.64649983e-04f, -2.14224348e-04f, -2.64019844e-04f, -3.13654244e-04f, -3.62990333e-04f,
-4.11800705e-04f, -4.59821928e-04f, -5.06946486e-04f, -5.52847863e-04f, -5.97397068e-04f, -6.40454770e-04f,
-6.81765968e-04f, -7.21210131e-04f, -7.58634477e-04f, -7.93939572e-04f, -8.26964876e-04f, -8.57585335e-04f,
-8.85733438e-04f, -9.11351007e-04f, -9.34300512e-04f, -9.54617442e-04f, -9.72159416e-04f, -9.87012089e-04f,
-9.99095133e-04f, -1.00846242e-03f, -1.01506022e-03f, -1.01897105e-03f, -1.02021427e-03f, -1.01887259e-03f,
-1.01497557e-03f, -1.00861358e-03f, -9.99877741e-04f, -9.88823136e-04f, -9.75617693e-04f, -9.60303769e-04f,
-9.43035535e-04f, -9.23922797e-04f, -9.03105429e-04f, -8.80708716e-04f, -8.56853281e-04f, -8.31685264e-04f,
-8.05348207e-04f, -7.77961627e-04f, -7.49713086e-04f, -7.20674604e-04f, -6.91032783e-04f, -6.60888020e-04f,
-6.30372917e-04f, -5.99673349e-04f, -5.68830563e-04f, -5.38013304e-04f, -5.07353303e-04f, -4.76915043e-04f,
-4.46832926e-04f, -4.17179291e-04f, -3.88083307e-04f, -3.59575024e-04f, -3.31820735e-04f, -3.04804303e-04f,
-2.78616041e-04f, -2.53335964e-04f, -2.28986996e-04f, -2.05619529e-04f, -1.83318449e-04f, -1.61979425e-04f,
-1.41791423e-04f, -1.22648816e-04f, -1.04625498e-04f, -8.77122910e-05f, -7.18653457e-05f, -5.71787106e-05f,
-4.34807639e-05f, -3.09618857e-05f, -1.94074401e-05f, -8.88017971e-06f, 6.09625220e-07f, 9.14020334e-06f,
1.67805558e-05f, 2.35369965e-05f, 2.94278194e-05f, 3.45049751e-05f, 3.88373828e-05f, 4.24291966e-05f,
4.53445665e-05f, 4.76965834e-05f, 4.93395567e-05f, 5.05392111e-05f, 5.12257065e-05f, 5.14579340e-05f,
5.12651750e-05f, 5.07312551e-05f, 4.98486765e-05f, 4.87082573e-05f, 4.73439631e-05f, 4.56740817e-05f,
4.38653618e-05f, 4.19399075e-05f, 3.99125668e-05f, 3.77616021e-05f, 3.56135997e-05f, 3.33554815e-05f,
3.11656899e-05f, 2.89038150e-05f, 2.67281634e-05f, 2.46192762e-05f, 2.24899205e-05f, 2.04698700e-05f,
1.84927655e-05f, 1.66762886e-05f, 1.49393771e-05f, 1.32258081e-05f, 1.16985586e-05f, 1.01874391e-05f,
8.99882100e-06f, 7.61267073e-06f, 6.57702907e-06f, 5.59829210e-06f, 4.27698546e-06f, 1.03248674e-05f,
};
//
// polyphase filter
//
static const int SRC_PHASEBITS = 8;
static const int SRC_PHASES = (1 << SRC_PHASEBITS);
static const int SRC_FRACBITS = 32 - SRC_PHASEBITS;
static const uint32_t SRC_FRACMASK = (1 << SRC_FRACBITS) - 1;
static const float QFRAC_TO_FLOAT = 1.0f / (1 << SRC_FRACBITS);
static const float Q32_TO_FLOAT = 1.0f / (1ULL << 32);
// blocking size in frames, chosen so block processing fits in L1 cache
static const int SRC_BLOCK = 1024;
#define lo32(a) ((uint32_t)(a))
#define hi32(a) ((int32_t)((a) >> 32))
// //
// Portable aligned malloc/free // Portable aligned malloc/free
@ -610,8 +69,8 @@ static void cubicInterpolation(const float* input, float* output, int inputSize,
// Lagrange interpolation using Farrow structure // Lagrange interpolation using Farrow structure
for (int j = 0; j < outputSize; j++) { for (int j = 0; j < outputSize; j++) {
int32_t i = hi32(offset); int32_t i = HI32(offset);
uint32_t f = lo32(offset); uint32_t f = LO32(offset);
// values outside the window are zero // values outside the window are zero
float x0 = (i - 1 < 0) ? 0.0f : input[i - 1]; float x0 = (i - 1 < 0) ? 0.0f : input[i - 1];
@ -649,7 +108,7 @@ int AudioSRC::createRationalFilter(int upFactor, int downFactor, float gain) {
numTaps = (numCoefs + upFactor - 1) / upFactor; numTaps = (numCoefs + upFactor - 1) / upFactor;
gain *= (float)oldCoefs / numCoefs; gain *= (float)oldCoefs / numCoefs;
} }
numTaps = (numTaps + 3) & ~3; // SIMD4 numTaps = (numTaps + 7) & ~7; // SIMD8
// interpolate the coefficients of the prototype filter // interpolate the coefficients of the prototype filter
float* tempFilter = new float[numTaps * numPhases]; float* tempFilter = new float[numTaps * numPhases];
@ -658,7 +117,7 @@ int AudioSRC::createRationalFilter(int upFactor, int downFactor, float gain) {
cubicInterpolation(prototypeFilter, tempFilter, prototypeCoefs, numCoefs, gain); cubicInterpolation(prototypeFilter, tempFilter, prototypeCoefs, numCoefs, gain);
// create the polyphase filter // create the polyphase filter
_polyphaseFilter = (float*)aligned_malloc(numTaps * numPhases * sizeof(float), 16); // SIMD4 _polyphaseFilter = (float*)aligned_malloc(numTaps * numPhases * sizeof(float), 32); // SIMD8
// rearrange into polyphase form, ordered by use // rearrange into polyphase form, ordered by use
for (int i = 0; i < numPhases; i++) { for (int i = 0; i < numPhases; i++) {
@ -699,7 +158,7 @@ int AudioSRC::createIrrationalFilter(int upFactor, int downFactor, float gain) {
numTaps = (numCoefs + upFactor - 1) / upFactor; numTaps = (numCoefs + upFactor - 1) / upFactor;
gain *= (float)oldCoefs / numCoefs; gain *= (float)oldCoefs / numCoefs;
} }
numTaps = (numTaps + 3) & ~3; // SIMD4 numTaps = (numTaps + 7) & ~7; // SIMD8
// interpolate the coefficients of the prototype filter // interpolate the coefficients of the prototype filter
float* tempFilter = new float[numTaps * numPhases]; float* tempFilter = new float[numTaps * numPhases];
@ -708,7 +167,7 @@ int AudioSRC::createIrrationalFilter(int upFactor, int downFactor, float gain) {
cubicInterpolation(prototypeFilter, tempFilter, prototypeCoefs, numCoefs, gain); cubicInterpolation(prototypeFilter, tempFilter, prototypeCoefs, numCoefs, gain);
// create the polyphase filter, with extra phase at the end to simplify coef interpolation // create the polyphase filter, with extra phase at the end to simplify coef interpolation
_polyphaseFilter = (float*)aligned_malloc(numTaps * (numPhases + 1) * sizeof(float), 16); // SIMD4 _polyphaseFilter = (float*)aligned_malloc(numTaps * (numPhases + 1) * sizeof(float), 32); // SIMD8
// rearrange into polyphase form, ordered by fractional delay // rearrange into polyphase form, ordered by fractional delay
for (int phase = 0; phase < numPhases; phase++) { for (int phase = 0; phase < numPhases; phase++) {
@ -741,14 +200,14 @@ int AudioSRC::createIrrationalFilter(int upFactor, int downFactor, float gain) {
#include <emmintrin.h> #include <emmintrin.h>
int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFrames) { int AudioSRC::multirateFilter1_SSE(const float* input0, float* output0, int inputFrames) {
int outputFrames = 0; int outputFrames = 0;
assert((_numTaps & 0x3) == 0); // SIMD4 assert(_numTaps % 4 == 0); // SIMD4
if (_step == 0) { // rational if (_step == 0) { // rational
int32_t i = hi32(_offset); int32_t i = HI32(_offset);
while (i < inputFrames) { while (i < inputFrames) {
@ -761,7 +220,7 @@ int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFra
//float coef = c0[j]; //float coef = c0[j];
__m128 coef0 = _mm_loadu_ps(&c0[j]); __m128 coef0 = _mm_loadu_ps(&c0[j]);
//acc0 += input0[i + j] * coef; //acc += input[i + j] * coef;
acc0 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input0[i + j]), coef0), acc0); acc0 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input0[i + j]), coef0), acc0);
} }
@ -781,10 +240,10 @@ int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFra
} else { // irrational } else { // irrational
while (hi32(_offset) < inputFrames) { while (HI32(_offset) < inputFrames) {
int32_t i = hi32(_offset); int32_t i = HI32(_offset);
uint32_t f = lo32(_offset); uint32_t f = LO32(_offset);
uint32_t phase = f >> SRC_FRACBITS; uint32_t phase = f >> SRC_FRACBITS;
__m128 frac = _mm_set1_ps((f & SRC_FRACMASK) * QFRAC_TO_FLOAT); __m128 frac = _mm_set1_ps((f & SRC_FRACMASK) * QFRAC_TO_FLOAT);
@ -802,7 +261,7 @@ int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFra
coef1 = _mm_sub_ps(coef1, coef0); coef1 = _mm_sub_ps(coef1, coef0);
coef0 = _mm_add_ps(_mm_mul_ps(coef1, frac), coef0); coef0 = _mm_add_ps(_mm_mul_ps(coef1, frac), coef0);
//acc0 += input0[i + j] * coef; //acc += input[i + j] * coef;
acc0 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input0[i + j]), coef0), acc0); acc0 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input0[i + j]), coef0), acc0);
} }
@ -821,14 +280,14 @@ int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFra
return outputFrames; return outputFrames;
} }
int AudioSRC::multirateFilter2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames) { int AudioSRC::multirateFilter2_SSE(const float* input0, const float* input1, float* output0, float* output1, int inputFrames) {
int outputFrames = 0; int outputFrames = 0;
assert((_numTaps & 0x3) == 0); // SIMD4 assert(_numTaps % 4 == 0); // SIMD4
if (_step == 0) { // rational if (_step == 0) { // rational
int32_t i = hi32(_offset); int32_t i = HI32(_offset);
while (i < inputFrames) { while (i < inputFrames) {
@ -842,7 +301,7 @@ int AudioSRC::multirateFilter2(const float* input0, const float* input1, float*
//float coef = c0[j]; //float coef = c0[j];
__m128 coef0 = _mm_loadu_ps(&c0[j]); __m128 coef0 = _mm_loadu_ps(&c0[j]);
//acc0 += input0[i + j] * coef; //acc += input[i + j] * coef;
acc0 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input0[i + j]), coef0), acc0); acc0 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input0[i + j]), coef0), acc0);
acc1 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input1[i + j]), coef0), acc1); acc1 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input1[i + j]), coef0), acc1);
} }
@ -866,10 +325,10 @@ int AudioSRC::multirateFilter2(const float* input0, const float* input1, float*
} else { // irrational } else { // irrational
while (hi32(_offset) < inputFrames) { while (HI32(_offset) < inputFrames) {
int32_t i = hi32(_offset); int32_t i = HI32(_offset);
uint32_t f = lo32(_offset); uint32_t f = LO32(_offset);
uint32_t phase = f >> SRC_FRACBITS; uint32_t phase = f >> SRC_FRACBITS;
__m128 frac = _mm_set1_ps((f & SRC_FRACMASK) * QFRAC_TO_FLOAT); __m128 frac = _mm_set1_ps((f & SRC_FRACMASK) * QFRAC_TO_FLOAT);
@ -888,7 +347,7 @@ int AudioSRC::multirateFilter2(const float* input0, const float* input1, float*
coef1 = _mm_sub_ps(coef1, coef0); coef1 = _mm_sub_ps(coef1, coef0);
coef0 = _mm_add_ps(_mm_mul_ps(coef1, frac), coef0); coef0 = _mm_add_ps(_mm_mul_ps(coef1, frac), coef0);
//acc0 += input0[i + j] * coef; //acc += input[i + j] * coef;
acc0 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input0[i + j]), coef0), acc0); acc0 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input0[i + j]), coef0), acc0);
acc1 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input1[i + j]), coef0), acc1); acc1 = _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(&input1[i + j]), coef0), acc1);
} }
@ -911,6 +370,24 @@ int AudioSRC::multirateFilter2(const float* input0, const float* input1, float*
return outputFrames; return outputFrames;
} }
//
// Runtime CPU dispatch
//
#include "CPUDetect.h"
int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFrames) {
static auto f = cpuSupportsAVX2() ? &AudioSRC::multirateFilter1_AVX2 : &AudioSRC::multirateFilter1_SSE;
return (this->*f)(input0, output0, inputFrames); // dispatch
}
int AudioSRC::multirateFilter2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames) {
static auto f = cpuSupportsAVX2() ? &AudioSRC::multirateFilter2_AVX2 : &AudioSRC::multirateFilter2_SSE;
return (this->*f)(input0, input1, output0, output1, inputFrames); // dispatch
}
// convert int16_t to float, deinterleave stereo // convert int16_t to float, deinterleave stereo
void AudioSRC::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) { void AudioSRC::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) {
__m128 scale = _mm_set1_ps(1/32768.0f); __m128 scale = _mm_set1_ps(1/32768.0f);
@ -1069,7 +546,7 @@ int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFra
if (_step == 0) { // rational if (_step == 0) { // rational
int32_t i = hi32(_offset); int32_t i = HI32(_offset);
while (i < inputFrames) { while (i < inputFrames) {
@ -1096,10 +573,10 @@ int AudioSRC::multirateFilter1(const float* input0, float* output0, int inputFra
} else { // irrational } else { // irrational
while (hi32(_offset) < inputFrames) { while (HI32(_offset) < inputFrames) {
int32_t i = hi32(_offset); int32_t i = HI32(_offset);
uint32_t f = lo32(_offset); uint32_t f = LO32(_offset);
uint32_t phase = f >> SRC_FRACBITS; uint32_t phase = f >> SRC_FRACBITS;
float frac = (f & SRC_FRACMASK) * QFRAC_TO_FLOAT; float frac = (f & SRC_FRACMASK) * QFRAC_TO_FLOAT;
@ -1132,7 +609,7 @@ int AudioSRC::multirateFilter2(const float* input0, const float* input1, float*
if (_step == 0) { // rational if (_step == 0) { // rational
int32_t i = hi32(_offset); int32_t i = HI32(_offset);
while (i < inputFrames) { while (i < inputFrames) {
@ -1162,10 +639,10 @@ int AudioSRC::multirateFilter2(const float* input0, const float* input1, float*
} else { // irrational } else { // irrational
while (hi32(_offset) < inputFrames) { while (HI32(_offset) < inputFrames) {
int32_t i = hi32(_offset); int32_t i = HI32(_offset);
uint32_t f = lo32(_offset); uint32_t f = LO32(_offset);
uint32_t phase = f >> SRC_FRACBITS; uint32_t phase = f >> SRC_FRACBITS;
float frac = (f & SRC_FRACMASK) * QFRAC_TO_FLOAT; float frac = (f & SRC_FRACMASK) * QFRAC_TO_FLOAT;
@ -1320,7 +797,7 @@ AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels) {
assert(inputSampleRate > 0); assert(inputSampleRate > 0);
assert(outputSampleRate > 0); assert(outputSampleRate > 0);
assert(numChannels > 0); assert(numChannels > 0);
assert(numChannels <= MAX_CHANNELS); assert(numChannels <= SRC_MAX_CHANNELS);
_inputSampleRate = inputSampleRate; _inputSampleRate = inputSampleRate;
_outputSampleRate = outputSampleRate; _outputSampleRate = outputSampleRate;
@ -1349,7 +826,7 @@ AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels) {
_numTaps = createIrrationalFilter(_upFactor, _downFactor, 1.0f); _numTaps = createIrrationalFilter(_upFactor, _downFactor, 1.0f);
} }
//printf("up=%d down=%.3f taps=%d\n", _upFactor, _downFactor + (lo32(_step)<<SRC_PHASEBITS) * Q32_TO_FLOAT, _numTaps); //printf("up=%d down=%.3f taps=%d\n", _upFactor, _downFactor + (LO32(_step)<<SRC_PHASEBITS) * Q32_TO_FLOAT, _numTaps);
// filter history buffers // filter history buffers
_numHistory = _numTaps - 1; _numHistory = _numTaps - 1;
@ -1357,10 +834,10 @@ AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels) {
_history[1] = new float[2 * _numHistory]; _history[1] = new float[2 * _numHistory];
// format conversion buffers // format conversion buffers
_inputs[0] = (float*)aligned_malloc(SRC_BLOCK * sizeof(float), 16); // SIMD4 _inputs[0] = (float*)aligned_malloc(4*SRC_BLOCK * sizeof(float), 16); // SIMD4
_inputs[1] = (float*)aligned_malloc(SRC_BLOCK * sizeof(float), 16); _inputs[1] = _inputs[0] + 1*SRC_BLOCK;
_outputs[0] = (float*)aligned_malloc(SRC_BLOCK * sizeof(float), 16); _outputs[0] = _inputs[0] + 2*SRC_BLOCK;
_outputs[1] = (float*)aligned_malloc(SRC_BLOCK * sizeof(float), 16); _outputs[1] = _inputs[0] + 3*SRC_BLOCK;
// input blocking size, such that input and output are both guaranteed not to exceed SRC_BLOCK frames // input blocking size, such that input and output are both guaranteed not to exceed SRC_BLOCK frames
_inputBlock = std::min(SRC_BLOCK, getMaxInput(SRC_BLOCK)); _inputBlock = std::min(SRC_BLOCK, getMaxInput(SRC_BLOCK));
@ -1380,9 +857,6 @@ AudioSRC::~AudioSRC() {
delete[] _history[1]; delete[] _history[1];
aligned_free(_inputs[0]); aligned_free(_inputs[0]);
aligned_free(_inputs[1]);
aligned_free(_outputs[0]);
aligned_free(_outputs[1]);
} }
// //

View file

@ -14,11 +14,23 @@
#include <stdint.h> #include <stdint.h>
static const int SRC_MAX_CHANNELS = 2;
// polyphase filter
static const int SRC_PHASEBITS = 8;
static const int SRC_PHASES = (1 << SRC_PHASEBITS);
static const int SRC_FRACBITS = 32 - SRC_PHASEBITS;
static const uint32_t SRC_FRACMASK = (1 << SRC_FRACBITS) - 1;
static const float QFRAC_TO_FLOAT = 1.0f / (1 << SRC_FRACBITS);
static const float Q32_TO_FLOAT = 1.0f / (1ULL << 32);
// blocking size in frames, chosen so block processing fits in L1 cache
static const int SRC_BLOCK = 256;
class AudioSRC { class AudioSRC {
public: public:
static const int MAX_CHANNELS = 2;
AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels); AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels);
~AudioSRC(); ~AudioSRC();
@ -33,9 +45,9 @@ private:
float* _polyphaseFilter; float* _polyphaseFilter;
int* _stepTable; int* _stepTable;
float* _history[MAX_CHANNELS]; float* _history[SRC_MAX_CHANNELS];
float* _inputs[MAX_CHANNELS]; float* _inputs[SRC_MAX_CHANNELS];
float* _outputs[MAX_CHANNELS]; float* _outputs[SRC_MAX_CHANNELS];
int _inputSampleRate; int _inputSampleRate;
int _outputSampleRate; int _outputSampleRate;
@ -57,6 +69,12 @@ private:
int multirateFilter1(const float* input0, float* output0, int inputFrames); int multirateFilter1(const float* input0, float* output0, int inputFrames);
int multirateFilter2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames); int multirateFilter2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
int multirateFilter1_SSE(const float* input0, float* output0, int inputFrames);
int multirateFilter2_SSE(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
int multirateFilter1_AVX2(const float* input0, float* output0, int inputFrames);
int multirateFilter2_AVX2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames); void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames);
void convertOutputToInt16(float** inputs, int16_t* output, int numFrames); void convertOutputToInt16(float** inputs, int16_t* output, int numFrames);

View file

@ -0,0 +1,548 @@
//
// AudioSRCData.h
// libraries/audio/src
//
// Created by Ken Cooke on 6/6/16.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
//
// Prototype filter coefficients for audio sampling rate conversion.
//
// See "Design of Optimal Minimum Phase Digital FIR Filters Using Discrete Hilbert Transforms"
// IEEE TRANSACTIONS ON SIGNAL PROCESSING, May 2000
//
// Minimum-phase equiripple FIR lowpass
// taps = 96, phases = 32
//
// passband = 0.918 (20.2khz @ 44.1khz sampling rate)
// stopband = 1.010 (22.2khz @ 44.1khz sampling rate)
// passband ripple = +-0.01dB
// stopband attn = -125dB (-70dB at 1.000)
//
// Resampling algorithm:
// One of two methods is used, depending on whether the conversion is reducible to a ratio of small integers L/M.
// For rational ratio, the prototype is upsampled to L/M polyphase filter using 3rd-order Lagrange interpolation.
// For irrational ratio, the prototype is upsampled to 256/M polyphase filter, followed by linear interpolation.
// For both cases, oversampling at each stage ensures the original passband and stopband specifications are met.
//
static const int PROTOTYPE_TAPS = 96; // filter taps per phase
static const int PROTOTYPE_PHASES = 32; // oversampling factor
static const float prototypeFilter[PROTOTYPE_TAPS * PROTOTYPE_PHASES] = {
0.00000000e+00f, 1.55021703e-05f, 1.46054865e-05f, 2.07057160e-05f, 2.91335519e-05f, 4.00091078e-05f,
5.33544450e-05f, 7.03618468e-05f, 9.10821639e-05f, 1.16484613e-04f, 1.47165999e-04f, 1.84168304e-04f,
2.28429617e-04f, 2.80913884e-04f, 3.42940399e-04f, 4.15773039e-04f, 5.01023255e-04f, 6.00234953e-04f,
7.15133271e-04f, 8.47838855e-04f, 1.00032516e-03f, 1.17508881e-03f, 1.37452550e-03f, 1.60147614e-03f,
1.85886458e-03f, 2.14985024e-03f, 2.47783071e-03f, 2.84666764e-03f, 3.26016878e-03f, 3.72252797e-03f,
4.23825900e-03f, 4.81207874e-03f, 5.44904143e-03f, 6.15447208e-03f, 6.93399929e-03f, 7.79337059e-03f,
8.73903392e-03f, 9.77729117e-03f, 1.09149561e-02f, 1.21591316e-02f, 1.35171164e-02f, 1.49965439e-02f,
1.66053136e-02f, 1.83515384e-02f, 2.02435362e-02f, 2.22899141e-02f, 2.44995340e-02f, 2.68813362e-02f,
2.94443254e-02f, 3.21979928e-02f, 3.51514690e-02f, 3.83143719e-02f, 4.16960560e-02f, 4.53060504e-02f,
4.91538115e-02f, 5.32486197e-02f, 5.75998650e-02f, 6.22164253e-02f, 6.71072811e-02f, 7.22809789e-02f,
7.77457552e-02f, 8.35095233e-02f, 8.95796944e-02f, 9.59631768e-02f, 1.02666457e-01f, 1.09695215e-01f,
1.17054591e-01f, 1.24748885e-01f, 1.32781656e-01f, 1.41155521e-01f, 1.49872243e-01f, 1.58932534e-01f,
1.68335961e-01f, 1.78081143e-01f, 1.88165339e-01f, 1.98584621e-01f, 2.09333789e-01f, 2.20406193e-01f,
2.31793899e-01f, 2.43487398e-01f, 2.55475740e-01f, 2.67746404e-01f, 2.80285305e-01f, 2.93076743e-01f,
3.06103423e-01f, 3.19346351e-01f, 3.32784916e-01f, 3.46396772e-01f, 3.60158039e-01f, 3.74043042e-01f,
3.88024564e-01f, 4.02073759e-01f, 4.16160177e-01f, 4.30251886e-01f, 4.44315429e-01f, 4.58315954e-01f,
4.72217175e-01f, 4.85981675e-01f, 4.99570709e-01f, 5.12944586e-01f, 5.26062401e-01f, 5.38882630e-01f,
5.51362766e-01f, 5.63459860e-01f, 5.75130384e-01f, 5.86330458e-01f, 5.97016050e-01f, 6.07143161e-01f,
6.16667840e-01f, 6.25546499e-01f, 6.33735979e-01f, 6.41193959e-01f, 6.47878856e-01f, 6.53750084e-01f,
6.58768549e-01f, 6.62896349e-01f, 6.66097381e-01f, 6.68337353e-01f, 6.69583869e-01f, 6.69807061e-01f,
6.68979117e-01f, 6.67075139e-01f, 6.64072812e-01f, 6.59952827e-01f, 6.54699116e-01f, 6.48298688e-01f,
6.40742160e-01f, 6.32023668e-01f, 6.22141039e-01f, 6.11095903e-01f, 5.98893921e-01f, 5.85544600e-01f,
5.71061707e-01f, 5.55463040e-01f, 5.38770639e-01f, 5.21010762e-01f, 5.02213839e-01f, 4.82414572e-01f,
4.61651859e-01f, 4.39968628e-01f, 4.17412000e-01f, 3.94032951e-01f, 3.69886464e-01f, 3.45031084e-01f,
3.19529091e-01f, 2.93446187e-01f, 2.66851164e-01f, 2.39815999e-01f, 2.12415399e-01f, 1.84726660e-01f,
1.56829293e-01f, 1.28804933e-01f, 1.00736965e-01f, 7.27100355e-02f, 4.48100810e-02f, 1.71237415e-02f,
-1.02620228e-02f, -3.72599591e-02f, -6.37832871e-02f, -8.97457733e-02f, -1.15062201e-01f, -1.39648782e-01f,
-1.63423488e-01f, -1.86306368e-01f, -2.08220103e-01f, -2.29090072e-01f, -2.48845046e-01f, -2.67417270e-01f,
-2.84742946e-01f, -3.00762597e-01f, -3.15421127e-01f, -3.28668542e-01f, -3.40459849e-01f, -3.50755400e-01f,
-3.59521402e-01f, -3.66729768e-01f, -3.72358475e-01f, -3.76391839e-01f, -3.78820421e-01f, -3.79641287e-01f,
-3.78858203e-01f, -3.76481336e-01f, -3.72527677e-01f, -3.67020780e-01f, -3.59990760e-01f, -3.51474372e-01f,
-3.41514630e-01f, -3.30160971e-01f, -3.17468898e-01f, -3.03499788e-01f, -2.88320749e-01f, -2.72004315e-01f,
-2.54628056e-01f, -2.36274454e-01f, -2.17030464e-01f, -1.96986952e-01f, -1.76238733e-01f, -1.54883647e-01f,
-1.33022496e-01f, -1.10758449e-01f, -8.81964466e-02f, -6.54430504e-02f, -4.26055475e-02f, -1.97916415e-02f,
2.89108184e-03f, 2.53355868e-02f, 4.74362201e-02f, 6.90887518e-02f, 9.01914308e-02f, 1.10644978e-01f,
1.30353494e-01f, 1.49224772e-01f, 1.67170735e-01f, 1.84107975e-01f, 1.99958067e-01f, 2.14648181e-01f,
2.28111323e-01f, 2.40286622e-01f, 2.51119890e-01f, 2.60563701e-01f, 2.68577740e-01f, 2.75129027e-01f,
2.80192144e-01f, 2.83749177e-01f, 2.85790223e-01f, 2.86312986e-01f, 2.85323221e-01f, 2.82834421e-01f,
2.78867915e-01f, 2.73452721e-01f, 2.66625431e-01f, 2.58429983e-01f, 2.48917457e-01f, 2.38145826e-01f,
2.26179680e-01f, 2.13089734e-01f, 1.98952740e-01f, 1.83850758e-01f, 1.67870897e-01f, 1.51104879e-01f,
1.33648388e-01f, 1.15600665e-01f, 9.70639763e-02f, 7.81429119e-02f, 5.89439889e-02f, 3.95749746e-02f,
2.01442353e-02f, 7.60241152e-04f, -1.84690990e-02f, -3.74370397e-02f, -5.60385970e-02f, -7.41711039e-02f,
-9.17348686e-02f, -1.08633632e-01f, -1.24775254e-01f, -1.40071993e-01f, -1.54441372e-01f, -1.67806284e-01f,
-1.80095654e-01f, -1.91244732e-01f, -2.01195605e-01f, -2.09897310e-01f, -2.17306320e-01f, -2.23386736e-01f,
-2.28110407e-01f, -2.31457193e-01f, -2.33415044e-01f, -2.33980051e-01f, -2.33156463e-01f, -2.30956673e-01f,
-2.27401097e-01f, -2.22518148e-01f, -2.16343899e-01f, -2.08921985e-01f, -2.00303365e-01f, -1.90545790e-01f,
-1.79713804e-01f, -1.67877977e-01f, -1.55114789e-01f, -1.41505907e-01f, -1.27137921e-01f, -1.12101628e-01f,
-9.64915640e-02f, -8.04054232e-02f, -6.39434707e-02f, -4.72078814e-02f, -3.03021635e-02f, -1.33305082e-02f,
3.60284977e-03f, 2.03942507e-02f, 3.69413014e-02f, 5.31433810e-02f, 6.89024656e-02f, 8.41234679e-02f,
9.87150268e-02f, 1.12589969e-01f, 1.25665865e-01f, 1.37865538e-01f, 1.49117506e-01f, 1.59356490e-01f,
1.68523664e-01f, 1.76567229e-01f, 1.83442499e-01f, 1.89112308e-01f, 1.93547212e-01f, 1.96725586e-01f,
1.98633878e-01f, 1.99266486e-01f, 1.98625999e-01f, 1.96723008e-01f, 1.93576075e-01f, 1.89211557e-01f,
1.83663562e-01f, 1.76973516e-01f, 1.69190033e-01f, 1.60368490e-01f, 1.50570805e-01f, 1.39864815e-01f,
1.28324021e-01f, 1.16026978e-01f, 1.03056879e-01f, 8.95008829e-02f, 7.54496798e-02f, 6.09968238e-02f,
4.62380664e-02f, 3.12708901e-02f, 1.61936956e-02f, 1.10531988e-03f, -1.38957653e-02f, -2.87119784e-02f,
-4.32472742e-02f, -5.74078385e-02f, -7.11026311e-02f, -8.42439713e-02f, -9.67481917e-02f, -1.08536049e-01f,
-1.19533350e-01f, -1.29671345e-01f, -1.38887238e-01f, -1.47124498e-01f, -1.54333373e-01f, -1.60470968e-01f,
-1.65501755e-01f, -1.69397631e-01f, -1.72138140e-01f, -1.73710602e-01f, -1.74110159e-01f, -1.73339798e-01f,
-1.71410274e-01f, -1.68340111e-01f, -1.64155335e-01f, -1.58889414e-01f, -1.52582850e-01f, -1.45283122e-01f,
-1.37044042e-01f, -1.27925722e-01f, -1.17993860e-01f, -1.07319421e-01f, -9.59781808e-02f, -8.40500777e-02f,
-7.16188049e-02f, -5.87710561e-02f, -4.55961475e-02f, -3.21851919e-02f, -1.86306406e-02f, -5.02554942e-03f,
8.53698384e-03f, 2.19645467e-02f, 3.51659468e-02f, 4.80518693e-02f, 6.05355056e-02f, 7.25330700e-02f,
8.39645094e-02f, 9.47537898e-02f, 1.04829753e-01f, 1.14126254e-01f, 1.22582788e-01f, 1.30144907e-01f,
1.36764459e-01f, 1.42400029e-01f, 1.47017076e-01f, 1.50588312e-01f, 1.53093700e-01f, 1.54520736e-01f,
1.54864367e-01f, 1.54127119e-01f, 1.52318991e-01f, 1.49457408e-01f, 1.45567062e-01f, 1.40679709e-01f,
1.34833933e-01f, 1.28074855e-01f, 1.20453893e-01f, 1.12028129e-01f, 1.02860307e-01f, 9.30178765e-02f,
8.25730032e-02f, 7.16016450e-02f, 6.01833134e-02f, 4.84002546e-02f, 3.63370724e-02f, 2.40800037e-02f,
1.17163168e-02f, -6.66217400e-04f, -1.29801121e-02f, -2.51385315e-02f, -3.70562030e-02f, -4.86497748e-02f,
-5.98384928e-02f, -7.05447859e-02f, -8.06947592e-02f, -9.02187441e-02f, -9.90517313e-02f, -1.07133911e-01f,
-1.14410951e-01f, -1.20834483e-01f, -1.26362422e-01f, -1.30959116e-01f, -1.34595787e-01f, -1.37250547e-01f,
-1.38908600e-01f, -1.39562374e-01f, -1.39211442e-01f, -1.37862602e-01f, -1.35529795e-01f, -1.32233909e-01f,
-1.28002721e-01f, -1.22870611e-01f, -1.16878278e-01f, -1.10072477e-01f, -1.02505698e-01f, -9.42356124e-02f,
-8.53248753e-02f, -7.58404912e-02f, -6.58532924e-02f, -5.54376360e-02f, -4.46705953e-02f, -3.36315414e-02f,
-2.24015972e-02f, -1.10628991e-02f, 3.01894735e-04f, 1.16101918e-02f, 2.27801642e-02f, 3.37311642e-02f,
4.43845430e-02f, 5.46640016e-02f, 6.44962637e-02f, 7.38115400e-02f, 8.25440784e-02f, 9.06325572e-02f,
9.80206066e-02f, 1.04657146e-01f, 1.10496723e-01f, 1.15499920e-01f, 1.19633523e-01f, 1.22870824e-01f,
1.25191729e-01f, 1.26582959e-01f, 1.27038061e-01f, 1.26557494e-01f, 1.25148528e-01f, 1.22825305e-01f,
1.19608512e-01f, 1.15525479e-01f, 1.10609643e-01f, 1.04900592e-01f, 9.84435537e-02f, 9.12890948e-02f,
8.34927732e-02f, 7.51146973e-02f, 6.62190194e-02f, 5.68735547e-02f, 4.71491262e-02f, 3.71191855e-02f,
2.68591932e-02f, 1.64459573e-02f, 5.95731808e-03f, -4.52874940e-03f, -1.49344723e-02f, -2.51829130e-02f,
-3.51986373e-02f, -4.49081427e-02f, -5.42404654e-02f, -6.31276969e-02f, -7.15054163e-02f, -7.93132713e-02f,
-8.64953327e-02f, -9.30005042e-02f, -9.87829011e-02f, -1.03802223e-01f, -1.08023943e-01f, -1.11419636e-01f,
-1.13967111e-01f, -1.15650603e-01f, -1.16460855e-01f, -1.16395152e-01f, -1.15457368e-01f, -1.13657871e-01f,
-1.11013433e-01f, -1.07547117e-01f, -1.03288073e-01f, -9.82712708e-02f, -9.25372646e-02f, -8.61318657e-02f,
-7.91057486e-02f, -7.15141053e-02f, -6.34161588e-02f, -5.48747791e-02f, -4.59559696e-02f, -3.67282941e-02f,
-2.72624874e-02f, -1.76307914e-02f, -7.90648674e-03f, 1.83670340e-03f, 1.15251424e-02f, 2.10858716e-02f,
3.04471304e-02f, 3.95388944e-02f, 4.82933904e-02f, 5.66456655e-02f, 6.45340054e-02f, 7.19003487e-02f,
7.86908695e-02f, 8.48562395e-02f, 9.03519908e-02f, 9.51389501e-02f, 9.91834077e-02f, 1.02457361e-01f,
1.04938834e-01f, 1.06611872e-01f, 1.07466724e-01f, 1.07499917e-01f, 1.06714213e-01f, 1.05118588e-01f,
1.02728167e-01f, 9.95640680e-02f, 9.56532488e-02f, 9.10282406e-02f, 8.57269309e-02f, 7.97922261e-02f,
7.32717395e-02f, 6.62174249e-02f, 5.86850536e-02f, 5.07339959e-02f, 4.24265058e-02f, 3.38274345e-02f,
2.50036502e-02f, 1.60234844e-02f, 6.95628026e-03f, -2.12820655e-03f, -1.11602438e-02f, -2.00708281e-02f,
-2.87920337e-02f, -3.72576320e-02f, -4.54035426e-02f, -5.31684173e-02f, -6.04938939e-02f, -6.73253212e-02f,
-7.36119310e-02f, -7.93072981e-02f, -8.43697556e-02f, -8.87625537e-02f, -9.24542939e-02f, -9.54189981e-02f,
-9.76364402e-02f, -9.90921435e-02f, -9.97776003e-02f, -9.96902366e-02f, -9.88334463e-02f, -9.72165780e-02f,
-9.48547668e-02f, -9.17688999e-02f, -8.79853312e-02f, -8.35357688e-02f, -7.84569594e-02f, -7.27903677e-02f,
-6.65818940e-02f, -5.98814932e-02f, -5.27427333e-02f, -4.52224733e-02f, -3.73802459e-02f, -2.92780037e-02f,
-2.09794209e-02f, -1.25495498e-02f, -4.05425988e-03f, 4.44034349e-03f, 1.28682571e-02f, 2.11643361e-02f,
2.92645357e-02f, 3.71066200e-02f, 4.46305203e-02f, 5.17788267e-02f, 5.84972389e-02f, 6.47349496e-02f,
7.04450836e-02f, 7.55849928e-02f, 8.01165748e-02f, 8.40066506e-02f, 8.72270848e-02f, 8.97550618e-02f,
9.15732179e-02f, 9.26698315e-02f, 9.30387881e-02f, 9.26796720e-02f, 9.15978025e-02f, 8.98040443e-02f,
8.73148489e-02f, 8.41520461e-02f, 8.03426093e-02f, 7.59185468e-02f, 7.09165136e-02f, 6.53776255e-02f,
5.93470480e-02f, 5.28736293e-02f, 4.60095655e-02f, 3.88099545e-02f, 3.13323302e-02f, 2.36362162e-02f,
1.57827398e-02f, 7.83395091e-03f, -1.47413782e-04f, -8.09864153e-03f, -1.59574406e-02f, -2.36623595e-02f,
-3.11534717e-02f, -3.83725840e-02f, -4.52638947e-02f, -5.17743411e-02f, -5.78539729e-02f, -6.34564348e-02f,
-6.85392092e-02f, -7.30640654e-02f, -7.69971954e-02f, -8.03096220e-02f, -8.29772975e-02f, -8.49813524e-02f,
-8.63081836e-02f, -8.69495746e-02f, -8.69027157e-02f, -8.61702687e-02f, -8.47602668e-02f, -8.26860569e-02f,
-7.99661981e-02f, -7.66242997e-02f, -7.26887788e-02f, -6.81926752e-02f, -6.31733712e-02f, -5.76722279e-02f,
-5.17343061e-02f, -4.54080069e-02f, -3.87446321e-02f, -3.17980032e-02f, -2.46239897e-02f, -1.72801497e-02f,
-9.82518156e-03f, -2.31845300e-03f, 5.18037510e-03f, 1.26119044e-02f, 1.99174857e-02f, 2.70395921e-02f,
3.39223499e-02f, 4.05119404e-02f, 4.67570465e-02f, 5.26092142e-02f, 5.80232695e-02f, 6.29576539e-02f,
6.73747113e-02f, 7.12410320e-02f, 7.45276905e-02f, 7.72104218e-02f, 7.92698394e-02f, 8.06915952e-02f,
8.14664004e-02f, 8.15901977e-02f, 8.10640907e-02f, 7.98943315e-02f, 7.80922975e-02f, 7.56743792e-02f,
7.26617861e-02f, 6.90804346e-02f, 6.49606433e-02f, 6.03370049e-02f, 5.52479503e-02f, 4.97355660e-02f,
4.38451300e-02f, 3.76248662e-02f, 3.11254263e-02f, 2.43995757e-02f, 1.75017105e-02f, 1.04874823e-02f,
3.41321948e-03f, -3.66433362e-03f, -1.06886566e-02f, -1.76037566e-02f, -2.43547422e-02f, -3.08881238e-02f,
-3.71523818e-02f, -4.30982377e-02f, -4.86791529e-02f, -5.38515978e-02f, -5.85754991e-02f, -6.28144137e-02f,
-6.65359631e-02f, -6.97119559e-02f, -7.23186409e-02f, -7.43369897e-02f, -7.57526047e-02f, -7.65560812e-02f,
-7.67428560e-02f, -7.63134051e-02f, -7.52730583e-02f, -7.36321241e-02f, -7.14055927e-02f, -6.86132027e-02f,
-6.52791213e-02f, -6.14318004e-02f, -5.71037475e-02f, -5.23312158e-02f, -4.71539306e-02f, -4.16147519e-02f,
-3.57593331e-02f, -2.96357023e-02f, -2.32939478e-02f, -1.67857228e-02f, -1.01639251e-02f, -3.48213128e-03f,
3.20566951e-03f, 9.84566549e-03f, 1.63845318e-02f, 2.27699627e-02f, 2.89509937e-02f, 3.48784838e-02f,
4.05054571e-02f, 4.57875191e-02f, 5.06831561e-02f, 5.51541055e-02f, 5.91656321e-02f, 6.26867948e-02f,
6.56907214e-02f, 6.81547545e-02f, 7.00607045e-02f, 7.13948753e-02f, 7.21482790e-02f, 7.23165894e-02f,
7.19002973e-02f, 7.09044846e-02f, 6.93390331e-02f, 6.72183039e-02f, 6.45611568e-02f, 6.13906537e-02f,
5.77340810e-02f, 5.36223917e-02f, 4.90902973e-02f, 4.41756853e-02f, 3.89195025e-02f, 3.33653266e-02f,
2.75589553e-02f, 2.15482187e-02f, 1.53823433e-02f, 9.11173206e-03f, 2.78750380e-03f, -3.53899736e-03f,
-9.81648845e-03f, -1.59942887e-02f, -2.20226002e-02f, -2.78530676e-02f, -3.34389835e-02f, -3.87358558e-02f,
-4.37015752e-02f, -4.82968641e-02f, -5.24856104e-02f, -5.62350079e-02f, -5.95160314e-02f, -6.23034090e-02f,
-6.45760369e-02f, -6.63170246e-02f, -6.75138263e-02f, -6.81583864e-02f, -6.82471093e-02f, -6.77809819e-02f,
-6.67654439e-02f, -6.52104027e-02f, -6.31301405e-02f, -6.05431381e-02f, -5.74719510e-02f, -5.39430121e-02f,
-4.99864152e-02f, -4.56356108e-02f, -4.09271785e-02f, -3.59005358e-02f, -3.05975021e-02f, -2.50620982e-02f,
-1.93400931e-02f, -1.34786109e-02f, -7.52582921e-03f, -1.53047296e-03f, 4.45846396e-03f, 1.03922252e-02f,
1.62226043e-02f, 2.19024111e-02f, 2.73857927e-02f, 3.26286453e-02f, 3.75889120e-02f, 4.22270162e-02f,
4.65060678e-02f, 5.03922602e-02f, 5.38550360e-02f, 5.68673912e-02f, 5.94061299e-02f, 6.14518959e-02f,
6.29894927e-02f, 6.40078422e-02f, 6.45002081e-02f, 6.44641312e-02f, 6.39014463e-02f, 6.28183549e-02f,
6.12252434e-02f, 5.91366226e-02f, 5.65710713e-02f, 5.35509478e-02f, 5.01023211e-02f, 4.62546289e-02f,
4.20405644e-02f, 3.74956324e-02f, 3.26580309e-02f, 2.75681921e-02f, 2.22685138e-02f, 1.68029869e-02f,
1.12168479e-02f, 5.55616360e-03f, -1.32475496e-04f, -5.80242145e-03f, -1.14072870e-02f, -1.69013632e-02f,
-2.22399629e-02f, -2.73798231e-02f, -3.22793559e-02f, -3.68992177e-02f, -4.12022700e-02f, -4.51542301e-02f,
-4.87237130e-02f, -5.18825743e-02f, -5.46061242e-02f, -5.68733215e-02f, -5.86668721e-02f, -5.99735198e-02f,
-6.07838952e-02f, -6.10928895e-02f, -6.08993923e-02f, -6.02064781e-02f, -5.90213291e-02f, -5.73550887e-02f,
-5.52228853e-02f, -5.26435817e-02f, -4.96396897e-02f, -4.62371294e-02f, -4.24650256e-02f, -3.83554628e-02f,
-3.39432096e-02f, -2.92654225e-02f, -2.43613233e-02f, -1.92718970e-02f, -1.40395616e-02f, -8.70771728e-03f,
-3.32056777e-03f, 2.07744785e-03f, 7.44190391e-03f, 1.27287222e-02f, 1.78946228e-02f, 2.28975002e-02f,
2.76965843e-02f, 3.22530140e-02f, 3.65299534e-02f, 4.04930363e-02f, 4.41105069e-02f, 4.73536159e-02f,
5.01967201e-02f, 5.26175750e-02f, 5.45974724e-02f, 5.61213729e-02f, 5.71780843e-02f, 5.77601946e-02f,
5.78643759e-02f, 5.74910914e-02f, 5.66448597e-02f, 5.53340158e-02f, 5.35707338e-02f, 5.13708843e-02f,
4.87538683e-02f, 4.57425137e-02f, 4.23627999e-02f, 3.86437075e-02f, 3.46169024e-02f, 3.03165387e-02f,
2.57788894e-02f, 2.10421222e-02f, 1.61459251e-02f, 1.11311994e-02f, 6.03970466e-03f, 9.13695817e-04f,
-4.20433431e-03f, -9.27218149e-03f, -1.42480682e-02f, -1.90911878e-02f, -2.37618648e-02f, -2.82220093e-02f,
-3.24353766e-02f, -3.63678336e-02f, -3.99876924e-02f, -4.32659237e-02f, -4.61764207e-02f, -4.86961602e-02f,
-5.08054551e-02f, -5.24880386e-02f, -5.37312181e-02f, -5.45260166e-02f, -5.48671104e-02f, -5.47530531e-02f,
-5.41860463e-02f, -5.31721475e-02f, -5.17210363e-02f, -4.98459868e-02f, -4.75637647e-02f, -4.48944406e-02f,
-4.18612746e-02f, -3.84904206e-02f, -3.48107925e-02f, -3.08537797e-02f, -2.66529685e-02f, -2.22438695e-02f,
-1.76636682e-02f, -1.29507560e-02f, -8.14466071e-03f, -3.28544776e-03f, 1.58643018e-03f, 6.43050440e-03f,
1.12067405e-02f, 1.58756642e-02f, 2.03989020e-02f, 2.47393345e-02f, 2.88614617e-02f, 3.27317634e-02f,
3.63187992e-02f, 3.95936470e-02f, 4.25300387e-02f, 4.51045672e-02f, 4.72968940e-02f, 4.90899703e-02f,
5.04700047e-02f, 5.14267809e-02f, 5.19535643e-02f, 5.20472034e-02f, 5.17082287e-02f, 5.09406434e-02f,
4.97521048e-02f, 4.81537188e-02f, 4.61599131e-02f, 4.37884262e-02f, 4.10600706e-02f, 3.79985488e-02f,
3.46302622e-02f, 3.09841217e-02f, 2.70912412e-02f, 2.29847199e-02f, 1.86992847e-02f, 1.42711599e-02f,
9.73752669e-03f, 5.13643650e-03f, 5.06379454e-04f, -4.11408166e-03f, -8.68649476e-03f, -1.31729621e-02f,
-1.75363807e-02f, -2.17408089e-02f, -2.57516979e-02f, -2.95362143e-02f, -3.30635093e-02f, -3.63049622e-02f,
-3.92344048e-02f, -4.18283298e-02f, -4.40661418e-02f, -4.59301913e-02f, -4.74060505e-02f, -4.84825511e-02f,
-4.91518827e-02f, -4.94096235e-02f, -4.92548579e-02f, -4.86900251e-02f, -4.77210458e-02f, -4.63571741e-02f,
-4.46108878e-02f, -4.24979107e-02f, -4.00368564e-02f, -3.72492987e-02f, -3.41594108e-02f, -3.07938448e-02f,
-2.71814552e-02f, -2.33531198e-02f, -1.93413598e-02f, -1.51802063e-02f, -1.09048013e-02f, -6.55114338e-03f,
-2.15581014e-03f, 2.24443555e-03f, 6.61280814e-03f, 1.09129453e-02f, 1.51091980e-02f, 1.91667630e-02f,
2.30522168e-02f, 2.67335907e-02f, 3.01807365e-02f, 3.33655579e-02f, 3.62622051e-02f, 3.88473226e-02f,
4.11002204e-02f, 4.30030300e-02f, 4.45408790e-02f, 4.57019705e-02f, 4.64777109e-02f, 4.68627135e-02f,
4.68549093e-02f, 4.64554958e-02f, 4.56689373e-02f, 4.45029599e-02f, 4.29683919e-02f, 4.10791386e-02f,
3.88520159e-02f, 3.63066475e-02f, 3.34652385e-02f, 3.03523892e-02f, 2.69949681e-02f, 2.34217263e-02f,
1.96632025e-02f, 1.57513974e-02f, 1.17194459e-02f, 7.60145677e-03f, 3.43215481e-03f, -7.53454950e-04f,
-4.92025229e-03f, -9.03345904e-03f, -1.30587503e-02f, -1.69627406e-02f, -2.07130441e-02f, -2.42787472e-02f,
-2.76304969e-02f, -3.07408842e-02f, -3.35845310e-02f, -3.61384026e-02f, -3.83819804e-02f, -4.02973364e-02f,
-4.18693911e-02f, -4.30859849e-02f, -4.39379525e-02f, -4.44192202e-02f, -4.45268207e-02f, -4.42609489e-02f,
-4.36249417e-02f, -4.26251693e-02f, -4.12710965e-02f, -3.95751119e-02f, -3.75524034e-02f, -3.52209020e-02f,
-3.26010732e-02f, -2.97156826e-02f, -2.65897306e-02f, -2.32501339e-02f, -1.97255230e-02f, -1.60459906e-02f,
-1.22428645e-02f, -8.34840613e-03f, -4.39555788e-03f, -4.17641093e-04f, 3.55186529e-03f, 7.47969548e-03f,
1.13330289e-02f, 1.50796895e-02f, 1.86886063e-02f, 2.21298440e-02f, 2.53750227e-02f, 2.83974776e-02f,
3.11724713e-02f, 3.36774564e-02f, 3.58921485e-02f, 3.77988281e-02f, 3.93823848e-02f, 4.06304645e-02f,
4.15335460e-02f, 4.20850895e-02f, 4.22814530e-02f, 4.21220657e-02f, 4.16092724e-02f, 4.07484568e-02f,
3.95478256e-02f, 3.80185099e-02f, 3.61742882e-02f, 3.40316228e-02f, 3.16093467e-02f, 2.89286854e-02f,
2.60129143e-02f, 2.28872072e-02f, 1.95785162e-02f, 1.61151429e-02f, 1.25266872e-02f, 8.84367289e-03f,
5.09737541e-03f, 1.31946573e-03f, -2.45819207e-03f, -6.20382907e-03f, -9.88599514e-03f, -1.34739714e-02f,
-1.69377975e-02f, -2.02487225e-02f, -2.33793144e-02f, -2.63038233e-02f, -2.89981802e-02f, -3.14404213e-02f,
-3.36107546e-02f, -3.54916723e-02f, -3.70682427e-02f, -3.83280672e-02f, -3.92614736e-02f, -3.98615776e-02f,
-4.01243243e-02f, -4.00484517e-02f, -3.96356708e-02f, -3.88903731e-02f, -3.78198781e-02f, -3.64341365e-02f,
-3.47457457e-02f, -3.27698392e-02f, -3.05238882e-02f, -2.80276282e-02f, -2.53028218e-02f, -2.23730957e-02f,
-1.92637467e-02f, -1.60015029e-02f, -1.26142882e-02f, -9.13104283e-03f, -5.58138981e-03f, -1.99542434e-03f,
1.59649307e-03f, 5.16408174e-03f, 8.67737144e-03f, 1.21068581e-02f, 1.54239205e-02f, 1.86009100e-02f,
2.16114772e-02f, 2.44306994e-02f, 2.70354163e-02f, 2.94042665e-02f, 3.15179985e-02f, 3.33595356e-02f,
3.49141593e-02f, 3.61696229e-02f, 3.71161871e-02f, 3.77468512e-02f, 3.80571878e-02f, 3.80455485e-02f,
3.77129900e-02f, 3.70632810e-02f, 3.61028508e-02f, 3.48407199e-02f, 3.32884428e-02f, 3.14600053e-02f,
2.93716228e-02f, 2.70417408e-02f, 2.44907277e-02f, 2.17407576e-02f, 1.88156734e-02f, 1.57406803e-02f,
1.25421761e-02f, 9.24754692e-03f, 5.88488640e-03f, 2.48280587e-03f, -9.29864758e-04f, -4.32426314e-03f,
-7.67179184e-03f, -1.09442952e-02f, -1.41143886e-02f, -1.71555974e-02f, -2.00425787e-02f, -2.27514891e-02f,
-2.52599054e-02f, -2.75472706e-02f, -2.95949315e-02f, -3.13863062e-02f, -3.29069832e-02f, -3.41450096e-02f,
-3.50907101e-02f, -3.57369992e-02f, -3.60793163e-02f, -3.61156751e-02f, -3.58467080e-02f, -3.52755740e-02f,
-3.44080617e-02f, -3.32523628e-02f, -3.18191314e-02f, -3.01213186e-02f, -2.81740846e-02f, -2.59946393e-02f,
-2.36021125e-02f, -2.10173975e-02f, -1.82629132e-02f, -1.53624700e-02f, -1.23410560e-02f, -9.22456599e-03f,
-6.03967755e-03f, -2.81350877e-03f, 4.26514319e-04f, 3.65292660e-03f, 6.83848944e-03f, 9.95638508e-03f,
1.29804234e-02f, 1.58853076e-02f, 1.86468203e-02f, 2.12420277e-02f, 2.36494909e-02f, 2.58493792e-02f,
2.78237450e-02f, 2.95565060e-02f, 3.10338053e-02f, 3.22438572e-02f, 3.31772716e-02f, 3.38269627e-02f,
3.41883176e-02f, 3.42591610e-02f, 3.40397435e-02f, 3.35328606e-02f, 3.27436351e-02f, 3.16796573e-02f,
3.03507246e-02f, 2.87689689e-02f, 2.69484839e-02f, 2.49054827e-02f, 2.26579086e-02f, 2.02254442e-02f,
1.76292617e-02f, 1.48918382e-02f, 1.20368159e-02f, 9.08872468e-03f, 6.07283273e-03f, 3.01489838e-03f,
-5.90212194e-05f, -3.12287666e-03f, -6.15069532e-03f, -9.11695091e-03f, -1.19967033e-02f, -1.47657868e-02f,
-1.74011004e-02f, -1.98807214e-02f, -2.21841025e-02f, -2.42922632e-02f, -2.61879368e-02f, -2.78557311e-02f,
-2.92821801e-02f, -3.04559562e-02f, -3.13678907e-02f, -3.20110632e-02f, -3.23808087e-02f, -3.24749193e-02f,
-3.22933847e-02f, -3.18386269e-02f, -3.11153366e-02f, -3.01304804e-02f, -2.88932552e-02f, -2.74148734e-02f,
-2.57086673e-02f, -2.37898314e-02f, -2.16752343e-02f, -1.93835013e-02f, -1.69345799e-02f, -1.43497284e-02f,
-1.16513243e-02f, -8.86259097e-03f, -6.00748525e-03f, -3.11044903e-03f, -1.96143386e-04f, 2.71056658e-03f,
5.58512222e-03f, 8.40318833e-03f, 1.11410160e-02f, 1.37756382e-02f, 1.62850338e-02f, 1.86482666e-02f,
2.08457445e-02f, 2.28593437e-02f, 2.46725329e-02f, 2.62705694e-02f, 2.76405329e-02f, 2.87715470e-02f,
2.96547092e-02f, 3.02833419e-02f, 3.06529059e-02f, 3.07610441e-02f, 3.06076742e-02f, 3.01949567e-02f,
2.95271502e-02f, 2.86107876e-02f, 2.74543883e-02f, 2.60685701e-02f, 2.44657863e-02f, 2.26603655e-02f,
2.06682557e-02f, 1.85070033e-02f, 1.61954603e-02f, 1.37537720e-02f, 1.12030588e-02f, 8.56537064e-03f,
5.86336215e-03f, 3.12021752e-03f, 3.59345288e-04f, -2.39571357e-03f, -5.12158252e-03f, -7.79518527e-03f,
-1.03939536e-02f, -1.28961026e-02f, -1.52805838e-02f, -1.75275761e-02f, -1.96183935e-02f, -2.15357712e-02f,
-2.32639542e-02f, -2.47888545e-02f, -2.60981899e-02f, -2.71814567e-02f, -2.80302370e-02f, -2.86380088e-02f,
-2.90003996e-02f, -2.91151172e-02f, -2.89819544e-02f, -2.86028697e-02f, -2.79818317e-02f, -2.71249297e-02f,
-2.60401957e-02f, -2.47375751e-02f, -2.32288414e-02f, -2.15275091e-02f, -1.96486443e-02f, -1.76087964e-02f,
-1.54258426e-02f, -1.31187994e-02f, -1.07076937e-02f, -8.21335282e-03f, -5.65730582e-03f, -3.06143405e-03f,
-4.47990175e-04f, 2.16074548e-03f, 4.74260737e-03f, 7.27569124e-03f, 9.73864733e-03f, 1.21106824e-02f,
1.43719841e-02f, 1.65036001e-02f, 1.84878471e-02f, 2.03083286e-02f, 2.19500531e-02f, 2.33996493e-02f,
2.46453861e-02f, 2.56773512e-02f, 2.64874345e-02f, 2.70694463e-02f, 2.74192279e-02f, 2.75344951e-02f,
2.74150667e-02f, 2.70627089e-02f, 2.64811913e-02f, 2.56761950e-02f, 2.46553112e-02f, 2.34279326e-02f,
2.20051823e-02f, 2.03998041e-02f, 1.86260730e-02f, 1.66996483e-02f, 1.46373888e-02f, 1.24573628e-02f,
1.01784699e-02f, 7.82046099e-03f, 5.40366356e-03f, 2.94886537e-03f, 4.77074685e-04f, -1.99056008e-03f,
-4.43309957e-03f, -6.82975366e-03f, -9.16032780e-03f, -1.14051392e-02f, -1.35453571e-02f, -1.55631186e-02f,
-1.74416221e-02f, -1.91653203e-02f, -2.07200521e-02f, -2.20931290e-02f, -2.32734389e-02f, -2.42515770e-02f,
-2.50198790e-02f, -2.55724740e-02f, -2.59053977e-02f, -2.60165073e-02f, -2.59056121e-02f, -2.55744100e-02f,
-2.50263861e-02f, -2.42670139e-02f, -2.33034172e-02f, -2.21444752e-02f, -2.08007704e-02f, -1.92843016e-02f,
-1.76086143e-02f, -1.57885066e-02f, -1.38399632e-02f, -1.17800468e-02f, -9.62665505e-03f, -7.39846180e-03f,
-5.11473979e-03f, -2.79509520e-03f, -4.59475153e-04f, 1.87219411e-03f, 4.18004886e-03f, 6.44446028e-03f,
8.64630036e-03f, 1.07670050e-02f, 1.27887263e-02f, 1.46946183e-02f, 1.64687696e-02f, 1.80965074e-02f,
1.95644657e-02f, 2.08606409e-02f, 2.19745569e-02f, 2.28973400e-02f, 2.36217678e-02f, 2.41423032e-02f,
2.44552329e-02f, 2.45585559e-02f, 2.44521268e-02f, 2.41375247e-02f, 2.36181843e-02f, 2.28991883e-02f,
2.19873596e-02f, 2.08911372e-02f, 1.96204854e-02f, 1.81868423e-02f, 1.66029686e-02f, 1.48829260e-02f,
1.30418196e-02f, 1.10957823e-02f, 9.06176569e-03f, 6.95742371e-03f, 4.80095797e-03f, 2.61094572e-03f,
4.06163422e-04f, -1.79448120e-03f, -3.97227507e-03f, -6.10867089e-03f, -8.18559133e-03f, -1.01855447e-02f,
-1.20916775e-02f, -1.38880736e-02f, -1.55597947e-02f, -1.70929424e-02f, -1.84749792e-02f, -1.96945768e-02f,
-2.07419008e-02f, -2.16086011e-02f, -2.22879060e-02f, -2.27746496e-02f, -2.30653527e-02f, -2.31582122e-02f,
-2.30530853e-02f, -2.27516002e-02f, -2.22569518e-02f, -2.15740851e-02f, -2.07094459e-02f, -1.96710504e-02f,
-1.84683607e-02f, -1.71122258e-02f, -1.56147530e-02f, -1.39891960e-02f, -1.22499260e-02f, -1.04121226e-02f,
-8.49187069e-03f, -6.50583812e-03f, -4.47121574e-03f, -2.40553061e-03f, -3.26560349e-04f, 1.74792849e-03f,
3.80020986e-03f, 5.81284812e-03f, 7.76878436e-03f, 9.65152189e-03f, 1.14452321e-02f, 1.31348903e-02f,
1.47064602e-02f, 1.61469015e-02f, 1.74443880e-02f, 1.85883329e-02f, 1.95694960e-02f, 2.03800747e-02f,
2.10137416e-02f, 2.14657028e-02f, 2.17327470e-02f, 2.18132189e-02f, 2.17071096e-02f, 2.14159688e-02f,
2.09429396e-02f, 2.02927056e-02f, 1.94714591e-02f, 1.84867806e-02f, 1.73476996e-02f, 1.60644888e-02f,
1.46486021e-02f, 1.31126305e-02f, 1.14700918e-02f, 9.73543186e-03f, 7.92379251e-03f, 6.05090462e-03f,
4.13301608e-03f, 2.18669055e-03f, 2.28581333e-04f, -1.72441072e-03f, -3.65572200e-03f, -5.54887990e-03f,
-7.38782061e-03f, -9.15706782e-03f, -1.08417082e-02f, -1.24276657e-02f, -1.39017311e-02f, -1.52516970e-02f,
-1.64664949e-02f, -1.75361817e-02f, -1.84521823e-02f, -1.92071599e-02f, -1.97953056e-02f, -2.02121243e-02f,
-2.04547147e-02f, -2.05216098e-02f, -2.04128534e-02f, -2.01300439e-02f, -1.96761990e-02f, -1.90558123e-02f,
-1.82748056e-02f, -1.73404276e-02f, -1.62612067e-02f, -1.50469098e-02f, -1.37084115e-02f, -1.22575769e-02f,
-1.07072432e-02f, -9.07102930e-03f, -7.36320826e-03f, -5.59869147e-03f, -3.79270806e-03f, -1.96092013e-03f,
-1.19027325e-04f, 1.71713152e-03f, 3.53191747e-03f, 5.30986343e-03f, 7.03590331e-03f, 8.69547560e-03f,
1.02746006e-02f, 1.17601122e-02f, 1.31396009e-02f, 1.44016653e-02f, 1.55359973e-02f, 1.65332483e-02f,
1.73855033e-02f, 1.80859434e-02f, 1.86291305e-02f, 1.90110277e-02f, 1.92289384e-02f, 1.92815880e-02f,
1.91691688e-02f, 1.88932135e-02f, 1.84567183e-02f, 1.78639790e-02f, 1.71206377e-02f, 1.62336473e-02f,
1.52110920e-02f, 1.40622274e-02f, 1.27973510e-02f, 1.14277163e-02f, 9.96541843e-03f, 8.42333112e-03f,
6.81491991e-03f, 5.15420944e-03f, 3.45559138e-03f, 1.73374462e-03f, 3.49154958e-06f, -1.72033182e-03f,
-3.42300908e-03f, -5.09002877e-03f, -6.70728983e-03f, -8.26110592e-03f, -9.73843101e-03f, -1.11269177e-02f,
-1.24149972e-02f, -1.35920411e-02f, -1.46483675e-02f, -1.55754162e-02f, -1.63657097e-02f, -1.70130158e-02f,
-1.75123254e-02f, -1.78599156e-02f, -1.80533642e-02f, -1.80916471e-02f, -1.79749596e-02f, -1.77049199e-02f,
-1.72844059e-02f, -1.67175734e-02f, -1.60098348e-02f, -1.51677846e-02f, -1.41991369e-02f, -1.31126308e-02f,
-1.19180614e-02f, -1.06260158e-02f, -9.24795820e-03f, -7.79599691e-03f, -6.28282689e-03f, -4.72166017e-03f,
-3.12602130e-03f, -1.50971188e-03f, 1.13358008e-04f, 1.72924640e-03f, 3.32419869e-03f, 4.88457483e-03f,
6.39719332e-03f, 7.84928507e-03f, 9.22860374e-03f, 1.05236737e-02f, 1.17237027e-02f, 1.28187631e-02f,
1.37999219e-02f, 1.46591627e-02f, 1.53896448e-02f, 1.59855771e-02f, 1.64423748e-02f, 1.67566705e-02f,
1.69263151e-02f, 1.69504088e-02f, 1.68293192e-02f, 1.65646048e-02f, 1.61591292e-02f, 1.56168830e-02f,
1.49430466e-02f, 1.41438870e-02f, 1.32267343e-02f, 1.21999194e-02f, 1.10726150e-02f, 9.85491162e-03f,
8.55755480e-03f, 7.19198626e-03f, 5.77013714e-03f, 4.30443841e-03f, 2.80758857e-03f, 1.29252809e-03f,
-2.27683018e-04f, -1.74000213e-03f, -3.23153173e-03f, -4.68956247e-03f, -6.10171563e-03f, -7.45612506e-03f,
-8.74136426e-03f, -9.94672023e-03f, -1.10621909e-02f, -1.20785406e-02f, -1.29874795e-02f, -1.37816456e-02f,
-1.44546479e-02f, -1.50012468e-02f, -1.54172106e-02f, -1.56995155e-02f, -1.58462779e-02f, -1.58567437e-02f,
-1.57313825e-02f, -1.54717967e-02f, -1.50807184e-02f, -1.45620705e-02f, -1.39207297e-02f, -1.31627253e-02f,
-1.22950111e-02f, -1.13254027e-02f, -1.02626834e-02f, -9.11627932e-03f, -7.89634415e-03f, -6.61364765e-03f,
-5.27939952e-03f, -3.90525708e-03f, -2.50314317e-03f, -1.08517576e-03f, 3.36418391e-04f, 1.74945190e-03f,
3.14186033e-03f, 4.50178261e-03f, 5.81769448e-03f, 7.07851939e-03f, 8.27365386e-03f, 9.39310326e-03f,
1.04276320e-02f, 1.13686527e-02f, 1.22085379e-02f, 1.29404450e-02f, 1.35585678e-02f, 1.40580446e-02f,
1.44350939e-02f, 1.46869568e-02f, 1.48120098e-02f, 1.48096348e-02f, 1.46804295e-02f, 1.44259781e-02f,
1.40489668e-02f, 1.35531325e-02f, 1.29432014e-02f, 1.22248563e-02f, 1.14046959e-02f, 1.04901687e-02f,
9.48948107e-03f, 8.41156632e-03f, 7.26596347e-03f, 6.06280447e-03f, 4.81257444e-03f, 3.52622627e-03f,
2.21492506e-03f, 8.89983592e-04f, -4.37153812e-04f, -1.75513167e-03f, -3.05265494e-03f, -4.31872834e-03f,
-5.54261874e-03f, -6.71396264e-03f, -7.82302244e-03f, -8.86045250e-03f, -9.81773278e-03f, -1.06869351e-02f,
-1.14610023e-02f, -1.21336754e-02f, -1.26995953e-02f, -1.31543908e-02f, -1.34945718e-02f, -1.37177266e-02f,
-1.38224110e-02f, -1.38082286e-02f, -1.36757739e-02f, -1.34266887e-02f, -1.30635886e-02f, -1.25900369e-02f,
-1.20105709e-02f, -1.13305978e-02f, -1.05563538e-02f, -9.69485926e-03f, -8.75389081e-03f, -7.74181164e-03f,
-6.66761679e-03f, -5.54076187e-03f, -4.37111830e-03f, -3.16893052e-03f, -1.94457115e-03f, -7.08705149e-04f,
5.28079290e-04f, 1.75515870e-03f, 2.96204304e-03f, 4.13848585e-03f, 5.27451557e-03f, 6.36060039e-03f,
7.38755863e-03f, 8.34692530e-03f, 9.23070802e-03f, 1.00316534e-02f, 1.07432528e-02f, 1.13597680e-02f,
1.18763350e-02f, 1.22889283e-02f, 1.25944631e-02f, 1.27907515e-02f, 1.28765994e-02f, 1.28517102e-02f,
1.27167966e-02f, 1.24734480e-02f, 1.21242371e-02f, 1.16725839e-02f, 1.11228281e-02f, 1.04800592e-02f,
9.75022575e-03f, 8.93990424e-03f, 8.05644990e-03f, 7.10768601e-03f, 6.10205625e-03f, 5.04843878e-03f,
3.95605458e-03f, 2.83441418e-03f, 1.69331277e-03f, 5.42568186e-04f, -6.07877124e-04f, -1.74818575e-03f,
-2.86860405e-03f, -3.95962685e-03f, -5.01201657e-03f, -6.01690058e-03f, -6.96589716e-03f, -7.85110424e-03f,
-8.66518231e-03f, -9.40145619e-03f, -1.00540095e-02f, -1.06175123e-02f, -1.10876024e-02f, -1.14606062e-02f,
-1.17337519e-02f, -1.19051415e-02f, -1.19737311e-02f, -1.19393909e-02f, -1.18028751e-02f, -1.15657387e-02f,
-1.12305357e-02f, -1.08005049e-02f, -1.02797519e-02f, -9.67318729e-03f, -8.98632838e-03f, -8.22543877e-03f,
-7.39737215e-03f, -6.50950785e-03f, -5.56975395e-03f, -4.58632875e-03f, -3.56792674e-03f, -2.52340823e-03f,
-1.46183597e-03f, -3.92391156e-04f, 6.75701684e-04f, 1.73331709e-03f, 2.77141530e-03f, 3.78118353e-03f,
4.75407672e-03f, 5.68193005e-03f, 6.55698994e-03f, 7.37195674e-03f, 8.12013345e-03f, 8.79539509e-03f,
9.39225030e-03f, 9.90597190e-03f, 1.03324819e-02f, 1.06685242e-02f, 1.09116177e-02f, 1.10600973e-02f,
1.11130936e-02f, 1.10705983e-02f, 1.09333788e-02f, 1.07030445e-02f, 1.03819949e-02f, 9.97335332e-03f,
9.48107464e-03f, 8.90968434e-03f, 8.26449756e-03f, 7.55132972e-03f, 6.77664458e-03f, 5.94731079e-03f,
5.07073939e-03f, 4.15462520e-03f, 3.20700306e-03f, 2.23616222e-03f, 1.25050340e-03f, 2.58592562e-04f,
-7.31105992e-04f, -1.71003848e-03f, -2.66991104e-03f, -3.60254805e-03f, -4.50009626e-03f, -5.35500152e-03f,
-6.16013372e-03f, -6.90880302e-03f, -7.59484887e-03f, -8.21267759e-03f, -8.75730297e-03f, -9.22437062e-03f,
-9.61022818e-03f, -9.91196266e-03f, -1.01273334e-02f, -1.02549146e-02f, -1.02939949e-02f, -1.02446487e-02f,
-1.01077102e-02f, -9.88473930e-03f, -9.57804506e-03f, -9.19065219e-03f, -8.72623997e-03f, -8.18914967e-03f,
-7.58431711e-03f, -6.91725624e-03f, -6.19393169e-03f, -5.42085678e-03f, -4.60486090e-03f, -3.75314479e-03f,
-2.87318400e-03f, -1.97263669e-03f, -1.05936420e-03f, -1.41184633e-04f, 7.73935206e-04f, 1.67818033e-03f,
2.56387121e-03f, 3.42348245e-03f, 4.24972968e-03f, 5.03575853e-03f, 5.77493594e-03f, 6.46117800e-03f,
7.08885263e-03f, 7.65282423e-03f, 8.14856911e-03f, 8.57214716e-03f, 8.92027019e-03f, 9.19029194e-03f,
9.38027470e-03f, 9.48895025e-03f, 9.51578399e-03f, 9.46091429e-03f, 9.32518284e-03f, 9.11016180e-03f,
8.81806173e-03f, 8.45171440e-03f, 8.01466407e-03f, 7.51094572e-03f, 6.94521826e-03f, 6.32261691e-03f,
5.64875255e-03f, 4.92963671e-03f, 4.17165548e-03f, 3.38149573e-03f, 2.56610069e-03f, 1.73253154e-03f,
8.88083719e-04f, 4.00140997e-05f, -8.04377007e-04f, -1.63786496e-03f, -2.45336348e-03f, -3.24394120e-03f,
-4.00297149e-03f, -4.72406012e-03f, -5.40122825e-03f, -6.02886353e-03f, -6.60184564e-03f, -7.11547043e-03f,
-7.56567204e-03f, -7.94886879e-03f, -8.26207948e-03f, -8.50298133e-03f, -8.66984745e-03f, -8.76158174e-03f,
-8.77778600e-03f, -8.71866903e-03f, -8.58510255e-03f, -8.37858953e-03f, -8.10125332e-03f, -7.75580633e-03f,
-7.34555568e-03f, -6.87431135e-03f, -6.34642360e-03f, -5.76669768e-03f, -5.14031767e-03f, -4.47294897e-03f,
-3.77043291e-03f, -3.03903272e-03f, -2.28511456e-03f, -1.51527024e-03f, -7.36178447e-04f, 4.54225562e-05f,
8.22859022e-04f, 1.58943109e-03f, 2.33866278e-03f, 3.06420334e-03f, 3.75990680e-03f, 4.42002538e-03f,
5.03901750e-03f, 5.61180111e-03f, 6.13366220e-03f, 6.60043272e-03f, 7.00831931e-03f, 7.35414500e-03f,
7.63524392e-03f, 7.84953557e-03f, 7.99547645e-03f, 8.07218955e-03f, 8.07933095e-03f, 8.01721906e-03f,
7.88666864e-03f, 7.68919343e-03f, 7.42679720e-03f, 7.10202788e-03f, 6.71802523e-03f, 6.27832934e-03f,
5.78702253e-03f, 5.24853339e-03f, 4.66776048e-03f, 4.04985033e-03f, 3.40032055e-03f, 2.72486114e-03f,
2.02943382e-03f, 1.32005555e-03f, 6.02922229e-04f, -1.15810889e-04f, -8.29962401e-04f, -1.53344695e-03f,
-2.22024937e-03f, -2.88460828e-03f, -3.52090915e-03f, -4.12386103e-03f, -4.68844782e-03f, -5.21000854e-03f,
-5.68433641e-03f, -6.10753890e-03f, -6.47629357e-03f, -6.78770430e-03f, -7.03936807e-03f, -7.22944790e-03f,
-7.35662441e-03f, -7.42012069e-03f, -7.41971164e-03f, -7.35573757e-03f, -7.22905724e-03f, -7.04107429e-03f,
-6.79370122e-03f, -6.48940038e-03f, -6.13102314e-03f, -5.72192873e-03f, -5.26590521e-03f, -4.76707464e-03f,
-4.22993214e-03f, -3.65930825e-03f, -3.06022345e-03f, -2.43797793e-03f, -1.79803310e-03f, -1.14594988e-03f,
-4.87389180e-04f, 1.71985886e-04f, 8.26505744e-04f, 1.47057292e-03f, 2.09875564e-03f, 2.70572827e-03f,
3.28638788e-03f, 3.83592350e-03f, 4.34975506e-03f, 4.82368759e-03f, 5.25383132e-03f, 5.63677359e-03f,
5.96942535e-03f, 6.24924092e-03f, 6.47405650e-03f, 6.64226721e-03f, 6.75269253e-03f, 6.80469430e-03f,
6.79815717e-03f, 6.73340631e-03f, 6.61130455e-03f, 6.43322863e-03f, 6.20094526e-03f, 5.91677710e-03f,
5.58340169e-03f, 5.20393196e-03f, 4.78187614e-03f, 4.32106320e-03f, 3.82565711e-03f, 3.30005613e-03f,
2.74895362e-03f, 2.17719303e-03f, 1.58978015e-03f, 9.91844057e-04f, 3.88540330e-04f, -2.14916878e-04f,
-8.13361192e-04f, -1.40168257e-03f, -1.97489740e-03f, -2.52818059e-03f, -3.05688539e-03f, -3.55662656e-03f,
-4.02326574e-03f, -4.45296958e-03f, -4.84228652e-03f, -5.18803438e-03f, -5.48755315e-03f, -5.73848611e-03f,
-5.93891991e-03f, -6.08745626e-03f, -6.18305471e-03f, -6.22520840e-03f, -6.21382472e-03f, -6.14928419e-03f,
-6.03244633e-03f, -5.86455879e-03f, -5.64736180e-03f, -5.38296537e-03f, -5.07389363e-03f, -4.72301916e-03f,
-4.33361321e-03f, -3.90915761e-03f, -3.45353173e-03f, -2.97077347e-03f, -2.46516689e-03f, -1.94119584e-03f,
-1.40340595e-03f, -8.56512644e-04f, -3.05232133e-04f, 2.45691031e-04f, 7.91538060e-04f, 1.32763724e-03f,
1.84949345e-03f, 2.35267547e-03f, 2.83299113e-03f, 3.28645035e-03f, 3.70931698e-03f, 4.09812665e-03f,
4.44973511e-03f, 4.76135341e-03f, 5.03050354e-03f, 5.25513155e-03f, 5.43353323e-03f, 5.56447821e-03f,
5.64705544e-03f, 5.68083601e-03f, 5.66583437e-03f, 5.60238431e-03f, 5.49135375e-03f, 5.33391723e-03f,
5.13169207e-03f, 4.88664671e-03f, 4.60113202e-03f, 4.27780860e-03f, 3.91964875e-03f, 3.52989866e-03f,
3.11212090e-03f, 2.66999053e-03f, 2.20744344e-03f, 1.72859110e-03f, 1.23756351e-03f, 7.38678150e-04f,
2.36236760e-04f, -2.65462378e-04f, -7.62072815e-04f, -1.24943395e-03f, -1.72337956e-03f, -2.17993754e-03f,
-2.61530935e-03f, -3.02588421e-03f, -3.40825196e-03f, -3.75935360e-03f, -4.07630652e-03f, -4.35660760e-03f,
-4.59808398e-03f, -4.79883718e-03f, -4.95743843e-03f, -5.07271280e-03f, -5.14393833e-03f, -5.17077608e-03f,
-5.15318763e-03f, -5.09164480e-03f, -4.98686807e-03f, -4.84002285e-03f, -4.65260103e-03f, -4.42642977e-03f,
-4.16366446e-03f, -3.86678300e-03f, -3.53847751e-03f, -3.18177292e-03f, -2.79986847e-03f, -2.39618401e-03f,
-1.97429017e-03f, -1.53788782e-03f, -1.09083664e-03f, -6.36973406e-04f, -1.80264329e-04f, 2.75399352e-04f,
7.26104424e-04f, 1.16802598e-03f, 1.59744046e-03f, 2.01073128e-03f, 2.40446819e-03f, 2.77538562e-03f,
3.12044615e-03f, 3.43683203e-03f, 3.72202393e-03f, 3.97374850e-03f, 4.19002854e-03f, 4.36925418e-03f,
4.51006070e-03f, 4.61152219e-03f, 4.67293053e-03f, 4.69404975e-03f, 4.67490366e-03f, 4.61589307e-03f,
4.51775252e-03f, 4.38154991e-03f, 4.20868532e-03f, 4.00082377e-03f, 3.75997274e-03f, 3.48836415e-03f,
3.18851504e-03f, 2.86314343e-03f, 2.51519536e-03f, 2.14776743e-03f, 1.76411750e-03f, 1.36763070e-03f,
9.61751835e-04f, 5.50052405e-04f, 1.36015058e-04f, -2.76720943e-04f, -6.84698152e-04f, -1.08442387e-03f,
-1.47253691e-03f, -1.84578853e-03f, -2.20105818e-03f, -2.53544188e-03f, -2.84616998e-03f, -3.13076058e-03f,
-3.38689733e-03f, -3.61260297e-03f, -3.80606518e-03f, -3.96589267e-03f, -4.09087232e-03f, -4.18013173e-03f,
-4.23315965e-03f, -4.24970953e-03f, -4.22981560e-03f, -4.17392494e-03f, -4.08267808e-03f, -3.95709577e-03f,
-3.79845153e-03f, -3.60829670e-03f, -3.38844338e-03f, -3.14094669e-03f, -2.86809742e-03f, -2.57237442e-03f,
-2.25643831e-03f, -1.92312165e-03f, -1.57535841e-03f, -1.21624129e-03f, -8.48868370e-04f, -4.76457354e-04f,
-1.02227062e-04f, 2.70659894e-04f, 6.38948957e-04f, 9.99596773e-04f, 1.34950884e-03f, 1.68579412e-03f,
2.00565112e-03f, 2.30644176e-03f, 2.58570970e-03f, 2.84121989e-03f, 3.07087670e-03f, 3.27296771e-03f,
3.44584695e-03f, 3.58825627e-03f, 3.69915439e-03f, 3.77779535e-03f, 3.82369144e-03f, 3.83666312e-03f,
3.81678507e-03f, 3.76444486e-03f, 3.68027755e-03f, 3.56519883e-03f, 3.42038694e-03f, 3.24725992e-03f,
3.04745181e-03f, 2.82287635e-03f, 2.57555610e-03f, 2.30778342e-03f, 2.02193938e-03f, 1.72060684e-03f,
1.40642226e-03f, 1.08218540e-03f, 7.50708128e-04f, 4.14852040e-04f, 7.75468400e-05f, -2.58336678e-04f,
-5.89954675e-04f, -9.14464553e-04f, -1.22917409e-03f, -1.53142096e-03f, -1.81874942e-03f, -2.08875765e-03f,
-2.33925204e-03f, -2.56824046e-03f, -2.77387464e-03f, -2.95457151e-03f, -3.10891286e-03f, -3.23576957e-03f,
-3.33422309e-03f, -3.40361730e-03f, -3.44352432e-03f, -3.45380945e-03f, -3.43454926e-03f, -3.38612359e-03f,
-3.30910238e-03f, -3.20434413e-03f, -3.07289782e-03f, -2.91605448e-03f, -2.73534798e-03f, -2.53242439e-03f,
-2.30918427e-03f, -2.06766744e-03f, -1.81002532e-03f, -1.53857461e-03f, -1.25572213e-03f, -9.63956082e-04f,
-6.65804929e-04f, -3.63875198e-04f, -6.07622519e-05f, 2.40955893e-04f, 5.38685581e-04f, 8.29936911e-04f,
1.11224977e-03f, 1.38328230e-03f, 1.64080028e-03f, 1.88265574e-03f, 2.10694670e-03f, 2.31181334e-03f,
2.49567938e-03f, 2.65707799e-03f, 2.79477329e-03f, 2.90778929e-03f, 2.99526804e-03f, 3.05666792e-03f,
3.09159989e-03f, 3.09996074e-03f, 3.08183486e-03f, 3.03757314e-03f, 2.96768997e-03f, 2.87296391e-03f,
2.75438271e-03f, 2.61305979e-03f, 2.45041225e-03f, 2.26792371e-03f, 2.06728115e-03f, 1.85034398e-03f,
1.61901728e-03f, 1.37543970e-03f, 1.12168235e-03f, 8.60048928e-04f, 5.92781787e-04f, 3.22217129e-04f,
5.06437951e-05f, -2.19547817e-04f, -4.86132510e-04f, -7.46817210e-04f, -9.99443627e-04f, -1.24188233e-03f,
-1.47217245e-03f, -1.68839648e-03f, -1.88883105e-03f, -2.07184785e-03f, -2.23601745e-03f, -2.38006048e-03f,
-2.50288118e-03f, -2.60358292e-03f, -2.68144174e-03f, -2.73595307e-03f, -2.76679595e-03f, -2.77388624e-03f,
-2.75729794e-03f, -2.71735188e-03f, -2.65451985e-03f, -2.56952130e-03f, -2.46319204e-03f, -2.33660956e-03f,
-2.19096493e-03f, -2.02765268e-03f, -1.84815939e-03f, -1.65412932e-03f, -1.44731483e-03f, -1.22956426e-03f,
-1.00280075e-03f, -7.69022668e-04f, -5.30268510e-04f, -2.88586883e-04f, -4.60956253e-05f, 1.95186584e-04f,
4.33161045e-04f, 6.65873263e-04f, 8.91328897e-04f, 1.10770620e-03f, 1.31316296e-03f, 1.50610067e-03f,
1.68489795e-03f, 1.84814923e-03f, 1.99458512e-03f, 2.12304250e-03f, 2.23258384e-03f, 2.32237953e-03f,
2.39181962e-03f, 2.44043032e-03f, 2.46796938e-03f, 2.47430968e-03f, 2.45957831e-03f, 2.42401283e-03f,
2.36808884e-03f, 2.29238471e-03f, 2.19773378e-03f, 2.08501666e-03f, 1.95534528e-03f, 1.80993801e-03f,
1.65014053e-03f, 1.47739854e-03f, 1.29329221e-03f, 1.09944593e-03f, 8.97596290e-04f, 6.89486470e-04f,
4.76967544e-04f, 2.61847472e-04f, 4.59979030e-05f, -1.68770369e-04f, -3.80612759e-04f, -5.87744421e-04f,
-7.88452414e-04f, -9.81081718e-04f, -1.16402219e-03f, -1.33580811e-03f, -1.49504859e-03f, -1.64047131e-03f,
-1.77095587e-03f, -1.88548340e-03f, -1.98318254e-03f, -2.06335667e-03f, -2.12544333e-03f, -2.16903096e-03f,
-2.19389731e-03f, -2.19994674e-03f, -2.18726700e-03f, -2.15609170e-03f, -2.10683457e-03f, -2.04002290e-03f,
-1.95633800e-03f, -1.85665258e-03f, -1.74189023e-03f, -1.61313165e-03f, -1.47159921e-03f, -1.31856217e-03f,
-1.15541374e-03f, -9.83590913e-04f, -8.04645529e-04f, -6.20138811e-04f, -4.31664744e-04f, -2.40859759e-04f,
-4.93718861e-05f, 1.41183920e-04f, 3.29184443e-04f, 5.13049545e-04f, 6.91252710e-04f, 8.62329668e-04f,
1.02486089e-03f, 1.17753306e-03f, 1.31912530e-03f, 1.44851584e-03f, 1.56468190e-03f, 1.66675270e-03f,
1.75393226e-03f, 1.82562545e-03f, 1.88129935e-03f, 1.92062935e-03f, 1.94336360e-03f, 1.94946381e-03f,
1.93898469e-03f, 1.91211060e-03f, 1.86925265e-03f, 1.81081128e-03f, 1.73745800e-03f, 1.64989979e-03f,
1.54896085e-03f, 1.43565148e-03f, 1.31095906e-03f, 1.17607031e-03f, 1.03219054e-03f, 8.80596006e-04f,
7.22634695e-04f, 5.59715925e-04f, 3.93223384e-04f, 2.24602808e-04f, 5.53223372e-05f, -1.13204206e-04f,
-2.79527886e-04f, -4.42273875e-04f, -6.00090187e-04f, -7.51646708e-04f, -8.95738714e-04f, -1.03117771e-03f,
-1.15687770e-03f, -1.27187587e-03f, -1.37523688e-03f, -1.46618576e-03f, -1.54403989e-03f, -1.60825931e-03f,
-1.65836399e-03f, -1.69405240e-03f, -1.71514183e-03f, -1.72154028e-03f, -1.71331327e-03f, -1.69063272e-03f,
-1.65381037e-03f, -1.60326168e-03f, -1.53948863e-03f, -1.46318779e-03f, -1.37503217e-03f, -1.27591969e-03f,
-1.16672308e-03f, -1.04846883e-03f, -9.22232848e-04f, -7.89108246e-04f, -6.50329911e-04f, -5.07057241e-04f,
-3.60579584e-04f, -2.12138548e-04f, -6.30166060e-05f, 8.55107333e-05f, 2.32212191e-04f, 3.75851456e-04f,
5.15213418e-04f, 6.49182851e-04f, 7.76642588e-04f, 8.96585347e-04f, 1.00803198e-03f, 1.11010987e-03f,
1.20203475e-03f, 1.28308439e-03f, 1.35268783e-03f, 1.41030687e-03f, 1.45558664e-03f, 1.48819124e-03f,
1.50798717e-03f, 1.51486502e-03f, 1.50888467e-03f, 1.49022209e-03f, 1.45906012e-03f, 1.41583581e-03f,
1.36095722e-03f, 1.29499749e-03f, 1.21859138e-03f, 1.13249419e-03f, 1.03745344e-03f, 9.34384957e-04f,
8.24209226e-04f, 7.07921644e-04f, 5.86535461e-04f, 4.61118668e-04f, 3.32797940e-04f, 2.02615430e-04f,
7.17560319e-05f, -5.87215139e-05f, -1.87700771e-04f, -3.14093799e-04f, -4.36855019e-04f, -5.54982470e-04f,
-6.67514567e-04f, -7.73539543e-04f, -8.72216549e-04f, -9.62754726e-04f, -1.04446836e-03f, -1.11673823e-03f,
-1.17901020e-03f, -1.23084835e-03f, -1.27191263e-03f, -1.30189831e-03f, -1.32066941e-03f, -1.32816613e-03f,
-1.32437715e-03f, -1.30944714e-03f, -1.28360668e-03f, -1.24710492e-03f, -1.20038313e-03f, -1.14391116e-03f,
-1.07822250e-03f, -1.00394823e-03f, -9.21799577e-04f, -8.32520513e-04f, -7.36916195e-04f, -6.35853312e-04f,
-5.30218398e-04f, -4.20950684e-04f, -3.08981087e-04f, -1.95310152e-04f, -8.08721649e-05f, 3.33481785e-05f,
1.46369769e-04f, 2.57271691e-04f, 3.65123878e-04f, 4.69053422e-04f, 5.68205019e-04f, 6.61777482e-04f,
7.49035427e-04f, 8.29295760e-04f, 9.01919035e-04f, 9.66370937e-04f, 1.02218113e-03f, 1.06892877e-03f,
1.10630552e-03f, 1.13406370e-03f, 1.15204451e-03f, 1.16019052e-03f, 1.15848806e-03f, 1.14706630e-03f,
1.12606449e-03f, 1.09574589e-03f, 1.05645362e-03f, 1.00859266e-03f, 9.52601766e-04f, 8.89057609e-04f,
8.18535938e-04f, 7.41697389e-04f, 6.59241262e-04f, 5.71884368e-04f, 4.80414698e-04f, 3.85677252e-04f,
2.88406796e-04f, 1.89536836e-04f, 8.98491837e-05f, -9.79888746e-06f, -1.08531507e-04f, -2.05575498e-04f,
-3.00092231e-04f, -3.91327952e-04f, -4.78537671e-04f, -5.61003964e-04f, -6.38090388e-04f, -7.09209697e-04f,
-7.73747838e-04f, -8.31297964e-04f, -8.81364804e-04f, -9.23641236e-04f, -9.57793553e-04f, -9.83624619e-04f,
-1.00098424e-03f, -1.00979404e-03f, -1.01003977e-03f, -1.00180772e-03f, -9.85219816e-04f, -9.60506778e-04f,
-9.27905874e-04f, -8.87790902e-04f, -8.40553609e-04f, -7.86632276e-04f, -7.26559669e-04f, -6.60872173e-04f,
-5.90177860e-04f, -5.15099219e-04f, -4.36341554e-04f, -3.54526447e-04f, -2.70436804e-04f, -1.84757234e-04f,
-9.82406108e-05f, -1.16228429e-05f, 7.44116225e-05f, 1.59099493e-04f, 2.41739119e-04f, 3.21707034e-04f,
3.98276352e-04f, 4.70887555e-04f, 5.38973046e-04f, 6.01940918e-04f, 6.59368174e-04f, 7.10783030e-04f,
7.55802336e-04f, 7.94127086e-04f, 8.25478803e-04f, 8.49639386e-04f, 8.66487952e-04f, 8.75935969e-04f,
8.77948893e-04f, 8.72611584e-04f, 8.59994515e-04f, 8.40271458e-04f, 8.13696181e-04f, 7.80491851e-04f,
7.41053306e-04f, 6.95727202e-04f, 6.44936090e-04f, 5.89181503e-04f, 5.28946796e-04f, 4.64790448e-04f,
3.97272420e-04f, 3.27000597e-04f, 2.54559578e-04f, 1.80597276e-04f, 1.05760446e-04f, 3.06209047e-05f,
-4.41172003e-05f, -1.17884760e-04f, -1.90032814e-04f, -2.60000039e-04f, -3.27213235e-04f, -3.91110007e-04f,
-4.51226928e-04f, -5.07042112e-04f, -5.58194586e-04f, -6.04189222e-04f, -6.44816381e-04f, -6.79653847e-04f,
-7.08557315e-04f, -7.31282579e-04f, -7.47702169e-04f, -7.57731688e-04f, -7.61359812e-04f, -7.58589885e-04f,
-7.49503361e-04f, -7.34226582e-04f, -7.12935677e-04f, -6.85882645e-04f, -6.53307567e-04f, -6.15569562e-04f,
-5.72978650e-04f, -5.25977418e-04f, -4.74963705e-04f, -4.20426590e-04f, -3.62819514e-04f, -3.02647353e-04f,
-2.40497241e-04f, -1.76810216e-04f, -1.12210871e-04f, -4.71976690e-05f, 1.76624641e-05f, 8.18440593e-05f,
1.44804207e-04f, 2.06021410e-04f, 2.65025446e-04f, 3.21327783e-04f, 3.74487008e-04f, 4.24062432e-04f,
4.69715655e-04f, 5.11042943e-04f, 5.47794530e-04f, 5.79655168e-04f, 6.06446384e-04f, 6.27934546e-04f,
6.44010762e-04f, 6.54614698e-04f, 6.59636425e-04f, 6.59157826e-04f, 6.53158826e-04f, 6.41794049e-04f,
6.25154916e-04f, 6.03470855e-04f, 5.76917242e-04f, 5.45789736e-04f, 5.10368292e-04f, 4.70998661e-04f,
4.28021656e-04f, 3.81834126e-04f, 3.32863326e-04f, 2.81489629e-04f, 2.28231239e-04f, 1.73484261e-04f,
1.17756607e-04f, 6.14881351e-05f, 5.17778269e-06f, -5.07352374e-05f, -1.05745987e-04f, -1.59454662e-04f,
-2.11394268e-04f, -2.61151905e-04f, -3.08351703e-04f, -3.52598590e-04f, -3.93545002e-04f, -4.30916147e-04f,
-4.64387406e-04f, -4.93756593e-04f, -5.18755281e-04f, -5.39265493e-04f, -5.55137934e-04f, -5.66259303e-04f,
-5.72606783e-04f, -5.74140344e-04f, -5.70903292e-04f, -5.62934741e-04f, -5.50388898e-04f, -5.33351962e-04f,
-5.12028510e-04f, -4.86612455e-04f, -4.57392981e-04f, -4.24578939e-04f, -3.88503808e-04f, -3.49487518e-04f,
-3.07895836e-04f, -2.64036522e-04f, -2.18356445e-04f, -1.71198300e-04f, -1.22998901e-04f, -7.41392080e-05f,
-2.50280393e-05f, 2.38852047e-05f, 7.22663332e-05f, 1.19659647e-04f, 1.65718806e-04f, 2.10055385e-04f,
2.52324173e-04f, 2.92190427e-04f, 3.29337577e-04f, 3.63510150e-04f, 3.94385715e-04f, 4.21803288e-04f,
4.45519433e-04f, 4.65391876e-04f, 4.81270460e-04f, 4.93057625e-04f, 5.00688030e-04f, 5.04121708e-04f,
5.03379627e-04f, 4.98485604e-04f, 4.89499566e-04f, 4.76539317e-04f, 4.59760023e-04f, 4.39274612e-04f,
4.15334876e-04f, 3.88103885e-04f, 3.57902146e-04f, 3.24908089e-04f, 2.89490480e-04f, 2.51922687e-04f,
2.12512220e-04f, 1.71637404e-04f, 1.29609890e-04f, 8.67866183e-05f, 4.35312276e-05f, 1.98808307e-07f,
-4.28589070e-05f, -8.52865394e-05f, -1.26765698e-04f, -1.66922292e-04f, -2.05456466e-04f, -2.42095652e-04f,
-2.76487494e-04f, -3.08425602e-04f, -3.37638832e-04f, -3.63923042e-04f, -3.87022898e-04f, -4.06875144e-04f,
-4.23245129e-04f, -4.36071615e-04f, -4.45236993e-04f, -4.50724682e-04f, -4.52491230e-04f, -4.50548104e-04f,
-4.44936790e-04f, -4.35725612e-04f, -4.22987381e-04f, -4.06882738e-04f, -3.87548587e-04f, -3.65123104e-04f,
-3.39860288e-04f, -3.11947486e-04f, -2.81618569e-04f, -2.49166817e-04f, -2.14824344e-04f, -1.78876370e-04f,
-1.41684861e-04f, -1.03466427e-04f, -6.45996088e-05f, -2.53738050e-05f, 1.39035721e-05f, 5.28977578e-05f,
9.13010773e-05f, 1.28809554e-04f, 1.65139924e-04f, 2.00005346e-04f, 2.33095696e-04f, 2.64232233e-04f,
2.93070034e-04f, 3.19508024e-04f, 3.43252648e-04f, 3.64165224e-04f, 3.82074036e-04f, 3.96868082e-04f,
4.08408250e-04f, 4.16671952e-04f, 4.21556517e-04f, 4.23035822e-04f, 4.21172111e-04f, 4.15928838e-04f,
4.07377025e-04f, 3.95568598e-04f, 3.80628038e-04f, 3.62729177e-04f, 3.41921136e-04f, 3.18489958e-04f,
2.92497406e-04f, 2.64266550e-04f, 2.33955571e-04f, 2.01809261e-04f, 1.68092145e-04f, 1.33141461e-04f,
9.71043460e-05f, 6.03452880e-05f, 2.31264055e-05f, -1.43105089e-05f, -5.15607083e-05f, -8.84833364e-05f,
-1.24679461e-04f, -1.59910519e-04f, -1.93952723e-04f, -2.26496145e-04f, -2.57307566e-04f, -2.86175538e-04f,
-3.12853472e-04f, -3.37140613e-04f, -3.58914997e-04f, -3.77932329e-04f, -3.94117065e-04f, -4.07317063e-04f,
-4.17422308e-04f, -4.24419479e-04f, -4.28161231e-04f, -4.28700484e-04f, -4.26016659e-04f, -4.20088126e-04f,
-4.11009185e-04f, -3.98835037e-04f, -3.83585114e-04f, -3.65493072e-04f, -3.44616197e-04f, -3.21064387e-04f,
-2.95119418e-04f, -2.66863117e-04f, -2.36549174e-04f, -2.04391686e-04f, -1.70585806e-04f, -1.35432614e-04f,
-9.91006984e-05f, -6.19152828e-05f, -2.41012311e-05f, 1.40621144e-05f, 5.22867497e-05f, 9.03199843e-05f,
1.27917614e-04f, 1.64740292e-04f, 2.00634478e-04f, 2.35261402e-04f, 2.68377430e-04f, 2.99818019e-04f,
3.29273634e-04f, 3.56562766e-04f, 3.81532332e-04f, 4.03948113e-04f, 4.23655375e-04f, 4.40488930e-04f,
4.54376777e-04f, 4.65137195e-04f, 4.72679704e-04f, 4.77014073e-04f, 4.77982201e-04f, 4.75625277e-04f,
4.69878507e-04f, 4.60802987e-04f, 4.48367418e-04f, 4.32641679e-04f, 4.13709630e-04f, 3.91634147e-04f,
3.66512902e-04f, 3.38481392e-04f, 3.07634938e-04f, 2.74189182e-04f, 2.38229594e-04f, 1.99985879e-04f,
1.59632210e-04f, 1.17351364e-04f, 7.33404728e-05f, 2.78844831e-05f, -1.89099461e-05f, -6.67343638e-05f,
-1.15367449e-04f, -1.64649983e-04f, -2.14224348e-04f, -2.64019844e-04f, -3.13654244e-04f, -3.62990333e-04f,
-4.11800705e-04f, -4.59821928e-04f, -5.06946486e-04f, -5.52847863e-04f, -5.97397068e-04f, -6.40454770e-04f,
-6.81765968e-04f, -7.21210131e-04f, -7.58634477e-04f, -7.93939572e-04f, -8.26964876e-04f, -8.57585335e-04f,
-8.85733438e-04f, -9.11351007e-04f, -9.34300512e-04f, -9.54617442e-04f, -9.72159416e-04f, -9.87012089e-04f,
-9.99095133e-04f, -1.00846242e-03f, -1.01506022e-03f, -1.01897105e-03f, -1.02021427e-03f, -1.01887259e-03f,
-1.01497557e-03f, -1.00861358e-03f, -9.99877741e-04f, -9.88823136e-04f, -9.75617693e-04f, -9.60303769e-04f,
-9.43035535e-04f, -9.23922797e-04f, -9.03105429e-04f, -8.80708716e-04f, -8.56853281e-04f, -8.31685264e-04f,
-8.05348207e-04f, -7.77961627e-04f, -7.49713086e-04f, -7.20674604e-04f, -6.91032783e-04f, -6.60888020e-04f,
-6.30372917e-04f, -5.99673349e-04f, -5.68830563e-04f, -5.38013304e-04f, -5.07353303e-04f, -4.76915043e-04f,
-4.46832926e-04f, -4.17179291e-04f, -3.88083307e-04f, -3.59575024e-04f, -3.31820735e-04f, -3.04804303e-04f,
-2.78616041e-04f, -2.53335964e-04f, -2.28986996e-04f, -2.05619529e-04f, -1.83318449e-04f, -1.61979425e-04f,
-1.41791423e-04f, -1.22648816e-04f, -1.04625498e-04f, -8.77122910e-05f, -7.18653457e-05f, -5.71787106e-05f,
-4.34807639e-05f, -3.09618857e-05f, -1.94074401e-05f, -8.88017971e-06f, 6.09625220e-07f, 9.14020334e-06f,
1.67805558e-05f, 2.35369965e-05f, 2.94278194e-05f, 3.45049751e-05f, 3.88373828e-05f, 4.24291966e-05f,
4.53445665e-05f, 4.76965834e-05f, 4.93395567e-05f, 5.05392111e-05f, 5.12257065e-05f, 5.14579340e-05f,
5.12651750e-05f, 5.07312551e-05f, 4.98486765e-05f, 4.87082573e-05f, 4.73439631e-05f, 4.56740817e-05f,
4.38653618e-05f, 4.19399075e-05f, 3.99125668e-05f, 3.77616021e-05f, 3.56135997e-05f, 3.33554815e-05f,
3.11656899e-05f, 2.89038150e-05f, 2.67281634e-05f, 2.46192762e-05f, 2.24899205e-05f, 2.04698700e-05f,
1.84927655e-05f, 1.66762886e-05f, 1.49393771e-05f, 1.32258081e-05f, 1.16985586e-05f, 1.01874391e-05f,
8.99882100e-06f, 7.61267073e-06f, 6.57702907e-06f, 5.59829210e-06f, 4.27698546e-06f, 1.03248674e-05f,
};

View file

@ -25,6 +25,8 @@
#include "AudioRingBuffer.h" #include "AudioRingBuffer.h"
#include "AudioLogging.h" #include "AudioLogging.h"
#include "AudioSRC.h"
#include "Sound.h" #include "Sound.h"
QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) { QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) {
@ -89,49 +91,22 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) {
// we want to convert it to the format that the audio-mixer wants // we want to convert it to the format that the audio-mixer wants
// which is signed, 16-bit, 24Khz // which is signed, 16-bit, 24Khz
int numSourceSamples = rawAudioByteArray.size() / sizeof(AudioConstants::AudioSample); int numChannels = _isStereo ? 2 : 1;
AudioSRC resampler(48000, AudioConstants::SAMPLE_RATE, numChannels);
if (_isStereo && numSourceSamples % 2 != 0){ // resize to max possible output
// in the unlikely case that we have stereo audio but we seem to be missing a sample int numSourceFrames = rawAudioByteArray.size() / (numChannels * sizeof(AudioConstants::AudioSample));
// (the sample for one channel is missing in a set of interleaved samples) int maxDestinationFrames = resampler.getMaxOutput(numSourceFrames);
// then drop the odd sample int maxDestinationBytes = maxDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
--numSourceSamples; _byteArray.resize(maxDestinationBytes);
}
int numDestinationSamples = numSourceSamples / 2.0f; int numDestinationFrames = resampler.render((int16_t*)rawAudioByteArray.data(),
(int16_t*)_byteArray.data(),
if (_isStereo && numDestinationSamples % 2 != 0) { numSourceFrames);
// if this is stereo we need to make sure we produce stereo output
// which means we should have an even number of output samples
numDestinationSamples += 1;
}
int numDestinationBytes = numDestinationSamples * sizeof(AudioConstants::AudioSample);
// truncate to actual output
int numDestinationBytes = numDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
_byteArray.resize(numDestinationBytes); _byteArray.resize(numDestinationBytes);
int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data();
int16_t* destinationSamples = (int16_t*) _byteArray.data();
if (_isStereo) {
for (int i = 0; i < numSourceSamples; i += 4) {
if (i + 2 >= numSourceSamples) {
destinationSamples[i / 2] = sourceSamples[i];
destinationSamples[(i / 2) + 1] = sourceSamples[i + 1];
} else {
destinationSamples[i / 2] = (sourceSamples[i] + sourceSamples[i + 2]) / 2;
destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] + sourceSamples[i + 3]) / 2;
}
}
} else {
for (int i = 1; i < numSourceSamples; i += 2) {
if (i + 1 >= numSourceSamples) {
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] + sourceSamples[i]) / 2;
} else {
destinationSamples[(i - 1) / 2] = ((sourceSamples[i - 1] + sourceSamples[i + 1]) / 4) + (sourceSamples[i] / 2);
}
}
}
} }
// //

View file

@ -0,0 +1,201 @@
//
// AudioSRC_avx2.cpp
// libraries/audio/src
//
// Created by Ken Cooke on 6/5/16.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
#include <assert.h>
#include <immintrin.h>
#include "../AudioSRC.h"
#ifndef __AVX2__
#error Must be compiled with /arch:AVX2 or -mavx2 -mfma.
#endif
// high/low part of int64_t
#define LO32(a) ((uint32_t)(a))
#define HI32(a) ((int32_t)((a) >> 32))
int AudioSRC::multirateFilter1_AVX2(const float* input0, float* output0, int inputFrames) {
int outputFrames = 0;
assert(_numTaps % 8 == 0); // SIMD8
if (_step == 0) { // rational
int32_t i = HI32(_offset);
while (i < inputFrames) {
const float* c0 = &_polyphaseFilter[_numTaps * _phase];
__m256 acc0 = _mm256_setzero_ps();
for (int j = 0; j < _numTaps; j += 8) {
//float coef = c0[j];
__m256 coef0 = _mm256_loadu_ps(&c0[j]);
//acc += input[i + j] * coef;
acc0 = _mm256_fmadd_ps(_mm256_loadu_ps(&input0[i + j]), coef0, acc0);
}
// horizontal sum
acc0 = _mm256_hadd_ps(acc0, acc0);
__m128 t0 = _mm_add_ps(_mm256_castps256_ps128(acc0), _mm256_extractf128_ps(acc0, 1));
t0 = _mm_add_ps(t0, _mm_movehdup_ps(t0));
_mm_store_ss(&output0[outputFrames], t0);
outputFrames += 1;
i += _stepTable[_phase];
if (++_phase == _upFactor) {
_phase = 0;
}
}
_offset = (int64_t)(i - inputFrames) << 32;
} else { // irrational
while (HI32(_offset) < inputFrames) {
int32_t i = HI32(_offset);
uint32_t f = LO32(_offset);
uint32_t phase = f >> SRC_FRACBITS;
float ftmp = (f & SRC_FRACMASK) * QFRAC_TO_FLOAT;
const float* c0 = &_polyphaseFilter[_numTaps * (phase + 0)];
const float* c1 = &_polyphaseFilter[_numTaps * (phase + 1)];
__m256 acc0 = _mm256_setzero_ps();
__m256 frac = _mm256_broadcast_ss(&ftmp);
for (int j = 0; j < _numTaps; j += 8) {
//float coef = c0[j] + frac * (c1[j] - c0[j]);
__m256 coef0 = _mm256_loadu_ps(&c0[j]);
__m256 coef1 = _mm256_loadu_ps(&c1[j]);
coef1 = _mm256_sub_ps(coef1, coef0);
coef0 = _mm256_fmadd_ps(coef1, frac, coef0);
//acc += input[i + j] * coef;
acc0 = _mm256_fmadd_ps(_mm256_loadu_ps(&input0[i + j]), coef0, acc0);
}
// horizontal sum
acc0 = _mm256_hadd_ps(acc0, acc0);
__m128 t0 = _mm_add_ps(_mm256_castps256_ps128(acc0), _mm256_extractf128_ps(acc0, 1));
t0 = _mm_add_ps(t0, _mm_movehdup_ps(t0));
_mm_store_ss(&output0[outputFrames], t0);
outputFrames += 1;
_offset += _step;
}
_offset -= (int64_t)inputFrames << 32;
}
_mm256_zeroupper();
return outputFrames;
}
int AudioSRC::multirateFilter2_AVX2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames) {
int outputFrames = 0;
assert(_numTaps % 8 == 0); // SIMD8
if (_step == 0) { // rational
int32_t i = HI32(_offset);
while (i < inputFrames) {
const float* c0 = &_polyphaseFilter[_numTaps * _phase];
__m256 acc0 = _mm256_setzero_ps();
__m256 acc1 = _mm256_setzero_ps();
for (int j = 0; j < _numTaps; j += 8) {
//float coef = c0[j];
__m256 coef0 = _mm256_loadu_ps(&c0[j]);
//acc += input[i + j] * coef;
acc0 = _mm256_fmadd_ps(_mm256_loadu_ps(&input0[i + j]), coef0, acc0);
acc1 = _mm256_fmadd_ps(_mm256_loadu_ps(&input1[i + j]), coef0, acc1);
}
// horizontal sum
acc0 = _mm256_hadd_ps(acc0, acc1);
__m128 t0 = _mm_add_ps(_mm256_castps256_ps128(acc0), _mm256_extractf128_ps(acc0, 1));
t0 = _mm_add_ps(t0, _mm_movehdup_ps(t0));
_mm_store_ss(&output0[outputFrames], t0);
_mm_store_ss(&output1[outputFrames], _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(0,0,0,2)));
outputFrames += 1;
i += _stepTable[_phase];
if (++_phase == _upFactor) {
_phase = 0;
}
}
_offset = (int64_t)(i - inputFrames) << 32;
} else { // irrational
while (HI32(_offset) < inputFrames) {
int32_t i = HI32(_offset);
uint32_t f = LO32(_offset);
uint32_t phase = f >> SRC_FRACBITS;
float ftmp = (f & SRC_FRACMASK) * QFRAC_TO_FLOAT;
const float* c0 = &_polyphaseFilter[_numTaps * (phase + 0)];
const float* c1 = &_polyphaseFilter[_numTaps * (phase + 1)];
__m256 acc0 = _mm256_setzero_ps();
__m256 acc1 = _mm256_setzero_ps();
__m256 frac = _mm256_broadcast_ss(&ftmp);
for (int j = 0; j < _numTaps; j += 8) {
//float coef = c0[j] + frac * (c1[j] - c0[j]);
__m256 coef0 = _mm256_loadu_ps(&c0[j]);
__m256 coef1 = _mm256_loadu_ps(&c1[j]);
coef1 = _mm256_sub_ps(coef1, coef0);
coef0 = _mm256_fmadd_ps(coef1, frac, coef0);
//acc += input[i + j] * coef;
acc0 = _mm256_fmadd_ps(_mm256_loadu_ps(&input0[i + j]), coef0, acc0);
acc1 = _mm256_fmadd_ps(_mm256_loadu_ps(&input1[i + j]), coef0, acc1);
}
// horizontal sum
acc0 = _mm256_hadd_ps(acc0, acc1);
__m128 t0 = _mm_add_ps(_mm256_castps256_ps128(acc0), _mm256_extractf128_ps(acc0, 1));
t0 = _mm_add_ps(t0, _mm_movehdup_ps(t0));
_mm_store_ss(&output0[outputFrames], t0);
_mm_store_ss(&output1[outputFrames], _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(0,0,0,2)));
outputFrames += 1;
_offset += _step;
}
_offset -= (int64_t)inputFrames << 32;
}
_mm256_zeroupper();
return outputFrames;
}
#endif

View file

@ -632,13 +632,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
#endif #endif
int numBytesRead = sourceBuffer - startPosition; int numBytesRead = sourceBuffer - startPosition;
if (numBytesRead != buffer.size()) {
if (shouldLogError(now)) {
qCWarning(avatars) << "AvatarData packet size mismatch: expected " << numBytesRead << " received " << buffer.size();
}
}
_averageBytesReceived.updateAverage(numBytesRead); _averageBytesReceived.updateAverage(numBytesRead);
return numBytesRead; return numBytesRead;
} }
@ -1270,6 +1263,10 @@ static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments"); static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities"); static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities");
static const QString JSON_AVATAR_SCALE = QStringLiteral("scale"); static const QString JSON_AVATAR_SCALE = QStringLiteral("scale");
static const QString JSON_AVATAR_VERSION = QStringLiteral("version");
static const int JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION = 0;
static const int JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION = 1;
QJsonValue toJsonValue(const JointData& joint) { QJsonValue toJsonValue(const JointData& joint) {
QJsonArray result; QJsonArray result;
@ -1293,6 +1290,8 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
QJsonObject AvatarData::toJson() const { QJsonObject AvatarData::toJson() const {
QJsonObject root; QJsonObject root;
root[JSON_AVATAR_VERSION] = JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION;
if (!getSkeletonModelURL().isEmpty()) { if (!getSkeletonModelURL().isEmpty()) {
root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString(); root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString();
} }
@ -1359,6 +1358,15 @@ QJsonObject AvatarData::toJson() const {
} }
void AvatarData::fromJson(const QJsonObject& json) { void AvatarData::fromJson(const QJsonObject& json) {
int version;
if (json.contains(JSON_AVATAR_VERSION)) {
version = json[JSON_AVATAR_VERSION].toInt();
} else {
// initial data did not have a version field.
version = JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION;
}
// The head setOrientation likes to overwrite the avatar orientation, // The head setOrientation likes to overwrite the avatar orientation,
// so lets do the head first // so lets do the head first
// Most head data is relative to the avatar, and needs no basis correction, // Most head data is relative to the avatar, and needs no basis correction,
@ -1424,20 +1432,28 @@ void AvatarData::fromJson(const QJsonObject& json) {
// } // }
// } // }
// Joint rotations are relative to the avatar, so they require no basis correction
if (json.contains(JSON_AVATAR_JOINT_ARRAY)) { if (json.contains(JSON_AVATAR_JOINT_ARRAY)) {
QVector<JointData> jointArray; if (version == JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION) {
QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray(); // because we don't have the full joint hierarchy skeleton of the model,
jointArray.reserve(jointArrayJson.size()); // we can't properly convert from relative rotations into absolute rotations.
int i = 0; quint64 now = usecTimestampNow();
for (const auto& jointJson : jointArrayJson) { if (shouldLogError(now)) {
auto joint = jointDataFromJsonValue(jointJson); qCWarning(avatars) << "Version 0 avatar recordings not supported. using default rotations";
jointArray.push_back(joint); }
setJointData(i, joint.rotation, joint.translation); } else {
_jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose QVector<JointData> jointArray;
i++; QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray();
jointArray.reserve(jointArrayJson.size());
int i = 0;
for (const auto& jointJson : jointArrayJson) {
auto joint = jointDataFromJsonValue(jointJson);
jointArray.push_back(joint);
setJointData(i, joint.rotation, joint.translation);
_jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose
i++;
}
setRawJointData(jointArray);
} }
setRawJointData(jointArray);
} }
} }

View file

@ -31,9 +31,6 @@ HeadData::HeadData(AvatarData* owningAvatar) :
_baseYaw(0.0f), _baseYaw(0.0f),
_basePitch(0.0f), _basePitch(0.0f),
_baseRoll(0.0f), _baseRoll(0.0f),
_leanSideways(0.0f),
_leanForward(0.0f),
_torsoTwist(0.0f),
_lookAtPosition(0.0f, 0.0f, 0.0f), _lookAtPosition(0.0f, 0.0f, 0.0f),
_audioLoudness(0.0f), _audioLoudness(0.0f),
_isFaceTrackerConnected(false), _isFaceTrackerConnected(false),
@ -132,12 +129,6 @@ QJsonObject HeadData::toJson() const {
if (getRawOrientation() != quat()) { if (getRawOrientation() != quat()) {
headJson[JSON_AVATAR_HEAD_ROTATION] = toJsonValue(getRawOrientation()); headJson[JSON_AVATAR_HEAD_ROTATION] = toJsonValue(getRawOrientation());
} }
if (getLeanForward() != 0.0f) {
headJson[JSON_AVATAR_HEAD_LEAN_FORWARD] = getLeanForward();
}
if (getLeanSideways() != 0.0f) {
headJson[JSON_AVATAR_HEAD_LEAN_SIDEWAYS] = getLeanSideways();
}
auto lookat = getLookAtPosition(); auto lookat = getLookAtPosition();
if (lookat != vec3()) { if (lookat != vec3()) {
vec3 relativeLookAt = glm::inverse(_owningAvatar->getOrientation()) * vec3 relativeLookAt = glm::inverse(_owningAvatar->getOrientation()) *
@ -171,12 +162,6 @@ void HeadData::fromJson(const QJsonObject& json) {
if (json.contains(JSON_AVATAR_HEAD_ROTATION)) { if (json.contains(JSON_AVATAR_HEAD_ROTATION)) {
setOrientation(quatFromJsonValue(json[JSON_AVATAR_HEAD_ROTATION])); setOrientation(quatFromJsonValue(json[JSON_AVATAR_HEAD_ROTATION]));
} }
if (json.contains(JSON_AVATAR_HEAD_LEAN_FORWARD)) {
setLeanForward((float)json[JSON_AVATAR_HEAD_LEAN_FORWARD].toDouble());
}
if (json.contains(JSON_AVATAR_HEAD_LEAN_SIDEWAYS)) {
setLeanSideways((float)json[JSON_AVATAR_HEAD_LEAN_SIDEWAYS].toDouble());
}
if (json.contains(JSON_AVATAR_HEAD_LOOKAT)) { if (json.contains(JSON_AVATAR_HEAD_LOOKAT)) {
auto relativeLookAt = vec3FromJsonValue(json[JSON_AVATAR_HEAD_LOOKAT]); auto relativeLookAt = vec3FromJsonValue(json[JSON_AVATAR_HEAD_LOOKAT]);

View file

@ -68,17 +68,6 @@ public:
const glm::vec3& getLookAtPosition() const { return _lookAtPosition; } const glm::vec3& getLookAtPosition() const { return _lookAtPosition; }
void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; } void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; }
float getLeanSideways() const { return _leanSideways; }
float getLeanForward() const { return _leanForward; }
float getTorsoTwist() const { return _torsoTwist; }
virtual float getFinalLeanSideways() const { return _leanSideways; }
virtual float getFinalLeanForward() const { return _leanForward; }
void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; }
void setLeanForward(float leanForward) { _leanForward = leanForward; }
void setTorsoTwist(float torsoTwist) { _torsoTwist = torsoTwist; }
friend class AvatarData; friend class AvatarData;
QJsonObject toJson() const; QJsonObject toJson() const;
@ -89,9 +78,6 @@ protected:
float _baseYaw; float _baseYaw;
float _basePitch; float _basePitch;
float _baseRoll; float _baseRoll;
float _leanSideways;
float _leanForward;
float _torsoTwist;
glm::vec3 _lookAtPosition; glm::vec3 _lookAtPosition;
float _audioLoudness; float _audioLoudness;

View file

@ -31,6 +31,12 @@ namespace controller {
class Endpoint; class Endpoint;
using EndpointPointer = std::shared_ptr<Endpoint>; using EndpointPointer = std::shared_ptr<Endpoint>;
enum Hand {
LEFT = 0,
RIGHT,
BOTH
};
// NOTE: If something inherits from both InputDevice and InputPlugin, InputPlugin must go first. // NOTE: If something inherits from both InputDevice and InputPlugin, InputPlugin must go first.
// e.g. class Example : public InputPlugin, public InputDevice // e.g. class Example : public InputPlugin, public InputDevice
// instead of class Example : public InputDevice, public InputPlugin // instead of class Example : public InputDevice, public InputPlugin
@ -55,6 +61,9 @@ public:
const QString& getName() const { return _name; } const QString& getName() const { return _name; }
// By default, Input Devices do not support haptics
virtual bool triggerHapticPulse(float strength, float duration, controller::Hand hand) { return false; }
// Update call MUST be called once per simulation loop // Update call MUST be called once per simulation loop
// It takes care of updating the action states and deltas // It takes care of updating the action states and deltas
virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData) {}; virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData) {};

View file

@ -140,6 +140,24 @@ namespace controller {
return DependencyManager::get<UserInputMapper>()->getActionNames(); return DependencyManager::get<UserInputMapper>()->getActionNames();
} }
bool ScriptingInterface::triggerHapticPulse(float strength, float duration, controller::Hand hand) const {
return DependencyManager::get<UserInputMapper>()->triggerHapticPulse(strength, duration, hand);
}
bool ScriptingInterface::triggerShortHapticPulse(float strength, controller::Hand hand) const {
const float SHORT_HAPTIC_DURATION_MS = 250.0f;
return DependencyManager::get<UserInputMapper>()->triggerHapticPulse(strength, SHORT_HAPTIC_DURATION_MS, hand);
}
bool ScriptingInterface::triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand) const {
return DependencyManager::get<UserInputMapper>()->triggerHapticPulseOnDevice(device, strength, duration, hand);
}
bool ScriptingInterface::triggerShortHapticPulseOnDevice(unsigned int device, float strength, controller::Hand hand) const {
const float SHORT_HAPTIC_DURATION_MS = 250.0f;
return DependencyManager::get<UserInputMapper>()->triggerHapticPulseOnDevice(device, strength, SHORT_HAPTIC_DURATION_MS, hand);
}
void ScriptingInterface::updateMaps() { void ScriptingInterface::updateMaps() {
QVariantMap newHardware; QVariantMap newHardware;
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();

View file

@ -84,6 +84,11 @@ namespace controller {
Q_INVOKABLE Pose getPoseValue(const int& source) const; Q_INVOKABLE Pose getPoseValue(const int& source) const;
Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const; Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
Q_INVOKABLE bool triggerHapticPulse(float strength, float duration, controller::Hand hand = BOTH) const;
Q_INVOKABLE bool triggerShortHapticPulse(float strength, controller::Hand hand = BOTH) const;
Q_INVOKABLE bool triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand = BOTH) const;
Q_INVOKABLE bool triggerShortHapticPulseOnDevice(unsigned int device, float strength, controller::Hand hand = BOTH) const;
Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString()); Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString());
Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true); Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true);
Q_INVOKABLE void disableMapping(const QString& mappingName) { enableMapping(mappingName, false); } Q_INVOKABLE void disableMapping(const QString& mappingName) { enableMapping(mappingName, false); }

View file

@ -66,9 +66,7 @@ namespace controller {
RIGHT_SECONDARY_INDEX_TOUCH, RIGHT_SECONDARY_INDEX_TOUCH,
RIGHT_INDEX_POINT, RIGHT_INDEX_POINT,
LEFT_GRIP,
LEFT_GRIP_TOUCH, LEFT_GRIP_TOUCH,
RIGHT_GRIP,
RIGHT_GRIP_TOUCH, RIGHT_GRIP_TOUCH,
NUM_STANDARD_BUTTONS NUM_STANDARD_BUTTONS
@ -85,9 +83,9 @@ namespace controller {
// Triggers // Triggers
LT, LT,
RT, RT,
// Grips (Oculus touch squeeze) // Grips
LG, LEFT_GRIP,
RG, RIGHT_GRIP,
NUM_STANDARD_AXES, NUM_STANDARD_AXES,
LZ = LT, LZ = LT,
RZ = RT RZ = RT

View file

@ -62,14 +62,6 @@ namespace controller {
UserInputMapper::~UserInputMapper() { UserInputMapper::~UserInputMapper() {
} }
int UserInputMapper::recordDeviceOfType(const QString& deviceName) {
if (!_deviceCounts.contains(deviceName)) {
_deviceCounts[deviceName] = 0;
}
_deviceCounts[deviceName] += 1;
return _deviceCounts[deviceName];
}
void UserInputMapper::registerDevice(InputDevice::Pointer device) { void UserInputMapper::registerDevice(InputDevice::Pointer device) {
Locker locker(_lock); Locker locker(_lock);
if (device->_deviceID == Input::INVALID_DEVICE) { if (device->_deviceID == Input::INVALID_DEVICE) {
@ -77,8 +69,6 @@ void UserInputMapper::registerDevice(InputDevice::Pointer device) {
} }
const auto& deviceID = device->_deviceID; const auto& deviceID = device->_deviceID;
recordDeviceOfType(device->getName());
qCDebug(controllers) << "Registered input device <" << device->getName() << "> deviceID = " << deviceID; qCDebug(controllers) << "Registered input device <" << device->getName() << "> deviceID = " << deviceID;
for (const auto& inputMapping : device->getAvailableInputs()) { for (const auto& inputMapping : device->getAvailableInputs()) {
@ -134,6 +124,15 @@ void UserInputMapper::removeDevice(int deviceID) {
_mappingsByDevice.erase(mappingsEntry); _mappingsByDevice.erase(mappingsEntry);
} }
for (const auto& inputMapping : device->getAvailableInputs()) {
const auto& input = inputMapping.first;
auto endpoint = _endpointsByInput.find(input);
if (endpoint != _endpointsByInput.end()) {
_inputsByEndpoint.erase((*endpoint).second);
_endpointsByInput.erase(input);
}
}
_registeredDevices.erase(proxyEntry); _registeredDevices.erase(proxyEntry);
emit hardwareChanged(); emit hardwareChanged();
@ -336,10 +335,28 @@ QVector<QString> UserInputMapper::getActionNames() const {
return result; return result;
} }
bool UserInputMapper::triggerHapticPulse(float strength, float duration, controller::Hand hand) {
Locker locker(_lock);
bool toReturn = false;
for (auto device : _registeredDevices) {
toReturn = toReturn || device.second->triggerHapticPulse(strength, duration, hand);
}
return toReturn;
}
bool UserInputMapper::triggerHapticPulseOnDevice(uint16 deviceID, float strength, float duration, controller::Hand hand) {
Locker locker(_lock);
if (_registeredDevices.find(deviceID) != _registeredDevices.end()) {
return _registeredDevices[deviceID]->triggerHapticPulse(strength, duration, hand);
}
return false;
}
int actionMetaTypeId = qRegisterMetaType<Action>(); int actionMetaTypeId = qRegisterMetaType<Action>();
int inputMetaTypeId = qRegisterMetaType<Input>(); int inputMetaTypeId = qRegisterMetaType<Input>();
int inputPairMetaTypeId = qRegisterMetaType<Input::NamedPair>(); int inputPairMetaTypeId = qRegisterMetaType<Input::NamedPair>();
int poseMetaTypeId = qRegisterMetaType<controller::Pose>("Pose"); int poseMetaTypeId = qRegisterMetaType<controller::Pose>("Pose");
int handMetaTypeId = qRegisterMetaType<controller::Hand>();
QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input); QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input);
void inputFromScriptValue(const QScriptValue& object, Input& input); void inputFromScriptValue(const QScriptValue& object, Input& input);
@ -347,6 +364,8 @@ QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action);
void actionFromScriptValue(const QScriptValue& object, Action& action); void actionFromScriptValue(const QScriptValue& object, Action& action);
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const Input::NamedPair& inputPair); QScriptValue inputPairToScriptValue(QScriptEngine* engine, const Input::NamedPair& inputPair);
void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inputPair); void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inputPair);
QScriptValue handToScriptValue(QScriptEngine* engine, const controller::Hand& hand);
void handFromScriptValue(const QScriptValue& object, controller::Hand& hand);
QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input) { QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input) {
QScriptValue obj = engine->newObject(); QScriptValue obj = engine->newObject();
@ -385,12 +404,21 @@ void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inpu
inputPair.second = QString(object.property("inputName").toVariant().toString()); inputPair.second = QString(object.property("inputName").toVariant().toString());
} }
QScriptValue handToScriptValue(QScriptEngine* engine, const controller::Hand& hand) {
return engine->newVariant((int)hand);
}
void handFromScriptValue(const QScriptValue& object, controller::Hand& hand) {
hand = Hand(object.toVariant().toInt());
}
void UserInputMapper::registerControllerTypes(QScriptEngine* engine) { void UserInputMapper::registerControllerTypes(QScriptEngine* engine) {
qScriptRegisterSequenceMetaType<QVector<Action> >(engine); qScriptRegisterSequenceMetaType<QVector<Action> >(engine);
qScriptRegisterSequenceMetaType<Input::NamedVector>(engine); qScriptRegisterSequenceMetaType<Input::NamedVector>(engine);
qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue); qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
qScriptRegisterMetaType(engine, handToScriptValue, handFromScriptValue);
qScriptRegisterMetaType(engine, Pose::toScriptValue, Pose::fromScriptValue); qScriptRegisterMetaType(engine, Pose::toScriptValue, Pose::fromScriptValue);
} }

View file

@ -89,6 +89,8 @@ namespace controller {
void setActionState(Action action, float value) { _actionStates[toInt(action)] = value; } void setActionState(Action action, float value) { _actionStates[toInt(action)] = value; }
void deltaActionState(Action action, float delta) { _actionStates[toInt(action)] += delta; } void deltaActionState(Action action, float delta) { _actionStates[toInt(action)] += delta; }
void setActionState(Action action, const Pose& value) { _poseStates[toInt(action)] = value; } void setActionState(Action action, const Pose& value) { _poseStates[toInt(action)] = value; }
bool triggerHapticPulse(float strength, float duration, controller::Hand hand);
bool triggerHapticPulseOnDevice(uint16 deviceID, float strength, float duration, controller::Hand hand);
static Input makeStandardInput(controller::StandardButtonChannel button); static Input makeStandardInput(controller::StandardButtonChannel button);
static Input makeStandardInput(controller::StandardAxisChannel axis); static Input makeStandardInput(controller::StandardAxisChannel axis);
@ -141,9 +143,6 @@ namespace controller {
std::vector<Pose> _poseStates = std::vector<Pose>(toInt(Action::NUM_ACTIONS)); std::vector<Pose> _poseStates = std::vector<Pose>(toInt(Action::NUM_ACTIONS));
std::vector<float> _lastStandardStates = std::vector<float>(); std::vector<float> _lastStandardStates = std::vector<float>();
int recordDeviceOfType(const QString& deviceName);
QHash<const QString&, int> _deviceCounts;
static float getValue(const EndpointPointer& endpoint, bool peek = false); static float getValue(const EndpointPointer& endpoint, bool peek = false);
static Pose getPose(const EndpointPointer& endpoint, bool peek = false); static Pose getPose(const EndpointPointer& endpoint, bool peek = false);
@ -199,6 +198,7 @@ Q_DECLARE_METATYPE(QVector<controller::Input::NamedPair>)
Q_DECLARE_METATYPE(controller::Input) Q_DECLARE_METATYPE(controller::Input)
Q_DECLARE_METATYPE(controller::Action) Q_DECLARE_METATYPE(controller::Action)
Q_DECLARE_METATYPE(QVector<controller::Action>) Q_DECLARE_METATYPE(QVector<controller::Action>)
Q_DECLARE_METATYPE(controller::Hand)
// Cheating. // Cheating.
using UserInputMapper = controller::UserInputMapper; using UserInputMapper = controller::UserInputMapper;

View file

@ -599,11 +599,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
ShapeType type = getShapeType(); ShapeType type = getShapeType();
if (type != SHAPE_TYPE_COMPOUND) { if (type == SHAPE_TYPE_COMPOUND) {
ModelEntityItem::computeShapeInfo(info);
info.setParams(type, 0.5f * getDimensions());
adjustShapeInfoByRegistration(info);
} else {
updateModelBounds(); updateModelBounds();
// should never fall in here when collision model not fully loaded // should never fall in here when collision model not fully loaded
@ -612,25 +608,27 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
const FBXGeometry& renderGeometry = _model->getFBXGeometry(); const FBXGeometry& renderGeometry = _model->getFBXGeometry();
const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry(); const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry();
_points.clear(); QVector<QVector<glm::vec3>>& points = info.getPoints();
unsigned int i = 0; points.clear();
uint32_t i = 0;
// the way OBJ files get read, each section under a "g" line is its own meshPart. We only expect // the way OBJ files get read, each section under a "g" line is its own meshPart. We only expect
// to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case. // to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case.
const uint32_t TRIANGLE_STRIDE = 3;
const uint32_t QUAD_STRIDE = 4;
foreach (const FBXMesh& mesh, collisionGeometry.meshes) { foreach (const FBXMesh& mesh, collisionGeometry.meshes) {
// each meshPart is a convex hull // each meshPart is a convex hull
foreach (const FBXMeshPart &meshPart, mesh.parts) { foreach (const FBXMeshPart &meshPart, mesh.parts) {
QVector<glm::vec3> pointsInPart; points.push_back(QVector<glm::vec3>());
QVector<glm::vec3>& pointsInPart = points[i];
// run through all the triangles and (uniquely) add each point to the hull // run through all the triangles and (uniquely) add each point to the hull
unsigned int triangleCount = meshPart.triangleIndices.size() / 3; uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size();
for (unsigned int j = 0; j < triangleCount; j++) { assert(numIndices % TRIANGLE_STRIDE == 0);
unsigned int p0Index = meshPart.triangleIndices[j*3]; for (uint32_t j = 0; j < numIndices; j += TRIANGLE_STRIDE) {
unsigned int p1Index = meshPart.triangleIndices[j*3+1]; glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[j]];
unsigned int p2Index = meshPart.triangleIndices[j*3+2]; glm::vec3 p1 = mesh.vertices[meshPart.triangleIndices[j + 1]];
glm::vec3 p0 = mesh.vertices[p0Index]; glm::vec3 p2 = mesh.vertices[meshPart.triangleIndices[j + 2]];
glm::vec3 p1 = mesh.vertices[p1Index];
glm::vec3 p2 = mesh.vertices[p2Index];
if (!pointsInPart.contains(p0)) { if (!pointsInPart.contains(p0)) {
pointsInPart << p0; pointsInPart << p0;
} }
@ -643,17 +641,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
} }
// run through all the quads and (uniquely) add each point to the hull // run through all the quads and (uniquely) add each point to the hull
unsigned int quadCount = meshPart.quadIndices.size() / 4; numIndices = (uint32_t)meshPart.quadIndices.size();
assert((unsigned int)meshPart.quadIndices.size() == quadCount*4); assert(numIndices % QUAD_STRIDE == 0);
for (unsigned int j = 0; j < quadCount; j++) { for (uint32_t j = 0; j < numIndices; j += QUAD_STRIDE) {
unsigned int p0Index = meshPart.quadIndices[j*4]; glm::vec3 p0 = mesh.vertices[meshPart.quadIndices[j]];
unsigned int p1Index = meshPart.quadIndices[j*4+1]; glm::vec3 p1 = mesh.vertices[meshPart.quadIndices[j + 1]];
unsigned int p2Index = meshPart.quadIndices[j*4+2]; glm::vec3 p2 = mesh.vertices[meshPart.quadIndices[j + 2]];
unsigned int p3Index = meshPart.quadIndices[j*4+3]; glm::vec3 p3 = mesh.vertices[meshPart.quadIndices[j + 3]];
glm::vec3 p0 = mesh.vertices[p0Index];
glm::vec3 p1 = mesh.vertices[p1Index];
glm::vec3 p2 = mesh.vertices[p2Index];
glm::vec3 p3 = mesh.vertices[p3Index];
if (!pointsInPart.contains(p0)) { if (!pointsInPart.contains(p0)) {
pointsInPart << p0; pointsInPart << p0;
} }
@ -670,14 +664,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
if (pointsInPart.size() == 0) { if (pointsInPart.size() == 0) {
qCDebug(entitiesrenderer) << "Warning -- meshPart has no faces"; qCDebug(entitiesrenderer) << "Warning -- meshPart has no faces";
points.pop_back();
continue; continue;
} }
++i;
// add next convex hull
QVector<glm::vec3> newMeshPoints;
_points << newMeshPoints;
// add points to the new convex hull
_points[i++] << pointsInPart;
} }
} }
@ -691,23 +681,26 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
// multiply each point by scale before handing the point-set off to the physics engine. // multiply each point by scale before handing the point-set off to the physics engine.
// also determine the extents of the collision model. // also determine the extents of the collision model.
AABox box; AABox box;
for (int i = 0; i < _points.size(); i++) { for (int i = 0; i < points.size(); i++) {
for (int j = 0; j < _points[i].size(); j++) { for (int j = 0; j < points[i].size(); j++) {
// compensate for registration // compensate for registration
_points[i][j] += _model->getOffset(); points[i][j] += _model->getOffset();
// scale so the collision points match the model points // scale so the collision points match the model points
_points[i][j] *= scale; points[i][j] *= scale;
// this next subtraction is done so we can give info the offset, which will cause // this next subtraction is done so we can give info the offset, which will cause
// the shape-key to change. // the shape-key to change.
_points[i][j] -= _model->getOffset(); points[i][j] -= _model->getOffset();
box += _points[i][j]; box += points[i][j];
} }
} }
glm::vec3 collisionModelDimensions = box.getDimensions(); glm::vec3 collisionModelDimensions = box.getDimensions();
info.setParams(type, collisionModelDimensions, _compoundShapeURL); info.setParams(type, collisionModelDimensions, _compoundShapeURL);
info.setConvexHulls(_points);
info.setOffset(_model->getOffset()); info.setOffset(_model->getOffset());
} else {
ModelEntityItem::computeShapeInfo(info);
info.setParams(type, 0.5f * getDimensions());
adjustShapeInfoByRegistration(info);
} }
} }

View file

@ -103,7 +103,6 @@ private:
QVariantMap _currentTextures; QVariantMap _currentTextures;
QVariantMap _originalTextures; QVariantMap _originalTextures;
bool _originalTexturesRead = false; bool _originalTexturesRead = false;
QVector<QVector<glm::vec3>> _points;
bool _dimensionsInitialized = true; bool _dimensionsInitialized = true;
AnimationPropertyGroup _renderAnimationProperties; AnimationPropertyGroup _renderAnimationProperties;

View file

@ -226,10 +226,15 @@ void RenderableWebEntityItem::setSourceUrl(const QString& value) {
} }
void RenderableWebEntityItem::setProxyWindow(QWindow* proxyWindow) { void RenderableWebEntityItem::setProxyWindow(QWindow* proxyWindow) {
_webSurface->setProxyWindow(proxyWindow); if (_webSurface) {
_webSurface->setProxyWindow(proxyWindow);
}
} }
QObject* RenderableWebEntityItem::getEventHandler() { QObject* RenderableWebEntityItem::getEventHandler() {
if (!_webSurface) {
return nullptr;
}
return _webSurface->getEventHandler(); return _webSurface->getEventHandler();
} }

View file

@ -88,7 +88,7 @@ void EntityItemProperties::setLastEdited(quint64 usecTime) {
_lastEdited = usecTime > _created ? usecTime : _created; _lastEdited = usecTime > _created ? usecTime : _created;
} }
const char* shapeTypeNames[] = {"none", "box", "sphere", "ellipsoid", "plane", "compound", "capsule-x", const char* shapeTypeNames[] = {"none", "box", "sphere", "plane", "compound", "capsule-x",
"capsule-y", "capsule-z", "cylinder-x", "cylinder-y", "cylinder-z"}; "capsule-y", "capsule-z", "cylinder-x", "cylinder-y", "cylinder-z"};
QHash<QString, ShapeType> stringToShapeTypeLookup; QHash<QString, ShapeType> stringToShapeTypeLookup;
@ -101,7 +101,6 @@ void buildStringToShapeTypeLookup() {
addShapeType(SHAPE_TYPE_NONE); addShapeType(SHAPE_TYPE_NONE);
addShapeType(SHAPE_TYPE_BOX); addShapeType(SHAPE_TYPE_BOX);
addShapeType(SHAPE_TYPE_SPHERE); addShapeType(SHAPE_TYPE_SPHERE);
addShapeType(SHAPE_TYPE_ELLIPSOID);
addShapeType(SHAPE_TYPE_PLANE); addShapeType(SHAPE_TYPE_PLANE);
addShapeType(SHAPE_TYPE_COMPOUND); addShapeType(SHAPE_TYPE_COMPOUND);
addShapeType(SHAPE_TYPE_CAPSULE_X); addShapeType(SHAPE_TYPE_CAPSULE_X);

View file

@ -1121,6 +1121,27 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) {
return result; return result;
} }
QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
QVector<QUuid> result;
if (!_entityTree) {
return result;
}
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID);
if (!entity) {
qDebug() << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
return result;
}
_entityTree->withReadLock([&] {
entity->forEachChild([&](SpatiallyNestablePointer child) {
result.push_back(child->getID());
});
});
return result;
}
QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) { QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) {
QVector<QUuid> result; QVector<QUuid> result;
if (!_entityTree) { if (!_entityTree) {

View file

@ -171,6 +171,7 @@ public slots:
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name); Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID); Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
Q_INVOKABLE QVector<QUuid> getChildrenIDs(const QUuid& parentID);
Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex); Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex);
signals: signals:

View file

@ -1284,6 +1284,7 @@ class ContentsDimensionOperator : public RecurseOctreeOperator {
public: public:
virtual bool preRecursion(OctreeElementPointer element); virtual bool preRecursion(OctreeElementPointer element);
virtual bool postRecursion(OctreeElementPointer element) { return true; } virtual bool postRecursion(OctreeElementPointer element) { return true; }
glm::vec3 getDimensions() const { return _contentExtents.size(); }
float getLargestDimension() const { return _contentExtents.largestDimension(); } float getLargestDimension() const { return _contentExtents.largestDimension(); }
private: private:
Extents _contentExtents; Extents _contentExtents;
@ -1295,6 +1296,12 @@ bool ContentsDimensionOperator::preRecursion(OctreeElementPointer element) {
return true; return true;
} }
glm::vec3 EntityTree::getContentsDimensions() {
ContentsDimensionOperator theOperator;
recurseTreeWithOperator(&theOperator);
return theOperator.getDimensions();
}
float EntityTree::getContentsLargestDimension() { float EntityTree::getContentsLargestDimension() {
ContentsDimensionOperator theOperator; ContentsDimensionOperator theOperator;
recurseTreeWithOperator(&theOperator); recurseTreeWithOperator(&theOperator);

View file

@ -207,6 +207,7 @@ public:
bool skipThoseWithBadParents) override; bool skipThoseWithBadParents) override;
virtual bool readFromMap(QVariantMap& entityDescription) override; virtual bool readFromMap(QVariantMap& entityDescription) override;
glm::vec3 getContentsDimensions();
float getContentsLargestDimension(); float getContentsLargestDimension();
virtual void resetEditStats() override { virtual void resetEditStats() override {

View file

@ -55,7 +55,7 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons
if (extraEncodeData->contains(this)) { if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
qCDebug(entities) << " encode data:" << entityTreeElementExtraEncodeData; qCDebug(entities) << " encode data:" << entityTreeElementExtraEncodeData;
} else { } else {
qCDebug(entities) << " encode data: MISSING!!"; qCDebug(entities) << " encode data: MISSING!!";
@ -97,7 +97,7 @@ bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamPa
if (extraEncodeData->contains(this)) { if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex]; bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex];
@ -126,7 +126,7 @@ bool EntityTreeElement::alreadyFullyEncoded(EncodeBitstreamParams& params) const
if (extraEncodeData->contains(this)) { if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
// If we know that ALL subtrees below us have already been recursed, then we don't // If we know that ALL subtrees below us have already been recursed, then we don't
// need to recurse this child. // need to recurse this child.
@ -140,7 +140,7 @@ void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppen
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
if (extraEncodeData->contains(this)) { if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
if (childAppendState == OctreeElement::COMPLETED) { if (childAppendState == OctreeElement::COMPLETED) {
entityTreeElementExtraEncodeData->childCompleted[childIndex] = true; entityTreeElementExtraEncodeData->childCompleted[childIndex] = true;
@ -165,7 +165,7 @@ void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) con
assert(extraEncodeData->contains(this)); assert(extraEncodeData->contains(this));
EntityTreeElementExtraEncodeData* thisExtraEncodeData EntityTreeElementExtraEncodeData* thisExtraEncodeData
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
// Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion() // Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion()
// which means, it's possible that our parent element hasn't finished encoding OUR data... so // which means, it's possible that our parent element hasn't finished encoding OUR data... so
@ -241,7 +241,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
bool hadElementExtraData = false; bool hadElementExtraData = false;
if (extraEncodeData && extraEncodeData->contains(this)) { if (extraEncodeData && extraEncodeData->contains(this)) {
entityTreeElementExtraEncodeData = entityTreeElementExtraEncodeData =
static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
hadElementExtraData = true; hadElementExtraData = true;
} else { } else {
// if there wasn't one already, then create one // if there wasn't one already, then create one
@ -268,7 +268,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
//assert(extraEncodeData); //assert(extraEncodeData);
//assert(extraEncodeData->contains(this)); //assert(extraEncodeData->contains(this));
//entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this)); //entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
LevelDetails elementLevel = packetData->startLevel(); LevelDetails elementLevel = packetData->startLevel();

View file

@ -60,7 +60,7 @@ class LineEntityItem : public EntityItem {
const QVector<glm::vec3>& getLinePoints() const{ return _points; } const QVector<glm::vec3>& getLinePoints() const{ return _points; }
virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; } virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }
// never have a ray intersection pick a LineEntityItem. // never have a ray intersection pick a LineEntityItem.
virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool supportsDetailedRayIntersection() const { return true; }

View file

@ -78,7 +78,7 @@ class PolyLineEntityItem : public EntityItem {
virtual bool needsToCallUpdate() const { return true; } virtual bool needsToCallUpdate() const { return true; }
virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; } virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }
// never have a ray intersection pick a PolyLineEntityItem. // never have a ray intersection pick a PolyLineEntityItem.
virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool supportsDetailedRayIntersection() const { return true; }

View file

@ -759,7 +759,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot); model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);
model.preRotation = glm::quat(glm::radians(preRotation)); model.preRotation = glm::quat(glm::radians(preRotation));
model.rotation = glm::quat(glm::radians(rotation)); model.rotation = glm::quat(glm::radians(rotation));
model.postRotation = glm::quat(glm::radians(postRotation)); model.postRotation = glm::inverse(glm::quat(glm::radians(postRotation)));
model.postTransform = glm::translate(-rotationPivot) * glm::translate(scaleOffset) * model.postTransform = glm::translate(-rotationPivot) * glm::translate(scaleOffset) *
glm::translate(scalePivot) * glm::scale(scale) * glm::translate(-scalePivot); glm::translate(scalePivot) * glm::scale(scale) * glm::translate(-scalePivot);
// NOTE: angles from the FBX file are in degrees // NOTE: angles from the FBX file are in degrees
@ -927,6 +927,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
// material.emissiveColor = getVec3(property.properties, index); // material.emissiveColor = getVec3(property.properties, index);
// material.emissiveFactor = 1.0; // material.emissiveFactor = 1.0;
} else if (property.properties.at(0) == "AmbientFactor") {
material.ambientFactor = property.properties.at(index).value<double>();
// Detected just for BLender AO vs lightmap
} else if (property.properties.at(0) == "Shininess") { } else if (property.properties.at(0) == "Shininess") {
material.shininess = property.properties.at(index).value<double>(); material.shininess = property.properties.at(index).value<double>();
@ -1128,8 +1131,10 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type.contains("tex_emissive_map")) { } else if (type.contains("tex_emissive_map")) {
emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type.contains("ambient")) { } else if (type.contains("ambientcolor")) {
ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type.contains("ambientfactor")) {
ambientFactorTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type.contains("tex_ao_map")) { } else if (type.contains("tex_ao_map")) {
occlusionTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); occlusionTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (type == "lcl rotation") { } else if (type == "lcl rotation") {

View file

@ -151,6 +151,7 @@ public:
float metallic{ 0.0f }; float metallic{ 0.0f };
float roughness{ 1.0f }; float roughness{ 1.0f };
float emissiveIntensity{ 1.0f }; float emissiveIntensity{ 1.0f };
float ambientFactor{ 1.0f };
QString materialID; QString materialID;
QString name; QString name;
@ -437,6 +438,7 @@ public:
QHash<QString, QString> shininessTextures; QHash<QString, QString> shininessTextures;
QHash<QString, QString> emissiveTextures; QHash<QString, QString> emissiveTextures;
QHash<QString, QString> ambientTextures; QHash<QString, QString> ambientTextures;
QHash<QString, QString> ambientFactorTextures;
QHash<QString, QString> occlusionTextures; QHash<QString, QString> occlusionTextures;
QHash<QString, FBXMaterial> _fbxMaterials; QHash<QString, FBXMaterial> _fbxMaterials;

View file

@ -186,6 +186,14 @@ void FBXReader::consolidateFBXMaterials() {
FBXTexture occlusionTexture; FBXTexture occlusionTexture;
QString occlusionTextureID = occlusionTextures.value(material.materialID); QString occlusionTextureID = occlusionTextures.value(material.materialID);
if (occlusionTextureID.isNull()) {
// 2nd chance
// For blender we use the ambient factor texture as AOMap ONLY if the ambientFactor value is > 0.0
if (material.ambientFactor > 0.0f) {
occlusionTextureID = ambientFactorTextures.value(material.materialID);
}
}
if (!occlusionTextureID.isNull()) { if (!occlusionTextureID.isNull()) {
occlusionTexture = getTexture(occlusionTextureID); occlusionTexture = getTexture(occlusionTextureID);
detectDifferentUVs |= (occlusionTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity()); detectDifferentUVs |= (occlusionTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
@ -198,6 +206,14 @@ void FBXReader::consolidateFBXMaterials() {
FBXTexture ambientTexture; FBXTexture ambientTexture;
QString ambientTextureID = ambientTextures.value(material.materialID); QString ambientTextureID = ambientTextures.value(material.materialID);
if (ambientTextureID.isNull()) {
// 2nd chance
// For blender we use the ambient factor texture as Lightmap ONLY if the ambientFactor value is set to 0
if (material.ambientFactor == 0.0f) {
ambientTextureID = ambientFactorTextures.value(material.materialID);
}
}
if (_loadLightmaps && !ambientTextureID.isNull()) { if (_loadLightmaps && !ambientTextureID.isNull()) {
ambientTexture = getTexture(ambientTextureID); ambientTexture = getTexture(ambientTextureID);
detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity()); detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity());

View file

@ -25,7 +25,6 @@ InputPluginList getInputPlugins() {
for (int i = 0; PLUGIN_POOL[i]; ++i) { for (int i = 0; PLUGIN_POOL[i]; ++i) {
InputPlugin* plugin = PLUGIN_POOL[i]; InputPlugin* plugin = PLUGIN_POOL[i];
if (plugin->isSupported()) { if (plugin->isSupported()) {
plugin->init();
result.push_back(InputPluginPointer(plugin)); result.push_back(InputPluginPointer(plugin));
} }
} }

View file

@ -418,6 +418,8 @@ model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, c
auto map = std::make_shared<model::TextureMap>(); auto map = std::make_shared<model::TextureMap>();
map->setTextureSource(texture->_textureSource); map->setTextureSource(texture->_textureSource);
map->setTextureTransform(fbxTexture.transform);
return map; return map;
} }
@ -427,6 +429,7 @@ model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, Textu
auto map = std::make_shared<model::TextureMap>(); auto map = std::make_shared<model::TextureMap>();
map->setTextureSource(texture->_textureSource); map->setTextureSource(texture->_textureSource);
return map; return map;
} }
@ -475,6 +478,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur
if (!material.occlusionTexture.filename.isEmpty()) { if (!material.occlusionTexture.filename.isEmpty()) {
auto map = fetchTextureMap(textureBaseUrl, material.occlusionTexture, NetworkTexture::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); auto map = fetchTextureMap(textureBaseUrl, material.occlusionTexture, NetworkTexture::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
map->setTextureTransform(material.occlusionTexture.transform);
setTextureMap(MapChannel::OCCLUSION_MAP, map); setTextureMap(MapChannel::OCCLUSION_MAP, map);
} }

View file

@ -122,6 +122,10 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur
_texMapArrayBuffer.edit<TexMapArraySchema>()._texcoordTransforms[0] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4()); _texMapArrayBuffer.edit<TexMapArraySchema>()._texcoordTransforms[0] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
} }
if (channel == MaterialKey::OCCLUSION_MAP) {
_texMapArrayBuffer.edit<TexMapArraySchema>()._texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
}
if (channel == MaterialKey::LIGHTMAP_MAP) { if (channel == MaterialKey::LIGHTMAP_MAP) {
// update the texcoord1 with lightmap // update the texcoord1 with lightmap
_texMapArrayBuffer.edit<TexMapArraySchema>()._texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4()); _texMapArrayBuffer.edit<TexMapArraySchema>()._texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());

View file

@ -14,6 +14,7 @@
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <atomic>
#include <btBulletDynamicsCommon.h> #include <btBulletDynamicsCommon.h>
#include <BulletDynamics/Character/btCharacterControllerInterface.h> #include <BulletDynamics/Character/btCharacterControllerInterface.h>
@ -105,8 +106,9 @@ public:
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
bool isEnabled() const { return _enabled; } // thread-safe
void setEnabled(bool enabled); void setEnabled(bool enabled);
bool isEnabled() const { return _enabled && _dynamicsWorld; } bool isEnabledAndReady() const { return _enabled && _dynamicsWorld; }
bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
@ -167,7 +169,7 @@ protected:
btQuaternion _followAngularDisplacement; btQuaternion _followAngularDisplacement;
btVector3 _linearAcceleration; btVector3 _linearAcceleration;
bool _enabled; std::atomic_bool _enabled;
State _state; State _state;
bool _isPushingUp; bool _isPushingUp;

View file

@ -17,6 +17,54 @@
#include "ShapeFactory.h" #include "ShapeFactory.h"
#include "BulletUtil.h" #include "BulletUtil.h"
// These are the same normalized directions used by the btShapeHull class.
// 12 points for the face centers of a duodecohedron plus another 30 points
// for the midpoints the edges, for a total of 42.
const uint32_t NUM_UNIT_SPHERE_DIRECTIONS = 42;
static const btVector3 _unitSphereDirections[NUM_UNIT_SPHERE_DIRECTIONS] = {
btVector3(btScalar(0.000000) , btScalar(-0.000000),btScalar(-1.000000)),
btVector3(btScalar(0.723608) , btScalar(-0.525725),btScalar(-0.447219)),
btVector3(btScalar(-0.276388) , btScalar(-0.850649),btScalar(-0.447219)),
btVector3(btScalar(-0.894426) , btScalar(-0.000000),btScalar(-0.447216)),
btVector3(btScalar(-0.276388) , btScalar(0.850649),btScalar(-0.447220)),
btVector3(btScalar(0.723608) , btScalar(0.525725),btScalar(-0.447219)),
btVector3(btScalar(0.276388) , btScalar(-0.850649),btScalar(0.447220)),
btVector3(btScalar(-0.723608) , btScalar(-0.525725),btScalar(0.447219)),
btVector3(btScalar(-0.723608) , btScalar(0.525725),btScalar(0.447219)),
btVector3(btScalar(0.276388) , btScalar(0.850649),btScalar(0.447219)),
btVector3(btScalar(0.894426) , btScalar(0.000000),btScalar(0.447216)),
btVector3(btScalar(-0.000000) , btScalar(0.000000),btScalar(1.000000)),
btVector3(btScalar(0.425323) , btScalar(-0.309011),btScalar(-0.850654)),
btVector3(btScalar(-0.162456) , btScalar(-0.499995),btScalar(-0.850654)),
btVector3(btScalar(0.262869) , btScalar(-0.809012),btScalar(-0.525738)),
btVector3(btScalar(0.425323) , btScalar(0.309011),btScalar(-0.850654)),
btVector3(btScalar(0.850648) , btScalar(-0.000000),btScalar(-0.525736)),
btVector3(btScalar(-0.525730) , btScalar(-0.000000),btScalar(-0.850652)),
btVector3(btScalar(-0.688190) , btScalar(-0.499997),btScalar(-0.525736)),
btVector3(btScalar(-0.162456) , btScalar(0.499995),btScalar(-0.850654)),
btVector3(btScalar(-0.688190) , btScalar(0.499997),btScalar(-0.525736)),
btVector3(btScalar(0.262869) , btScalar(0.809012),btScalar(-0.525738)),
btVector3(btScalar(0.951058) , btScalar(0.309013),btScalar(0.000000)),
btVector3(btScalar(0.951058) , btScalar(-0.309013),btScalar(0.000000)),
btVector3(btScalar(0.587786) , btScalar(-0.809017),btScalar(0.000000)),
btVector3(btScalar(0.000000) , btScalar(-1.000000),btScalar(0.000000)),
btVector3(btScalar(-0.587786) , btScalar(-0.809017),btScalar(0.000000)),
btVector3(btScalar(-0.951058) , btScalar(-0.309013),btScalar(-0.000000)),
btVector3(btScalar(-0.951058) , btScalar(0.309013),btScalar(-0.000000)),
btVector3(btScalar(-0.587786) , btScalar(0.809017),btScalar(-0.000000)),
btVector3(btScalar(-0.000000) , btScalar(1.000000),btScalar(-0.000000)),
btVector3(btScalar(0.587786) , btScalar(0.809017),btScalar(-0.000000)),
btVector3(btScalar(0.688190) , btScalar(-0.499997),btScalar(0.525736)),
btVector3(btScalar(-0.262869) , btScalar(-0.809012),btScalar(0.525738)),
btVector3(btScalar(-0.850648) , btScalar(0.000000),btScalar(0.525736)),
btVector3(btScalar(-0.262869) , btScalar(0.809012),btScalar(0.525738)),
btVector3(btScalar(0.688190) , btScalar(0.499997),btScalar(0.525736)),
btVector3(btScalar(0.525730) , btScalar(0.000000),btScalar(0.850652)),
btVector3(btScalar(0.162456) , btScalar(-0.499995),btScalar(0.850654)),
btVector3(btScalar(-0.425323) , btScalar(-0.309011),btScalar(0.850654)),
btVector3(btScalar(-0.425323) , btScalar(0.309011),btScalar(0.850654)),
btVector3(btScalar(0.162456) , btScalar(0.499995),btScalar(0.850654))
};
btConvexHullShape* ShapeFactory::createConvexHull(const QVector<glm::vec3>& points) { btConvexHullShape* ShapeFactory::createConvexHull(const QVector<glm::vec3>& points) {
@ -66,15 +114,40 @@ btConvexHullShape* ShapeFactory::createConvexHull(const QVector<glm::vec3>& poin
hull->addPoint(btVector3(correctedPoint[0], correctedPoint[1], correctedPoint[2]), false); hull->addPoint(btVector3(correctedPoint[0], correctedPoint[1], correctedPoint[2]), false);
} }
if (points.size() > MAX_HULL_POINTS) { uint32_t numPoints = (uint32_t)hull->getNumPoints();
// create hull approximation if (numPoints > MAX_HULL_POINTS) {
btShapeHull shapeHull(hull); // we have too many points, so we compute point projections along canonical unit vectors
shapeHull.buildHull(margin); // and keep the those that project the farthest
btVector3 btCenter = glmToBullet(center);
btVector3* shapePoints = hull->getUnscaledPoints();
std::vector<uint32_t> finalIndices;
finalIndices.reserve(NUM_UNIT_SPHERE_DIRECTIONS);
for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) {
uint32_t bestIndex = 0;
btScalar maxDistance = _unitSphereDirections[i].dot(shapePoints[0] - btCenter);
for (uint32_t j = 1; j < numPoints; ++j) {
btScalar distance = _unitSphereDirections[i].dot(shapePoints[j] - btCenter);
if (distance > maxDistance) {
maxDistance = distance;
bestIndex = j;
}
}
bool keep = true;
for (uint32_t j = 0; j < finalIndices.size(); ++j) {
if (finalIndices[j] == bestIndex) {
keep = false;
break;
}
}
if (keep) {
finalIndices.push_back(bestIndex);
}
}
// we cannot copy Bullet shapes so we must create a new one... // we cannot copy Bullet shapes so we must create a new one...
btConvexHullShape* newHull = new btConvexHullShape(); btConvexHullShape* newHull = new btConvexHullShape();
const btVector3* newPoints = shapeHull.getVertexPointer(); for (uint32_t i = 0; i < finalIndices.size(); ++i) {
for (int i = 0; i < shapeHull.numVertices(); ++i) { newHull->addPoint(shapePoints[finalIndices[i]], false);
newHull->addPoint(newPoints[i], false);
} }
// ...and delete the old one // ...and delete the old one
delete hull; delete hull;

View file

@ -137,7 +137,7 @@ public:
} }
// will query the underlying hmd api to compute the most recent head pose // will query the underlying hmd api to compute the most recent head pose
virtual void beginFrameRender(uint32_t frameIndex) {} virtual bool beginFrameRender(uint32_t frameIndex) { return true; }
// returns a copy of the most recent head pose, computed via updateHeadPose // returns a copy of the most recent head pose, computed via updateHeadPose
virtual glm::mat4 getHeadPose() const { virtual glm::mat4 getHeadPose() const {
@ -170,6 +170,10 @@ public:
signals: signals:
void recommendedFramebufferSizeChanged(const QSize & size); void recommendedFramebufferSizeChanged(const QSize & size);
// Indicates that this display plugin is no longer valid for use.
// For instance if a user exits Oculus Home or Steam VR while
// using the corresponding plugin, that plugin should be disabled.
void outputDeviceLost();
protected: protected:
void incrementPresentCount(); void incrementPresentCount();

View file

@ -25,6 +25,50 @@ PluginManager* PluginManager::getInstance() {
return &_manager; return &_manager;
} }
QString getPluginNameFromMetaData(QJsonObject object) {
static const char* METADATA_KEY = "MetaData";
static const char* NAME_KEY = "name";
if (!object.contains(METADATA_KEY) || !object[METADATA_KEY].isObject()) {
return QString();
}
auto metaDataObject = object[METADATA_KEY].toObject();
if (!metaDataObject.contains(NAME_KEY) || !metaDataObject[NAME_KEY].isString()) {
return QString();
}
return metaDataObject[NAME_KEY].toString();
}
QString getPluginIIDFromMetaData(QJsonObject object) {
static const char* IID_KEY = "IID";
if (!object.contains(IID_KEY) || !object[IID_KEY].isString()) {
return QString();
}
return object[IID_KEY].toString();
}
QStringList preferredDisplayPlugins;
QStringList disabledDisplays;
QStringList disabledInputs;
bool isDisabled(QJsonObject metaData) {
auto name = getPluginNameFromMetaData(metaData);
auto iid = getPluginIIDFromMetaData(metaData);
if (iid == DisplayProvider_iid) {
return disabledDisplays.contains(name);
} else if (iid == InputProvider_iid) {
return disabledInputs.contains(name);
}
return false;
}
using Loader = QSharedPointer<QPluginLoader>; using Loader = QSharedPointer<QPluginLoader>;
using LoaderList = QList<Loader>; using LoaderList = QList<Loader>;
@ -43,11 +87,21 @@ const LoaderList& getLoadedPlugins() {
qDebug() << "Loading runtime plugins from " << pluginPath; qDebug() << "Loading runtime plugins from " << pluginPath;
auto candidates = pluginDir.entryList(); auto candidates = pluginDir.entryList();
for (auto plugin : candidates) { for (auto plugin : candidates) {
qDebug() << "Attempting plugins " << plugin; qDebug() << "Attempting plugin" << qPrintable(plugin);
QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin)); QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin));
if (isDisabled(loader->metaData())) {
qWarning() << "Plugin" << qPrintable(plugin) << "is disabled";
// Skip this one, it's disabled
continue;
}
if (loader->load()) { if (loader->load()) {
qDebug() << "Plugins " << plugin << " success"; qDebug() << "Plugin" << qPrintable(plugin) << "loaded successfully";
loadedPlugins.push_back(loader); loadedPlugins.push_back(loader);
} else {
qDebug() << "Plugin" << qPrintable(plugin) << "failed to load:";
qDebug() << " " << qPrintable(loader->errorString());
} }
} }
} }
@ -62,11 +116,10 @@ PluginManager::PluginManager() {
extern DisplayPluginList getDisplayPlugins(); extern DisplayPluginList getDisplayPlugins();
extern InputPluginList getInputPlugins(); extern InputPluginList getInputPlugins();
extern void saveInputPluginSettings(const InputPluginList& plugins); extern void saveInputPluginSettings(const InputPluginList& plugins);
static DisplayPluginList displayPlugins;
const DisplayPluginList& PluginManager::getDisplayPlugins() { const DisplayPluginList& PluginManager::getDisplayPlugins() {
static DisplayPluginList displayPlugins;
static std::once_flag once; static std::once_flag once;
std::call_once(once, [&] { std::call_once(once, [&] {
// Grab the built in plugins // Grab the built in plugins
displayPlugins = ::getDisplayPlugins(); displayPlugins = ::getDisplayPlugins();
@ -90,6 +143,16 @@ const DisplayPluginList& PluginManager::getDisplayPlugins() {
return displayPlugins; return displayPlugins;
} }
void PluginManager::disableDisplayPlugin(const QString& name) {
for (size_t i = 0; i < displayPlugins.size(); ++i) {
if (displayPlugins[i]->getName() == name) {
displayPlugins.erase(displayPlugins.begin() + i);
break;
}
}
}
const InputPluginList& PluginManager::getInputPlugins() { const InputPluginList& PluginManager::getInputPlugins() {
static InputPluginList inputPlugins; static InputPluginList inputPlugins;
static std::once_flag once; static std::once_flag once;
@ -101,7 +164,9 @@ const InputPluginList& PluginManager::getInputPlugins() {
InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance()); InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance());
if (inputProvider) { if (inputProvider) {
for (auto inputPlugin : inputProvider->getInputPlugins()) { for (auto inputPlugin : inputProvider->getInputPlugins()) {
inputPlugins.push_back(inputPlugin); if (inputPlugin->isSupported()) {
inputPlugins.push_back(inputPlugin);
}
} }
} }
} }
@ -115,6 +180,40 @@ const InputPluginList& PluginManager::getInputPlugins() {
return inputPlugins; return inputPlugins;
} }
void PluginManager::setPreferredDisplayPlugins(const QStringList& displays) {
preferredDisplayPlugins = displays;
}
DisplayPluginList PluginManager::getPreferredDisplayPlugins() {
static DisplayPluginList displayPlugins;
static std::once_flag once;
std::call_once(once, [&] {
// Grab the built in plugins
auto plugins = getDisplayPlugins();
for (auto pluginName : preferredDisplayPlugins) {
auto it = std::find_if(plugins.begin(), plugins.end(), [&](DisplayPluginPointer plugin) {
return plugin->getName() == pluginName;
});
if (it != plugins.end()) {
displayPlugins.push_back(*it);
}
}
});
return displayPlugins;
}
void PluginManager::disableDisplays(const QStringList& displays) {
disabledDisplays << displays;
}
void PluginManager::disableInputs(const QStringList& inputs) {
disabledInputs << inputs;
}
void PluginManager::saveSettings() { void PluginManager::saveSettings() {
saveInputPluginSettings(getInputPlugins()); saveInputPluginSettings(getInputPlugins());
} }

View file

@ -13,10 +13,17 @@
class PluginManager : public QObject { class PluginManager : public QObject {
public: public:
static PluginManager* getInstance(); static PluginManager* getInstance();
PluginManager(); PluginManager();
const DisplayPluginList& getDisplayPlugins(); const DisplayPluginList& getDisplayPlugins();
const InputPluginList& getInputPlugins(); const InputPluginList& getInputPlugins();
void saveSettings();
DisplayPluginList getPreferredDisplayPlugins();
void setPreferredDisplayPlugins(const QStringList& displays);
void disableDisplayPlugin(const QString& name);
void disableDisplays(const QStringList& displays);
void disableInputs(const QStringList& inputs);
void saveSettings();
}; };

View file

@ -84,7 +84,7 @@ static const std::string DEFAULT_NORMAL_SHADER {
static const std::string DEFAULT_OCCLUSION_SHADER{ static const std::string DEFAULT_OCCLUSION_SHADER{
"vec4 getFragmentColor() {" "vec4 getFragmentColor() {"
" DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);"
" return vec4(vec3(frag.obscurance), 1.0);" " return vec4(vec3(pow(frag.obscurance, 1.0 / 2.2)), 1.0);"
" }" " }"
}; };

View file

@ -90,7 +90,7 @@ float fetchOcclusionMap(vec2 uv) {
<@endfunc@> <@endfunc@>
<@func fetchMaterialTextures(matKey, texcoord0, albedo, roughness, normal, metallic, emissive, occlusion)@> <@func fetchMaterialTexturesCoord0(matKey, texcoord0, albedo, roughness, normal, metallic, emissive)@>
<@if albedo@> <@if albedo@>
vec4 <$albedo$> = (((<$matKey$> & (ALBEDO_MAP_BIT | OPACITY_MASK_MAP_BIT | OPACITY_TRANSLUCENT_MAP_BIT)) != 0) ? fetchAlbedoMap(<$texcoord0$>) : vec4(1.0)); vec4 <$albedo$> = (((<$matKey$> & (ALBEDO_MAP_BIT | OPACITY_MASK_MAP_BIT | OPACITY_TRANSLUCENT_MAP_BIT)) != 0) ? fetchAlbedoMap(<$texcoord0$>) : vec4(1.0));
<@endif@> <@endif@>
@ -106,12 +106,19 @@ float fetchOcclusionMap(vec2 uv) {
<@if emissive@> <@if emissive@>
vec3 <$emissive$> = (((<$matKey$> & EMISSIVE_MAP_BIT) != 0) ? fetchEmissiveMap(<$texcoord0$>) : vec3(0.0)); vec3 <$emissive$> = (((<$matKey$> & EMISSIVE_MAP_BIT) != 0) ? fetchEmissiveMap(<$texcoord0$>) : vec3(0.0));
<@endif@> <@endif@>
<@endfunc@>
<@func fetchMaterialTexturesCoord1(matKey, texcoord1, occlusion, lightmapVal)@>
<@if occlusion@> <@if occlusion@>
float <$occlusion$> = (((<$matKey$> & OCCLUSION_MAP_BIT) != 0) ? fetchOcclusionMap(<$texcoord0$>) : 1.0); float <$occlusion$> = (((<$matKey$> & OCCLUSION_MAP_BIT) != 0) ? fetchOcclusionMap(<$texcoord1$>) : 1.0);
<@endif@>
<@if lightmapVal@>
vec3 <$lightmapVal$> = fetchLightmapMap(<$texcoord1$>);
<@endif@> <@endif@>
<@endfunc@> <@endfunc@>
<@func declareMaterialLightmap()@> <@func declareMaterialLightmap()@>
<$declareMaterialTexMapArrayBuffer()$> <$declareMaterialTexMapArrayBuffer()$>
@ -123,11 +130,6 @@ vec3 fetchLightmapMap(vec2 uv) {
} }
<@endfunc@> <@endfunc@>
<@func fetchMaterialLightmap(texcoord1, lightmapVal)@>
vec3 <$lightmapVal$> = fetchLightmapMap(<$texcoord1$>);
<@endfunc@>
<@func tangentToViewSpace(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@> <@func tangentToViewSpace(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{ {
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz); vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);

View file

@ -35,7 +35,46 @@ int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
#define HTTP_INVALID_COM "http://invalid.com" #define HTTP_INVALID_COM "http://invalid.com"
model::MaterialPointer Model::_collisionHullMaterial; const int NUM_COLLISION_HULL_COLORS = 24;
std::vector<model::MaterialPointer> _collisionHullMaterials;
void initCollisionHullMaterials() {
// generates bright colors in red, green, blue, yellow, magenta, and cyan spectrums
// (no browns, greys, or dark shades)
float component[NUM_COLLISION_HULL_COLORS] = {
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.2f, 0.4f, 0.6f, 0.8f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
0.8f, 0.6f, 0.4f, 0.2f
};
_collisionHullMaterials.reserve(NUM_COLLISION_HULL_COLORS);
// each component gets the same cuve
// but offset by a multiple of one third the full width
int numComponents = 3;
int sectionWidth = NUM_COLLISION_HULL_COLORS / numComponents;
int greenPhase = sectionWidth;
int bluePhase = 2 * sectionWidth;
// we stride through the colors to scatter adjacent shades
// so they don't tend to group together for large models
for (int i = 0; i < sectionWidth; ++i) {
for (int j = 0; j < numComponents; ++j) {
model::MaterialPointer material;
material = std::make_shared<model::Material>();
int index = j * sectionWidth + i;
float red = component[index];
float green = component[(index + greenPhase) % NUM_COLLISION_HULL_COLORS];
float blue = component[(index + bluePhase) % NUM_COLLISION_HULL_COLORS];
material->setAlbedo(glm::vec3(red, green, blue));
material->setMetallic(0.02f);
material->setRoughness(0.5f);
_collisionHullMaterials.push_back(material);
}
}
}
Model::Model(RigPointer rig, QObject* parent) : Model::Model(RigPointer rig, QObject* parent) :
QObject(parent), QObject(parent),
@ -1217,13 +1256,10 @@ void Model::segregateMeshGroups() {
int totalParts = mesh.parts.size(); int totalParts = mesh.parts.size();
for (int partIndex = 0; partIndex < totalParts; partIndex++) { for (int partIndex = 0; partIndex < totalParts; partIndex++) {
if (showingCollisionHull) { if (showingCollisionHull) {
if (!_collisionHullMaterial) { if (_collisionHullMaterials.empty()) {
_collisionHullMaterial = std::make_shared<model::Material>(); initCollisionHullMaterials();
_collisionHullMaterial->setAlbedo(glm::vec3(1.0f, 0.5f, 0.0f));
_collisionHullMaterial->setMetallic(0.02f);
_collisionHullMaterial->setRoughness(0.5f);
} }
_collisionRenderItemsSet << std::make_shared<MeshPartPayload>(networkMesh, partIndex, _collisionHullMaterial, transform, offset); _collisionRenderItemsSet << std::make_shared<MeshPartPayload>(networkMesh, partIndex, _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS], transform, offset);
} else { } else {
_modelMeshRenderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset); _modelMeshRenderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
} }

View file

@ -22,12 +22,14 @@ in vec4 _position;
in vec3 _normal; in vec3 _normal;
in vec3 _color; in vec3 _color;
in vec2 _texCoord0; in vec2 _texCoord0;
in vec2 _texCoord1;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0; float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;

View file

@ -22,6 +22,7 @@
out vec3 _color; out vec3 _color;
out float _alpha; out float _alpha;
out vec2 _texCoord0; out vec2 _texCoord0;
out vec2 _texCoord1;
out vec4 _position; out vec4 _position;
out vec3 _normal; out vec3 _normal;
@ -31,6 +32,7 @@ void main(void) {
TexMapArray texMapArray = getTexMapArray(); TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
// standard transform // standard transform
TransformCamera cam = getTransformCamera(); TransformCamera cam = getTransformCamera();

View file

@ -29,8 +29,8 @@ in vec3 _color;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness)$>
<$fetchMaterialLightmap(_texCoord1, lightmapVal)$> <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
packDeferredFragmentLightmap( packDeferredFragmentLightmap(

View file

@ -30,8 +30,8 @@ in vec3 _color;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness, normalTexel)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel)$>
<$fetchMaterialLightmap(_texCoord1, lightmapVal)$> <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
vec3 viewNormal; vec3 viewNormal;
<$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$>

View file

@ -30,8 +30,8 @@ in vec3 _color;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$>
<$fetchMaterialLightmap(_texCoord1, lightmapVal)$> <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
vec3 viewNormal; vec3 viewNormal;
<$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$>

View file

@ -29,8 +29,8 @@ in vec3 _color;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness, _SCRIBE_NULL, metallicTex)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, _SCRIBE_NULL, metallicTex)$>
<$fetchMaterialLightmap(_texCoord1, lightmapVal)$> <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
packDeferredFragmentLightmap( packDeferredFragmentLightmap(
normalize(_normal), normalize(_normal),

View file

@ -21,6 +21,7 @@
in vec4 _position; in vec4 _position;
in vec2 _texCoord0; in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal; in vec3 _normal;
in vec3 _tangent; in vec3 _tangent;
in vec3 _color; in vec3 _color;
@ -28,7 +29,8 @@ in vec3 _color;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex, occlusionTex)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0; float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;

View file

@ -22,6 +22,7 @@
out vec4 _position; out vec4 _position;
out vec2 _texCoord0; out vec2 _texCoord0;
out vec2 _texCoord1;
out vec3 _normal; out vec3 _normal;
out vec3 _tangent; out vec3 _tangent;
out vec3 _color; out vec3 _color;
@ -34,6 +35,7 @@ void main(void) {
TexMapArray texMapArray = getTexMapArray(); TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
// standard transform // standard transform
TransformCamera cam = getTransformCamera(); TransformCamera cam = getTransformCamera();

View file

@ -21,6 +21,7 @@
in vec4 _position; in vec4 _position;
in vec2 _texCoord0; in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal; in vec3 _normal;
in vec3 _tangent; in vec3 _tangent;
in vec3 _color; in vec3 _color;
@ -28,7 +29,8 @@ in vec3 _color;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex, emissiveTex, occlusionTex)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0; float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>;

View file

@ -21,6 +21,7 @@
in vec4 _position; in vec4 _position;
in vec2 _texCoord0; in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal; in vec3 _normal;
in vec3 _color; in vec3 _color;
@ -28,7 +29,8 @@ in vec3 _color;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex, occlusionTex)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0; float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;

View file

@ -25,6 +25,7 @@
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> <$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
in vec2 _texCoord0; in vec2 _texCoord0;
in vec2 _texCoord1;
in vec4 _position; in vec4 _position;
in vec3 _normal; in vec3 _normal;
in vec3 _color; in vec3 _color;
@ -35,7 +36,8 @@ out vec4 _fragColor;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = getMaterialOpacity(mat) * _alpha; float opacity = getMaterialOpacity(mat) * _alpha;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
@ -61,7 +63,7 @@ void main(void) {
_fragColor = vec4(evalGlobalLightingAlphaBlended( _fragColor = vec4(evalGlobalLightingAlphaBlended(
cam._viewInverse, cam._viewInverse,
1.0, 1.0,
1.0, occlusionTex,
fragPosition, fragPosition,
fragNormal, fragNormal,
albedo, albedo,

View file

@ -26,7 +26,7 @@ out vec4 _fragColor;
void main(void) { void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
float opacity = getMaterialOpacity(mat) * _alpha; float opacity = getMaterialOpacity(mat) * _alpha;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;

View file

@ -16,7 +16,7 @@
<@include model/Material.slh@> <@include model/Material.slh@>
<@include MaterialTextures.slh@> <@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$> <$declareMaterialTextures(ALBEDO)$>
in vec2 _texCoord0; in vec2 _texCoord0;
in vec3 _normal; in vec3 _normal;
@ -27,7 +27,7 @@ void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
float opacity = 1.0; float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;

View file

@ -24,6 +24,7 @@
out vec4 _position; out vec4 _position;
out vec2 _texCoord0; out vec2 _texCoord0;
out vec2 _texCoord1;
out vec3 _normal; out vec3 _normal;
out vec3 _color; out vec3 _color;
out float _alpha; out float _alpha;
@ -40,6 +41,7 @@ void main(void) {
TexMapArray texMapArray = getTexMapArray(); TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
// standard transform // standard transform
TransformCamera cam = getTransformCamera(); TransformCamera cam = getTransformCamera();

View file

@ -24,6 +24,7 @@
out vec4 _position; out vec4 _position;
out vec2 _texCoord0; out vec2 _texCoord0;
out vec2 _texCoord1;
out vec3 _normal; out vec3 _normal;
out vec3 _tangent; out vec3 _tangent;
out vec3 _color; out vec3 _color;
@ -42,6 +43,7 @@ void main(void) {
TexMapArray texMapArray = getTexMapArray(); TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0);

View file

@ -0,0 +1,181 @@
//
// CPUDetect.h
// libraries/shared/src
//
// Created by Ken Cooke on 6/6/16.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_CPUDetect_h
#define hifi_CPUDetect_h
//
// Lightweight functions to detect SSE/AVX/AVX2 support
//
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
#define ARCH_X86
#endif
#define MASK_SSE3 (1 << 0) // SSE3
#define MASK_SSSE3 (1 << 9) // SSSE3
#define MASK_SSE41 (1 << 19) // SSE4.1
#define MASK_SSE42 ((1 << 20) | (1 << 23)) // SSE4.2 and POPCNT
#define MASK_AVX ((1 << 27) | (1 << 28)) // OSXSAVE and AVX
#define MASK_AVX2 (1 << 5) // AVX2
#if defined(ARCH_X86) && defined(_MSC_VER)
#include <intrin.h>
static inline bool cpuSupportsSSE3() {
int info[4];
__cpuidex(info, 0x1, 0);
return ((info[2] & MASK_SSE3) == MASK_SSE3);
}
static inline bool cpuSupportsSSSE3() {
int info[4];
__cpuidex(info, 0x1, 0);
return ((info[2] & MASK_SSSE3) == MASK_SSSE3);
}
static inline bool cpuSupportsSSE41() {
int info[4];
__cpuidex(info, 0x1, 0);
return ((info[2] & MASK_SSE41) == MASK_SSE41);
}
static inline bool cpuSupportsSSE42() {
int info[4];
__cpuidex(info, 0x1, 0);
return ((info[2] & MASK_SSE42) == MASK_SSE42);
}
static inline bool cpuSupportsAVX() {
int info[4];
__cpuidex(info, 0x1, 0);
bool result = false;
if ((info[2] & MASK_AVX) == MASK_AVX) {
// verify OS support for YMM state
if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
result = true;
}
}
return result;
}
static inline bool cpuSupportsAVX2() {
int info[4];
bool result = false;
if (cpuSupportsAVX()) {
__cpuidex(info, 0x7, 0);
if ((info[1] & MASK_AVX2) == MASK_AVX2) {
result = true;
}
}
return result;
}
#elif defined(ARCH_X86) && defined(__GNUC__)
#include <cpuid.h>
static inline bool cpuSupportsSSE3() {
unsigned int eax, ebx, ecx, edx;
return __get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_SSE3) == MASK_SSE3);
}
static inline bool cpuSupportsSSSE3() {
unsigned int eax, ebx, ecx, edx;
return __get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_SSSE3) == MASK_SSSE3);
}
static inline bool cpuSupportsSSE41() {
unsigned int eax, ebx, ecx, edx;
return __get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_SSE41) == MASK_SSE41);
}
static inline bool cpuSupportsSSE42() {
unsigned int eax, ebx, ecx, edx;
return __get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_SSE42) == MASK_SSE42);
}
static inline bool cpuSupportsAVX() {
unsigned int eax, ebx, ecx, edx;
bool result = false;
if (__get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_AVX) == MASK_AVX)) {
// verify OS support for YMM state
__asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
if ((eax & 0x6) == 0x6) {
result = true;
}
}
return result;
}
static inline bool cpuSupportsAVX2() {
unsigned int eax, ebx, ecx, edx;
bool result = false;
if (cpuSupportsAVX()) {
if (__get_cpuid(0x7, &eax, &ebx, &ecx, &edx) && ((ebx & MASK_AVX2) == MASK_AVX2)) {
result = true;
}
}
return result;
}
#else
static inline bool cpuSupportsSSE3() {
return false;
}
static inline bool cpuSupportsSSSE3() {
return false;
}
static inline bool cpuSupportsSSE41() {
return false;
}
static inline bool cpuSupportsSSE42() {
return false;
}
static inline bool cpuSupportsAVX() {
return false;
}
static inline bool cpuSupportsAVX2() {
return false;
}
#endif
#endif // hifi_CPUDetect_h

View file

@ -10,11 +10,80 @@
// //
#include "SettingHandle.h" #include "SettingHandle.h"
#include "SettingManager.h"
#include <math.h> #include <math.h>
const QString Settings::firstRun { "firstRun" }; const QString Settings::firstRun { "firstRun" };
Settings::Settings() :
_manager(DependencyManager::get<Setting::Manager>()),
_locker(&(_manager->getLock()))
{
}
Settings::~Settings() {
}
void Settings::remove(const QString& key) {
if (key == "" || _manager->contains(key)) {
_manager->remove(key);
}
}
QStringList Settings::childGroups() const {
return _manager->childGroups();
}
QStringList Settings::childKeys() const {
return _manager->childKeys();
}
QStringList Settings::allKeys() const {
return _manager->allKeys();
}
bool Settings::contains(const QString& key) const {
return _manager->contains(key);
}
int Settings::beginReadArray(const QString & prefix) {
return _manager->beginReadArray(prefix);
}
void Settings::beginWriteArray(const QString& prefix, int size) {
_manager->beginWriteArray(prefix, size);
}
void Settings::endArray() {
_manager->endArray();
}
void Settings::setArrayIndex(int i) {
_manager->setArrayIndex(i);
}
void Settings::beginGroup(const QString& prefix) {
_manager->beginGroup(prefix);
}
void Settings::endGroup() {
_manager->endGroup();
}
void Settings::setValue(const QString& name, const QVariant& value) {
if (_manager->value(name) != value) {
_manager->setValue(name, value);
}
}
QVariant Settings::value(const QString& name, const QVariant& defaultValue) const {
return _manager->value(name, defaultValue);
}
void Settings::getFloatValueIfValid(const QString& name, float& floatValue) { void Settings::getFloatValueIfValid(const QString& name, float& floatValue) {
const QVariant badDefaultValue = NAN; const QVariant badDefaultValue = NAN;
bool ok = true; bool ok = true;

View file

@ -14,19 +14,40 @@
#include <type_traits> #include <type_traits>
#include <QSettings> #include <QtCore/QSettings>
#include <QString> #include <QtCore/QStack>
#include <QVariant> #include <QtCore/QString>
#include <QtCore/QVariant>
#include <QtCore/QReadWriteLock>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include "SettingInterface.h" #include "SettingInterface.h"
// TODO: remove // TODO: remove
class Settings : public QSettings { class Settings {
public: public:
static const QString firstRun; static const QString firstRun;
Settings();
~Settings();
void remove(const QString& key);
QStringList childGroups() const;
QStringList childKeys() const;
QStringList allKeys() const;
bool contains(const QString& key) const;
int beginReadArray(const QString & prefix);
void beginWriteArray(const QString& prefix, int size = -1);
void endArray();
void setArrayIndex(int i);
void beginGroup(const QString& prefix);
void endGroup();
void setValue(const QString& name, const QVariant& value);
QVariant value(const QString& name, const QVariant& defaultValue = QVariant()) const;
void getFloatValueIfValid(const QString& name, float& floatValue); void getFloatValueIfValid(const QString& name, float& floatValue);
void getBoolValue(const QString& name, bool& boolValue); void getBoolValue(const QString& name, bool& boolValue);
@ -36,6 +57,9 @@ public:
void setQuatValue(const QString& name, const glm::quat& quatValue); void setQuatValue(const QString& name, const glm::quat& quatValue);
void getQuatValueIfValid(const QString& name, glm::quat& quatValue); void getQuatValueIfValid(const QString& name, glm::quat& quatValue);
QSharedPointer<Setting::Manager> _manager;
QWriteLocker _locker;
}; };
namespace Setting { namespace Setting {

View file

@ -9,27 +9,33 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "SettingInterface.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QThread> #include <QThread>
#include "PathUtils.h" #include "PathUtils.h"
#include "SettingInterface.h"
#include "SettingManager.h" #include "SettingManager.h"
#include "SharedLogging.h" #include "SharedLogging.h"
namespace Setting { namespace Setting {
static Manager* privateInstance = nullptr; static QSharedPointer<Manager> globalManager;
const QString Interface::FIRST_RUN { "firstRun" };
// cleans up the settings private instance. Should only be run once at closing down. // cleans up the settings private instance. Should only be run once at closing down.
void cleanupPrivateInstance() { void cleanupPrivateInstance() {
// grab the thread before we nuke the instance // grab the thread before we nuke the instance
QThread* settingsManagerThread = privateInstance->thread(); QThread* settingsManagerThread = DependencyManager::get<Manager>()->thread();
// tell the private instance to clean itself up on its thread // tell the private instance to clean itself up on its thread
privateInstance->deleteLater(); DependencyManager::destroy<Manager>();
privateInstance = NULL;
//
globalManager->deleteLater();
globalManager.reset();
// quit the settings manager thread and wait on it to make sure it's gone // quit the settings manager thread and wait on it to make sure it's gone
settingsManagerThread->quit(); settingsManagerThread->quit();
@ -63,14 +69,13 @@ namespace Setting {
QThread* thread = new QThread(); QThread* thread = new QThread();
Q_CHECK_PTR(thread); Q_CHECK_PTR(thread);
thread->setObjectName("Settings Thread"); thread->setObjectName("Settings Thread");
privateInstance = new Manager();
Q_CHECK_PTR(privateInstance);
QObject::connect(privateInstance, SIGNAL(destroyed()), thread, SLOT(quit())); globalManager = DependencyManager::set<Manager>();
QObject::connect(thread, SIGNAL(started()), privateInstance, SLOT(startTimer()));
QObject::connect(globalManager.data(), SIGNAL(destroyed()), thread, SLOT(quit()));
QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer()));
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
privateInstance->moveToThread(thread); globalManager->moveToThread(thread);
thread->start(); thread->start();
qCDebug(shared) << "Settings thread started."; qCDebug(shared) << "Settings thread started.";
@ -79,7 +84,7 @@ namespace Setting {
} }
void Interface::init() { void Interface::init() {
if (!privateInstance) { if (!DependencyManager::isSet<Manager>()) {
// WARNING: As long as we are using QSettings this should always be triggered for each Setting::Handle // WARNING: As long as we are using QSettings this should always be triggered for each Setting::Handle
// in an assignment-client - the QSettings backing we use for this means persistence of these // in an assignment-client - the QSettings backing we use for this means persistence of these
// settings from an AC (when there can be multiple terminating at same time on one machine) // settings from an AC (when there can be multiple terminating at same time on one machine)
@ -87,9 +92,13 @@ namespace Setting {
qWarning() << "Setting::Interface::init() for key" << _key << "- Manager not yet created." << qWarning() << "Setting::Interface::init() for key" << _key << "- Manager not yet created." <<
"Settings persistence disabled."; "Settings persistence disabled.";
} else { } else {
// Register Handle _manager = DependencyManager::get<Manager>();
privateInstance->registerHandle(this); auto manager = _manager.lock();
_isInitialized = true; if (manager) {
// Register Handle
manager->registerHandle(this);
_isInitialized = true;
}
// Load value from disk // Load value from disk
load(); load();
@ -97,11 +106,13 @@ namespace Setting {
} }
void Interface::deinit() { void Interface::deinit() {
if (_isInitialized && privateInstance) { if (_isInitialized && _manager) {
// Save value to disk auto manager = _manager.lock();
save(); if (manager) {
// Save value to disk
privateInstance->removeHandle(_key); save();
manager->removeHandle(_key);
}
} }
} }
@ -113,14 +124,16 @@ namespace Setting {
} }
void Interface::save() { void Interface::save() {
if (privateInstance) { auto manager = _manager.lock();
privateInstance->saveSetting(this); if (manager) {
manager->saveSetting(this);
} }
} }
void Interface::load() { void Interface::load() {
if (privateInstance) { auto manager = _manager.lock();
privateInstance->loadSetting(this); if (manager) {
manager->loadSetting(this);
} }
} }
} }

View file

@ -12,17 +12,23 @@
#ifndef hifi_SettingInterface_h #ifndef hifi_SettingInterface_h
#define hifi_SettingInterface_h #define hifi_SettingInterface_h
#include <QString> #include <memory>
#include <QVariant> #include <QtCore/QWeakPointer>
#include <QtCore/QString>
#include <QtCore/QVariant>
namespace Setting { namespace Setting {
class Manager;
void preInit(); void preInit();
void init(); void init();
void cleanupSettings(); void cleanupSettings();
class Interface { class Interface {
public: public:
QString getKey() const { return _key; } static const QString FIRST_RUN;
const QString& getKey() const { return _key; }
bool isSet() const { return _isSet; } bool isSet() const { return _isSet; }
virtual void setVariant(const QVariant& variant) = 0; virtual void setVariant(const QVariant& variant) = 0;
@ -44,6 +50,8 @@ namespace Setting {
const QString _key; const QString _key;
friend class Manager; friend class Manager;
QWeakPointer<Manager> _manager;
}; };
} }

View file

@ -9,13 +9,15 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QThread> #include <QtCore/QThread>
#include <QDebug> #include <QtCore/QDebug>
#include <QtCore/QUuid>
#include "SettingInterface.h" #include "SettingInterface.h"
#include "SettingManager.h" #include "SettingManager.h"
namespace Setting { namespace Setting {
Manager::~Manager() { Manager::~Manager() {
// Cleanup timer // Cleanup timer
stopTimer(); stopTimer();
@ -27,6 +29,10 @@ namespace Setting {
// sync will be called in the QSettings destructor // sync will be called in the QSettings destructor
} }
// Custom deleter does nothing, because we need to shutdown later than the dependency manager
void Manager::customDeleter() { }
void Manager::registerHandle(Setting::Interface* handle) { void Manager::registerHandle(Setting::Interface* handle) {
QString key = handle->getKey(); QString key = handle->getKey();
withWriteLock([&] { withWriteLock([&] {
@ -44,15 +50,29 @@ namespace Setting {
} }
void Manager::loadSetting(Interface* handle) { void Manager::loadSetting(Interface* handle) {
handle->setVariant(value(handle->getKey())); const auto& key = handle->getKey();
withWriteLock([&] {
QVariant loadedValue;
if (_pendingChanges.contains(key)) {
loadedValue = _pendingChanges[key];
} else {
loadedValue = value(key);
}
handle->setVariant(loadedValue);
});
} }
void Manager::saveSetting(Interface* handle) { void Manager::saveSetting(Interface* handle) {
const auto& key = handle->getKey();
QVariant handleValue = UNSET_VALUE;
if (handle->isSet()) { if (handle->isSet()) {
setValue(handle->getKey(), handle->getVariant()); handleValue = handle->getVariant();
} else {
remove(handle->getKey());
} }
withWriteLock([&] {
_pendingChanges[key] = handleValue;
});
} }
static const int SAVE_INTERVAL_MSEC = 5 * 1000; // 5 sec static const int SAVE_INTERVAL_MSEC = 5 * 1000; // 5 sec
@ -74,10 +94,20 @@ namespace Setting {
} }
void Manager::saveAll() { void Manager::saveAll() {
withReadLock([&] { withWriteLock([&] {
for (auto handle : _handles) { for (auto key : _pendingChanges.keys()) {
saveSetting(handle); auto newValue = _pendingChanges[key];
auto savedValue = value(key, UNSET_VALUE);
if (newValue == savedValue) {
continue;
}
if (newValue == UNSET_VALUE) {
remove(key);
} else {
setValue(key, newValue);
}
} }
_pendingChanges.clear();
}); });
// Restart timer // Restart timer

View file

@ -12,17 +12,23 @@
#ifndef hifi_SettingManager_h #ifndef hifi_SettingManager_h
#define hifi_SettingManager_h #define hifi_SettingManager_h
#include <QPointer> #include <QtCore/QPointer>
#include <QSettings> #include <QtCore/QSettings>
#include <QTimer> #include <QtCore/QTimer>
#include <QtCore/QUuid>
#include "DependencyManager.h"
#include "shared/ReadWriteLockable.h" #include "shared/ReadWriteLockable.h"
namespace Setting { namespace Setting {
class Interface; class Interface;
class Manager : public QSettings, public ReadWriteLockable { class Manager : public QSettings, public ReadWriteLockable, public Dependency {
Q_OBJECT Q_OBJECT
public:
void customDeleter() override;
protected: protected:
~Manager(); ~Manager();
void registerHandle(Interface* handle); void registerHandle(Interface* handle);
@ -40,6 +46,8 @@ namespace Setting {
private: private:
QHash<QString, Interface*> _handles; QHash<QString, Interface*> _handles;
QPointer<QTimer> _saveTimer = nullptr; QPointer<QTimer> _saveTimer = nullptr;
const QVariant UNSET_VALUE { QUuid::createUuid().variant() };
QHash<QString, QVariant> _pendingChanges;
friend class Interface; friend class Interface;
friend void cleanupPrivateInstance(); friend void cleanupPrivateInstance();

View file

@ -23,7 +23,6 @@ void ShapeInfo::clear() {
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) {
_type = type; _type = type;
_points.clear();
switch(type) { switch(type) {
case SHAPE_TYPE_NONE: case SHAPE_TYPE_NONE:
_halfExtents = glm::vec3(0.0f); _halfExtents = glm::vec3(0.0f);
@ -52,7 +51,6 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) {
_url = ""; _url = "";
_type = SHAPE_TYPE_BOX; _type = SHAPE_TYPE_BOX;
_halfExtents = halfExtents; _halfExtents = halfExtents;
_points.clear();
_doubleHashKey.clear(); _doubleHashKey.clear();
} }
@ -60,15 +58,6 @@ void ShapeInfo::setSphere(float radius) {
_url = ""; _url = "";
_type = SHAPE_TYPE_SPHERE; _type = SHAPE_TYPE_SPHERE;
_halfExtents = glm::vec3(radius, radius, radius); _halfExtents = glm::vec3(radius, radius, radius);
_points.clear();
_doubleHashKey.clear();
}
void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) {
_url = "";
_type = SHAPE_TYPE_ELLIPSOID;
_halfExtents = halfExtents;
_points.clear();
_doubleHashKey.clear(); _doubleHashKey.clear();
} }
@ -82,7 +71,6 @@ void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
_url = ""; _url = "";
_type = SHAPE_TYPE_CAPSULE_Y; _type = SHAPE_TYPE_CAPSULE_Y;
_halfExtents = glm::vec3(radius, halfHeight, radius); _halfExtents = glm::vec3(radius, halfHeight, radius);
_points.clear();
_doubleHashKey.clear(); _doubleHashKey.clear();
} }
@ -146,10 +134,6 @@ bool ShapeInfo::contains(const glm::vec3& point) const {
switch(_type) { switch(_type) {
case SHAPE_TYPE_SPHERE: case SHAPE_TYPE_SPHERE:
return glm::length(point) <= _halfExtents.x; return glm::length(point) <= _halfExtents.x;
case SHAPE_TYPE_ELLIPSOID: {
glm::vec3 scaledPoint = glm::abs(point) / _halfExtents;
return glm::length(scaledPoint) <= 1.0f;
}
case SHAPE_TYPE_CYLINDER_X: case SHAPE_TYPE_CYLINDER_X:
return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z; return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z;
case SHAPE_TYPE_CYLINDER_Y: case SHAPE_TYPE_CYLINDER_Y:

View file

@ -30,7 +30,6 @@ enum ShapeType {
SHAPE_TYPE_NONE, SHAPE_TYPE_NONE,
SHAPE_TYPE_BOX, SHAPE_TYPE_BOX,
SHAPE_TYPE_SPHERE, SHAPE_TYPE_SPHERE,
SHAPE_TYPE_ELLIPSOID,
SHAPE_TYPE_PLANE, SHAPE_TYPE_PLANE,
SHAPE_TYPE_COMPOUND, SHAPE_TYPE_COMPOUND,
SHAPE_TYPE_CAPSULE_X, SHAPE_TYPE_CAPSULE_X,
@ -39,7 +38,7 @@ enum ShapeType {
SHAPE_TYPE_CYLINDER_X, SHAPE_TYPE_CYLINDER_X,
SHAPE_TYPE_CYLINDER_Y, SHAPE_TYPE_CYLINDER_Y,
SHAPE_TYPE_CYLINDER_Z, SHAPE_TYPE_CYLINDER_Z,
SHAPE_TYPE_LINE SHAPE_TYPE_STATIC_MESH
}; };
class ShapeInfo { class ShapeInfo {
@ -50,7 +49,6 @@ public:
void setParams(ShapeType type, const glm::vec3& halfExtents, QString url=""); void setParams(ShapeType type, const glm::vec3& halfExtents, QString url="");
void setBox(const glm::vec3& halfExtents); void setBox(const glm::vec3& halfExtents);
void setSphere(float radius); void setSphere(float radius);
void setEllipsoid(const glm::vec3& halfExtents);
void setConvexHulls(const QVector<QVector<glm::vec3>>& points); void setConvexHulls(const QVector<QVector<glm::vec3>>& points);
void setCapsuleY(float radius, float halfHeight); void setCapsuleY(float radius, float halfHeight);
void setOffset(const glm::vec3& offset); void setOffset(const glm::vec3& offset);
@ -60,10 +58,10 @@ public:
const glm::vec3& getHalfExtents() const { return _halfExtents; } const glm::vec3& getHalfExtents() const { return _halfExtents; }
const glm::vec3& getOffset() const { return _offset; } const glm::vec3& getOffset() const { return _offset; }
QVector<QVector<glm::vec3>>& getPoints() { return _points; }
const QVector<QVector<glm::vec3>>& getPoints() const { return _points; } const QVector<QVector<glm::vec3>>& getPoints() const { return _points; }
uint32_t getNumSubShapes() const; uint32_t getNumSubShapes() const;
void clearPoints () { _points.clear(); }
void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; } void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; }
int getMaxNumPoints() const; int getMaxNumPoints() const;

View file

@ -45,6 +45,8 @@ public:
template <typename F> template <typename F>
bool withTryReadLock(F&& f, int timeout) const; bool withTryReadLock(F&& f, int timeout) const;
QReadWriteLock& getLock() const { return _lock; }
private: private:
mutable QReadWriteLock _lock { QReadWriteLock::Recursive }; mutable QReadWriteLock _lock { QReadWriteLock::Recursive };
}; };

View file

@ -1 +1 @@
{} {"name":"Neuron"}

View file

@ -21,9 +21,16 @@ Joystick::Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameControl
InputDevice("GamePad"), InputDevice("GamePad"),
_sdlGameController(sdlGameController), _sdlGameController(sdlGameController),
_sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)), _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
_sdlHaptic(SDL_HapticOpenFromJoystick(_sdlJoystick)),
_instanceId(instanceId) _instanceId(instanceId)
{ {
if (!_sdlHaptic) {
qDebug() << "SDL Haptic Open Failure: " << QString(SDL_GetError());
} else {
if (SDL_HapticRumbleInit(_sdlHaptic) != 0) {
qDebug() << "SDL Haptic Rumble Init Failure: " << QString(SDL_GetError());
}
}
} }
Joystick::~Joystick() { Joystick::~Joystick() {
@ -31,6 +38,9 @@ Joystick::~Joystick() {
} }
void Joystick::closeJoystick() { void Joystick::closeJoystick() {
if (_sdlHaptic) {
SDL_HapticClose(_sdlHaptic);
}
SDL_GameControllerClose(_sdlGameController); SDL_GameControllerClose(_sdlGameController);
} }
@ -62,55 +72,64 @@ void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
} }
} }
bool Joystick::triggerHapticPulse(float strength, float duration, controller::Hand hand) {
if (SDL_HapticRumblePlay(_sdlHaptic, strength, duration) != 0) {
return false;
}
return true;
}
controller::Input::NamedVector Joystick::getAvailableInputs() const { controller::Input::NamedVector Joystick::getAvailableInputs() const {
using namespace controller; using namespace controller;
static const Input::NamedVector availableInputs{ if (_availableInputs.length() == 0) {
makePair(A, "A"), _availableInputs = {
makePair(B, "B"), makePair(A, "A"),
makePair(X, "X"), makePair(B, "B"),
makePair(Y, "Y"), makePair(X, "X"),
// DPad makePair(Y, "Y"),
makePair(DU, "DU"), // DPad
makePair(DD, "DD"), makePair(DU, "DU"),
makePair(DL, "DL"), makePair(DD, "DD"),
makePair(DR, "DR"), makePair(DL, "DL"),
// Bumpers makePair(DR, "DR"),
makePair(LB, "LB"), // Bumpers
makePair(RB, "RB"), makePair(LB, "LB"),
// Stick press makePair(RB, "RB"),
makePair(LS, "LS"), // Stick press
makePair(RS, "RS"), makePair(LS, "LS"),
// Center buttons makePair(RS, "RS"),
makePair(START, "Start"), // Center buttons
makePair(BACK, "Back"), makePair(START, "Start"),
// Analog sticks makePair(BACK, "Back"),
makePair(LX, "LX"), // Analog sticks
makePair(LY, "LY"), makePair(LX, "LX"),
makePair(RX, "RX"), makePair(LY, "LY"),
makePair(RY, "RY"), makePair(RX, "RX"),
makePair(RY, "RY"),
// Triggers
makePair(LT, "LT"),
makePair(RT, "RT"),
// Aliases, PlayStation style names // Triggers
makePair(LB, "L1"), makePair(LT, "LT"),
makePair(RB, "R1"), makePair(RT, "RT"),
makePair(LT, "L2"),
makePair(RT, "R2"), // Aliases, PlayStation style names
makePair(LS, "L3"), makePair(LB, "L1"),
makePair(RS, "R3"), makePair(RB, "R1"),
makePair(BACK, "Select"), makePair(LT, "L2"),
makePair(A, "Cross"), makePair(RT, "R2"),
makePair(B, "Circle"), makePair(LS, "L3"),
makePair(X, "Square"), makePair(RS, "R3"),
makePair(Y, "Triangle"), makePair(BACK, "Select"),
makePair(DU, "Up"), makePair(A, "Cross"),
makePair(DD, "Down"), makePair(B, "Circle"),
makePair(DL, "Left"), makePair(X, "Square"),
makePair(DR, "Right"), makePair(Y, "Triangle"),
}; makePair(DU, "Up"),
return availableInputs; makePair(DD, "Down"),
makePair(DL, "Left"),
makePair(DR, "Right"),
};
}
return _availableInputs;
} }
QString Joystick::getDefaultMappingConfig() const { QString Joystick::getDefaultMappingConfig() const {

View file

@ -36,6 +36,8 @@ public:
virtual QString getDefaultMappingConfig() const override; virtual QString getDefaultMappingConfig() const override;
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
virtual void focusOutEvent() override; virtual void focusOutEvent() override;
bool triggerHapticPulse(float strength, float duration, controller::Hand hand) override;
Joystick() : InputDevice("GamePad") {} Joystick() : InputDevice("GamePad") {}
~Joystick(); ~Joystick();
@ -52,7 +54,10 @@ public:
private: private:
SDL_GameController* _sdlGameController; SDL_GameController* _sdlGameController;
SDL_Joystick* _sdlJoystick; SDL_Joystick* _sdlJoystick;
SDL_Haptic* _sdlHaptic;
SDL_JoystickID _instanceId; SDL_JoystickID _instanceId;
mutable controller::Input::NamedVector _availableInputs;
}; };
#endif // hifi_Joystick_h #endif // hifi_Joystick_h

View file

@ -49,7 +49,7 @@ SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) {
} }
void SDL2Manager::init() { void SDL2Manager::init() {
bool initSuccess = (SDL_Init(SDL_INIT_GAMECONTROLLER) == 0); bool initSuccess = (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) == 0);
if (initSuccess) { if (initSuccess) {
int joystickCount = SDL_NumJoysticks(); int joystickCount = SDL_NumJoysticks();

View file

@ -1 +1 @@
{} {"name":"SDL2"}

View file

@ -1 +1 @@
{} {"name":"Sixense"}

View file

@ -1 +1 @@
{} {"name":"Spacemouse"}

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