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:
commit
b70c1a4960
37 changed files with 271 additions and 162 deletions
BUILD.mdBUILD_OSX.mdBUILD_WIN.md
domain-server/src
interface
resources/images
src
libraries
animation/src
fbx/src
gpu/src/gpu
networking/src
DataServerAccountInfo.cppDataServerAccountInfo.hDomainHandler.cppDomainHandler.hNodeList.cppNodeList.h
udt
octree/src
render-utils/src
tests
1
BUILD.md
1
BUILD.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
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.
|
||||
|
||||
####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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
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);
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <limits>
|
||||
|
||||
#include <render/Scene.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -73,7 +73,8 @@ namespace PacketType {
|
|||
EntityQuery,
|
||||
EntityAdd,
|
||||
EntityErase,
|
||||
EntityEdit
|
||||
EntityEdit,
|
||||
DomainServerConnectionToken
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -350,6 +350,7 @@ private:
|
|||
int emissiveTextureUnit;
|
||||
int emissiveParams;
|
||||
int glowIntensity;
|
||||
int normalFittingMapUnit;
|
||||
int materialBufferUnit;
|
||||
int clusterMatrices;
|
||||
int clusterIndices;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
|
||||
float rate() const {
|
||||
if (elapsed() == 0.0f) {
|
||||
return NAN;
|
||||
return 0.0f;
|
||||
}
|
||||
return (float) count() / elapsed();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue