mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 21:05:04 +02:00
Merge branch 'master' into 20639
This commit is contained in:
commit
b70c1a4960
37 changed files with 271 additions and 162 deletions
1
BUILD.md
1
BUILD.md
|
@ -5,6 +5,7 @@
|
||||||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1m
|
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1m
|
||||||
* IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
|
* IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
|
||||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||||
|
* [zlib](http://www.zlib.net/)
|
||||||
|
|
||||||
####CMake External Project Dependencies
|
####CMake External Project Dependencies
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
||||||
|
|
||||||
###Homebrew
|
###Homebrew
|
||||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all hifi dependencies very simple.
|
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all High Fidelity dependencies very simple.
|
||||||
|
|
||||||
brew tap highfidelity/homebrew-formulas
|
brew tap highfidelity/homebrew-formulas
|
||||||
brew install cmake openssl
|
brew install cmake openssl
|
||||||
|
|
10
BUILD_WIN.md
10
BUILD_WIN.md
|
@ -75,6 +75,16 @@ To prevent these problems, install OpenSSL yourself. Download the following bina
|
||||||
|
|
||||||
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
|
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
|
||||||
|
|
||||||
|
####zlib
|
||||||
|
|
||||||
|
Install zlib from
|
||||||
|
|
||||||
|
[Zlib for Windows](http://gnuwin32.sourceforge.net/packages/zlib.htm)
|
||||||
|
|
||||||
|
and fix a header file, as described here:
|
||||||
|
|
||||||
|
[zlib zconf.h bug](http://sourceforge.net/p/gnuwin32/bugs/169/)
|
||||||
|
|
||||||
###Build High Fidelity using Visual Studio
|
###Build High Fidelity using Visual Studio
|
||||||
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.
|
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.
|
||||||
|
|
||||||
|
|
|
@ -580,7 +580,6 @@ void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet)
|
||||||
NodeType_t nodeType;
|
NodeType_t nodeType;
|
||||||
HifiSockAddr publicSockAddr, localSockAddr;
|
HifiSockAddr publicSockAddr, localSockAddr;
|
||||||
|
|
||||||
|
|
||||||
if (packet->getPayloadSize() == 0) {
|
if (packet->getPayloadSize() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -625,31 +624,62 @@ void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<NodeType_t> nodeInterestList;
|
QList<NodeType_t> nodeInterestList;
|
||||||
QString username;
|
QString username;
|
||||||
QByteArray usernameSignature;
|
QByteArray usernameSignature;
|
||||||
|
|
||||||
packetStream >> nodeInterestList >> username >> usernameSignature;
|
|
||||||
|
|
||||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
|
packetStream >> nodeInterestList;
|
||||||
|
|
||||||
|
if (packet->bytesLeftToRead() > 0) {
|
||||||
|
// try to verify username
|
||||||
|
packetStream >> username;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRestrictingAccess =
|
||||||
|
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
|
||||||
|
|
||||||
|
// we always let in a user who is sending a packet from our local socket or from the localhost address
|
||||||
|
bool isLocalUser = (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress() || senderSockAddr.getAddress() == QHostAddress::LocalHost);
|
||||||
|
|
||||||
|
if (isRestrictingAccess && !isLocalUser) {
|
||||||
|
if (!username.isEmpty()) {
|
||||||
|
// if there's a username, try to unpack username signature
|
||||||
|
packetStream >> usernameSignature;
|
||||||
|
|
||||||
|
if (usernameSignature.isEmpty()) {
|
||||||
|
// if user didn't include usernameSignature in connect request, send a connectionToken packet
|
||||||
|
QUuid& connectionToken = _connectionTokenHash[username.toLower()];
|
||||||
|
|
||||||
|
if (connectionToken.isNull()) {
|
||||||
|
connectionToken = QUuid::createUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto connectionTokenPacket = NLPacket::create(PacketType::DomainServerConnectionToken, NUM_BYTES_RFC4122_UUID);
|
||||||
|
connectionTokenPacket->reset();
|
||||||
|
connectionTokenPacket->write(connectionToken.toRfc4122());
|
||||||
|
limitedNodeList->sendUnreliablePacket(*connectionTokenPacket, packet->getSenderSockAddr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString reason;
|
QString reason;
|
||||||
if (!isAssignment && !shouldAllowConnectionFromNode(username, usernameSignature, senderSockAddr, reason)) {
|
if (!isAssignment && !shouldAllowConnectionFromNode(username, usernameSignature, senderSockAddr, reason)) {
|
||||||
// this is an agent and we've decided we won't let them connect - send them a packet to deny connection
|
// this is an agent and we've decided we won't let them connect - send them a packet to deny connection
|
||||||
|
|
||||||
QByteArray utfString = reason.toUtf8();
|
QByteArray utfString = reason.toUtf8();
|
||||||
quint16 payloadSize = utfString.size();
|
quint16 payloadSize = utfString.size();
|
||||||
|
|
||||||
auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, payloadSize + sizeof(payloadSize));
|
auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, payloadSize + sizeof(payloadSize));
|
||||||
|
if (payloadSize > 0) {
|
||||||
connectionDeniedPacket->writePrimitive(payloadSize);
|
connectionDeniedPacket->writePrimitive(payloadSize);
|
||||||
connectionDeniedPacket->write(utfString);
|
connectionDeniedPacket->write(utfString);
|
||||||
|
}
|
||||||
// tell client it has been refused.
|
// tell client it has been refused.
|
||||||
limitedNodeList->sendPacket(std::move(connectionDeniedPacket), senderSockAddr);
|
limitedNodeList->sendPacket(std::move(connectionDeniedPacket), senderSockAddr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,6 +766,7 @@ void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DomainServer::processListRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
void DomainServer::processListRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||||
|
|
||||||
NodeType_t throwawayNodeType;
|
NodeType_t throwawayNodeType;
|
||||||
|
@ -766,13 +797,16 @@ unsigned int DomainServer::countConnectedUsers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DomainServer::verifyUsersKey(const QString& username,
|
bool DomainServer::verifyUserSignature(const QString& username,
|
||||||
const QByteArray& usernameSignature,
|
const QByteArray& usernameSignature,
|
||||||
QString& reasonReturn) {
|
QString& reasonReturn) {
|
||||||
// it's possible this user can be allowed to connect, but we need to check their username signature
|
|
||||||
|
|
||||||
|
// it's possible this user can be allowed to connect, but we need to check their username signature
|
||||||
QByteArray publicKeyArray = _userPublicKeys.value(username);
|
QByteArray publicKeyArray = _userPublicKeys.value(username);
|
||||||
if (!publicKeyArray.isEmpty()) {
|
|
||||||
|
const QUuid& connectionToken = _connectionTokenHash.value(username.toLower());
|
||||||
|
|
||||||
|
if (!publicKeyArray.isEmpty() && !connectionToken.isNull()) {
|
||||||
// if we do have a public key for the user, check for a signature match
|
// if we do have a public key for the user, check for a signature match
|
||||||
|
|
||||||
const unsigned char* publicKeyData = reinterpret_cast<const unsigned char*>(publicKeyArray.constData());
|
const unsigned char* publicKeyData = reinterpret_cast<const unsigned char*>(publicKeyArray.constData());
|
||||||
|
@ -780,38 +814,44 @@ bool DomainServer::verifyUsersKey(const QString& username,
|
||||||
// first load up the public key into an RSA struct
|
// first load up the public key into an RSA struct
|
||||||
RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, publicKeyArray.size());
|
RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, publicKeyArray.size());
|
||||||
|
|
||||||
|
QByteArray lowercaseUsername = username.toLower().toUtf8();
|
||||||
|
QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()),
|
||||||
|
QCryptographicHash::Sha256);
|
||||||
|
|
||||||
if (rsaPublicKey) {
|
if (rsaPublicKey) {
|
||||||
QByteArray decryptedArray(RSA_size(rsaPublicKey), 0);
|
QByteArray decryptedArray(RSA_size(rsaPublicKey), 0);
|
||||||
int decryptResult =
|
int decryptResult = RSA_verify(NID_sha256,
|
||||||
RSA_public_decrypt(usernameSignature.size(),
|
reinterpret_cast<const unsigned char*>(usernameWithToken.constData()),
|
||||||
|
usernameWithToken.size(),
|
||||||
reinterpret_cast<const unsigned char*>(usernameSignature.constData()),
|
reinterpret_cast<const unsigned char*>(usernameSignature.constData()),
|
||||||
reinterpret_cast<unsigned char*>(decryptedArray.data()),
|
usernameSignature.size(),
|
||||||
rsaPublicKey, RSA_PKCS1_PADDING);
|
rsaPublicKey);
|
||||||
|
|
||||||
if (decryptResult != -1) {
|
if (decryptResult == 1) {
|
||||||
if (username.toLower() == decryptedArray) {
|
|
||||||
qDebug() << "Username signature matches for" << username << "- allowing connection.";
|
qDebug() << "Username signature matches for" << username << "- allowing connection.";
|
||||||
|
|
||||||
// free up the public key before we return
|
// free up the public key and remove connection token before we return
|
||||||
RSA_free(rsaPublicKey);
|
RSA_free(rsaPublicKey);
|
||||||
|
_connectionTokenHash.remove(username);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
qDebug() << "Username signature did not match for" << username << "- denying connection.";
|
|
||||||
reasonReturn = "Username signature did not match.";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qDebug() << "Couldn't decrypt user signature for" << username << "- denying connection.";
|
|
||||||
reasonReturn = "Couldn't decrypt user signature.";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qDebug() << "Error decrypting username signature for " << username << "- denying connection.";
|
||||||
|
reasonReturn = "Error decrypting username signature.";
|
||||||
// free up the public key, we don't need it anymore
|
// free up the public key, we don't need it anymore
|
||||||
RSA_free(rsaPublicKey);
|
RSA_free(rsaPublicKey);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// we can't let this user in since we couldn't convert their public key to an RSA key we could use
|
// we can't let this user in since we couldn't convert their public key to an RSA key we could use
|
||||||
qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection.";
|
qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection.";
|
||||||
reasonReturn = "Couldn't convert data to RSA key.";
|
reasonReturn = "Couldn't convert data to RSA key.";
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "Insufficient data to decrypt username signature - denying connection.";
|
||||||
|
reasonReturn = "Insufficient data";
|
||||||
}
|
}
|
||||||
|
|
||||||
requestUserPublicKey(username); // no joy. maybe next time?
|
requestUserPublicKey(username); // no joy. maybe next time?
|
||||||
|
@ -824,22 +864,22 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
|
||||||
const HifiSockAddr& senderSockAddr,
|
const HifiSockAddr& senderSockAddr,
|
||||||
QString& reasonReturn) {
|
QString& reasonReturn) {
|
||||||
|
|
||||||
|
//TODO: improve flow so these bools aren't declared twice
|
||||||
bool isRestrictingAccess =
|
bool isRestrictingAccess =
|
||||||
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
|
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
|
||||||
|
bool isLocalUser = (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress() || senderSockAddr.getAddress() == QHostAddress::LocalHost);
|
||||||
|
|
||||||
// we always let in a user who is sending a packet from our local socket or from the localhost address
|
if (isRestrictingAccess && !isLocalUser) {
|
||||||
if (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress()
|
|
||||||
|| senderSockAddr.getAddress() == QHostAddress::LocalHost) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isRestrictingAccess) {
|
|
||||||
|
|
||||||
QStringList allowedUsers =
|
QStringList allowedUsers =
|
||||||
_settingsManager.valueOrDefaultValueForKeyPath(ALLOWED_USERS_SETTINGS_KEYPATH).toStringList();
|
_settingsManager.valueOrDefaultValueForKeyPath(ALLOWED_USERS_SETTINGS_KEYPATH).toStringList();
|
||||||
|
|
||||||
if (allowedUsers.contains(username, Qt::CaseInsensitive)) {
|
if (allowedUsers.contains(username, Qt::CaseInsensitive)) {
|
||||||
if (!verifyUsersKey(username, usernameSignature, reasonReturn)) {
|
if (username.isEmpty()) {
|
||||||
|
qDebug() << "Connect request denied - no username provided.";
|
||||||
|
reasonReturn = "No username provided";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!verifyUserSignature(username, usernameSignature, reasonReturn)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -851,13 +891,12 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
|
||||||
}
|
}
|
||||||
|
|
||||||
// either we aren't restricting users, or this user is in the allowed list
|
// either we aren't restricting users, or this user is in the allowed list
|
||||||
|
|
||||||
// if this user is in the editors list, exempt them from the max-capacity check
|
// if this user is in the editors list, exempt them from the max-capacity check
|
||||||
const QVariant* allowedEditorsVariant =
|
const QVariant* allowedEditorsVariant =
|
||||||
valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH);
|
valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH);
|
||||||
QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList();
|
QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList();
|
||||||
if (allowedEditors.contains(username)) {
|
if (allowedEditors.contains(username)) {
|
||||||
if (verifyUsersKey(username, usernameSignature, reasonReturn)) {
|
if (verifyUserSignature(username, usernameSignature, reasonReturn)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ private:
|
||||||
void pingPunchForConnectingPeer(const SharedNetworkPeer& peer);
|
void pingPunchForConnectingPeer(const SharedNetworkPeer& peer);
|
||||||
|
|
||||||
unsigned int countConnectedUsers();
|
unsigned int countConnectedUsers();
|
||||||
bool verifyUsersKey (const QString& username, const QByteArray& usernameSignature, QString& reasonReturn);
|
bool verifyUserSignature (const QString& username, const QByteArray& usernameSignature, QString& reasonReturn);
|
||||||
bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature,
|
bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature,
|
||||||
const HifiSockAddr& senderSockAddr, QString& reasonReturn);
|
const HifiSockAddr& senderSockAddr, QString& reasonReturn);
|
||||||
|
|
||||||
|
@ -150,6 +150,8 @@ private:
|
||||||
QSet<QUuid> _webAuthenticationStateSet;
|
QSet<QUuid> _webAuthenticationStateSet;
|
||||||
QHash<QUuid, DomainServerWebSessionData> _cookieSessionHash;
|
QHash<QUuid, DomainServerWebSessionData> _cookieSessionHash;
|
||||||
|
|
||||||
|
QHash<QString, QUuid> _connectionTokenHash;
|
||||||
|
|
||||||
QHash<QString, QByteArray> _userPublicKeys;
|
QHash<QString, QByteArray> _userPublicKeys;
|
||||||
|
|
||||||
QHash<QUuid, SharedNetworkPeer> _icePeers;
|
QHash<QUuid, SharedNetworkPeer> _icePeers;
|
||||||
|
|
BIN
interface/resources/images/normalFittingScale.dds
Normal file
BIN
interface/resources/images/normalFittingScale.dds
Normal file
Binary file not shown.
|
@ -107,7 +107,7 @@ JointReferential::JointReferential(Referential* referential, EntityTree* tree, A
|
||||||
|
|
||||||
EntityItemPointer item = _tree->findEntityByID(_entityID);
|
EntityItemPointer item = _tree->findEntityByID(_entityID);
|
||||||
const Model* model = getModel(item);
|
const Model* model = getModel(item);
|
||||||
if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) {
|
if (isValid() && model != NULL && _jointIndex < (uint32_t)(model->getJointStateCount())) {
|
||||||
_lastRefDimension = item->getDimensions();
|
_lastRefDimension = item->getDimensions();
|
||||||
model->getJointRotationInWorldFrame(_jointIndex, _refRotation);
|
model->getJointRotationInWorldFrame(_jointIndex, _refRotation);
|
||||||
model->getJointPositionInWorldFrame(_jointIndex, _refPosition);
|
model->getJointPositionInWorldFrame(_jointIndex, _refPosition);
|
||||||
|
|
|
@ -47,9 +47,6 @@
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "InterfaceLogging.h"
|
#include "InterfaceLogging.h"
|
||||||
|
|
||||||
#include "gpu/GLBackend.h"
|
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||||
|
|
|
@ -97,7 +97,6 @@ void SkeletonModel::initJointStates(QVector<JointState> states) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const float PALM_PRIORITY = DEFAULT_PRIORITY;
|
const float PALM_PRIORITY = DEFAULT_PRIORITY;
|
||||||
const float LEAN_PRIORITY = DEFAULT_PRIORITY;
|
|
||||||
|
|
||||||
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
if (_owningAvatar->isMyAvatar()) {
|
if (_owningAvatar->isMyAvatar()) {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include <avatar/AvatarManager.h>
|
#include <avatar/AvatarManager.h>
|
||||||
#include <DeferredLightingEffect.h>
|
#include <DeferredLightingEffect.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <gpu/GLBackend.h>
|
|
||||||
#include <gpu/GLBackendShared.h>
|
#include <gpu/GLBackendShared.h>
|
||||||
#include <FramebufferCache.h>
|
#include <FramebufferCache.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
|
@ -32,7 +31,6 @@
|
||||||
#include "ui/AvatarInputs.h"
|
#include "ui/AvatarInputs.h"
|
||||||
|
|
||||||
const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f };
|
const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f };
|
||||||
const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
|
|
||||||
static const float ORTHO_NEAR_CLIP = -1000.0f;
|
static const float ORTHO_NEAR_CLIP = -1000.0f;
|
||||||
static const float ORTHO_FAR_CLIP = 1000.0f;
|
static const float ORTHO_FAR_CLIP = 1000.0f;
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ void BillboardOverlay::render(RenderArgs* args) {
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(transform);
|
||||||
batch->setResourceTexture(0, _texture->getGPUTexture());
|
batch->setResourceTexture(0, _texture->getGPUTexture());
|
||||||
|
|
||||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch, true, true, false, true);
|
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch, true, false, false, true);
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(
|
DependencyManager::get<GeometryCache>()->renderQuad(
|
||||||
*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||||
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha)
|
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha)
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include <render/Scene.h>
|
#include <render/Scene.h>
|
||||||
#include <gpu/GLBackend.h>
|
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <gpu/GLBackend.h>
|
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
|
@ -70,6 +70,7 @@ void Rig::startAnimation(const QString& url, float fps, float priority,
|
||||||
handle = createAnimationHandle();
|
handle = createAnimationHandle();
|
||||||
handle->setURL(url);
|
handle->setURL(url);
|
||||||
}
|
}
|
||||||
|
handle->setFade(1.0f); // If you want to fade, use the startAnimationByRole system.
|
||||||
handle->setFPS(fps);
|
handle->setFPS(fps);
|
||||||
handle->setPriority(priority);
|
handle->setPriority(priority);
|
||||||
handle->setLoop(loop);
|
handle->setLoop(loop);
|
||||||
|
@ -150,7 +151,8 @@ void Rig::stopAnimationByRole(const QString& role) {
|
||||||
void Rig::stopAnimation(const QString& url) {
|
void Rig::stopAnimation(const QString& url) {
|
||||||
foreach (const AnimationHandlePointer& handle, getRunningAnimations()) {
|
foreach (const AnimationHandlePointer& handle, getRunningAnimations()) {
|
||||||
if (handle->getURL() == url) {
|
if (handle->getURL() == url) {
|
||||||
handle->stop();
|
handle->setFade(0.0f); // right away. Will be remove during updateAnimations, without locking
|
||||||
|
handle->setFadePerSecond(-1.0f); // so that the updateAnimation code notices
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,7 +474,9 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 parentTransform) {
|
||||||
float fadeSumSoFar = 0.0f;
|
float fadeSumSoFar = 0.0f;
|
||||||
foreach (const AnimationHandlePointer& handle, _runningAnimations) {
|
foreach (const AnimationHandlePointer& handle, _runningAnimations) {
|
||||||
handle->setPriority(1.0f);
|
handle->setPriority(1.0f);
|
||||||
float normalizedFade = handle->getFade() / fadeTotal;
|
// if no fadeTotal, everyone's (typically just one running) is starting at zero. In that case, blend equally.
|
||||||
|
float normalizedFade = (fadeTotal != 0.0f) ? (handle->getFade() / fadeTotal) : (1.0f / _runningAnimations.count());
|
||||||
|
assert(normalizedFade != 0.0f);
|
||||||
// simulate() will blend each animation result into the result so far, based on the pairwise mix at at each step.
|
// simulate() will blend each animation result into the result so far, based on the pairwise mix at at each step.
|
||||||
// i.e., slerp the 'mix' distance from the result so far towards this iteration's animation result.
|
// i.e., slerp the 'mix' distance from the result so far towards this iteration's animation result.
|
||||||
// The formula here for mix is based on the idea that, at each step:
|
// The formula here for mix is based on the idea that, at each step:
|
||||||
|
|
|
@ -976,6 +976,8 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) {
|
||||||
data.extracted.mesh.meshIndex = meshIndex++;
|
data.extracted.mesh.meshIndex = meshIndex++;
|
||||||
QVector<int> materials;
|
QVector<int> materials;
|
||||||
QVector<int> textures;
|
QVector<int> textures;
|
||||||
|
bool isMaterialPerPolygon = false;
|
||||||
|
|
||||||
foreach (const FBXNode& child, object.children) {
|
foreach (const FBXNode& child, object.children) {
|
||||||
if (child.name == "Vertices") {
|
if (child.name == "Vertices") {
|
||||||
data.vertices = createVec3Vector(getDoubleVector(child));
|
data.vertices = createVec3Vector(getDoubleVector(child));
|
||||||
|
@ -1105,8 +1107,16 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) {
|
||||||
foreach (const FBXNode& subdata, child.children) {
|
foreach (const FBXNode& subdata, child.children) {
|
||||||
if (subdata.name == "Materials") {
|
if (subdata.name == "Materials") {
|
||||||
materials = getIntVector(subdata);
|
materials = getIntVector(subdata);
|
||||||
|
} else if (subdata.name == "MappingInformationType") {
|
||||||
|
if (subdata.properties.at(0) == "ByPolygon") {
|
||||||
|
isMaterialPerPolygon = true;
|
||||||
|
} else {
|
||||||
|
isMaterialPerPolygon = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} else if (child.name == "LayerElementTexture") {
|
} else if (child.name == "LayerElementTexture") {
|
||||||
foreach (const FBXNode& subdata, child.children) {
|
foreach (const FBXNode& subdata, child.children) {
|
||||||
if (subdata.name == "TextureId") {
|
if (subdata.name == "TextureId") {
|
||||||
|
@ -1116,6 +1126,12 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool isMultiMaterial = false;
|
||||||
|
if (isMaterialPerPolygon) {
|
||||||
|
isMultiMaterial = true;
|
||||||
|
}
|
||||||
|
|
||||||
// convert the polygons to quads and triangles
|
// convert the polygons to quads and triangles
|
||||||
int polygonIndex = 0;
|
int polygonIndex = 0;
|
||||||
QHash<QPair<int, int>, int> materialTextureParts;
|
QHash<QPair<int, int>, int> materialTextureParts;
|
||||||
|
@ -2104,6 +2120,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
||||||
if (type.contains("diffuse")) {
|
if (type.contains("diffuse")) {
|
||||||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
|
} else if (type.contains("transparentcolor")) { // it should be TransparentColor...
|
||||||
|
// THis is how Maya assign a texture that affect diffuse color AND transparency ?
|
||||||
|
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
} else if (type.contains("bump") || type.contains("normal")) {
|
} else if (type.contains("bump") || type.contains("normal")) {
|
||||||
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,6 @@ void GLBackend::releaseUniformBuffer(uint32_t slot) {
|
||||||
if (buf) {
|
if (buf) {
|
||||||
auto* object = Backend::getGPUObject<GLBackend::GLBuffer>(*buf);
|
auto* object = Backend::getGPUObject<GLBackend::GLBuffer>(*buf);
|
||||||
if (object) {
|
if (object) {
|
||||||
GLuint bo = object->_buffer;
|
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
|
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
|
||||||
|
|
||||||
(void) CHECK_GL_ERROR();
|
(void) CHECK_GL_ERROR();
|
||||||
|
@ -222,7 +221,6 @@ void GLBackend::releaseResourceTexture(uint32_t slot) {
|
||||||
if (tex) {
|
if (tex) {
|
||||||
auto* object = Backend::getGPUObject<GLBackend::GLTexture>(*tex);
|
auto* object = Backend::getGPUObject<GLBackend::GLTexture>(*tex);
|
||||||
if (object) {
|
if (object) {
|
||||||
GLuint to = object->_texture;
|
|
||||||
GLuint target = object->_target;
|
GLuint target = object->_target;
|
||||||
glActiveTexture(GL_TEXTURE0 + slot);
|
glActiveTexture(GL_TEXTURE0 + slot);
|
||||||
glBindTexture(target, 0); // RELEASE
|
glBindTexture(target, 0); // RELEASE
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
|
||||||
#include <qjsondocument.h>
|
#include <qjsondocument.h>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QDataStream>
|
#include <QtCore/QDataStream>
|
||||||
|
|
||||||
|
#include "UUID.h"
|
||||||
#include "NetworkLogging.h"
|
#include "NetworkLogging.h"
|
||||||
#include "DataServerAccountInfo.h"
|
#include "DataServerAccountInfo.h"
|
||||||
|
|
||||||
|
@ -30,8 +32,7 @@ DataServerAccountInfo::DataServerAccountInfo() :
|
||||||
_walletID(),
|
_walletID(),
|
||||||
_balance(0),
|
_balance(0),
|
||||||
_hasBalance(false),
|
_hasBalance(false),
|
||||||
_privateKey(),
|
_privateKey()
|
||||||
_usernameSignature()
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -74,9 +75,6 @@ void DataServerAccountInfo::setUsername(const QString& username) {
|
||||||
if (_username != username) {
|
if (_username != username) {
|
||||||
_username = username;
|
_username = username;
|
||||||
|
|
||||||
// clear our username signature so it has to be re-created
|
|
||||||
_usernameSignature = QByteArray();
|
|
||||||
|
|
||||||
qCDebug(networking) << "Username changed to" << username;
|
qCDebug(networking) << "Username changed to" << username;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,8 +126,8 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject
|
||||||
setWalletID(QUuid(user["wallet_id"].toString()));
|
setWalletID(QUuid(user["wallet_id"].toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray& DataServerAccountInfo::getUsernameSignature() {
|
QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) {
|
||||||
if (_usernameSignature.isEmpty()) {
|
|
||||||
if (!_privateKey.isEmpty()) {
|
if (!_privateKey.isEmpty()) {
|
||||||
const char* privateKeyData = _privateKey.constData();
|
const char* privateKeyData = _privateKey.constData();
|
||||||
RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL,
|
RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL,
|
||||||
|
@ -137,36 +135,41 @@ const QByteArray& DataServerAccountInfo::getUsernameSignature() {
|
||||||
_privateKey.size());
|
_privateKey.size());
|
||||||
if (rsaPrivateKey) {
|
if (rsaPrivateKey) {
|
||||||
QByteArray lowercaseUsername = _username.toLower().toUtf8();
|
QByteArray lowercaseUsername = _username.toLower().toUtf8();
|
||||||
_usernameSignature.resize(RSA_size(rsaPrivateKey));
|
QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()),
|
||||||
|
QCryptographicHash::Sha256);
|
||||||
|
|
||||||
int encryptReturn = RSA_private_encrypt(lowercaseUsername.size(),
|
QByteArray usernameSignature(RSA_size(rsaPrivateKey), 0);
|
||||||
reinterpret_cast<const unsigned char*>(lowercaseUsername.constData()),
|
unsigned int usernameSignatureSize = 0;
|
||||||
reinterpret_cast<unsigned char*>(_usernameSignature.data()),
|
|
||||||
rsaPrivateKey, RSA_PKCS1_PADDING);
|
int encryptReturn = RSA_sign(NID_sha256,
|
||||||
|
reinterpret_cast<const unsigned char*>(usernameWithToken.constData()),
|
||||||
|
usernameWithToken.size(),
|
||||||
|
reinterpret_cast<unsigned char*>(usernameSignature.data()),
|
||||||
|
&usernameSignatureSize,
|
||||||
|
rsaPrivateKey);
|
||||||
|
|
||||||
|
// free the private key RSA struct now that we are done with it
|
||||||
|
RSA_free(rsaPrivateKey);
|
||||||
|
|
||||||
if (encryptReturn == -1) {
|
if (encryptReturn == -1) {
|
||||||
qCDebug(networking) << "Error encrypting username signature.";
|
qCDebug(networking) << "Error encrypting username signature.";
|
||||||
qCDebug(networking) << "Will re-attempt on next domain-server check in.";
|
qCDebug(networking) << "Will re-attempt on next domain-server check in.";
|
||||||
_usernameSignature = QByteArray();
|
} else {
|
||||||
|
qDebug(networking) << "Returning username" << _username << "signed with connection UUID" << uuidStringWithoutCurlyBraces(connectionToken);
|
||||||
|
return usernameSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
// free the private key RSA struct now that we are done with it
|
|
||||||
RSA_free(rsaPrivateKey);
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(networking) << "Could not create RSA struct from QByteArray private key.";
|
qCDebug(networking) << "Could not create RSA struct from QByteArray private key.";
|
||||||
qCDebug(networking) << "Will re-attempt on next domain-server check in.";
|
qCDebug(networking) << "Will re-attempt on next domain-server check in.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return QByteArray();
|
||||||
|
|
||||||
return _usernameSignature;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataServerAccountInfo::setPrivateKey(const QByteArray& privateKey) {
|
void DataServerAccountInfo::setPrivateKey(const QByteArray& privateKey) {
|
||||||
_privateKey = privateKey;
|
_privateKey = privateKey;
|
||||||
|
|
||||||
// clear our username signature so it has to be re-created
|
|
||||||
_usernameSignature = QByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) {
|
QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) {
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
const QUuid& getWalletID() const { return _walletID; }
|
const QUuid& getWalletID() const { return _walletID; }
|
||||||
void setWalletID(const QUuid& walletID);
|
void setWalletID(const QUuid& walletID);
|
||||||
|
|
||||||
const QByteArray& getUsernameSignature();
|
QByteArray getUsernameSignature(const QUuid& connectionToken);
|
||||||
bool hasPrivateKey() const { return !_privateKey.isEmpty(); }
|
bool hasPrivateKey() const { return !_privateKey.isEmpty(); }
|
||||||
void setPrivateKey(const QByteArray& privateKey);
|
void setPrivateKey(const QByteArray& privateKey);
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ private:
|
||||||
qint64 _balance;
|
qint64 _balance;
|
||||||
bool _hasBalance;
|
bool _hasBalance;
|
||||||
QByteArray _privateKey;
|
QByteArray _privateKey;
|
||||||
QByteArray _usernameSignature;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_DataServerAccountInfo_h
|
#endif // hifi_DataServerAccountInfo_h
|
||||||
|
|
|
@ -29,6 +29,7 @@ DomainHandler::DomainHandler(QObject* parent) :
|
||||||
_uuid(),
|
_uuid(),
|
||||||
_sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
|
_sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
|
||||||
_assignmentUUID(),
|
_assignmentUUID(),
|
||||||
|
_connectionToken(),
|
||||||
_iceDomainID(),
|
_iceDomainID(),
|
||||||
_iceClientID(),
|
_iceClientID(),
|
||||||
_iceServerSockAddr(),
|
_iceServerSockAddr(),
|
||||||
|
@ -43,6 +44,7 @@ DomainHandler::DomainHandler(QObject* parent) :
|
||||||
|
|
||||||
void DomainHandler::clearConnectionInfo() {
|
void DomainHandler::clearConnectionInfo() {
|
||||||
_uuid = QUuid();
|
_uuid = QUuid();
|
||||||
|
_connectionToken = QUuid();
|
||||||
|
|
||||||
_icePeer.reset();
|
_icePeer.reset();
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,9 @@ public:
|
||||||
unsigned short getPort() const { return _sockAddr.getPort(); }
|
unsigned short getPort() const { return _sockAddr.getPort(); }
|
||||||
void setPort(quint16 port) { _sockAddr.setPort(port); }
|
void setPort(quint16 port) { _sockAddr.setPort(port); }
|
||||||
|
|
||||||
|
const QUuid& getConnectionToken() const { return _connectionToken; }
|
||||||
|
void setConnectionToken(const QUuid& connectionToken) { _connectionToken = connectionToken; }
|
||||||
|
|
||||||
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
|
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
|
||||||
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
|
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
|
||||||
|
|
||||||
|
@ -114,6 +117,7 @@ private:
|
||||||
QString _hostname;
|
QString _hostname;
|
||||||
HifiSockAddr _sockAddr;
|
HifiSockAddr _sockAddr;
|
||||||
QUuid _assignmentUUID;
|
QUuid _assignmentUUID;
|
||||||
|
QUuid _connectionToken;
|
||||||
QUuid _iceDomainID;
|
QUuid _iceDomainID;
|
||||||
QUuid _iceClientID;
|
QUuid _iceClientID;
|
||||||
HifiSockAddr _iceServerSockAddr;
|
HifiSockAddr _iceServerSockAddr;
|
||||||
|
|
|
@ -94,7 +94,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
||||||
packetReceiver.registerListener(PacketType::PingReply, this, "processPingReplyPacket");
|
packetReceiver.registerListener(PacketType::PingReply, this, "processPingReplyPacket");
|
||||||
packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket");
|
packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket");
|
||||||
packetReceiver.registerListener(PacketType::DomainServerAddedNode, this, "processDomainServerAddedNode");
|
packetReceiver.registerListener(PacketType::DomainServerAddedNode, this, "processDomainServerAddedNode");
|
||||||
|
packetReceiver.registerListener(PacketType::DomainServerConnectionToken, this, "processDomainServerConnectionTokenPacket");
|
||||||
packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_domainHandler, "processICEResponsePacket");
|
packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_domainHandler, "processICEResponsePacket");
|
||||||
packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, &_domainHandler, "processDTLSRequirementPacket");
|
packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, &_domainHandler, "processDTLSRequirementPacket");
|
||||||
packetReceiver.registerListener(PacketType::ICEPingReply, &_domainHandler, "processICEPingReplyPacket");
|
packetReceiver.registerListener(PacketType::ICEPingReply, &_domainHandler, "processICEPingReplyPacket");
|
||||||
|
@ -277,16 +277,22 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
|
|
||||||
// if this is a connect request, and we can present a username signature, send it along
|
// if this is a connect request, and we can present a username signature, send it along
|
||||||
if (!_domainHandler.isConnected() ) {
|
if (!_domainHandler.isConnected() ) {
|
||||||
|
|
||||||
DataServerAccountInfo& accountInfo = AccountManager::getInstance().getAccountInfo();
|
DataServerAccountInfo& accountInfo = AccountManager::getInstance().getAccountInfo();
|
||||||
packetStream << accountInfo.getUsername();
|
packetStream << accountInfo.getUsername();
|
||||||
|
|
||||||
const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature();
|
// get connection token from the domain-server
|
||||||
|
const QUuid& connectionToken = _domainHandler.getConnectionToken();
|
||||||
|
|
||||||
|
if (!connectionToken.isNull()) {
|
||||||
|
|
||||||
|
const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature(connectionToken);
|
||||||
|
|
||||||
if (!usernameSignature.isEmpty()) {
|
if (!usernameSignature.isEmpty()) {
|
||||||
qCDebug(networking) << "Including username signature in domain connect request.";
|
|
||||||
packetStream << usernameSignature;
|
packetStream << usernameSignature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendDSCheckIn);
|
flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendDSCheckIn);
|
||||||
|
|
||||||
|
@ -361,6 +367,7 @@ void NodeList::sendDSPathQuery(const QString& newPath) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NodeList::processDomainServerPathResponse(QSharedPointer<NLPacket> packet) {
|
void NodeList::processDomainServerPathResponse(QSharedPointer<NLPacket> packet) {
|
||||||
// This is a response to a path query we theoretically made.
|
// This is a response to a path query we theoretically made.
|
||||||
// In the future we may want to check that this was actually from our DS and for a query we actually made.
|
// In the future we may want to check that this was actually from our DS and for a query we actually made.
|
||||||
|
@ -450,6 +457,17 @@ void NodeList::pingPunchForDomainServer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer<NLPacket> packet) {
|
||||||
|
if (_domainHandler.getSockAddr().isNull()) {
|
||||||
|
// refuse to process this packet if we aren't currently connected to the DS
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// read in the connection token from the packet, then send domain-server checkin
|
||||||
|
_domainHandler.setConnectionToken(QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID)));
|
||||||
|
sendDomainServerCheckIn();
|
||||||
|
}
|
||||||
|
|
||||||
void NodeList::processDomainServerList(QSharedPointer<NLPacket> packet) {
|
void NodeList::processDomainServerList(QSharedPointer<NLPacket> packet) {
|
||||||
if (_domainHandler.getSockAddr().isNull()) {
|
if (_domainHandler.getSockAddr().isNull()) {
|
||||||
// refuse to process this packet if we aren't currently connected to the DS
|
// refuse to process this packet if we aren't currently connected to the DS
|
||||||
|
|
|
@ -76,6 +76,8 @@ public slots:
|
||||||
void processDomainServerAddedNode(QSharedPointer<NLPacket> packet);
|
void processDomainServerAddedNode(QSharedPointer<NLPacket> packet);
|
||||||
void processDomainServerPathResponse(QSharedPointer<NLPacket> packet);
|
void processDomainServerPathResponse(QSharedPointer<NLPacket> packet);
|
||||||
|
|
||||||
|
void processDomainServerConnectionTokenPacket(QSharedPointer<NLPacket> packet);
|
||||||
|
|
||||||
void processPingPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
void processPingPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||||
void processPingReplyPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
void processPingReplyPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ const QSet<PacketType::Value> SEQUENCE_NUMBERED_PACKETS = QSet<PacketType::Value
|
||||||
|
|
||||||
const QSet<PacketType::Value> NON_SOURCED_PACKETS = QSet<PacketType::Value>()
|
const QSet<PacketType::Value> NON_SOURCED_PACKETS = QSet<PacketType::Value>()
|
||||||
<< StunResponse << CreateAssignment << RequestAssignment
|
<< StunResponse << CreateAssignment << RequestAssignment
|
||||||
<< DomainServerRequireDTLS << DomainConnectRequest
|
<< DomainServerRequireDTLS << DomainConnectRequest << DomainServerConnectionToken
|
||||||
<< DomainList << DomainConnectionDenied
|
<< DomainList << DomainConnectionDenied
|
||||||
<< DomainServerPathQuery << DomainServerPathResponse
|
<< DomainServerPathQuery << DomainServerPathResponse
|
||||||
<< DomainServerAddedNode
|
<< DomainServerAddedNode
|
||||||
|
@ -119,6 +119,7 @@ QString nameForPacketType(PacketType::Value packetType) {
|
||||||
PACKET_TYPE_NAME_LOOKUP(ICEPingReply);
|
PACKET_TYPE_NAME_LOOKUP(ICEPingReply);
|
||||||
PACKET_TYPE_NAME_LOOKUP(EntityAdd);
|
PACKET_TYPE_NAME_LOOKUP(EntityAdd);
|
||||||
PACKET_TYPE_NAME_LOOKUP(EntityEdit);
|
PACKET_TYPE_NAME_LOOKUP(EntityEdit);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(DomainServerConnectionToken);
|
||||||
default:
|
default:
|
||||||
return QString("Type: ") + QString::number((int)packetType);
|
return QString("Type: ") + QString::number((int)packetType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,8 @@ namespace PacketType {
|
||||||
EntityQuery,
|
EntityQuery,
|
||||||
EntityAdd,
|
EntityAdd,
|
||||||
EntityErase,
|
EntityErase,
|
||||||
EntityEdit
|
EntityEdit,
|
||||||
|
DomainServerConnectionToken
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -636,8 +636,6 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float
|
||||||
if (s > halfOurScale) {
|
if (s > halfOurScale) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
// otherwise, we need to find which of our children we should recurse
|
|
||||||
glm::vec3 ourCenter = _cube.calcCenter();
|
|
||||||
|
|
||||||
int childIndex = getMyChildContainingPoint(glm::vec3(x, y, z));
|
int childIndex = getMyChildContainingPoint(glm::vec3(x, y, z));
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,23 @@ uniform float glowIntensity;
|
||||||
// the alpha threshold
|
// the alpha threshold
|
||||||
uniform float alphaThreshold;
|
uniform float alphaThreshold;
|
||||||
|
|
||||||
|
uniform sampler2D normalFittingMap;
|
||||||
|
|
||||||
|
vec3 bestFitNormal(vec3 normal) {
|
||||||
|
vec3 absNorm = abs(normal);
|
||||||
|
float maxNAbs = max(absNorm.z, max(absNorm.x, absNorm.y));
|
||||||
|
|
||||||
|
vec2 texcoord = (absNorm.z < maxNAbs ?
|
||||||
|
(absNorm.y < maxNAbs ? absNorm.yz : absNorm.xz) :
|
||||||
|
absNorm.xy);
|
||||||
|
texcoord = (texcoord.x < texcoord.y ? texcoord.yx : texcoord.xy);
|
||||||
|
texcoord.y /= texcoord.x;
|
||||||
|
vec3 cN = normal / maxNAbs;
|
||||||
|
float fittingScale = texture(normalFittingMap, texcoord).a;
|
||||||
|
cN *= fittingScale;
|
||||||
|
return (cN * 0.5 + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
float evalOpaqueFinalAlpha(float alpha, float mapAlpha) {
|
float evalOpaqueFinalAlpha(float alpha, float mapAlpha) {
|
||||||
return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold));
|
return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold));
|
||||||
}
|
}
|
||||||
|
@ -33,7 +50,7 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular,
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
_fragColor0 = vec4(diffuse.rgb, alpha);
|
_fragColor0 = vec4(diffuse.rgb, alpha);
|
||||||
_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
_fragColor1 = vec4(bestFitNormal(normal), 1.0);
|
||||||
_fragColor2 = vec4(specular, shininess / 128.0);
|
_fragColor2 = vec4(specular, shininess / 128.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +61,7 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 s
|
||||||
|
|
||||||
_fragColor0 = vec4(diffuse.rgb, alpha);
|
_fragColor0 = vec4(diffuse.rgb, alpha);
|
||||||
//_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
//_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||||
_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);
|
_fragColor1 = vec4(bestFitNormal(normal), 0.5);
|
||||||
_fragColor2 = vec4(emissive, shininess / 128.0);
|
_fragColor2 = vec4(emissive, shininess / 128.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||||
_emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive));
|
_emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive));
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
gpu::Shader::BindingSet slotBindings;
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
|
||||||
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
|
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
|
||||||
gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
|
gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
|
||||||
|
|
||||||
|
@ -151,6 +152,8 @@ void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured,
|
||||||
// If it is not textured, bind white texture and keep using textured pipeline
|
// If it is not textured, bind white texture and keep using textured pipeline
|
||||||
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
batch.setResourceTexture(NORMAL_FITTING_MAP_SLOT, DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) {
|
void DeferredLightingEffect::renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ class DeferredLightingEffect : public Dependency {
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static const int NORMAL_FITTING_MAP_SLOT = 10;
|
||||||
|
|
||||||
void init(AbstractViewStateInterface* viewState);
|
void init(AbstractViewStateInterface* viewState);
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <FSTReader.h>
|
#include <FSTReader.h>
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
|
|
||||||
#include <gpu/Batch.h>
|
|
||||||
#include <gpu/GLBackend.h>
|
#include <gpu/GLBackend.h>
|
||||||
|
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
|
@ -2240,10 +2239,17 @@ bool NetworkMeshPart::isTranslucent() const {
|
||||||
return diffuseTexture && diffuseTexture->isTranslucent();
|
return diffuseTexture && diffuseTexture->isTranslucent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NetworkMesh::isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const {
|
||||||
|
assert(partIndex >= 0);
|
||||||
|
assert(partIndex < parts.size());
|
||||||
|
return (parts.at(partIndex).isTranslucent() || fbxMesh.parts.at(partIndex).opacity != 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
int NetworkMesh::getTranslucentPartCount(const FBXMesh& fbxMesh) const {
|
int NetworkMesh::getTranslucentPartCount(const FBXMesh& fbxMesh) const {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < parts.size(); i++) {
|
for (int i = 0; i < parts.size(); i++) {
|
||||||
if (parts.at(i).isTranslucent() || fbxMesh.parts.at(i).opacity != 1.0f) {
|
if (isPartTranslucent(fbxMesh, i)) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -398,6 +398,7 @@ public:
|
||||||
QVector<NetworkMeshPart> parts;
|
QVector<NetworkMeshPart> parts;
|
||||||
|
|
||||||
int getTranslucentPartCount(const FBXMesh& fbxMesh) const;
|
int getTranslucentPartCount(const FBXMesh& fbxMesh) const;
|
||||||
|
bool isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_GeometryCache_h
|
#endif // hifi_GeometryCache_h
|
||||||
|
|
|
@ -105,6 +105,8 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key,
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
|
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3));
|
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), 4));
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), 4));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
|
||||||
|
|
||||||
|
|
||||||
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader));
|
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader));
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
@ -180,6 +182,8 @@ void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model:
|
||||||
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
|
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
|
||||||
locations.glowIntensity = program->getUniforms().findLocation("glowIntensity");
|
locations.glowIntensity = program->getUniforms().findLocation("glowIntensity");
|
||||||
|
|
||||||
|
locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
|
||||||
|
|
||||||
locations.specularTextureUnit = program->getTextures().findLocation("specularMap");
|
locations.specularTextureUnit = program->getTextures().findLocation("specularMap");
|
||||||
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
|
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
|
||||||
|
|
||||||
|
@ -1820,11 +1824,10 @@ void Model::segregateMeshGroups() {
|
||||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug...
|
// Create the render payloads
|
||||||
int totalParts = mesh.parts.size();
|
int totalParts = mesh.parts.size();
|
||||||
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
||||||
// this is a good place to create our renderPayloads
|
if (networkMesh.isPartTranslucent(mesh, partIndex)) {
|
||||||
if (translucentMesh) {
|
|
||||||
_transparentRenderItems << std::make_shared<MeshPartPayload>(true, this, i, partIndex);
|
_transparentRenderItems << std::make_shared<MeshPartPayload>(true, this, i, partIndex);
|
||||||
} else {
|
} else {
|
||||||
_opaqueRenderItems << std::make_shared<MeshPartPayload>(false, this, i, partIndex);
|
_opaqueRenderItems << std::make_shared<MeshPartPayload>(false, this, i, partIndex);
|
||||||
|
@ -1864,6 +1867,10 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
|
||||||
const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed
|
const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed
|
||||||
batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY);
|
batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((locations->normalFittingMapUnit > -1)) {
|
||||||
|
batch.setResourceTexture(locations->normalFittingMapUnit, DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::initWhenReady(render::ScenePointer scene) {
|
bool Model::initWhenReady(render::ScenePointer scene) {
|
||||||
|
|
|
@ -350,6 +350,7 @@ private:
|
||||||
int emissiveTextureUnit;
|
int emissiveTextureUnit;
|
||||||
int emissiveParams;
|
int emissiveParams;
|
||||||
int glowIntensity;
|
int glowIntensity;
|
||||||
|
int normalFittingMapUnit;
|
||||||
int materialBufferUnit;
|
int materialBufferUnit;
|
||||||
int clusterMatrices;
|
int clusterMatrices;
|
||||||
int clusterIndices;
|
int clusterIndices;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <QRunnable>
|
#include <QRunnable>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
#include <qimagereader.h>
|
#include <qimagereader.h>
|
||||||
|
#include "PathUtils.h"
|
||||||
|
|
||||||
#include <gpu/Batch.h>
|
#include <gpu/Batch.h>
|
||||||
|
|
||||||
|
@ -129,6 +130,14 @@ const gpu::TexturePointer& TextureCache::getBlackTexture() {
|
||||||
return _blackTexture;
|
return _blackTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const gpu::TexturePointer& TextureCache::getNormalFittingTexture() {
|
||||||
|
if (!_normalFittingTexture) {
|
||||||
|
_normalFittingTexture = getImageTexture(PathUtils::resourcesPath() + "images/normalFittingScale.dds");
|
||||||
|
}
|
||||||
|
return _normalFittingTexture;
|
||||||
|
}
|
||||||
|
|
||||||
/// Extra data for creating textures.
|
/// Extra data for creating textures.
|
||||||
class TextureExtra {
|
class TextureExtra {
|
||||||
public:
|
public:
|
||||||
|
@ -170,6 +179,7 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path) {
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
||||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||||
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
||||||
|
|
|
@ -54,6 +54,9 @@ public:
|
||||||
/// Returns the a black texture (useful for a default).
|
/// Returns the a black texture (useful for a default).
|
||||||
const gpu::TexturePointer& getBlackTexture();
|
const gpu::TexturePointer& getBlackTexture();
|
||||||
|
|
||||||
|
// Returns a map used to compress the normals through a fitting scale algorithm
|
||||||
|
const gpu::TexturePointer& getNormalFittingTexture();
|
||||||
|
|
||||||
/// Returns a texture version of an image file
|
/// Returns a texture version of an image file
|
||||||
static gpu::TexturePointer getImageTexture(const QString& path);
|
static gpu::TexturePointer getImageTexture(const QString& path);
|
||||||
|
|
||||||
|
@ -76,6 +79,7 @@ private:
|
||||||
gpu::TexturePointer _grayTexture;
|
gpu::TexturePointer _grayTexture;
|
||||||
gpu::TexturePointer _blueTexture;
|
gpu::TexturePointer _blueTexture;
|
||||||
gpu::TexturePointer _blackTexture;
|
gpu::TexturePointer _blackTexture;
|
||||||
|
gpu::TexturePointer _normalFittingTexture;
|
||||||
|
|
||||||
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;
|
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,37 +9,21 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <string>
|
||||||
#include <mutex>
|
#include <vector>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include <QWindow>
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
#include <gpu/Context.h>
|
|
||||||
#include <gpu/GLBackend.h>
|
#include <gpu/GLBackend.h>
|
||||||
|
|
||||||
#include <QOpenGLBuffer>
|
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QOpenGLDebugLogger>
|
#include <QOpenGLDebugLogger>
|
||||||
#include <QOpenGLShaderProgram>
|
|
||||||
#include <QOpenGLTexture>
|
#include <QDir>
|
||||||
#include <QOpenGLVertexArrayObject>
|
#include <QElapsedTimer>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QLoggingCategory>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QTime>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <QElapsedTimer>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QGuiApplication>
|
|
||||||
|
|
||||||
#include <PathUtils.h>
|
|
||||||
|
|
||||||
#include "gpu/Batch.h"
|
|
||||||
#include "gpu/Context.h"
|
|
||||||
|
|
||||||
class RateCounter {
|
class RateCounter {
|
||||||
std::vector<float> times;
|
std::vector<float> times;
|
||||||
|
@ -71,7 +55,7 @@ public:
|
||||||
|
|
||||||
float rate() const {
|
float rate() const {
|
||||||
if (elapsed() == 0.0f) {
|
if (elapsed() == 0.0f) {
|
||||||
return NAN;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
return (float) count() / elapsed();
|
return (float) count() / elapsed();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,39 +6,20 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include <QWindow>
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
#include <gpu/Context.h>
|
|
||||||
#include <gpu/GLBackend.h>
|
#include <gpu/GLBackend.h>
|
||||||
|
|
||||||
#include <QOpenGLBuffer>
|
|
||||||
#include <QOpenGLContext>
|
|
||||||
#include <QOpenGLDebugLogger>
|
#include <QOpenGLDebugLogger>
|
||||||
#include <QOpenGLShaderProgram>
|
|
||||||
#include <QOpenGLTexture>
|
#include <QLoggingCategory>
|
||||||
#include <QOpenGLVertexArrayObject>
|
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QTime>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
|
||||||
#include <PathUtils.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "gpu/Batch.h"
|
|
||||||
#include "gpu/Context.h"
|
|
||||||
|
|
||||||
#include "../model/Skybox_vert.h"
|
#include "../model/Skybox_vert.h"
|
||||||
#include "../model/Skybox_frag.h"
|
#include "../model/Skybox_frag.h"
|
||||||
|
|
||||||
|
@ -159,7 +140,7 @@ public:
|
||||||
|
|
||||||
float rate() const {
|
float rate() const {
|
||||||
if (elapsed() == 0.0f) {
|
if (elapsed() == 0.0f) {
|
||||||
return NAN;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
return (float) count() / elapsed();
|
return (float) count() / elapsed();
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
|
|
||||||
float rate() const {
|
float rate() const {
|
||||||
if (elapsed() == 0.0f) {
|
if (elapsed() == 0.0f) {
|
||||||
return NAN;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
return (float) count() / elapsed();
|
return (float) count() / elapsed();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue