3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-26 18:15:49 +02:00

Merge branch 'master' into 20639

This commit is contained in:
David Rowe 2015-08-07 12:33:13 -07:00
commit b70c1a4960
37 changed files with 271 additions and 162 deletions

View file

@ -5,6 +5,7 @@
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1m
* IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
* [zlib](http://www.zlib.net/)
####CMake External Project Dependencies

View file

@ -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.
###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 install cmake openssl

View file

@ -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.
####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
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.

View file

@ -579,7 +579,6 @@ const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet) {
NodeType_t nodeType;
HifiSockAddr publicSockAddr, localSockAddr;
if (packet->getPayloadSize() == 0) {
return;
@ -625,31 +624,62 @@ void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet)
return;
}
}
}
QList<NodeType_t> nodeInterestList;
QString username;
QByteArray usernameSignature;
packetStream >> nodeInterestList >> username >> usernameSignature;
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;
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
QByteArray utfString = reason.toUtf8();
quint16 payloadSize = utfString.size();
auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, payloadSize + sizeof(payloadSize));
connectionDeniedPacket->writePrimitive(payloadSize);
connectionDeniedPacket->write(utfString);
if (payloadSize > 0) {
connectionDeniedPacket->writePrimitive(payloadSize);
connectionDeniedPacket->write(utfString);
}
// tell client it has been refused.
limitedNodeList->sendPacket(std::move(connectionDeniedPacket), senderSockAddr);
return;
}
@ -736,6 +766,7 @@ void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet)
}
}
void DomainServer::processListRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
NodeType_t throwawayNodeType;
@ -766,52 +797,61 @@ unsigned int DomainServer::countConnectedUsers() {
}
bool DomainServer::verifyUsersKey(const QString& username,
const QByteArray& usernameSignature,
QString& reasonReturn) {
bool DomainServer::verifyUserSignature(const QString& username,
const QByteArray& usernameSignature,
QString& reasonReturn) {
// it's possible this user can be allowed to connect, but we need to check their username signature
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
const unsigned char* publicKeyData = reinterpret_cast<const unsigned char*>(publicKeyArray.constData());
// first load up the public key into an RSA struct
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) {
QByteArray decryptedArray(RSA_size(rsaPublicKey), 0);
int decryptResult =
RSA_public_decrypt(usernameSignature.size(),
reinterpret_cast<const unsigned char*>(usernameSignature.constData()),
reinterpret_cast<unsigned char*>(decryptedArray.data()),
rsaPublicKey, RSA_PKCS1_PADDING);
int decryptResult = RSA_verify(NID_sha256,
reinterpret_cast<const unsigned char*>(usernameWithToken.constData()),
usernameWithToken.size(),
reinterpret_cast<const unsigned char*>(usernameSignature.constData()),
usernameSignature.size(),
rsaPublicKey);
if (decryptResult == 1) {
qDebug() << "Username signature matches for" << username << "- allowing connection.";
if (decryptResult != -1) {
if (username.toLower() == decryptedArray) {
qDebug() << "Username signature matches for" << username << "- allowing connection.";
// free up the public key and remove connection token before we return
RSA_free(rsaPublicKey);
_connectionTokenHash.remove(username);
// free up the public key before we return
RSA_free(rsaPublicKey);
return true;
} else {
qDebug() << "Username signature did not match for" << username << "- denying connection.";
reasonReturn = "Username signature did not match.";
}
return true;
} else {
qDebug() << "Couldn't decrypt user signature for" << username << "- denying connection.";
reasonReturn = "Couldn't decrypt user signature.";
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
RSA_free(rsaPublicKey);
}
// free up the public key, we don't need it anymore
RSA_free(rsaPublicKey);
} else {
// 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.";
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?
@ -823,41 +863,40 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
const QByteArray& usernameSignature,
const HifiSockAddr& senderSockAddr,
QString& reasonReturn) {
//TODO: improve flow so these bools aren't declared twice
bool isRestrictingAccess =
_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 (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress()
|| senderSockAddr.getAddress() == QHostAddress::LocalHost) {
return true;
}
if (isRestrictingAccess) {
if (isRestrictingAccess && !isLocalUser) {
QStringList allowedUsers =
_settingsManager.valueOrDefaultValueForKeyPath(ALLOWED_USERS_SETTINGS_KEYPATH).toStringList();
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;
}
} else {
qDebug() << "Connect request denied for user" << username << "not in allowed users list.";
reasonReturn = "User not on whitelist.";
return false;
}
}
// 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
const QVariant* allowedEditorsVariant =
valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH);
QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList();
if (allowedEditors.contains(username)) {
if (verifyUsersKey(username, usernameSignature, reasonReturn)) {
if (verifyUserSignature(username, usernameSignature, reasonReturn)) {
return true;
}
}

View file

@ -90,7 +90,7 @@ private:
void pingPunchForConnectingPeer(const SharedNetworkPeer& peer);
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,
const HifiSockAddr& senderSockAddr, QString& reasonReturn);
@ -149,6 +149,8 @@ private:
QSet<QUuid> _webAuthenticationStateSet;
QHash<QUuid, DomainServerWebSessionData> _cookieSessionHash;
QHash<QString, QUuid> _connectionTokenHash;
QHash<QString, QByteArray> _userPublicKeys;

Binary file not shown.

View file

@ -107,7 +107,7 @@ JointReferential::JointReferential(Referential* referential, EntityTree* tree, A
EntityItemPointer item = _tree->findEntityByID(_entityID);
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();
model->getJointRotationInWorldFrame(_jointIndex, _refRotation);
model->getJointPositionInWorldFrame(_jointIndex, _refPosition);

View file

@ -47,9 +47,6 @@
#include "Util.h"
#include "InterfaceLogging.h"
#include "gpu/GLBackend.h"
using namespace std;
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);

View file

@ -97,7 +97,6 @@ void SkeletonModel::initJointStates(QVector<JointState> states) {
}
const float PALM_PRIORITY = DEFAULT_PRIORITY;
const float LEAN_PRIORITY = DEFAULT_PRIORITY;
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
if (_owningAvatar->isMyAvatar()) {

View file

@ -14,7 +14,6 @@
#include <avatar/AvatarManager.h>
#include <DeferredLightingEffect.h>
#include <GLMHelpers.h>
#include <gpu/GLBackend.h>
#include <gpu/GLBackendShared.h>
#include <FramebufferCache.h>
#include <GLMHelpers.h>
@ -32,7 +31,6 @@
#include "ui/AvatarInputs.h"
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_FAR_CLIP = 1000.0f;

View file

@ -105,7 +105,7 @@ void BillboardOverlay::render(RenderArgs* args) {
batch->setModelTransform(transform);
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(
*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha)

View file

@ -15,7 +15,6 @@
#include <limits>
#include <render/Scene.h>
#include <gpu/GLBackend.h>
#include <RegisteredMetaTypes.h>
#include "Application.h"

View file

@ -15,7 +15,6 @@
#include <DependencyManager.h>
#include <GeometryCache.h>
#include <GLMHelpers.h>
#include <gpu/GLBackend.h>
#include <OffscreenUi.h>
#include <RegisteredMetaTypes.h>
#include <SharedUtil.h>

View file

@ -70,6 +70,7 @@ void Rig::startAnimation(const QString& url, float fps, float priority,
handle = createAnimationHandle();
handle->setURL(url);
}
handle->setFade(1.0f); // If you want to fade, use the startAnimationByRole system.
handle->setFPS(fps);
handle->setPriority(priority);
handle->setLoop(loop);
@ -150,7 +151,8 @@ void Rig::stopAnimationByRole(const QString& role) {
void Rig::stopAnimation(const QString& url) {
foreach (const AnimationHandlePointer& handle, getRunningAnimations()) {
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;
foreach (const AnimationHandlePointer& handle, _runningAnimations) {
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.
// 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:

View file

@ -976,6 +976,8 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) {
data.extracted.mesh.meshIndex = meshIndex++;
QVector<int> materials;
QVector<int> textures;
bool isMaterialPerPolygon = false;
foreach (const FBXNode& child, object.children) {
if (child.name == "Vertices") {
data.vertices = createVec3Vector(getDoubleVector(child));
@ -1105,8 +1107,16 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) {
foreach (const FBXNode& subdata, child.children) {
if (subdata.name == "Materials") {
materials = getIntVector(subdata);
} else if (subdata.name == "MappingInformationType") {
if (subdata.properties.at(0) == "ByPolygon") {
isMaterialPerPolygon = true;
} else {
isMaterialPerPolygon = false;
}
}
}
} else if (child.name == "LayerElementTexture") {
foreach (const FBXNode& subdata, child.children) {
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
int polygonIndex = 0;
QHash<QPair<int, int>, int> materialTextureParts;
@ -2104,6 +2120,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
if (type.contains("diffuse")) {
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")) {
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));

View file

@ -153,7 +153,6 @@ void GLBackend::releaseUniformBuffer(uint32_t slot) {
if (buf) {
auto* object = Backend::getGPUObject<GLBackend::GLBuffer>(*buf);
if (object) {
GLuint bo = object->_buffer;
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
(void) CHECK_GL_ERROR();
@ -222,7 +221,6 @@ void GLBackend::releaseResourceTexture(uint32_t slot) {
if (tex) {
auto* object = Backend::getGPUObject<GLBackend::GLTexture>(*tex);
if (object) {
GLuint to = object->_texture;
GLuint target = object->_target;
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(target, 0); // RELEASE

View file

@ -10,11 +10,13 @@
//
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <qjsondocument.h>
#include <QtCore/QDebug>
#include <QtCore/QDataStream>
#include "UUID.h"
#include "NetworkLogging.h"
#include "DataServerAccountInfo.h"
@ -30,8 +32,7 @@ DataServerAccountInfo::DataServerAccountInfo() :
_walletID(),
_balance(0),
_hasBalance(false),
_privateKey(),
_usernameSignature()
_privateKey()
{
}
@ -73,9 +74,6 @@ void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject
void DataServerAccountInfo::setUsername(const QString& username) {
if (_username != username) {
_username = username;
// clear our username signature so it has to be re-created
_usernameSignature = QByteArray();
qCDebug(networking) << "Username changed to" << username;
}
@ -128,8 +126,8 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject
setWalletID(QUuid(user["wallet_id"].toString()));
}
const QByteArray& DataServerAccountInfo::getUsernameSignature() {
if (_usernameSignature.isEmpty()) {
QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) {
if (!_privateKey.isEmpty()) {
const char* privateKeyData = _privateKey.constData();
RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL,
@ -137,36 +135,41 @@ const QByteArray& DataServerAccountInfo::getUsernameSignature() {
_privateKey.size());
if (rsaPrivateKey) {
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(),
reinterpret_cast<const unsigned char*>(lowercaseUsername.constData()),
reinterpret_cast<unsigned char*>(_usernameSignature.data()),
rsaPrivateKey, RSA_PKCS1_PADDING);
QByteArray usernameSignature(RSA_size(rsaPrivateKey), 0);
unsigned int usernameSignatureSize = 0;
if (encryptReturn == -1) {
qCDebug(networking) << "Error encrypting username signature.";
qCDebug(networking) << "Will re-attempt on next domain-server check in.";
_usernameSignature = QByteArray();
}
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) {
qCDebug(networking) << "Error encrypting username signature.";
qCDebug(networking) << "Will re-attempt on next domain-server check in.";
} else {
qDebug(networking) << "Returning username" << _username << "signed with connection UUID" << uuidStringWithoutCurlyBraces(connectionToken);
return usernameSignature;
}
} else {
qCDebug(networking) << "Could not create RSA struct from QByteArray private key.";
qCDebug(networking) << "Will re-attempt on next domain-server check in.";
}
}
}
return _usernameSignature;
return QByteArray();
}
void DataServerAccountInfo::setPrivateKey(const QByteArray& privateKey) {
_privateKey = privateKey;
// clear our username signature so it has to be re-created
_usernameSignature = QByteArray();
}
QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) {

View file

@ -43,7 +43,7 @@ public:
const QUuid& getWalletID() const { return _walletID; }
void setWalletID(const QUuid& walletID);
const QByteArray& getUsernameSignature();
QByteArray getUsernameSignature(const QUuid& connectionToken);
bool hasPrivateKey() const { return !_privateKey.isEmpty(); }
void setPrivateKey(const QByteArray& privateKey);
@ -73,7 +73,7 @@ private:
qint64 _balance;
bool _hasBalance;
QByteArray _privateKey;
QByteArray _usernameSignature;
};
#endif // hifi_DataServerAccountInfo_h

View file

@ -29,6 +29,7 @@ DomainHandler::DomainHandler(QObject* parent) :
_uuid(),
_sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
_assignmentUUID(),
_connectionToken(),
_iceDomainID(),
_iceClientID(),
_iceServerSockAddr(),
@ -43,7 +44,8 @@ DomainHandler::DomainHandler(QObject* parent) :
void DomainHandler::clearConnectionInfo() {
_uuid = QUuid();
_connectionToken = QUuid();
_icePeer.reset();
if (requiresICE()) {

View file

@ -50,9 +50,12 @@ public:
unsigned short getPort() const { return _sockAddr.getPort(); }
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; }
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
const QUuid& getICEDomainID() const { return _iceDomainID; }
const QUuid& getICEClientID() const { return _iceClientID; }
@ -114,6 +117,7 @@ private:
QString _hostname;
HifiSockAddr _sockAddr;
QUuid _assignmentUUID;
QUuid _connectionToken;
QUuid _iceDomainID;
QUuid _iceClientID;
HifiSockAddr _iceServerSockAddr;

View file

@ -94,7 +94,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
packetReceiver.registerListener(PacketType::PingReply, this, "processPingReplyPacket");
packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket");
packetReceiver.registerListener(PacketType::DomainServerAddedNode, this, "processDomainServerAddedNode");
packetReceiver.registerListener(PacketType::DomainServerConnectionToken, this, "processDomainServerConnectionTokenPacket");
packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_domainHandler, "processICEResponsePacket");
packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, &_domainHandler, "processDTLSRequirementPacket");
packetReceiver.registerListener(PacketType::ICEPingReply, &_domainHandler, "processICEPingReplyPacket");
@ -274,17 +274,23 @@ void NodeList::sendDomainServerCheckIn() {
// pack our data to send to the domain-server
packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList();
// 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();
packetStream << accountInfo.getUsername();
const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature();
if (!usernameSignature.isEmpty()) {
qCDebug(networking) << "Including username signature in domain connect request.";
packetStream << usernameSignature;
// 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()) {
packetStream << usernameSignature;
}
}
}
@ -361,6 +367,7 @@ void NodeList::sendDSPathQuery(const QString& newPath) {
}
}
void NodeList::processDomainServerPathResponse(QSharedPointer<NLPacket> packet) {
// 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.
@ -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) {
if (_domainHandler.getSockAddr().isNull()) {
// refuse to process this packet if we aren't currently connected to the DS

View file

@ -76,6 +76,8 @@ public slots:
void processDomainServerAddedNode(QSharedPointer<NLPacket> packet);
void processDomainServerPathResponse(QSharedPointer<NLPacket> packet);
void processDomainServerConnectionTokenPacket(QSharedPointer<NLPacket> packet);
void processPingPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
void processPingReplyPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);

View file

@ -26,7 +26,7 @@ const QSet<PacketType::Value> SEQUENCE_NUMBERED_PACKETS = QSet<PacketType::Value
const QSet<PacketType::Value> NON_SOURCED_PACKETS = QSet<PacketType::Value>()
<< StunResponse << CreateAssignment << RequestAssignment
<< DomainServerRequireDTLS << DomainConnectRequest
<< DomainServerRequireDTLS << DomainConnectRequest << DomainServerConnectionToken
<< DomainList << DomainConnectionDenied
<< DomainServerPathQuery << DomainServerPathResponse
<< DomainServerAddedNode
@ -119,6 +119,7 @@ QString nameForPacketType(PacketType::Value packetType) {
PACKET_TYPE_NAME_LOOKUP(ICEPingReply);
PACKET_TYPE_NAME_LOOKUP(EntityAdd);
PACKET_TYPE_NAME_LOOKUP(EntityEdit);
PACKET_TYPE_NAME_LOOKUP(DomainServerConnectionToken);
default:
return QString("Type: ") + QString::number((int)packetType);
}

View file

@ -73,7 +73,8 @@ namespace PacketType {
EntityQuery,
EntityAdd,
EntityErase,
EntityEdit
EntityEdit,
DomainServerConnectionToken
};
};

View file

@ -636,8 +636,6 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float
if (s > halfOurScale) {
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));

View file

@ -21,6 +21,23 @@ uniform float glowIntensity;
// the alpha threshold
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) {
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;
}
_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);
}
@ -44,7 +61,7 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 s
_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, 0.5);
_fragColor1 = vec4(bestFitNormal(normal), 0.5);
_fragColor2 = vec4(emissive, shininess / 128.0);
}

View file

@ -86,6 +86,7 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
_emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive));
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(*_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
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) {

View file

@ -30,7 +30,8 @@ class DeferredLightingEffect : public Dependency {
SINGLETON_DEPENDENCY
public:
static const int NORMAL_FITTING_MAP_SLOT = 10;
void init(AbstractViewStateInterface* viewState);
/// Sets up the state necessary to render static untextured geometry with the simple program.

View file

@ -20,7 +20,6 @@
#include <FSTReader.h>
#include <NumericalConstants.h>
#include <gpu/Batch.h>
#include <gpu/GLBackend.h>
#include "TextureCache.h"
@ -2240,10 +2239,17 @@ bool NetworkMeshPart::isTranslucent() const {
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 count = 0;
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++;
}
}

View file

@ -398,6 +398,7 @@ public:
QVector<NetworkMeshPart> parts;
int getTranslucentPartCount(const FBXMesh& fbxMesh) const;
bool isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const;
};
#endif // hifi_GeometryCache_h

View file

@ -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("emissiveMap"), 3));
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::Shader::makeProgram(*program, slotBindings);
@ -180,6 +182,8 @@ void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model:
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
locations.glowIntensity = program->getUniforms().findLocation("glowIntensity");
locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
locations.specularTextureUnit = program->getTextures().findLocation("specularMap");
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
@ -1820,11 +1824,10 @@ void Model::segregateMeshGroups() {
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
}
// Debug...
// Create the render payloads
int totalParts = mesh.parts.size();
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
// this is a good place to create our renderPayloads
if (translucentMesh) {
if (networkMesh.isPartTranslucent(mesh, partIndex)) {
_transparentRenderItems << std::make_shared<MeshPartPayload>(true, this, i, partIndex);
} else {
_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
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) {

View file

@ -350,6 +350,7 @@ private:
int emissiveTextureUnit;
int emissiveParams;
int glowIntensity;
int normalFittingMapUnit;
int materialBufferUnit;
int clusterMatrices;
int clusterIndices;

View file

@ -21,6 +21,7 @@
#include <QRunnable>
#include <QThreadPool>
#include <qimagereader.h>
#include "PathUtils.h"
#include <gpu/Batch.h>
@ -129,6 +130,14 @@ const gpu::TexturePointer& TextureCache::getBlackTexture() {
return _blackTexture;
}
const gpu::TexturePointer& TextureCache::getNormalFittingTexture() {
if (!_normalFittingTexture) {
_normalFittingTexture = getImageTexture(PathUtils::resourcesPath() + "images/normalFittingScale.dds");
}
return _normalFittingTexture;
}
/// Extra data for creating textures.
class TextureExtra {
public:
@ -170,6 +179,7 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path) {
return texture;
}
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);

View file

@ -54,6 +54,9 @@ public:
/// Returns the a black texture (useful for a default).
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
static gpu::TexturePointer getImageTexture(const QString& path);
@ -76,6 +79,7 @@ private:
gpu::TexturePointer _grayTexture;
gpu::TexturePointer _blueTexture;
gpu::TexturePointer _blackTexture;
gpu::TexturePointer _normalFittingTexture;
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;
};

