mirror of
https://github.com/overte-org/overte.git
synced 2025-07-24 00:43:49 +02:00
Imroving the roughness/specular highlight nd fixing a bug with the CUbemap texture
This commit is contained in:
commit
16ac69315f
30 changed files with 457 additions and 245 deletions
|
@ -55,13 +55,7 @@ Agent::Agent(ReceivedMessage& message) :
|
||||||
{
|
{
|
||||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||||
|
|
||||||
auto assetClient = DependencyManager::set<AssetClient>();
|
ResourceManager::init();
|
||||||
|
|
||||||
QThread* assetThread = new QThread;
|
|
||||||
assetThread->setObjectName("Asset Thread");
|
|
||||||
assetClient->moveToThread(assetThread);
|
|
||||||
connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init);
|
|
||||||
assetThread->start();
|
|
||||||
|
|
||||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||||
|
|
||||||
|
@ -471,11 +465,7 @@ void Agent::aboutToFinish() {
|
||||||
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||||
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
|
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
|
||||||
|
|
||||||
// cleanup the AssetClient thread
|
ResourceManager::cleanup();
|
||||||
QThread* assetThread = DependencyManager::get<AssetClient>()->thread();
|
|
||||||
DependencyManager::destroy<AssetClient>();
|
|
||||||
assetThread->quit();
|
|
||||||
assetThread->wait();
|
|
||||||
|
|
||||||
// cleanup the AudioInjectorManager (and any still running injectors)
|
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||||
DependencyManager::destroy<AudioInjectorManager>();
|
DependencyManager::destroy<AudioInjectorManager>();
|
||||||
|
|
115
examples/away.js
115
examples/away.js
|
@ -13,13 +13,30 @@
|
||||||
//
|
//
|
||||||
// Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key.
|
// Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key.
|
||||||
// See MAIN CONTROL, below, for what "paused" actually does.
|
// See MAIN CONTROL, below, for what "paused" actually does.
|
||||||
var OVERLAY_RATIO = 1920 / 1080;
|
var OVERLAY_WIDTH = 1920;
|
||||||
|
var OVERLAY_HEIGHT = 1080;
|
||||||
|
var OVERLAY_RATIO = OVERLAY_WIDTH / OVERLAY_HEIGHT;
|
||||||
var OVERLAY_DATA = {
|
var OVERLAY_DATA = {
|
||||||
|
width: OVERLAY_WIDTH,
|
||||||
|
height: OVERLAY_HEIGHT,
|
||||||
imageURL: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png",
|
imageURL: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png",
|
||||||
color: {red: 255, green: 255, blue: 255},
|
color: {red: 255, green: 255, blue: 255},
|
||||||
alpha: 1
|
alpha: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var lastOverlayPosition = { x: 0, y: 0, z: 0};
|
||||||
|
var OVERLAY_DATA_HMD = {
|
||||||
|
position: lastOverlayPosition,
|
||||||
|
width: OVERLAY_WIDTH,
|
||||||
|
height: OVERLAY_HEIGHT,
|
||||||
|
url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png",
|
||||||
|
color: {red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
scale: 2,
|
||||||
|
isFacingAvatar: true,
|
||||||
|
drawInFront: true
|
||||||
|
};
|
||||||
|
|
||||||
// ANIMATION
|
// ANIMATION
|
||||||
// We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect
|
// We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect
|
||||||
// using an animation graph with a state that we turn on and off through the animation var defined with that state.
|
// using an animation graph with a state that we turn on and off through the animation var defined with that state.
|
||||||
|
@ -64,29 +81,74 @@ function stopAwayAnimation() {
|
||||||
|
|
||||||
// OVERLAY
|
// OVERLAY
|
||||||
var overlay = Overlays.addOverlay("image", OVERLAY_DATA);
|
var overlay = Overlays.addOverlay("image", OVERLAY_DATA);
|
||||||
|
var overlayHMD = Overlays.addOverlay("image3d", OVERLAY_DATA_HMD);
|
||||||
|
|
||||||
|
function moveCloserToCamera(positionAtHUD) {
|
||||||
|
// we don't actually want to render at the slerped look at... instead, we want to render
|
||||||
|
// slightly closer to the camera than that.
|
||||||
|
var MOVE_CLOSER_TO_CAMERA_BY = -0.25;
|
||||||
|
var cameraFront = Quat.getFront(Camera.orientation);
|
||||||
|
var closerToCamera = Vec3.multiply(cameraFront, MOVE_CLOSER_TO_CAMERA_BY); // slightly closer to camera
|
||||||
|
var slightlyCloserPosition = Vec3.sum(positionAtHUD, closerToCamera);
|
||||||
|
|
||||||
|
return slightlyCloserPosition;
|
||||||
|
}
|
||||||
|
|
||||||
function showOverlay() {
|
function showOverlay() {
|
||||||
var properties = {visible: true},
|
var properties = {visible: true};
|
||||||
// Update for current screen size, keeping overlay proportions constant.
|
|
||||||
screen = Controller.getViewportDimensions(),
|
if (HMD.active) {
|
||||||
screenRatio = screen.x / screen.y;
|
// make sure desktop version is hidden
|
||||||
if (screenRatio < OVERLAY_RATIO) {
|
Overlays.editOverlay(overlay, { visible: false });
|
||||||
properties.width = screen.x;
|
|
||||||
properties.height = screen.x / OVERLAY_RATIO;
|
lastOverlayPosition = HMD.getHUDLookAtPosition3D();
|
||||||
properties.x = 0;
|
var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition);
|
||||||
properties.y = (screen.y - properties.height) / 2;
|
Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon });
|
||||||
} else {
|
} else {
|
||||||
properties.height = screen.y;
|
// make sure HMD is hidden
|
||||||
properties.width = screen.y * OVERLAY_RATIO;
|
Overlays.editOverlay(overlayHMD, { visible: false });
|
||||||
properties.y = 0;
|
|
||||||
properties.x = (screen.x - properties.width) / 2;
|
// Update for current screen size, keeping overlay proportions constant.
|
||||||
|
var screen = Controller.getViewportDimensions();
|
||||||
|
|
||||||
|
// keep the overlay it's natural size and always center it...
|
||||||
|
Overlays.editOverlay(overlay, { visible: true,
|
||||||
|
x: ((screen.x - OVERLAY_WIDTH) / 2),
|
||||||
|
y: ((screen.y - OVERLAY_HEIGHT) / 2) });
|
||||||
}
|
}
|
||||||
Overlays.editOverlay(overlay, properties);
|
|
||||||
}
|
}
|
||||||
function hideOverlay() {
|
function hideOverlay() {
|
||||||
Overlays.editOverlay(overlay, {visible: false});
|
Overlays.editOverlay(overlay, {visible: false});
|
||||||
|
Overlays.editOverlay(overlayHMD, {visible: false});
|
||||||
}
|
}
|
||||||
hideOverlay();
|
hideOverlay();
|
||||||
|
|
||||||
|
function maybeMoveOverlay() {
|
||||||
|
if (isAway) {
|
||||||
|
// if we switched from HMD to Desktop, make sure to hide our HUD overlay and show the
|
||||||
|
// desktop overlay
|
||||||
|
if (!HMD.active) {
|
||||||
|
showOverlay(); // this will also recenter appropriately
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HMD.active) {
|
||||||
|
// Note: instead of moving it directly to the lookAt, we will move it slightly toward the
|
||||||
|
// new look at. This will result in a more subtle slerp toward the look at and reduce jerkiness
|
||||||
|
var EASE_BY_RATIO = 0.1;
|
||||||
|
var lookAt = HMD.getHUDLookAtPosition3D();
|
||||||
|
var lookAtChange = Vec3.subtract(lookAt, lastOverlayPosition);
|
||||||
|
var halfWayBetweenOldAndLookAt = Vec3.multiply(lookAtChange, EASE_BY_RATIO);
|
||||||
|
var newOverlayPosition = Vec3.sum(lastOverlayPosition, halfWayBetweenOldAndLookAt);
|
||||||
|
lastOverlayPosition = newOverlayPosition;
|
||||||
|
|
||||||
|
var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition);
|
||||||
|
Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon });
|
||||||
|
|
||||||
|
// make sure desktop version is hidden
|
||||||
|
Overlays.editOverlay(overlay, { visible: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MAIN CONTROL
|
// MAIN CONTROL
|
||||||
var wasMuted, isAway;
|
var wasMuted, isAway;
|
||||||
|
@ -106,6 +168,12 @@ function goAway() {
|
||||||
MyAvatar.setEnableMeshVisible(false); // just for our own display, without changing point of view
|
MyAvatar.setEnableMeshVisible(false); // just for our own display, without changing point of view
|
||||||
playAwayAnimation(); // animation is still seen by others
|
playAwayAnimation(); // animation is still seen by others
|
||||||
showOverlay();
|
showOverlay();
|
||||||
|
|
||||||
|
// tell the Reticle, we want to stop capturing the mouse until we come back
|
||||||
|
Reticle.allowMouseCapture = false;
|
||||||
|
if (HMD.active) {
|
||||||
|
Reticle.visible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function goActive() {
|
function goActive() {
|
||||||
if (!isAway) {
|
if (!isAway) {
|
||||||
|
@ -119,13 +187,20 @@ function goActive() {
|
||||||
MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting.
|
MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting.
|
||||||
stopAwayAnimation();
|
stopAwayAnimation();
|
||||||
hideOverlay();
|
hideOverlay();
|
||||||
|
|
||||||
|
// tell the Reticle, we are ready to capture the mouse again and it should be visible
|
||||||
|
Reticle.allowMouseCapture = true;
|
||||||
|
Reticle.visible = true;
|
||||||
|
if (HMD.active) {
|
||||||
|
Reticle.position = HMD.getHUDLookAtPosition2D();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeGoActive(event) {
|
function maybeGoActive(event) {
|
||||||
if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it)
|
if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isAway && (event.text === '.')) {
|
if (!isAway && (event.text == 'ESC')) {
|
||||||
goAway();
|
goAway();
|
||||||
} else {
|
} else {
|
||||||
goActive();
|
goActive();
|
||||||
|
@ -141,10 +216,8 @@ function maybeGoAway() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the mouse has gone from captured, to non-captured state,
|
// If the mouse has gone from captured, to non-captured state, then it likely means the person is still in the HMD, but
|
||||||
// then it likely means the person is still in the HMD, but has
|
// tabbed away from the application (meaning they don't have mouse control) and they likely want to go into an away state
|
||||||
// tabbed away from the application (meaning they don't have mouse
|
|
||||||
// control) and they likely want to go into an away state
|
|
||||||
if (Reticle.mouseCaptured !== wasMouseCaptured) {
|
if (Reticle.mouseCaptured !== wasMouseCaptured) {
|
||||||
wasMouseCaptured = !wasMouseCaptured;
|
wasMouseCaptured = !wasMouseCaptured;
|
||||||
if (!wasMouseCaptured) {
|
if (!wasMouseCaptured) {
|
||||||
|
@ -153,6 +226,8 @@ function maybeGoAway() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Script.update.connect(maybeMoveOverlay);
|
||||||
|
|
||||||
Script.update.connect(maybeGoAway);
|
Script.update.connect(maybeGoAway);
|
||||||
Controller.mousePressEvent.connect(goActive);
|
Controller.mousePressEvent.connect(goActive);
|
||||||
Controller.keyPressEvent.connect(maybeGoActive);
|
Controller.keyPressEvent.connect(maybeGoActive);
|
||||||
|
|
|
@ -35,8 +35,8 @@ var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50;
|
||||||
Controller.mouseMoveEvent.connect(function(mouseEvent) {
|
Controller.mouseMoveEvent.connect(function(mouseEvent) {
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
|
|
||||||
// if the reticle is hidden, show it...
|
// if the reticle is hidden, and we're not in away mode...
|
||||||
if (!Reticle.visible) {
|
if (!Reticle.visible && Reticle.allowMouseCapture) {
|
||||||
Reticle.visible = true;
|
Reticle.visible = true;
|
||||||
if (HMD.active) {
|
if (HMD.active) {
|
||||||
shouldSeekToLookAt = true;
|
shouldSeekToLookAt = true;
|
||||||
|
@ -44,7 +44,7 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) {
|
||||||
} else {
|
} else {
|
||||||
// even if the reticle is visible, if we're in HMD mode, and the person is moving their mouse quickly (shaking it)
|
// even if the reticle is visible, if we're in HMD mode, and the person is moving their mouse quickly (shaking it)
|
||||||
// then they are probably looking for it, and we should move into seekToLookAt mode
|
// then they are probably looking for it, and we should move into seekToLookAt mode
|
||||||
if (HMD.active && !shouldSeekToLookAt) {
|
if (HMD.active && !shouldSeekToLookAt && Reticle.allowMouseCapture) {
|
||||||
var dx = Reticle.position.x - lastMouseX;
|
var dx = Reticle.position.x - lastMouseX;
|
||||||
var dy = Reticle.position.y - lastMouseY;
|
var dy = Reticle.position.y - lastMouseY;
|
||||||
var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move
|
var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move
|
||||||
|
|
|
@ -370,7 +370,6 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
DependencyManager::set<AutoUpdater>();
|
DependencyManager::set<AutoUpdater>();
|
||||||
DependencyManager::set<PathUtils>();
|
DependencyManager::set<PathUtils>();
|
||||||
DependencyManager::set<InterfaceActionFactory>();
|
DependencyManager::set<InterfaceActionFactory>();
|
||||||
DependencyManager::set<AssetClient>();
|
|
||||||
DependencyManager::set<AudioInjectorManager>();
|
DependencyManager::set<AudioInjectorManager>();
|
||||||
DependencyManager::set<MessagesClient>();
|
DependencyManager::set<MessagesClient>();
|
||||||
DependencyManager::set<UserInputMapper>();
|
DependencyManager::set<UserInputMapper>();
|
||||||
|
@ -528,13 +527,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
|
|
||||||
audioThread->start();
|
audioThread->start();
|
||||||
|
|
||||||
// Setup AssetClient
|
ResourceManager::init();
|
||||||
auto assetClient = DependencyManager::get<AssetClient>();
|
|
||||||
QThread* assetThread = new QThread;
|
|
||||||
assetThread->setObjectName("Asset Thread");
|
|
||||||
assetClient->moveToThread(assetThread);
|
|
||||||
connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init);
|
|
||||||
assetThread->start();
|
|
||||||
|
|
||||||
// Setup MessagesClient
|
// Setup MessagesClient
|
||||||
auto messagesClient = DependencyManager::get<MessagesClient>();
|
auto messagesClient = DependencyManager::get<MessagesClient>();
|
||||||
|
@ -547,7 +540,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||||
|
|
||||||
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
||||||
connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));
|
connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
|
||||||
connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle()));
|
connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle()));
|
||||||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
||||||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
|
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
|
||||||
|
@ -644,13 +637,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
connect(&identityPacketTimer, &QTimer::timeout, getMyAvatar(), &MyAvatar::sendIdentityPacket);
|
connect(&identityPacketTimer, &QTimer::timeout, getMyAvatar(), &MyAvatar::sendIdentityPacket);
|
||||||
identityPacketTimer.start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
|
identityPacketTimer.start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
|
||||||
|
|
||||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
|
||||||
QNetworkDiskCache* cache = new QNetworkDiskCache();
|
|
||||||
cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE);
|
|
||||||
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache");
|
|
||||||
networkAccessManager.setCache(cache);
|
|
||||||
|
|
||||||
ResourceCache::setRequestLimit(3);
|
ResourceCache::setRequestLimit(3);
|
||||||
|
|
||||||
_glWidget = new GLCanvas();
|
_glWidget = new GLCanvas();
|
||||||
|
@ -661,15 +647,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
|
|
||||||
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
||||||
_glWidget->setFocus();
|
_glWidget->setFocus();
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
// OSX doesn't seem to provide for hiding the cursor only on the GL widget
|
auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget
|
||||||
_window->setCursor(Qt::BlankCursor);
|
|
||||||
#else
|
#else
|
||||||
// On windows and linux, hiding the top level cursor also means it's invisible
|
// On windows and linux, hiding the top level cursor also means it's invisible when hovering over the
|
||||||
// when hovering over the window menu, which is a pain, so only hide it for
|
// window menu, which is a pain, so only hide it for the GL surface
|
||||||
// the GL surface
|
auto cursorTarget = _glWidget;
|
||||||
_glWidget->setCursor(Qt::BlankCursor);
|
|
||||||
#endif
|
#endif
|
||||||
|
cursorTarget->setCursor(Qt::BlankCursor);
|
||||||
|
|
||||||
// enable mouse tracking; otherwise, we only get drag events
|
// enable mouse tracking; otherwise, we only get drag events
|
||||||
_glWidget->setMouseTracking(true);
|
_glWidget->setMouseTracking(true);
|
||||||
|
@ -981,6 +967,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
_idleTimer->start(0);
|
_idleTimer->start(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Application::checkChangeCursor() {
|
||||||
|
QMutexLocker locker(&_changeCursorLock);
|
||||||
|
if (_cursorNeedsChanging) {
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget
|
||||||
|
#else
|
||||||
|
// On windows and linux, hiding the top level cursor also means it's invisible when hovering over the
|
||||||
|
// window menu, which is a pain, so only hide it for the GL surface
|
||||||
|
auto cursorTarget = _glWidget;
|
||||||
|
#endif
|
||||||
|
cursorTarget->setCursor(_desiredCursor);
|
||||||
|
|
||||||
|
_cursorNeedsChanging = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::showCursor(const QCursor& cursor) {
|
||||||
|
QMutexLocker locker(&_changeCursorLock);
|
||||||
|
_desiredCursor = cursor;
|
||||||
|
_cursorNeedsChanging = true;
|
||||||
|
}
|
||||||
|
|
||||||
void Application::aboutToQuit() {
|
void Application::aboutToQuit() {
|
||||||
emit beforeAboutToQuit();
|
emit beforeAboutToQuit();
|
||||||
|
|
||||||
|
@ -1062,13 +1071,6 @@ void Application::cleanupBeforeQuit() {
|
||||||
DependencyManager::destroy<OffscreenUi>();
|
DependencyManager::destroy<OffscreenUi>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::emptyLocalCache() {
|
|
||||||
if (auto cache = NetworkAccessManager::getInstance().cache()) {
|
|
||||||
qDebug() << "DiskCacheEditor::clear(): Clearing disk cache.";
|
|
||||||
cache->clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Application::~Application() {
|
Application::~Application() {
|
||||||
EntityTreePointer tree = getEntities()->getTree();
|
EntityTreePointer tree = getEntities()->getTree();
|
||||||
tree->setSimulation(NULL);
|
tree->setSimulation(NULL);
|
||||||
|
@ -1106,11 +1108,7 @@ Application::~Application() {
|
||||||
DependencyManager::destroy<ScriptCache>();
|
DependencyManager::destroy<ScriptCache>();
|
||||||
DependencyManager::destroy<SoundCache>();
|
DependencyManager::destroy<SoundCache>();
|
||||||
|
|
||||||
// cleanup the AssetClient thread
|
ResourceManager::cleanup();
|
||||||
QThread* assetThread = DependencyManager::get<AssetClient>()->thread();
|
|
||||||
DependencyManager::destroy<AssetClient>();
|
|
||||||
assetThread->quit();
|
|
||||||
assetThread->wait();
|
|
||||||
|
|
||||||
QThread* nodeThread = DependencyManager::get<NodeList>()->thread();
|
QThread* nodeThread = DependencyManager::get<NodeList>()->thread();
|
||||||
|
|
||||||
|
@ -2431,6 +2429,9 @@ void Application::idle(uint64_t now) {
|
||||||
return; // bail early, nothing to do here.
|
return; // bail early, nothing to do here.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
checkChangeCursor();
|
||||||
|
|
||||||
Stats::getInstance()->updateStats();
|
Stats::getInstance()->updateStats();
|
||||||
AvatarInputs::getInstance()->update();
|
AvatarInputs::getInstance()->update();
|
||||||
|
|
||||||
|
@ -3055,7 +3056,7 @@ void Application::reloadResourceCaches() {
|
||||||
_viewFrustum.setOrientation(glm::quat());
|
_viewFrustum.setOrientation(glm::quat());
|
||||||
queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions);
|
queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions);
|
||||||
|
|
||||||
emptyLocalCache();
|
DependencyManager::get<AssetClient>()->clearCache();
|
||||||
|
|
||||||
DependencyManager::get<AnimationCache>()->refreshAll();
|
DependencyManager::get<AnimationCache>()->refreshAll();
|
||||||
DependencyManager::get<ModelCache>()->refreshAll();
|
DependencyManager::get<ModelCache>()->refreshAll();
|
||||||
|
@ -3978,13 +3979,8 @@ void Application::handleDomainConnectionDeniedPacket(QSharedPointer<ReceivedMess
|
||||||
AccountManager::getInstance().checkAndSignalForAccessToken();
|
AccountManager::getInstance().checkAndSignalForAccessToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::connectedToDomain(const QString& hostname) {
|
void Application::resettingDomain() {
|
||||||
AccountManager& accountManager = AccountManager::getInstance();
|
|
||||||
const QUuid& domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID();
|
|
||||||
|
|
||||||
if (accountManager.isLoggedIn() && !domainID.isNull()) {
|
|
||||||
_notifiedPacketVersionMismatchThisDomain = false;
|
_notifiedPacketVersionMismatchThisDomain = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::nodeAdded(SharedNodePointer node) {
|
void Application::nodeAdded(SharedNodePointer node) {
|
||||||
|
|
|
@ -120,6 +120,8 @@ public:
|
||||||
QSize getDeviceSize() const;
|
QSize getDeviceSize() const;
|
||||||
bool hasFocus() const;
|
bool hasFocus() const;
|
||||||
|
|
||||||
|
void showCursor(const QCursor& cursor);
|
||||||
|
|
||||||
bool isThrottleRendering() const;
|
bool isThrottleRendering() const;
|
||||||
|
|
||||||
Camera* getCamera() { return &_myCamera; }
|
Camera* getCamera() { return &_myCamera; }
|
||||||
|
@ -288,7 +290,7 @@ private slots:
|
||||||
void idle(uint64_t now);
|
void idle(uint64_t now);
|
||||||
void aboutToQuit();
|
void aboutToQuit();
|
||||||
|
|
||||||
void connectedToDomain(const QString& hostname);
|
void resettingDomain();
|
||||||
|
|
||||||
void audioMuteToggled();
|
void audioMuteToggled();
|
||||||
void faceTrackerMuteToggled();
|
void faceTrackerMuteToggled();
|
||||||
|
@ -328,8 +330,6 @@ private:
|
||||||
|
|
||||||
void cleanupBeforeQuit();
|
void cleanupBeforeQuit();
|
||||||
|
|
||||||
void emptyLocalCache();
|
|
||||||
|
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
|
|
||||||
void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue);
|
void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue);
|
||||||
|
@ -515,6 +515,11 @@ private:
|
||||||
QTimer* _idleTimer { nullptr };
|
QTimer* _idleTimer { nullptr };
|
||||||
|
|
||||||
bool _fakedMouseEvent { false };
|
bool _fakedMouseEvent { false };
|
||||||
|
|
||||||
|
void checkChangeCursor();
|
||||||
|
mutable QMutex _changeCursorLock { QMutex::Recursive };
|
||||||
|
QCursor _desiredCursor{ Qt::BlankCursor };
|
||||||
|
bool _cursorNeedsChanging { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Application_h
|
#endif // hifi_Application_h
|
||||||
|
|
|
@ -337,9 +337,21 @@ QPointF ApplicationCompositor::getMouseEventPosition(QMouseEvent* event) {
|
||||||
|
|
||||||
bool ApplicationCompositor::shouldCaptureMouse() const {
|
bool ApplicationCompositor::shouldCaptureMouse() const {
|
||||||
// if we're in HMD mode, and some window of ours is active, but we're not currently showing a popup menu
|
// if we're in HMD mode, and some window of ours is active, but we're not currently showing a popup menu
|
||||||
return qApp->isHMDMode() && QApplication::activeWindow() && !Menu::isSomeSubmenuShown();
|
return _allowMouseCapture && qApp->isHMDMode() && QApplication::activeWindow() && !Menu::isSomeSubmenuShown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplicationCompositor::setAllowMouseCapture(bool capture) {
|
||||||
|
if (qApp->isHMDMode()) {
|
||||||
|
if (capture) {
|
||||||
|
qApp->showCursor(Qt::BlankCursor);
|
||||||
|
} else {
|
||||||
|
qApp->showCursor(Qt::ArrowCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_allowMouseCapture = capture;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ApplicationCompositor::handleLeaveEvent() {
|
void ApplicationCompositor::handleLeaveEvent() {
|
||||||
|
|
||||||
if (shouldCaptureMouse()) {
|
if (shouldCaptureMouse()) {
|
||||||
|
|
|
@ -106,6 +106,9 @@ public:
|
||||||
|
|
||||||
bool shouldCaptureMouse() const;
|
bool shouldCaptureMouse() const;
|
||||||
|
|
||||||
|
bool getAllowMouseCapture() const { return _allowMouseCapture; }
|
||||||
|
void setAllowMouseCapture(bool capture);
|
||||||
|
|
||||||
/// if the reticle is pointing to a system overlay (a dialog box for example) then the function returns true otherwise false
|
/// if the reticle is pointing to a system overlay (a dialog box for example) then the function returns true otherwise false
|
||||||
bool getReticleOverDesktop() const;
|
bool getReticleOverDesktop() const;
|
||||||
void setReticleOverDesktop(bool value) { _isOverDesktop = value; }
|
void setReticleOverDesktop(bool value) { _isOverDesktop = value; }
|
||||||
|
@ -162,6 +165,8 @@ private:
|
||||||
|
|
||||||
bool _reticleOverQml { false };
|
bool _reticleOverQml { false };
|
||||||
|
|
||||||
|
bool _allowMouseCapture { true };
|
||||||
|
|
||||||
ReticleInterface* _reticleInterface;
|
ReticleInterface* _reticleInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -173,12 +178,17 @@ class ReticleInterface : public QObject {
|
||||||
Q_PROPERTY(float depth READ getDepth WRITE setDepth)
|
Q_PROPERTY(float depth READ getDepth WRITE setDepth)
|
||||||
Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition)
|
Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition)
|
||||||
Q_PROPERTY(bool mouseCaptured READ isMouseCaptured)
|
Q_PROPERTY(bool mouseCaptured READ isMouseCaptured)
|
||||||
|
Q_PROPERTY(bool allowMouseCapture READ getAllowMouseCapture WRITE setAllowMouseCapture)
|
||||||
Q_PROPERTY(bool pointingAtSystemOverlay READ isPointingAtSystemOverlay)
|
Q_PROPERTY(bool pointingAtSystemOverlay READ isPointingAtSystemOverlay)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ReticleInterface(ApplicationCompositor* outer) : QObject(outer), _compositor(outer) {}
|
ReticleInterface(ApplicationCompositor* outer) : QObject(outer), _compositor(outer) {}
|
||||||
|
|
||||||
Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); }
|
Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); }
|
||||||
|
|
||||||
|
Q_INVOKABLE bool getAllowMouseCapture() { return _compositor->getAllowMouseCapture(); }
|
||||||
|
Q_INVOKABLE void setAllowMouseCapture(bool value) { return _compositor->setAllowMouseCapture(value); }
|
||||||
|
|
||||||
Q_INVOKABLE bool isPointingAtSystemOverlay() { return !_compositor->getReticleOverDesktop(); }
|
Q_INVOKABLE bool isPointingAtSystemOverlay() { return !_compositor->getReticleOverDesktop(); }
|
||||||
|
|
||||||
Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); }
|
Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); }
|
||||||
|
|
|
@ -9,23 +9,21 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <functional>
|
#include "DiskCacheEditor.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QNetworkDiskCache>
|
#include <QTimer>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include <NetworkAccessManager.h>
|
#include <AssetClient.h>
|
||||||
|
|
||||||
#include "DiskCacheEditor.h"
|
|
||||||
#include "OffscreenUi.h"
|
#include "OffscreenUi.h"
|
||||||
|
|
||||||
DiskCacheEditor::DiskCacheEditor(QWidget* parent) : QObject(parent) {
|
DiskCacheEditor::DiskCacheEditor(QWidget* parent) : QObject(parent) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QWindow* DiskCacheEditor::windowHandle() {
|
QWindow* DiskCacheEditor::windowHandle() {
|
||||||
|
@ -33,7 +31,6 @@ QWindow* DiskCacheEditor::windowHandle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskCacheEditor::toggle() {
|
void DiskCacheEditor::toggle() {
|
||||||
qDebug() << "DiskCacheEditor::toggle()";
|
|
||||||
if (!_dialog) {
|
if (!_dialog) {
|
||||||
makeDialog();
|
makeDialog();
|
||||||
}
|
}
|
||||||
|
@ -92,12 +89,12 @@ void DiskCacheEditor::makeDialog() {
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
|
|
||||||
QPushButton* refreshCacheButton = new QPushButton(_dialog);
|
static const int REFRESH_INTERVAL = 100; // msec
|
||||||
Q_CHECK_PTR(refreshCacheButton);
|
_refreshTimer = new QTimer(_dialog);
|
||||||
refreshCacheButton->setText("Refresh");
|
_refreshTimer->setInterval(REFRESH_INTERVAL);
|
||||||
refreshCacheButton->setToolTip("Reload the cache stats.");
|
_refreshTimer->setSingleShot(false);
|
||||||
connect(refreshCacheButton, SIGNAL(clicked()), SLOT(refresh()));
|
QObject::connect(_refreshTimer.data(), &QTimer::timeout, this, &DiskCacheEditor::refresh);
|
||||||
layout->addWidget(refreshCacheButton, 3, 2);
|
_refreshTimer->start();
|
||||||
|
|
||||||
QPushButton* clearCacheButton = new QPushButton(_dialog);
|
QPushButton* clearCacheButton = new QPushButton(_dialog);
|
||||||
Q_CHECK_PTR(clearCacheButton);
|
Q_CHECK_PTR(clearCacheButton);
|
||||||
|
@ -108,7 +105,11 @@ void DiskCacheEditor::makeDialog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskCacheEditor::refresh() {
|
void DiskCacheEditor::refresh() {
|
||||||
static const std::function<QString(qint64)> stringify = [](qint64 number) {
|
DependencyManager::get<AssetClient>()->cacheInfoRequest(this, "cacheInfoCallback");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiskCacheEditor::cacheInfoCallback(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize) {
|
||||||
|
static const auto stringify = [](qint64 number) {
|
||||||
static const QStringList UNITS = QStringList() << "B" << "KB" << "MB" << "GB";
|
static const QStringList UNITS = QStringList() << "B" << "KB" << "MB" << "GB";
|
||||||
static const qint64 CHUNK = 1024;
|
static const qint64 CHUNK = 1024;
|
||||||
QString unit;
|
QString unit;
|
||||||
|
@ -122,30 +123,24 @@ void DiskCacheEditor::refresh() {
|
||||||
}
|
}
|
||||||
return QString("%0 %1").arg(number).arg(UNITS[i]);
|
return QString("%0 %1").arg(number).arg(UNITS[i]);
|
||||||
};
|
};
|
||||||
QNetworkDiskCache* cache = qobject_cast<QNetworkDiskCache*>(NetworkAccessManager::getInstance().cache());
|
|
||||||
|
|
||||||
if (_path) {
|
if (_path) {
|
||||||
_path->setText(cache->cacheDirectory());
|
_path->setText(cacheDirectory);
|
||||||
}
|
}
|
||||||
if (_size) {
|
if (_size) {
|
||||||
_size->setText(stringify(cache->cacheSize()));
|
_size->setText(stringify(cacheSize));
|
||||||
}
|
}
|
||||||
if (_maxSize) {
|
if (_maxSize) {
|
||||||
_maxSize->setText(stringify(cache->maximumCacheSize()));
|
_maxSize->setText(stringify(maximumCacheSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskCacheEditor::clear() {
|
void DiskCacheEditor::clear() {
|
||||||
QMessageBox::StandardButton buttonClicked =
|
auto buttonClicked = OffscreenUi::question(_dialog, "Clearing disk cache",
|
||||||
OffscreenUi::question(_dialog, "Clearing disk cache",
|
|
||||||
"You are about to erase all the content of the disk cache, "
|
"You are about to erase all the content of the disk cache, "
|
||||||
"are you sure you want to do that?",
|
"are you sure you want to do that?",
|
||||||
QMessageBox::Ok | QMessageBox::Cancel);
|
QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
if (buttonClicked == QMessageBox::Ok) {
|
if (buttonClicked == QMessageBox::Ok) {
|
||||||
if (auto cache = NetworkAccessManager::getInstance().cache()) {
|
DependencyManager::get<AssetClient>()->clearCache();
|
||||||
qDebug() << "DiskCacheEditor::clear(): Clearing disk cache.";
|
|
||||||
cache->clear();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
refresh();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
class QDialog;
|
class QDialog;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QWindow;
|
class QWindow;
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
class DiskCacheEditor : public QObject {
|
class DiskCacheEditor : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -32,6 +33,7 @@ public slots:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void refresh();
|
void refresh();
|
||||||
|
void cacheInfoCallback(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -41,6 +43,7 @@ private:
|
||||||
QPointer<QLabel> _path;
|
QPointer<QLabel> _path;
|
||||||
QPointer<QLabel> _size;
|
QPointer<QLabel> _size;
|
||||||
QPointer<QLabel> _maxSize;
|
QPointer<QLabel> _maxSize;
|
||||||
|
QPointer<QTimer> _refreshTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_DiskCacheEditor_h
|
#endif // hifi_DiskCacheEditor_h
|
|
@ -322,7 +322,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
||||||
_ambientTexture.clear();
|
_ambientTexture.clear();
|
||||||
} else {
|
} else {
|
||||||
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), CUBE_TEXTURE);
|
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), CUBE_TEXTURE);
|
||||||
if (_ambientTexture->getGPUTexture()) {
|
if (_ambientTexture && _ambientTexture->isLoaded() && _ambientTexture->getGPUTexture()) {
|
||||||
_pendingAmbientTexture = false;
|
_pendingAmbientTexture = false;
|
||||||
if (_ambientTexture->getGPUTexture()->getIrradiance()) {
|
if (_ambientTexture->getGPUTexture()->getIrradiance()) {
|
||||||
sceneKeyLight->setAmbientSphere(_ambientTexture->getGPUTexture()->getIrradiance());
|
sceneKeyLight->setAmbientSphere(_ambientTexture->getGPUTexture()->getIrradiance());
|
||||||
|
@ -356,7 +356,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
||||||
// Update the Texture of the Skybox with the one pointed by this zone
|
// Update the Texture of the Skybox with the one pointed by this zone
|
||||||
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE);
|
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE);
|
||||||
|
|
||||||
if (_skyboxTexture->getGPUTexture()) {
|
if (_skyboxTexture && _skyboxTexture->isLoaded() && _skyboxTexture->getGPUTexture()) {
|
||||||
auto texture = _skyboxTexture->getGPUTexture();
|
auto texture = _skyboxTexture->getGPUTexture();
|
||||||
skybox->setCubemap(texture);
|
skybox->setCubemap(texture);
|
||||||
_pendingSkyboxTexture = false;
|
_pendingSkyboxTexture = false;
|
||||||
|
|
|
@ -338,105 +338,84 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas
|
||||||
return networkMesh;
|
return networkMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FBXMaterial& material, const QUrl& textureBaseUrl) {
|
|
||||||
auto textureCache = DependencyManager::get<TextureCache>();
|
|
||||||
NetworkMaterial* networkMaterial = new NetworkMaterial();
|
|
||||||
|
|
||||||
|
static model::TextureMapPointer setupNetworkTextureMap(NetworkGeometry* geometry, const QUrl& textureBaseUrl,
|
||||||
|
const FBXTexture& texture, TextureType type,
|
||||||
|
NetworkTexturePointer& networkTexture, QString& networkTextureName) {
|
||||||
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
|
|
||||||
|
// If content is inline, cache it under the fbx file, not its base url
|
||||||
|
const auto baseUrl = texture.content.isEmpty() ? textureBaseUrl : QUrl(textureBaseUrl.url() + "/");
|
||||||
|
const auto filename = baseUrl.resolved(QUrl(texture.filename));
|
||||||
|
|
||||||
|
networkTexture = textureCache->getTexture(filename, type, texture.content);
|
||||||
|
QObject::connect(networkTexture.data(), &NetworkTexture::networkTextureCreated, geometry, &NetworkGeometry::textureLoaded);
|
||||||
|
networkTextureName = texture.name;
|
||||||
|
|
||||||
|
auto map = std::make_shared<model::TextureMap>();
|
||||||
|
map->setTextureSource(networkTexture->_textureSource);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FBXMaterial& material, const QUrl& textureBaseUrl) {
|
||||||
|
NetworkMaterial* networkMaterial = new NetworkMaterial();
|
||||||
networkMaterial->_material = material._material;
|
networkMaterial->_material = material._material;
|
||||||
|
|
||||||
if (!material.albedoTexture.filename.isEmpty()) {
|
if (!material.albedoTexture.filename.isEmpty()) {
|
||||||
networkMaterial->albedoTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.albedoTexture.filename)), DEFAULT_TEXTURE, material.albedoTexture.content);
|
auto albedoMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE,
|
||||||
QObject::connect(networkMaterial->albedoTexture.data(), &NetworkTexture::networkTextureCreated,
|
networkMaterial->albedoTexture, networkMaterial->albedoTextureName);
|
||||||
geometry, &NetworkGeometry::textureLoaded);
|
|
||||||
|
|
||||||
networkMaterial->albedoTextureName = material.albedoTexture.name;
|
|
||||||
|
|
||||||
auto albedoMap = model::TextureMapPointer(new model::TextureMap());
|
|
||||||
albedoMap->setTextureSource(networkMaterial->albedoTexture->_textureSource);
|
|
||||||
albedoMap->setTextureTransform(material.albedoTexture.transform);
|
albedoMap->setTextureTransform(material.albedoTexture.transform);
|
||||||
|
|
||||||
material._material->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap);
|
material._material->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!material.normalTexture.filename.isEmpty()) {
|
if (!material.normalTexture.filename.isEmpty()) {
|
||||||
networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content);
|
auto normalMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.normalTexture,
|
||||||
networkMaterial->normalTextureName = material.normalTexture.name;
|
(material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE),
|
||||||
|
networkMaterial->normalTexture, networkMaterial->normalTextureName);
|
||||||
auto normalMap = model::TextureMapPointer(new model::TextureMap());
|
networkMaterial->_material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap);
|
||||||
normalMap->setTextureSource(networkMaterial->normalTexture->_textureSource);
|
|
||||||
|
|
||||||
material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Roughness first or gloss maybe
|
// Roughness first or gloss maybe
|
||||||
if (!material.roughnessTexture.filename.isEmpty()) {
|
if (!material.roughnessTexture.filename.isEmpty()) {
|
||||||
networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.roughnessTexture.filename)), ROUGHNESS_TEXTURE, material.roughnessTexture.content);
|
auto roughnessMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.roughnessTexture, ROUGHNESS_TEXTURE,
|
||||||
networkMaterial->roughnessTextureName = material.roughnessTexture.name;
|
networkMaterial->roughnessTexture, networkMaterial->roughnessTextureName);
|
||||||
|
|
||||||
auto roughnessMap = model::TextureMapPointer(new model::TextureMap());
|
|
||||||
roughnessMap->setTextureSource(networkMaterial->roughnessTexture->_textureSource);
|
|
||||||
|
|
||||||
material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap);
|
material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap);
|
||||||
} else if (!material.glossTexture.filename.isEmpty()) {
|
} else if (!material.glossTexture.filename.isEmpty()) {
|
||||||
networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.glossTexture.filename)), GLOSS_TEXTURE, material.glossTexture.content);
|
auto roughnessMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.glossTexture, GLOSS_TEXTURE,
|
||||||
networkMaterial->roughnessTextureName = material.roughnessTexture.name;
|
networkMaterial->roughnessTexture, networkMaterial->roughnessTextureName);
|
||||||
|
|
||||||
auto roughnessMap = model::TextureMapPointer(new model::TextureMap());
|
|
||||||
roughnessMap->setTextureSource(networkMaterial->roughnessTexture->_textureSource);
|
|
||||||
|
|
||||||
material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap);
|
material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metallic first or specular maybe
|
// Metallic first or specular maybe
|
||||||
|
|
||||||
if (!material.metallicTexture.filename.isEmpty()) {
|
if (!material.metallicTexture.filename.isEmpty()) {
|
||||||
networkMaterial->metallicTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.metallicTexture.filename)), METALLIC_TEXTURE, material.metallicTexture.content);
|
auto metallicMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.metallicTexture, METALLIC_TEXTURE,
|
||||||
networkMaterial->metallicTextureName = material.metallicTexture.name;
|
networkMaterial->metallicTexture, networkMaterial->metallicTextureName);
|
||||||
|
|
||||||
auto metallicMap = model::TextureMapPointer(new model::TextureMap());
|
|
||||||
metallicMap->setTextureSource(networkMaterial->metallicTexture->_textureSource);
|
|
||||||
|
|
||||||
material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap);
|
material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap);
|
||||||
} else if (!material.specularTexture.filename.isEmpty()) {
|
} else if (!material.specularTexture.filename.isEmpty()) {
|
||||||
networkMaterial->metallicTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content);
|
|
||||||
networkMaterial->metallicTextureName = material.specularTexture.name;
|
|
||||||
|
|
||||||
auto metallicMap = model::TextureMapPointer(new model::TextureMap());
|
|
||||||
metallicMap->setTextureSource(networkMaterial->metallicTexture->_textureSource);
|
|
||||||
|
|
||||||
|
auto metallicMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.specularTexture, SPECULAR_TEXTURE,
|
||||||
|
networkMaterial->metallicTexture, networkMaterial->metallicTextureName);
|
||||||
material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap);
|
material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!material.occlusionTexture.filename.isEmpty()) {
|
if (!material.occlusionTexture.filename.isEmpty()) {
|
||||||
networkMaterial->occlusionTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.occlusionTexture.filename)), OCCLUSION_TEXTURE, material.occlusionTexture.content);
|
auto occlusionMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.occlusionTexture, OCCLUSION_TEXTURE,
|
||||||
networkMaterial->occlusionTextureName = material.occlusionTexture.name;
|
networkMaterial->occlusionTexture, networkMaterial->occlusionTextureName);
|
||||||
|
|
||||||
auto occlusionMap = model::TextureMapPointer(new model::TextureMap());
|
|
||||||
occlusionMap->setTextureSource(networkMaterial->occlusionTexture->_textureSource);
|
|
||||||
|
|
||||||
material._material->setTextureMap(model::MaterialKey::OCCLUSION_MAP, occlusionMap);
|
material._material->setTextureMap(model::MaterialKey::OCCLUSION_MAP, occlusionMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!material.emissiveTexture.filename.isEmpty()) {
|
if (!material.emissiveTexture.filename.isEmpty()) {
|
||||||
networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content);
|
auto emissiveMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.emissiveTexture, EMISSIVE_TEXTURE,
|
||||||
networkMaterial->emissiveTextureName = material.emissiveTexture.name;
|
networkMaterial->emissiveTexture, networkMaterial->emissiveTextureName);
|
||||||
|
|
||||||
auto emissiveMap = model::TextureMapPointer(new model::TextureMap());
|
|
||||||
emissiveMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
|
|
||||||
|
|
||||||
material._material->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap);
|
material._material->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!material.lightmapTexture.filename.isEmpty()) {
|
if (!material.lightmapTexture.filename.isEmpty()) {
|
||||||
networkMaterial->lightmapTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.lightmapTexture.filename)), LIGHTMAP_TEXTURE, material.lightmapTexture.content);
|
auto lightmapMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.lightmapTexture, LIGHTMAP_TEXTURE,
|
||||||
networkMaterial->lightmapTextureName = material.lightmapTexture.name;
|
networkMaterial->lightmapTexture, networkMaterial->lightmapTextureName);
|
||||||
|
|
||||||
|
|
||||||
auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
|
|
||||||
lightmapMap->setTextureSource(networkMaterial->lightmapTexture->_textureSource);
|
|
||||||
lightmapMap->setTextureTransform(material.lightmapTexture.transform);
|
lightmapMap->setTextureTransform(material.lightmapTexture.transform);
|
||||||
lightmapMap->setLightmapOffsetScale(material.lightmapParams.x, material.lightmapParams.y);
|
lightmapMap->setLightmapOffsetScale(material.lightmapParams.x, material.lightmapParams.y);
|
||||||
|
|
||||||
material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap);
|
material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,12 +47,10 @@ AssetClient::AssetClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetClient::init() {
|
void AssetClient::init() {
|
||||||
if (QThread::currentThread() != thread()) {
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
QMetaObject::invokeMethod(this, "init", Qt::BlockingQueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup disk cache if not already
|
// Setup disk cache if not already
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
auto& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
if (!networkAccessManager.cache()) {
|
if (!networkAccessManager.cache()) {
|
||||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||||
cachePath = !cachePath.isEmpty() ? cachePath : "interfaceCache";
|
cachePath = !cachePath.isEmpty() ? cachePath : "interfaceCache";
|
||||||
|
@ -61,11 +59,44 @@ void AssetClient::init() {
|
||||||
cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE);
|
cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE);
|
||||||
cache->setCacheDirectory(cachePath);
|
cache->setCacheDirectory(cachePath);
|
||||||
networkAccessManager.setCache(cache);
|
networkAccessManager.setCache(cache);
|
||||||
qCDebug(asset_client) << "AssetClient disk cache setup at" << cachePath
|
qDebug() << "ResourceManager disk cache setup at" << cachePath
|
||||||
<< "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)";
|
<< "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AssetClient::cacheInfoRequest(QObject* reciever, QString slot) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "cacheInfoRequest", Qt::QueuedConnection,
|
||||||
|
Q_ARG(QObject*, reciever), Q_ARG(QString, slot));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (auto* cache = qobject_cast<QNetworkDiskCache*>(NetworkAccessManager::getInstance().cache())) {
|
||||||
|
QMetaObject::invokeMethod(reciever, slot.toStdString().data(), Qt::QueuedConnection,
|
||||||
|
Q_ARG(QString, cache->cacheDirectory()),
|
||||||
|
Q_ARG(qint64, cache->cacheSize()),
|
||||||
|
Q_ARG(qint64, cache->maximumCacheSize()));
|
||||||
|
} else {
|
||||||
|
qCWarning(asset_client) << "No disk cache to get info from.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetClient::clearCache() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "clearCache", Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto cache = NetworkAccessManager::getInstance().cache()) {
|
||||||
|
qDebug() << "AssetClient::clearCache(): Clearing disk cache.";
|
||||||
|
cache->clear();
|
||||||
|
} else {
|
||||||
|
qCWarning(asset_client) << "No disk cache to clear.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool haveAssetServer() {
|
bool haveAssetServer() {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
|
@ -44,12 +44,16 @@ class AssetClient : public QObject, public Dependency {
|
||||||
public:
|
public:
|
||||||
AssetClient();
|
AssetClient();
|
||||||
|
|
||||||
Q_INVOKABLE void init();
|
|
||||||
|
|
||||||
Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension);
|
Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension);
|
||||||
Q_INVOKABLE AssetUpload* createUpload(const QString& filename);
|
Q_INVOKABLE AssetUpload* createUpload(const QString& filename);
|
||||||
Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension);
|
Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void cacheInfoRequest(QObject* reciever, QString slot);
|
||||||
|
void clearCache();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleAssetGetInfoReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
void handleAssetGetInfoReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||||
void handleAssetGetReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
void handleAssetGetReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
class AssetResourceRequest : public ResourceRequest {
|
class AssetResourceRequest : public ResourceRequest {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AssetResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { }
|
AssetResourceRequest(const QUrl& url) : ResourceRequest(url) { }
|
||||||
~AssetResourceRequest();
|
~AssetResourceRequest();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -98,6 +98,8 @@ void DomainHandler::softReset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainHandler::hardReset() {
|
void DomainHandler::hardReset() {
|
||||||
|
emit resetting();
|
||||||
|
|
||||||
softReset();
|
softReset();
|
||||||
|
|
||||||
qCDebug(networking) << "Hard reset in NodeList DomainHandler.";
|
qCDebug(networking) << "Hard reset in NodeList DomainHandler.";
|
||||||
|
|
|
@ -104,6 +104,7 @@ signals:
|
||||||
// It means that, either from DNS lookup or ICE, we think we have a socket we can talk to DS on
|
// It means that, either from DNS lookup or ICE, we think we have a socket we can talk to DS on
|
||||||
void completedSocketDiscovery();
|
void completedSocketDiscovery();
|
||||||
|
|
||||||
|
void resetting();
|
||||||
void connectedToDomain(const QString& hostname);
|
void connectedToDomain(const QString& hostname);
|
||||||
void disconnectedFromDomain();
|
void disconnectedFromDomain();
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
class FileResourceRequest : public ResourceRequest {
|
class FileResourceRequest : public ResourceRequest {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
FileResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { }
|
FileResourceRequest(const QUrl& url) : ResourceRequest(url) { }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void doSend() override;
|
virtual void doSend() override;
|
||||||
|
|
|
@ -28,6 +28,25 @@ HTTPResourceRequest::~HTTPResourceRequest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPResourceRequest::setupTimer() {
|
||||||
|
Q_ASSERT(!_sendTimer);
|
||||||
|
static const int TIMEOUT_MS = 10000;
|
||||||
|
|
||||||
|
_sendTimer = new QTimer();
|
||||||
|
connect(this, &QObject::destroyed, _sendTimer, &QTimer::deleteLater);
|
||||||
|
connect(_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout);
|
||||||
|
|
||||||
|
_sendTimer->setSingleShot(true);
|
||||||
|
_sendTimer->start(TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPResourceRequest::cleanupTimer() {
|
||||||
|
Q_ASSERT(_sendTimer);
|
||||||
|
_sendTimer->disconnect(this);
|
||||||
|
_sendTimer->deleteLater();
|
||||||
|
_sendTimer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void HTTPResourceRequest::doSend() {
|
void HTTPResourceRequest::doSend() {
|
||||||
QNetworkRequest networkRequest(_url);
|
QNetworkRequest networkRequest(_url);
|
||||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||||
|
@ -42,18 +61,15 @@ void HTTPResourceRequest::doSend() {
|
||||||
|
|
||||||
connect(_reply, &QNetworkReply::finished, this, &HTTPResourceRequest::onRequestFinished);
|
connect(_reply, &QNetworkReply::finished, this, &HTTPResourceRequest::onRequestFinished);
|
||||||
connect(_reply, &QNetworkReply::downloadProgress, this, &HTTPResourceRequest::onDownloadProgress);
|
connect(_reply, &QNetworkReply::downloadProgress, this, &HTTPResourceRequest::onDownloadProgress);
|
||||||
connect(&_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout);
|
|
||||||
|
|
||||||
static const int TIMEOUT_MS = 10000;
|
setupTimer();
|
||||||
_sendTimer.setSingleShot(true);
|
|
||||||
_sendTimer.start(TIMEOUT_MS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPResourceRequest::onRequestFinished() {
|
void HTTPResourceRequest::onRequestFinished() {
|
||||||
Q_ASSERT(_state == InProgress);
|
Q_ASSERT(_state == InProgress);
|
||||||
Q_ASSERT(_reply);
|
Q_ASSERT(_reply);
|
||||||
|
|
||||||
_sendTimer.stop();
|
cleanupTimer();
|
||||||
|
|
||||||
switch(_reply->error()) {
|
switch(_reply->error()) {
|
||||||
case QNetworkReply::NoError:
|
case QNetworkReply::NoError:
|
||||||
|
@ -80,7 +96,7 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
|
||||||
Q_ASSERT(_state == InProgress);
|
Q_ASSERT(_state == InProgress);
|
||||||
|
|
||||||
// We've received data, so reset the timer
|
// We've received data, so reset the timer
|
||||||
_sendTimer.start();
|
_sendTimer->start();
|
||||||
|
|
||||||
emit progress(bytesReceived, bytesTotal);
|
emit progress(bytesReceived, bytesTotal);
|
||||||
}
|
}
|
||||||
|
@ -92,6 +108,8 @@ void HTTPResourceRequest::onTimeout() {
|
||||||
_reply->deleteLater();
|
_reply->deleteLater();
|
||||||
_reply = nullptr;
|
_reply = nullptr;
|
||||||
|
|
||||||
|
cleanupTimer();
|
||||||
|
|
||||||
_result = Timeout;
|
_result = Timeout;
|
||||||
_state = Finished;
|
_state = Finished;
|
||||||
emit finished();
|
emit finished();
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
class HTTPResourceRequest : public ResourceRequest {
|
class HTTPResourceRequest : public ResourceRequest {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
HTTPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { }
|
HTTPResourceRequest(const QUrl& url) : ResourceRequest(url) { }
|
||||||
~HTTPResourceRequest();
|
~HTTPResourceRequest();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -33,7 +33,10 @@ private slots:
|
||||||
void onRequestFinished();
|
void onRequestFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTimer _sendTimer;
|
void setupTimer();
|
||||||
|
void cleanupTimer();
|
||||||
|
|
||||||
|
QTimer* _sendTimer { nullptr };
|
||||||
QNetworkReply* _reply { nullptr };
|
QNetworkReply* _reply { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,20 @@
|
||||||
|
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
|
||||||
#include "AssetResourceRequest.h"
|
#include <QNetworkDiskCache>
|
||||||
#include "FileResourceRequest.h"
|
#include <QStandardPaths>
|
||||||
#include "HTTPResourceRequest.h"
|
#include <QThread>
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "AssetResourceRequest.h"
|
||||||
|
#include "FileResourceRequest.h"
|
||||||
|
#include "HTTPResourceRequest.h"
|
||||||
|
#include "NetworkAccessManager.h"
|
||||||
|
|
||||||
|
|
||||||
|
QThread ResourceManager::_thread;
|
||||||
ResourceManager::PrefixMap ResourceManager::_prefixMap;
|
ResourceManager::PrefixMap ResourceManager::_prefixMap;
|
||||||
QMutex ResourceManager::_prefixMapLock;
|
QMutex ResourceManager::_prefixMapLock;
|
||||||
|
|
||||||
|
@ -67,18 +75,41 @@ QUrl ResourceManager::normalizeURL(const QUrl& originalUrl) {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResourceManager::init() {
|
||||||
|
_thread.setObjectName("Ressource Manager Thread");
|
||||||
|
|
||||||
|
auto assetClient = DependencyManager::set<AssetClient>();
|
||||||
|
assetClient->moveToThread(&_thread);
|
||||||
|
QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init);
|
||||||
|
|
||||||
|
_thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::cleanup() {
|
||||||
|
// cleanup the AssetClient thread
|
||||||
|
DependencyManager::destroy<AssetClient>();
|
||||||
|
_thread.quit();
|
||||||
|
_thread.wait();
|
||||||
|
}
|
||||||
|
|
||||||
ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) {
|
ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) {
|
||||||
auto normalizedURL = normalizeURL(url);
|
auto normalizedURL = normalizeURL(url);
|
||||||
auto scheme = normalizedURL.scheme();
|
auto scheme = normalizedURL.scheme();
|
||||||
|
|
||||||
|
ResourceRequest* request = nullptr;
|
||||||
|
|
||||||
if (scheme == URL_SCHEME_FILE) {
|
if (scheme == URL_SCHEME_FILE) {
|
||||||
return new FileResourceRequest(parent, normalizedURL);
|
request = new FileResourceRequest(normalizedURL);
|
||||||
} else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) {
|
} else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) {
|
||||||
return new HTTPResourceRequest(parent, normalizedURL);
|
request = new HTTPResourceRequest(normalizedURL);
|
||||||
} else if (scheme == URL_SCHEME_ATP) {
|
} else if (scheme == URL_SCHEME_ATP) {
|
||||||
return new AssetResourceRequest(parent, normalizedURL);
|
request = new AssetResourceRequest(normalizedURL);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url();
|
qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url();
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
Q_ASSERT(request);
|
||||||
|
|
||||||
|
request->moveToThread(&_thread);
|
||||||
|
return request;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,15 @@ public:
|
||||||
static void setUrlPrefixOverride(const QString& prefix, const QString& replacement);
|
static void setUrlPrefixOverride(const QString& prefix, const QString& replacement);
|
||||||
static QString normalizeURL(const QString& urlString);
|
static QString normalizeURL(const QString& urlString);
|
||||||
static QUrl normalizeURL(const QUrl& url);
|
static QUrl normalizeURL(const QUrl& url);
|
||||||
|
|
||||||
static ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url);
|
static ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url);
|
||||||
|
|
||||||
|
static void init();
|
||||||
|
static void cleanup();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static QThread _thread;
|
||||||
|
|
||||||
using PrefixMap = std::map<QString, QString>;
|
using PrefixMap = std::map<QString, QString>;
|
||||||
|
|
||||||
static PrefixMap _prefixMap;
|
static PrefixMap _prefixMap;
|
||||||
|
|
|
@ -11,12 +11,15 @@
|
||||||
|
|
||||||
#include "ResourceRequest.h"
|
#include "ResourceRequest.h"
|
||||||
|
|
||||||
ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) :
|
#include <QtCore/QThread>
|
||||||
QObject(parent),
|
|
||||||
_url(url) {
|
ResourceRequest::ResourceRequest(const QUrl& url) : _url(url) { }
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceRequest::send() {
|
void ResourceRequest::send() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Q_ASSERT(_state == NotStarted);
|
Q_ASSERT(_state == NotStarted);
|
||||||
|
|
||||||
_state = InProgress;
|
_state = InProgress;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
class ResourceRequest : public QObject {
|
class ResourceRequest : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ResourceRequest(QObject* parent, const QUrl& url);
|
ResourceRequest(const QUrl& url);
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
NotStarted = 0,
|
NotStarted = 0,
|
||||||
|
@ -38,7 +38,6 @@ public:
|
||||||
NotFound
|
NotFound
|
||||||
};
|
};
|
||||||
|
|
||||||
void send();
|
|
||||||
QByteArray getData() { return _data; }
|
QByteArray getData() { return _data; }
|
||||||
State getState() const { return _state; }
|
State getState() const { return _state; }
|
||||||
Result getResult() const { return _result; }
|
Result getResult() const { return _result; }
|
||||||
|
@ -47,8 +46,11 @@ public:
|
||||||
|
|
||||||
void setCacheEnabled(bool value) { _cacheEnabled = value; }
|
void setCacheEnabled(bool value) { _cacheEnabled = value; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void send();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void progress(uint64_t bytesReceived, uint64_t bytesTotal);
|
void progress(qint64 bytesReceived, qint64 bytesTotal);
|
||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -58,7 +58,7 @@ BasePacket::BasePacket(qint64 size) {
|
||||||
Q_ASSERT(size >= 0 || size < maxPayload);
|
Q_ASSERT(size >= 0 || size < maxPayload);
|
||||||
|
|
||||||
_packetSize = size;
|
_packetSize = size;
|
||||||
_packet.reset(new char[_packetSize]);
|
_packet.reset(new char[_packetSize]());
|
||||||
_payloadCapacity = _packetSize;
|
_payloadCapacity = _packetSize;
|
||||||
_payloadSize = 0;
|
_payloadSize = 0;
|
||||||
_payloadStart = _packet.get();
|
_payloadStart = _packet.get();
|
||||||
|
|
|
@ -87,7 +87,8 @@ SendQueue& Connection::getSendQueue() {
|
||||||
// receiver is getting the sequence numbers it expects (given that the connection must still be active)
|
// receiver is getting the sequence numbers it expects (given that the connection must still be active)
|
||||||
|
|
||||||
// Lasily create send queue
|
// Lasily create send queue
|
||||||
_sendQueue = SendQueue::create(_parentSocket, _destination, _inactiveSendQueueSequenceNumber);
|
_sendQueue = SendQueue::create(_parentSocket, _destination);
|
||||||
|
_lastReceivedACK = _sendQueue->getCurrentSequenceNumber();
|
||||||
|
|
||||||
#ifdef UDT_CONNECTION_DEBUG
|
#ifdef UDT_CONNECTION_DEBUG
|
||||||
qCDebug(networking) << "Created SendQueue for connection to" << _destination;
|
qCDebug(networking) << "Created SendQueue for connection to" << _destination;
|
||||||
|
@ -109,10 +110,6 @@ SendQueue& Connection::getSendQueue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::queueInactive() {
|
void Connection::queueInactive() {
|
||||||
// get the current sequence number from the send queue, this is to be re-used if the send
|
|
||||||
// queue is re-activated for this connection
|
|
||||||
_inactiveSendQueueSequenceNumber = _sendQueue->getCurrentSequenceNumber();
|
|
||||||
|
|
||||||
// tell our current send queue to go down and reset our ptr to it to null
|
// tell our current send queue to go down and reset our ptr to it to null
|
||||||
stopSendQueue();
|
stopSendQueue();
|
||||||
|
|
||||||
|
@ -728,15 +725,28 @@ void Connection::processNAK(std::unique_ptr<ControlPacket> controlPacket) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::processHandshake(std::unique_ptr<ControlPacket> controlPacket) {
|
void Connection::processHandshake(std::unique_ptr<ControlPacket> controlPacket) {
|
||||||
|
SequenceNumber initialSequenceNumber;
|
||||||
|
controlPacket->readPrimitive(&initialSequenceNumber);
|
||||||
|
|
||||||
if (!_hasReceivedHandshake || _isReceivingData) {
|
if (!_hasReceivedHandshake || initialSequenceNumber != _initialReceiveSequenceNumber) {
|
||||||
// server sent us a handshake - we need to assume this means state should be reset
|
// server sent us a handshake - we need to assume this means state should be reset
|
||||||
// as long as we haven't received a handshake yet or we have and we've received some data
|
// as long as we haven't received a handshake yet or we have and we've received some data
|
||||||
|
|
||||||
|
#ifdef UDT_CONNECTION_DEBUG
|
||||||
|
if (initialSequenceNumber != _initialReceiveSequenceNumber) {
|
||||||
|
qCDebug(networking) << "Resetting receive state, received a new initial sequence number in handshake";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
resetReceiveState();
|
resetReceiveState();
|
||||||
|
_initialReceiveSequenceNumber = initialSequenceNumber;
|
||||||
|
_lastReceivedSequenceNumber = initialSequenceNumber - 1;
|
||||||
|
_lastSentACK = initialSequenceNumber - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// immediately respond with a handshake ACK
|
// immediately respond with a handshake ACK
|
||||||
static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, 0);
|
static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, sizeof(SequenceNumber));
|
||||||
|
handshakeACK->seek(0);
|
||||||
|
handshakeACK->writePrimitive(initialSequenceNumber);
|
||||||
_parentSocket->writeBasePacket(*handshakeACK, _destination);
|
_parentSocket->writeBasePacket(*handshakeACK, _destination);
|
||||||
|
|
||||||
// indicate that handshake has been received
|
// indicate that handshake has been received
|
||||||
|
@ -746,8 +756,11 @@ void Connection::processHandshake(std::unique_ptr<ControlPacket> controlPacket)
|
||||||
void Connection::processHandshakeACK(std::unique_ptr<ControlPacket> controlPacket) {
|
void Connection::processHandshakeACK(std::unique_ptr<ControlPacket> controlPacket) {
|
||||||
// if we've decided to clean up the send queue then this handshake ACK should be ignored, it's useless
|
// if we've decided to clean up the send queue then this handshake ACK should be ignored, it's useless
|
||||||
if (_sendQueue) {
|
if (_sendQueue) {
|
||||||
|
SequenceNumber initialSequenceNumber;
|
||||||
|
controlPacket->readPrimitive(&initialSequenceNumber);
|
||||||
|
|
||||||
// hand off this handshake ACK to the send queue so it knows it can start sending
|
// hand off this handshake ACK to the send queue so it knows it can start sending
|
||||||
getSendQueue().handshakeACK();
|
getSendQueue().handshakeACK(initialSequenceNumber);
|
||||||
|
|
||||||
// indicate that handshake ACK was received
|
// indicate that handshake ACK was received
|
||||||
_hasReceivedHandshakeACK = true;
|
_hasReceivedHandshakeACK = true;
|
||||||
|
|
|
@ -131,6 +131,8 @@ private:
|
||||||
bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection
|
bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection
|
||||||
bool _isActive { true }; // flag used for inactivity of connection
|
bool _isActive { true }; // flag used for inactivity of connection
|
||||||
|
|
||||||
|
SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer SendQueue on creation, identifies connection during re-connect requests
|
||||||
|
|
||||||
LossList _lossList; // List of all missing packets
|
LossList _lossList; // List of all missing packets
|
||||||
SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer
|
SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer
|
||||||
SequenceNumber _lastReceivedACK; // The last ACK received
|
SequenceNumber _lastReceivedACK; // The last ACK received
|
||||||
|
@ -140,8 +142,6 @@ private:
|
||||||
SequenceNumber _lastSentACK; // The last sent ACK
|
SequenceNumber _lastSentACK; // The last sent ACK
|
||||||
SequenceNumber _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2
|
SequenceNumber _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2
|
||||||
|
|
||||||
SequenceNumber _inactiveSendQueueSequenceNumber { 0 };
|
|
||||||
|
|
||||||
int _acksDuringSYN { 1 }; // The number of non-SYN ACKs sent during SYN
|
int _acksDuringSYN { 1 }; // The number of non-SYN ACKs sent during SYN
|
||||||
int _lightACKsDuringSYN { 1 }; // The number of lite ACKs sent during SYN interval
|
int _lightACKsDuringSYN { 1 }; // The number of lite ACKs sent during SYN interval
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QMetaEnum>
|
#include <QtCore/QMetaEnum>
|
||||||
|
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(PacketType);
|
||||||
|
static int packetTypeMetaTypeId = qRegisterMetaType<PacketType>();
|
||||||
|
|
||||||
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
||||||
<< PacketType::NodeJsonStats << PacketType::EntityQuery
|
<< PacketType::NodeJsonStats << PacketType::EntityQuery
|
||||||
<< PacketType::OctreeDataNack << PacketType::EntityEditNack
|
<< PacketType::OctreeDataNack << PacketType::EntityEditNack
|
||||||
|
@ -38,6 +42,8 @@ const QSet<PacketType> RELIABLE_PACKETS = QSet<PacketType>();
|
||||||
|
|
||||||
PacketVersion versionForPacketType(PacketType packetType) {
|
PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
|
case PacketType::DomainList:
|
||||||
|
return 18;
|
||||||
case PacketType::EntityAdd:
|
case PacketType::EntityAdd:
|
||||||
case PacketType::EntityEdit:
|
case PacketType::EntityEdit:
|
||||||
case PacketType::EntityData:
|
case PacketType::EntityData:
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "SendQueue.h"
|
#include "SendQueue.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
@ -53,10 +54,10 @@ private:
|
||||||
Mutex2& _mutex2;
|
Mutex2& _mutex2;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<SendQueue> SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber) {
|
std::unique_ptr<SendQueue> SendQueue::create(Socket* socket, HifiSockAddr destination) {
|
||||||
Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*");
|
Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*");
|
||||||
|
|
||||||
auto queue = std::unique_ptr<SendQueue>(new SendQueue(socket, destination, currentSequenceNumber));
|
auto queue = std::unique_ptr<SendQueue>(new SendQueue(socket, destination));
|
||||||
|
|
||||||
// Setup queue private thread
|
// Setup queue private thread
|
||||||
QThread* thread = new QThread;
|
QThread* thread = new QThread;
|
||||||
|
@ -75,12 +76,23 @@ std::unique_ptr<SendQueue> SendQueue::create(Socket* socket, HifiSockAddr destin
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendQueue::SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber) :
|
SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) :
|
||||||
_socket(socket),
|
_socket(socket),
|
||||||
_destination(dest),
|
_destination(dest)
|
||||||
_currentSequenceNumber(currentSequenceNumber)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// setup psuedo-random number generation for all instances of SendQueue
|
||||||
|
static std::random_device rd;
|
||||||
|
static std::mt19937 generator(rd());
|
||||||
|
static std::uniform_int_distribution<> distribution(0, SequenceNumber::MAX);
|
||||||
|
|
||||||
|
// randomize the intial sequence number
|
||||||
|
_initialSequenceNumber = SequenceNumber(distribution(generator));
|
||||||
|
|
||||||
|
// set our member variables from randomized initial number
|
||||||
|
_currentSequenceNumber = _initialSequenceNumber - 1;
|
||||||
|
_atomicCurrentSequenceNumber = uint32_t(_currentSequenceNumber);
|
||||||
|
_lastACKSequenceNumber = uint32_t(_currentSequenceNumber) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendQueue::queuePacket(std::unique_ptr<Packet> packet) {
|
void SendQueue::queuePacket(std::unique_ptr<Packet> packet) {
|
||||||
|
@ -190,7 +202,11 @@ void SendQueue::sendHandshake() {
|
||||||
std::unique_lock<std::mutex> handshakeLock { _handshakeMutex };
|
std::unique_lock<std::mutex> handshakeLock { _handshakeMutex };
|
||||||
if (!_hasReceivedHandshakeACK) {
|
if (!_hasReceivedHandshakeACK) {
|
||||||
// we haven't received a handshake ACK from the client, send another now
|
// we haven't received a handshake ACK from the client, send another now
|
||||||
static const auto handshakePacket = ControlPacket::create(ControlPacket::Handshake, 0);
|
static const auto handshakePacket = ControlPacket::create(ControlPacket::Handshake, sizeof(SequenceNumber));
|
||||||
|
|
||||||
|
handshakePacket->seek(0);
|
||||||
|
|
||||||
|
handshakePacket->writePrimitive(_initialSequenceNumber);
|
||||||
_socket->writeBasePacket(*handshakePacket, _destination);
|
_socket->writeBasePacket(*handshakePacket, _destination);
|
||||||
|
|
||||||
// we wait for the ACK or the re-send interval to expire
|
// we wait for the ACK or the re-send interval to expire
|
||||||
|
@ -199,7 +215,8 @@ void SendQueue::sendHandshake() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendQueue::handshakeACK() {
|
void SendQueue::handshakeACK(SequenceNumber initialSequenceNumber) {
|
||||||
|
if (initialSequenceNumber == _initialSequenceNumber) {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> locker { _handshakeMutex };
|
std::lock_guard<std::mutex> locker { _handshakeMutex };
|
||||||
_hasReceivedHandshakeACK = true;
|
_hasReceivedHandshakeACK = true;
|
||||||
|
@ -207,6 +224,7 @@ void SendQueue::handshakeACK() {
|
||||||
|
|
||||||
// Notify on the handshake ACK condition
|
// Notify on the handshake ACK condition
|
||||||
_handshakeACKCondition.notify_one();
|
_handshakeACKCondition.notify_one();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SequenceNumber SendQueue::getNextSequenceNumber() {
|
SequenceNumber SendQueue::getNextSequenceNumber() {
|
||||||
|
|
|
@ -50,8 +50,7 @@ public:
|
||||||
Stopped
|
Stopped
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unique_ptr<SendQueue> create(Socket* socket, HifiSockAddr destination,
|
static std::unique_ptr<SendQueue> create(Socket* socket, HifiSockAddr destination);
|
||||||
SequenceNumber currentSequenceNumber = SequenceNumber());
|
|
||||||
|
|
||||||
void queuePacket(std::unique_ptr<Packet> packet);
|
void queuePacket(std::unique_ptr<Packet> packet);
|
||||||
void queuePacketList(std::unique_ptr<PacketList> packetList);
|
void queuePacketList(std::unique_ptr<PacketList> packetList);
|
||||||
|
@ -72,7 +71,7 @@ public slots:
|
||||||
void ack(SequenceNumber ack);
|
void ack(SequenceNumber ack);
|
||||||
void nak(SequenceNumber start, SequenceNumber end);
|
void nak(SequenceNumber start, SequenceNumber end);
|
||||||
void overrideNAKListFromPacket(ControlPacket& packet);
|
void overrideNAKListFromPacket(ControlPacket& packet);
|
||||||
void handshakeACK();
|
void handshakeACK(SequenceNumber initialSequenceNumber);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void packetSent(int dataSize, int payloadSize);
|
void packetSent(int dataSize, int payloadSize);
|
||||||
|
@ -84,7 +83,7 @@ private slots:
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber);
|
SendQueue(Socket* socket, HifiSockAddr dest);
|
||||||
SendQueue(SendQueue& other) = delete;
|
SendQueue(SendQueue& other) = delete;
|
||||||
SendQueue(SendQueue&& other) = delete;
|
SendQueue(SendQueue&& other) = delete;
|
||||||
|
|
||||||
|
@ -107,6 +106,8 @@ private:
|
||||||
Socket* _socket { nullptr }; // Socket to send packet on
|
Socket* _socket { nullptr }; // Socket to send packet on
|
||||||
HifiSockAddr _destination; // Destination addr
|
HifiSockAddr _destination; // Destination addr
|
||||||
|
|
||||||
|
SequenceNumber _initialSequenceNumber; // Randomized on SendQueue creation, identifies connection during re-connect requests
|
||||||
|
|
||||||
std::atomic<uint32_t> _lastACKSequenceNumber { 0 }; // Last ACKed sequence number
|
std::atomic<uint32_t> _lastACKSequenceNumber { 0 }; // Last ACKed sequence number
|
||||||
|
|
||||||
SequenceNumber _currentSequenceNumber { 0 }; // Last sequence number sent out
|
SequenceNumber _currentSequenceNumber { 0 }; // Last sequence number sent out
|
||||||
|
|
|
@ -19,13 +19,20 @@ vec3 fresnelSchlick(vec3 fresnelColor, vec3 lightDir, vec3 halfDir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float specularDistribution(float roughness, vec3 normal, vec3 halfDir) {
|
float specularDistribution(float roughness, vec3 normal, vec3 halfDir) {
|
||||||
float gloss = (1.0 - roughness) * 128.0;
|
float ndoth = clamp(dot(halfDir, normal), 0.0, 1.0);
|
||||||
gloss *= gloss;
|
float gloss2 = pow(roughness, 4);
|
||||||
|
float denom = (ndoth * ndoth*(gloss2 - 1) + 1);
|
||||||
|
float power = gloss2 / (3.14159 * denom * denom);
|
||||||
|
return power;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
float specularDistribution(float roughness, vec3 normal, vec3 halfDir) {
|
||||||
|
float gloss = exp2(10 * (1.0 - roughness) + 1);
|
||||||
float power = pow(clamp(dot(halfDir, normal), 0.0, 1.0), gloss);
|
float power = pow(clamp(dot(halfDir, normal), 0.0, 1.0), gloss);
|
||||||
power *= (gloss * 0.125 + 0.25);
|
power *= (gloss * 0.125 + 0.25);
|
||||||
return power;
|
return power;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Frag Shading returns the diffuse amount as W and the specular rgb as xyz
|
// Frag Shading returns the diffuse amount as W and the specular rgb as xyz
|
||||||
vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness) {
|
vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness) {
|
||||||
// Diffuse Lighting
|
// Diffuse Lighting
|
||||||
|
|
Loading…
Reference in a new issue