View file

@ -9,37 +9,21 @@
//
#include <iostream>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <string>
#include <vector>
#include <QWindow>
#include <QtGlobal>
#include <QFile>
#include <QImage>
#include <QLoggingCategory>
#include <gpu/Context.h>
#include <gpu/GLBackend.h>
#include <QOpenGLBuffer>
#include <QOpenGLContext>
#include <QOpenGLDebugLogger>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QOpenGLVertexArrayObject>
#include <QDir>
#include <QElapsedTimer>
#include <QGuiApplication>
#include <QLoggingCategory>
#include <QResizeEvent>
#include <QTime>
#include <QTimer>
#include <QWindow>
#include <QElapsedTimer>
#include <QDir>
#include <QGuiApplication>
#include <PathUtils.h>
#include "gpu/Batch.h"
#include "gpu/Context.h"
class RateCounter {
std::vector<float> times;
@ -71,7 +55,7 @@ public:
float rate() const {
if (elapsed() == 0.0f) {
return NAN;
return 0.0f;
}
return (float) count() / elapsed();
}

View file

@ -6,39 +6,20 @@
//
#include <iostream>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <QWindow>
#include <QtGlobal>
#include <QFile>
#include <QImage>
#include <QLoggingCategory>
#include <gpu/Context.h>
#include <gpu/GLBackend.h>
#include <QOpenGLBuffer>
#include <QOpenGLContext>
#include <QOpenGLDebugLogger>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QOpenGLVertexArrayObject>
#include <QLoggingCategory>
#include <QResizeEvent>
#include <QTime>
#include <QTimer>
#include <QWindow>
#include <QElapsedTimer>
#include <QDir>
#include <QGuiApplication>
#include <PathUtils.h>
#include "gpu/Batch.h"
#include "gpu/Context.h"
#include "../model/Skybox_vert.h"
#include "../model/Skybox_frag.h"
@ -159,7 +140,7 @@ public:
float rate() const {
if (elapsed() == 0.0f) {
return NAN;
return 0.0f;
}
return (float) count() / elapsed();
}

View file

@ -68,7 +68,7 @@ public:
float rate() const {
if (elapsed() == 0.0f) {
return NAN;
return 0.0f;
}
return (float) count() / elapsed();
}