Merge branch 'master' into snoretoast

This commit is contained in:
SimonWalton-HiFi 2018-06-13 12:10:51 -07:00 committed by GitHub
commit 66cad7831e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 498 additions and 276 deletions

View file

@ -4,12 +4,15 @@ android {
compileSdkVersion 26 compileSdkVersion 26
//buildToolsVersion '27.0.3' //buildToolsVersion '27.0.3'
def appVersionCode = Integer.valueOf(RELEASE_NUMBER ?: 1)
def appVersionName = RELEASE_NUMBER ?: "1.0"
defaultConfig { defaultConfig {
applicationId "io.highfidelity.hifiinterface" applicationId "io.highfidelity.hifiinterface"
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 26 targetSdkVersion 26
versionCode 1 versionCode appVersionCode
versionName "1.0" versionName appVersionName
ndk { abiFilters 'arm64-v8a' } ndk { abiFilters 'arm64-v8a' }
externalNativeBuild { externalNativeBuild {
cmake { cmake {

View file

@ -291,18 +291,6 @@ AssetServer::AssetServer(ReceivedMessage& message) :
_bakingTaskPool(this), _bakingTaskPool(this),
_filesizeLimit(AssetUtils::MAX_UPLOAD_SIZE) _filesizeLimit(AssetUtils::MAX_UPLOAD_SIZE)
{ {
// store the current state of image compression so we can reset it when this assignment is complete
_wasColorTextureCompressionEnabled = image::isColorTexturesCompressionEnabled();
_wasGrayscaleTextureCompressionEnabled = image::isGrayscaleTexturesCompressionEnabled();
_wasNormalTextureCompressionEnabled = image::isNormalTexturesCompressionEnabled();
_wasCubeTextureCompressionEnabled = image::isCubeTexturesCompressionEnabled();
// enable compression in image library
image::setColorTexturesCompressionEnabled(true);
image::setGrayscaleTexturesCompressionEnabled(true);
image::setNormalTexturesCompressionEnabled(true);
image::setCubeTexturesCompressionEnabled(true);
BAKEABLE_TEXTURE_EXTENSIONS = image::getSupportedFormats(); BAKEABLE_TEXTURE_EXTENSIONS = image::getSupportedFormats();
qDebug() << "Supported baking texture formats:" << BAKEABLE_MODEL_EXTENSIONS; qDebug() << "Supported baking texture formats:" << BAKEABLE_MODEL_EXTENSIONS;
@ -354,12 +342,6 @@ void AssetServer::aboutToFinish() {
while (_pendingBakes.size() > 0) { while (_pendingBakes.size() > 0) {
QCoreApplication::processEvents(); QCoreApplication::processEvents();
} }
// re-set defaults in image library
image::setColorTexturesCompressionEnabled(_wasCubeTextureCompressionEnabled);
image::setGrayscaleTexturesCompressionEnabled(_wasGrayscaleTextureCompressionEnabled);
image::setNormalTexturesCompressionEnabled(_wasNormalTextureCompressionEnabled);
image::setCubeTexturesCompressionEnabled(_wasCubeTextureCompressionEnabled);
} }
void AssetServer::run() { void AssetServer::run() {

View file

@ -167,11 +167,6 @@ private:
using RequestQueue = QVector<QPair<QSharedPointer<ReceivedMessage>, SharedNodePointer>>; using RequestQueue = QVector<QPair<QSharedPointer<ReceivedMessage>, SharedNodePointer>>;
RequestQueue _queuedRequests; RequestQueue _queuedRequests;
bool _wasColorTextureCompressionEnabled { false };
bool _wasGrayscaleTextureCompressionEnabled { false };
bool _wasNormalTextureCompressionEnabled { false };
bool _wasCubeTextureCompressionEnabled { false };
uint64_t _filesizeLimit; uint64_t _filesizeLimit;
}; };

View file

@ -96,7 +96,7 @@ macro(SET_PACKAGING_PARAMETERS)
endif () endif ()
execute_process( execute_process(
COMMAND git log -1 --format=${_GIT_LOG_FORMAT} COMMAND git log -1 --abbrev=7 --format=${_GIT_LOG_FORMAT}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE _GIT_LOG_OUTPUT OUTPUT_VARIABLE _GIT_LOG_OUTPUT
ERROR_VARIABLE _GIT_LOG_ERROR ERROR_VARIABLE _GIT_LOG_ERROR

View file

@ -1,5 +1,7 @@
{ {
"releaseType": "@RELEASE_TYPE@", "releaseType": "@RELEASE_TYPE@",
"buildNumber": "@BUILD_NUMBER@",
"stableBuild": "@STABLE_BUILD@",
"buildIdentifier": "@BUILD_VERSION@", "buildIdentifier": "@BUILD_VERSION@",
"organization": "@BUILD_ORGANIZATION@", "organization": "@BUILD_ORGANIZATION@",
"appUserModelId": "@APP_USER_MODEL_ID@" "appUserModelId": "@APP_USER_MODEL_ID@"

View file

@ -905,7 +905,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<DiscoverabilityManager>(); DependencyManager::set<DiscoverabilityManager>();
DependencyManager::set<SceneScriptingInterface>(); DependencyManager::set<SceneScriptingInterface>();
DependencyManager::set<OffscreenUi>(); DependencyManager::set<OffscreenUi>();
DependencyManager::set<AutoUpdater>();
DependencyManager::set<Midi>(); DependencyManager::set<Midi>();
DependencyManager::set<PathUtils>(); DependencyManager::set<PathUtils>();
DependencyManager::set<InterfaceDynamicFactory>(); DependencyManager::set<InterfaceDynamicFactory>();
@ -1776,10 +1775,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// If launched from Steam, let it handle updates // If launched from Steam, let it handle updates
const QString HIFI_NO_UPDATER_COMMAND_LINE_KEY = "--no-updater"; const QString HIFI_NO_UPDATER_COMMAND_LINE_KEY = "--no-updater";
bool noUpdater = arguments().indexOf(HIFI_NO_UPDATER_COMMAND_LINE_KEY) != -1; bool noUpdater = arguments().indexOf(HIFI_NO_UPDATER_COMMAND_LINE_KEY) != -1;
if (!noUpdater) { bool buildCanUpdate = BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable
|| BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Master;
if (!noUpdater && buildCanUpdate) {
constexpr auto INSTALLER_TYPE_CLIENT_ONLY = "client_only"; constexpr auto INSTALLER_TYPE_CLIENT_ONLY = "client_only";
auto applicationUpdater = DependencyManager::get<AutoUpdater>(); auto applicationUpdater = DependencyManager::set<AutoUpdater>();
AutoUpdater::InstallerType type = installerType == INSTALLER_TYPE_CLIENT_ONLY AutoUpdater::InstallerType type = installerType == INSTALLER_TYPE_CLIENT_ONLY
? AutoUpdater::InstallerType::CLIENT_ONLY : AutoUpdater::InstallerType::FULL; ? AutoUpdater::InstallerType::CLIENT_ONLY : AutoUpdater::InstallerType::FULL;

View file

@ -21,19 +21,31 @@ UpdateDialog::UpdateDialog(QQuickItem* parent) :
OffscreenQmlDialog(parent) OffscreenQmlDialog(parent)
{ {
auto applicationUpdater = DependencyManager::get<AutoUpdater>(); auto applicationUpdater = DependencyManager::get<AutoUpdater>();
int currentVersion = QCoreApplication::applicationVersion().toInt(); if (applicationUpdater) {
int latestVersion = applicationUpdater.data()->getBuildData().lastKey();
_updateAvailableDetails = "v" + QString::number(latestVersion) + " released on "
+ QString(applicationUpdater.data()->getBuildData()[latestVersion]["releaseTime"]).replace(" ", " ");
_releaseNotes = ""; auto buildData = applicationUpdater.data()->getBuildData();
for (int i = latestVersion; i > currentVersion; i--) { ApplicationVersion latestVersion = buildData.lastKey();
if (applicationUpdater.data()->getBuildData().contains(i)) { _updateAvailableDetails = "v" + latestVersion.versionString + " released on "
QString releaseNotes = applicationUpdater.data()->getBuildData()[i]["releaseNotes"]; + QString(buildData[latestVersion]["releaseTime"]).replace(" ", " ");
releaseNotes.remove("<br />");
releaseNotes.remove(QRegExp("^\n+")); _releaseNotes = "";
_releaseNotes += "\n" + QString().sprintf("%d", i) + "\n" + releaseNotes + "\n";
auto it = buildData.end();
while (it != buildData.begin()) {
--it;
if (applicationUpdater->getCurrentVersion() < it.key()) {
// grab the release notes for this later version
QString releaseNotes = it.value()["releaseNotes"];
releaseNotes.remove("<br />");
releaseNotes.remove(QRegExp("^\n+"));
_releaseNotes += "\n" + it.key().versionString + "\n" + releaseNotes + "\n";
} else {
break;
}
} }
} }
} }
@ -47,5 +59,5 @@ const QString& UpdateDialog::releaseNotes() const {
void UpdateDialog::triggerUpgrade() { void UpdateDialog::triggerUpgrade() {
auto applicationUpdater = DependencyManager::get<AutoUpdater>(); auto applicationUpdater = DependencyManager::get<AutoUpdater>();
applicationUpdater.data()->performAutoUpdate(applicationUpdater.data()->getBuildData().lastKey()); applicationUpdater.data()->openLatestUpdateURL();
} }

View file

@ -11,13 +11,16 @@
#include "AutoUpdater.h" #include "AutoUpdater.h"
#include <BuildInfo.h>
#include <NetworkAccessManager.h>
#include <SharedUtil.h>
#include <unordered_map> #include <unordered_map>
AutoUpdater::AutoUpdater() { #include <ApplicationVersion.h>
#include <BuildInfo.h>
#include <NetworkAccessManager.h>
#include <SharedUtil.h>
AutoUpdater::AutoUpdater() :
_currentVersion(BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable ? BuildInfo::VERSION : BuildInfo::BUILD_NUMBER)
{
#if defined Q_OS_WIN32 #if defined Q_OS_WIN32
_operatingSystem = "windows"; _operatingSystem = "windows";
#elif defined Q_OS_MAC #elif defined Q_OS_MAC
@ -33,9 +36,22 @@ void AutoUpdater::checkForUpdate() {
this->getLatestVersionData(); this->getLatestVersionData();
} }
const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
const QUrl MASTER_BUILDS_XML_URL("https://highfidelity.com/dev-builds.xml");
void AutoUpdater::getLatestVersionData() { void AutoUpdater::getLatestVersionData() {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest latestVersionRequest(BUILDS_XML_URL);
QUrl buildsURL;
if (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable) {
buildsURL = BUILDS_XML_URL;
} else if (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Master) {
buildsURL = MASTER_BUILDS_XML_URL;
}
QNetworkRequest latestVersionRequest(buildsURL);
latestVersionRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); latestVersionRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(latestVersionRequest); QNetworkReply* reply = networkAccessManager.get(latestVersionRequest);
@ -52,12 +68,22 @@ void AutoUpdater::parseLatestVersionData() {
QString clientOnly; QString clientOnly;
}; };
int version { 0 }; QString version;
QString downloadUrl; QString downloadUrl;
QString releaseTime; QString releaseTime;
QString releaseNotes; QString releaseNotes;
QString commitSha; QString commitSha;
QString pullRequestNumber; QString pullRequestNumber;
QString versionKey;
// stable builds look at the stable_version node (semantic version)
// master builds look at the version node (build number)
if (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable) {
versionKey = "stable_version";
} else if (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Master) {
versionKey = "version";
}
while (xml.readNextStartElement()) { while (xml.readNextStartElement()) {
if (xml.name() == "projects") { if (xml.name() == "projects") {
@ -77,8 +103,8 @@ void AutoUpdater::parseLatestVersionData() {
QHash<QString, InstallerURLs> campaignInstallers; QHash<QString, InstallerURLs> campaignInstallers;
while (xml.readNextStartElement()) { while (xml.readNextStartElement()) {
if (xml.name() == "version") { if (xml.name() == versionKey) {
version = xml.readElementText().toInt(); version = xml.readElementText();
} else if (xml.name() == "url") { } else if (xml.name() == "url") {
downloadUrl = xml.readElementText(); downloadUrl = xml.readElementText();
} else if (xml.name() == "installers") { } else if (xml.name() == "installers") {
@ -159,31 +185,31 @@ void AutoUpdater::parseLatestVersionData() {
} }
void AutoUpdater::checkVersionAndNotify() { void AutoUpdater::checkVersionAndNotify() {
if (BuildInfo::BUILD_TYPE != BuildInfo::BuildType::Stable || _builds.empty()) { if (_builds.empty()) {
// No version checking is required in nightly/PR/dev builds or when no build // no build data was found for this platform
// data was found for the platform
return; return;
} }
int latestVersionAvailable = _builds.lastKey();
if (QCoreApplication::applicationVersion().toInt() < latestVersionAvailable) { qDebug() << "Checking if update version" << _builds.lastKey().versionString
<< "is newer than current version" << _currentVersion.versionString;
if (_builds.lastKey() > _currentVersion) {
emit newVersionIsAvailable(); emit newVersionIsAvailable();
} }
} }
void AutoUpdater::performAutoUpdate(int version) { void AutoUpdater::openLatestUpdateURL() {
// NOTE: This is not yet auto updating - however this is a checkpoint towards that end const QMap<QString, QString>& chosenVersion = _builds.last();
// Next PR will handle the automatic download, upgrading and application restart
const QMap<QString, QString>& chosenVersion = _builds.value(version);
const QUrl& downloadUrl = chosenVersion.value("downloadUrl"); const QUrl& downloadUrl = chosenVersion.value("downloadUrl");
QDesktopServices::openUrl(downloadUrl); QDesktopServices::openUrl(downloadUrl);
QCoreApplication::quit(); QCoreApplication::quit();
} }
void AutoUpdater::downloadUpdateVersion(int version) { void AutoUpdater::downloadUpdateVersion(const QString& version) {
emit newVersionIsDownloaded(); emit newVersionIsDownloaded();
} }
void AutoUpdater::appendBuildData(int versionNumber, void AutoUpdater::appendBuildData(const QString& versionNumber,
const QString& downloadURL, const QString& downloadURL,
const QString& releaseTime, const QString& releaseTime,
const QString& releaseNotes, const QString& releaseNotes,
@ -194,6 +220,6 @@ void AutoUpdater::appendBuildData(int versionNumber,
thisBuildDetails.insert("releaseTime", releaseTime); thisBuildDetails.insert("releaseTime", releaseTime);
thisBuildDetails.insert("releaseNotes", releaseNotes); thisBuildDetails.insert("releaseNotes", releaseNotes);
thisBuildDetails.insert("pullRequestNumber", pullRequestNumber); thisBuildDetails.insert("pullRequestNumber", pullRequestNumber);
_builds.insert(versionNumber, thisBuildDetails); _builds.insert(ApplicationVersion(versionNumber), thisBuildDetails);
} }

View file

@ -26,10 +26,9 @@
#include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest> #include <QtNetwork/QNetworkRequest>
#include <ApplicationVersion.h>
#include <DependencyManager.h> #include <DependencyManager.h>
const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
class AutoUpdater : public QObject, public Dependency { class AutoUpdater : public QObject, public Dependency {
Q_OBJECT Q_OBJECT
SINGLETON_DEPENDENCY SINGLETON_DEPENDENCY
@ -43,25 +42,29 @@ public:
}; };
void checkForUpdate(); void checkForUpdate();
const QMap<int, QMap<QString, QString>>& getBuildData() { return _builds; } const QMap<ApplicationVersion, QMap<QString, QString>>& getBuildData() { return _builds; }
void performAutoUpdate(int version); void openLatestUpdateURL();
void setInstallerType(InstallerType type) { _installerType = type; } void setInstallerType(InstallerType type) { _installerType = type; }
void setInstallerCampaign(QString campaign) { _installerCampaign = campaign; } void setInstallerCampaign(QString campaign) { _installerCampaign = campaign; }
const ApplicationVersion& getCurrentVersion() const { return _currentVersion; }
signals: signals:
void latestVersionDataParsed(); void latestVersionDataParsed();
void newVersionIsAvailable(); void newVersionIsAvailable();
void newVersionIsDownloaded(); void newVersionIsDownloaded();
private: private:
QMap<int, QMap<QString, QString>> _builds; QMap<ApplicationVersion, QMap<QString, QString>> _builds;
QString _operatingSystem; QString _operatingSystem;
InstallerType _installerType { InstallerType::FULL }; InstallerType _installerType { InstallerType::FULL };
QString _installerCampaign { "" }; QString _installerCampaign { "" };
ApplicationVersion _currentVersion;
void getLatestVersionData(); void getLatestVersionData();
void downloadUpdateVersion(int version); void downloadUpdateVersion(const QString& version);
void appendBuildData(int versionNumber, void appendBuildData(const QString& versionNumber,
const QString& downloadURL, const QString& downloadURL,
const QString& releaseTime, const QString& releaseTime,
const QString& releaseNotes, const QString& releaseNotes,

View file

@ -22,12 +22,16 @@
#include <SharedUtil.h> #include <SharedUtil.h>
#include <TextureMeta.h> #include <TextureMeta.h>
#include <OwningBuffer.h>
#include "ModelBakingLoggingCategory.h" #include "ModelBakingLoggingCategory.h"
const QString BAKED_TEXTURE_KTX_EXT = ".ktx"; const QString BAKED_TEXTURE_KTX_EXT = ".ktx";
const QString BAKED_TEXTURE_BCN_SUFFIX = "_bcn.ktx"; const QString BAKED_TEXTURE_BCN_SUFFIX = "_bcn.ktx";
const QString BAKED_META_TEXTURE_SUFFIX = ".texmeta.json"; const QString BAKED_META_TEXTURE_SUFFIX = ".texmeta.json";
bool TextureBaker::_compressionEnabled = true;
TextureBaker::TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType, TextureBaker::TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType,
const QDir& outputDirectory, const QString& metaTexturePathPrefix, const QDir& outputDirectory, const QString& metaTexturePathPrefix,
const QString& baseFilename, const QByteArray& textureContent) : const QString& baseFilename, const QByteArray& textureContent) :
@ -124,42 +128,45 @@ void TextureBaker::processTexture() {
TextureMeta meta; TextureMeta meta;
auto originalCopyFilePath = _outputDirectory.absoluteFilePath(_textureURL.fileName());
{ {
auto filePath = _outputDirectory.absoluteFilePath(_textureURL.fileName()); QFile file { originalCopyFilePath };
QFile file { filePath };
if (!file.open(QIODevice::WriteOnly) || file.write(_originalTexture) == -1) { if (!file.open(QIODevice::WriteOnly) || file.write(_originalTexture) == -1) {
handleError("Could not write original texture for " + _textureURL.toString()); handleError("Could not write original texture for " + _textureURL.toString());
return; return;
} }
_outputFiles.push_back(filePath); // IMPORTANT: _originalTexture is empty past this point
_originalTexture.clear();
_outputFiles.push_back(originalCopyFilePath);
meta.original = _metaTexturePathPrefix +_textureURL.fileName(); meta.original = _metaTexturePathPrefix +_textureURL.fileName();
} }
// IMPORTANT: _originalTexture is empty past this point auto buffer = std::static_pointer_cast<QIODevice>(std::make_shared<QFile>(originalCopyFilePath));
auto processedTexture = image::processImage(std::move(_originalTexture), _textureURL.toString().toStdString(), if (!buffer->open(QIODevice::ReadOnly)) {
ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, _textureType, _abortProcessing); handleError("Could not open original file at " + originalCopyFilePath);
processedTexture->setSourceHash(hash);
if (shouldStop()) {
return; return;
} }
if (!processedTexture) { // Compressed KTX
handleError("Could not process texture " + _textureURL.toString()); if (_compressionEnabled) {
return; auto processedTexture = image::processImage(buffer, _textureURL.toString().toStdString(),
} ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, _textureType, true, _abortProcessing);
if (!processedTexture) {
handleError("Could not process texture " + _textureURL.toString());
return;
}
processedTexture->setSourceHash(hash);
if (shouldStop()) {
auto memKTX = gpu::Texture::serialize(*processedTexture); return;
}
if (!memKTX) { auto memKTX = gpu::Texture::serialize(*processedTexture);
handleError("Could not serialize " + _textureURL.toString() + " to KTX"); if (!memKTX) {
return; handleError("Could not serialize " + _textureURL.toString() + " to KTX");
} return;
}
// attempt to write the baked texture to the destination file path
if (memKTX->_header.isCompressed()) {
const char* name = khronos::gl::texture::toString(memKTX->_header.getGLInternaFormat()); const char* name = khronos::gl::texture::toString(memKTX->_header.getGLInternaFormat());
if (name == nullptr) { if (name == nullptr) {
handleError("Could not determine internal format for compressed KTX: " + _textureURL.toString()); handleError("Could not determine internal format for compressed KTX: " + _textureURL.toString());
@ -178,21 +185,45 @@ void TextureBaker::processTexture() {
} }
_outputFiles.push_back(filePath); _outputFiles.push_back(filePath);
meta.availableTextureTypes[memKTX->_header.getGLInternaFormat()] = _metaTexturePathPrefix + fileName; meta.availableTextureTypes[memKTX->_header.getGLInternaFormat()] = _metaTexturePathPrefix + fileName;
} else { }
// Uncompressed KTX
if (_textureType == image::TextureUsage::Type::CUBE_TEXTURE) {
buffer->reset();
auto processedTexture = image::processImage(std::move(buffer), _textureURL.toString().toStdString(),
ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, _textureType, false, _abortProcessing);
if (!processedTexture) {
handleError("Could not process texture " + _textureURL.toString());
return;
}
processedTexture->setSourceHash(hash);
if (shouldStop()) {
return;
}
auto memKTX = gpu::Texture::serialize(*processedTexture);
if (!memKTX) {
handleError("Could not serialize " + _textureURL.toString() + " to KTX");
return;
}
const char* data = reinterpret_cast<const char*>(memKTX->_storage->data()); const char* data = reinterpret_cast<const char*>(memKTX->_storage->data());
const size_t length = memKTX->_storage->size(); const size_t length = memKTX->_storage->size();
auto fileName = _baseFilename + ".ktx"; auto fileName = _baseFilename + ".ktx";
auto filePath = _outputDirectory.absoluteFilePath(fileName); auto filePath = _outputDirectory.absoluteFilePath(fileName);
QFile ktxTextureFile { filePath }; QFile bakedTextureFile { filePath };
if (!ktxTextureFile.open(QIODevice::WriteOnly) || ktxTextureFile.write(data, length) == -1) { if (!bakedTextureFile.open(QIODevice::WriteOnly) || bakedTextureFile.write(data, length) == -1) {
handleError("Could not write ktx texture for " + _textureURL.toString()); handleError("Could not write baked texture for " + _textureURL.toString());
return; return;
} }
_outputFiles.push_back(filePath); _outputFiles.push_back(filePath);
meta.uncompressed = _metaTexturePathPrefix + fileName;
} else {
buffer.reset();
} }
{ {
auto data = meta.serialize(); auto data = meta.serialize();
_metaTextureFileName = _outputDirectory.absoluteFilePath(_baseFilename + BAKED_META_TEXTURE_SUFFIX); _metaTextureFileName = _outputDirectory.absoluteFilePath(_baseFilename + BAKED_META_TEXTURE_SUFFIX);

View file

@ -41,6 +41,8 @@ public:
virtual void setWasAborted(bool wasAborted) override; virtual void setWasAborted(bool wasAborted) override;
static void setCompressionEnabled(bool enabled) { _compressionEnabled = enabled; }
public slots: public slots:
virtual void bake() override; virtual void bake() override;
virtual void abort() override; virtual void abort() override;
@ -65,6 +67,8 @@ private:
QString _metaTexturePathPrefix; QString _metaTexturePathPrefix;
std::atomic<bool> _abortProcessing { false }; std::atomic<bool> _abortProcessing { false };
static bool _compressionEnabled;
}; };
#endif // hifi_TextureBaker_h #endif // hifi_TextureBaker_h

View file

@ -50,11 +50,6 @@ std::atomic<size_t> RECTIFIED_TEXTURE_COUNT{ 0 };
// possibly causing the element not to be constructed yet // possibly causing the element not to be constructed yet
static const auto& HDR_FORMAT = gpu::Element::COLOR_R11G11B10; static const auto& HDR_FORMAT = gpu::Element::COLOR_R11G11B10;
static std::atomic<bool> compressColorTextures { false };
static std::atomic<bool> compressNormalTextures { false };
static std::atomic<bool> compressGrayscaleTextures { false };
static std::atomic<bool> compressCubeTextures { false };
uint rectifyDimension(const uint& dimension) { uint rectifyDimension(const uint& dimension) {
if (dimension == 0) { if (dimension == 0) {
return 0; return 0;
@ -128,112 +123,63 @@ TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, con
} }
gpu::TexturePointer TextureUsage::createStrict2DTextureFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createStrict2DTextureFromImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureColorFromImage(std::move(srcImage), srcImageName, true, abortProcessing); return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, true, abortProcessing);
} }
gpu::TexturePointer TextureUsage::create2DTextureFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::create2DTextureFromImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createAlbedoTextureFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createAlbedoTextureFromImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createEmissiveTextureFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createEmissiveTextureFromImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createLightmapTextureFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createLightmapTextureFromImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createNormalTextureFromNormalImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createNormalTextureFromNormalImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureNormalMapFromImage(std::move(srcImage), srcImageName, false, abortProcessing); return process2DTextureNormalMapFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createNormalTextureFromBumpImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createNormalTextureFromBumpImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureNormalMapFromImage(std::move(srcImage), srcImageName, true, abortProcessing); return process2DTextureNormalMapFromImage(std::move(srcImage), srcImageName, compress, true, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createRoughnessTextureFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createRoughnessTextureFromImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, false, abortProcessing); return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createRoughnessTextureFromGlossImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createRoughnessTextureFromGlossImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, true, abortProcessing); return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, compress, true, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createMetallicTextureFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createMetallicTextureFromImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, false, abortProcessing); return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createCubeTextureFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createCubeTextureFromImage(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, true, abortProcessing); return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, compress, true, abortProcessing);
} }
gpu::TexturePointer TextureUsage::createCubeTextureFromImageWithoutIrradiance(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::createCubeTextureFromImageWithoutIrradiance(QImage&& srcImage, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing);
}
bool isColorTexturesCompressionEnabled() {
#if CPU_MIPMAPS
return compressColorTextures.load();
#else
return false;
#endif
}
bool isNormalTexturesCompressionEnabled() {
#if CPU_MIPMAPS
return compressNormalTextures.load();
#else
return false;
#endif
}
bool isGrayscaleTexturesCompressionEnabled() {
#if CPU_MIPMAPS
return compressGrayscaleTextures.load();
#else
return false;
#endif
}
bool isCubeTexturesCompressionEnabled() {
#if CPU_MIPMAPS
return compressCubeTextures.load();
#else
return false;
#endif
}
void setColorTexturesCompressionEnabled(bool enabled) {
compressColorTextures.store(enabled);
}
void setNormalTexturesCompressionEnabled(bool enabled) {
compressNormalTextures.store(enabled);
}
void setGrayscaleTexturesCompressionEnabled(bool enabled) {
compressGrayscaleTextures.store(enabled);
}
void setCubeTexturesCompressionEnabled(bool enabled) {
compressCubeTextures.store(enabled);
} }
static float denormalize(float value, const float minValue) { static float denormalize(float value, const float minValue) {
@ -255,17 +201,11 @@ uint32 packR11G11B10F(const glm::vec3& color) {
return glm::packF2x11_1x10(ucolor); return glm::packF2x11_1x10(ucolor);
} }
QImage processRawImageData(QByteArray&& content, const std::string& filename) { QImage processRawImageData(QIODevice& content, const std::string& filename) {
// Take a local copy to force move construction
// https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f18-for-consume-parameters-pass-by-x-and-stdmove-the-parameter
QByteArray localCopy = std::move(content);
// Help the QImage loader by extracting the image file format from the url filename ext. // Help the QImage loader by extracting the image file format from the url filename ext.
// Some tga are not created properly without it. // Some tga are not created properly without it.
auto filenameExtension = filename.substr(filename.find_last_of('.') + 1); auto filenameExtension = filename.substr(filename.find_last_of('.') + 1);
QBuffer buffer; QImageReader imageReader(&content, filenameExtension.c_str());
buffer.setData(localCopy);
QImageReader imageReader(&buffer, filenameExtension.c_str());
if (imageReader.canRead()) { if (imageReader.canRead()) {
return imageReader.read(); return imageReader.read();
@ -273,8 +213,8 @@ QImage processRawImageData(QByteArray&& content, const std::string& filename) {
// Extension could be incorrect, try to detect the format from the content // Extension could be incorrect, try to detect the format from the content
QImageReader newImageReader; QImageReader newImageReader;
newImageReader.setDecideFormatFromContent(true); newImageReader.setDecideFormatFromContent(true);
buffer.setData(localCopy); content.reset();
newImageReader.setDevice(&buffer); newImageReader.setDevice(&content);
if (newImageReader.canRead()) { if (newImageReader.canRead()) {
qCWarning(imagelogging) << "Image file" << filename.c_str() << "has extension" << filenameExtension.c_str() qCWarning(imagelogging) << "Image file" << filename.c_str() << "has extension" << filenameExtension.c_str()
@ -286,11 +226,14 @@ QImage processRawImageData(QByteArray&& content, const std::string& filename) {
return QImage(); return QImage();
} }
gpu::TexturePointer processImage(QByteArray&& content, const std::string& filename, gpu::TexturePointer processImage(std::shared_ptr<QIODevice> content, const std::string& filename,
int maxNumPixels, TextureUsage::Type textureType, int maxNumPixels, TextureUsage::Type textureType,
const std::atomic<bool>& abortProcessing) { bool compress, const std::atomic<bool>& abortProcessing) {
QImage image = processRawImageData(std::move(content), filename); QImage image = processRawImageData(*content.get(), filename);
// Texture content can take up a lot of memory. Here we release our ownership of that content
// in case it can be released.
content.reset();
int imageWidth = image.width(); int imageWidth = image.width();
int imageHeight = image.height(); int imageHeight = image.height();
@ -316,7 +259,7 @@ gpu::TexturePointer processImage(QByteArray&& content, const std::string& filena
} }
auto loader = TextureUsage::getTextureLoaderForType(textureType); auto loader = TextureUsage::getTextureLoaderForType(textureType);
auto texture = loader(std::move(image), filename, abortProcessing); auto texture = loader(std::move(image), filename, compress, abortProcessing);
return texture; return texture;
} }
@ -806,7 +749,7 @@ void processTextureAlpha(const QImage& srcImage, bool& validAlpha, bool& alphaAs
validAlpha = (numOpaques != NUM_PIXELS); validAlpha = (numOpaques != NUM_PIXELS);
} }
gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress,
bool isStrict, const std::atomic<bool>& abortProcessing) { bool isStrict, const std::atomic<bool>& abortProcessing) {
PROFILE_RANGE(resource_parse, "process2DTextureColorFromImage"); PROFILE_RANGE(resource_parse, "process2DTextureColorFromImage");
QImage image = processSourceImage(std::move(srcImage), false); QImage image = processSourceImage(std::move(srcImage), false);
@ -827,7 +770,7 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma
if ((image.width() > 0) && (image.height() > 0)) { if ((image.width() > 0) && (image.height() > 0)) {
gpu::Element formatMip; gpu::Element formatMip;
gpu::Element formatGPU; gpu::Element formatGPU;
if (isColorTexturesCompressionEnabled()) { if (compress) {
if (validAlpha) { if (validAlpha) {
// NOTE: This disables BC1a compression because it was producing odd artifacts on text textures // NOTE: This disables BC1a compression because it was producing odd artifacts on text textures
// for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts). // for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts).
@ -944,7 +887,8 @@ QImage processBumpMap(QImage&& image) {
return result; return result;
} }
gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& srcImage, const std::string& srcImageName,
bool isBumpMap, const std::atomic<bool>& abortProcessing) { bool compress, bool isBumpMap,
const std::atomic<bool>& abortProcessing) {
PROFILE_RANGE(resource_parse, "process2DTextureNormalMapFromImage"); PROFILE_RANGE(resource_parse, "process2DTextureNormalMapFromImage");
QImage image = processSourceImage(std::move(srcImage), false); QImage image = processSourceImage(std::move(srcImage), false);
@ -961,7 +905,7 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr
if ((image.width() > 0) && (image.height() > 0)) { if ((image.width() > 0) && (image.height() > 0)) {
gpu::Element formatMip; gpu::Element formatMip;
gpu::Element formatGPU; gpu::Element formatGPU;
if (isNormalTexturesCompressionEnabled()) { if (compress) {
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY; formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY;
} else { } else {
#ifdef USE_GLES #ifdef USE_GLES
@ -983,7 +927,7 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr
} }
gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& srcImage, const std::string& srcImageName,
bool isInvertedPixels, bool compress, bool isInvertedPixels,
const std::atomic<bool>& abortProcessing) { const std::atomic<bool>& abortProcessing) {
PROFILE_RANGE(resource_parse, "process2DTextureGrayscaleFromImage"); PROFILE_RANGE(resource_parse, "process2DTextureGrayscaleFromImage");
QImage image = processSourceImage(std::move(srcImage), false); QImage image = processSourceImage(std::move(srcImage), false);
@ -1001,7 +945,7 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr
if ((image.width() > 0) && (image.height() > 0)) { if ((image.width() > 0) && (image.height() > 0)) {
gpu::Element formatMip; gpu::Element formatMip;
gpu::Element formatGPU; gpu::Element formatGPU;
if (isGrayscaleTexturesCompressionEnabled()) { if (compress) {
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED; formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED;
} else { } else {
#ifdef USE_GLES #ifdef USE_GLES
@ -1348,7 +1292,7 @@ QImage convertToHDRFormat(QImage&& srcImage, gpu::Element format) {
} }
gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName,
bool generateIrradiance, bool compress, bool generateIrradiance,
const std::atomic<bool>& abortProcessing) { const std::atomic<bool>& abortProcessing) {
PROFILE_RANGE(resource_parse, "processCubeTextureColorFromImage"); PROFILE_RANGE(resource_parse, "processCubeTextureColorFromImage");
@ -1376,7 +1320,7 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
gpu::Element formatMip; gpu::Element formatMip;
gpu::Element formatGPU; gpu::Element formatGPU;
if (isCubeTexturesCompressionEnabled()) { if (compress) {
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB;
} else { } else {
#ifdef USE_GLES #ifdef USE_GLES

View file

@ -41,60 +41,50 @@ enum Type {
UNUSED_TEXTURE UNUSED_TEXTURE
}; };
using TextureLoader = std::function<gpu::TexturePointer(QImage&&, const std::string&, const std::atomic<bool>&)>; using TextureLoader = std::function<gpu::TexturePointer(QImage&&, const std::string&, bool, const std::atomic<bool>&)>;
TextureLoader getTextureLoaderForType(Type type, const QVariantMap& options = QVariantMap()); TextureLoader getTextureLoaderForType(Type type, const QVariantMap& options = QVariantMap());
gpu::TexturePointer create2DTextureFromImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer create2DTextureFromImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createStrict2DTextureFromImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createStrict2DTextureFromImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createAlbedoTextureFromImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createAlbedoTextureFromImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createEmissiveTextureFromImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createEmissiveTextureFromImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createNormalTextureFromNormalImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createNormalTextureFromNormalImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createNormalTextureFromBumpImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createNormalTextureFromBumpImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createRoughnessTextureFromImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createRoughnessTextureFromImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createRoughnessTextureFromGlossImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createRoughnessTextureFromGlossImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createMetallicTextureFromImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createMetallicTextureFromImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createCubeTextureFromImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createCubeTextureFromImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createCubeTextureFromImageWithoutIrradiance(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createCubeTextureFromImageWithoutIrradiance(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer createLightmapTextureFromImage(QImage&& image, const std::string& srcImageName, gpu::TexturePointer createLightmapTextureFromImage(QImage&& image, const std::string& srcImageName,
const std::atomic<bool>& abortProcessing); bool compress, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool isStrict, gpu::TexturePointer process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress,
const std::atomic<bool>& abortProcessing); bool isStrict, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer process2DTextureNormalMapFromImage(QImage&& srcImage, const std::string& srcImageName, bool isBumpMap, gpu::TexturePointer process2DTextureNormalMapFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress,
const std::atomic<bool>& abortProcessing); bool isBumpMap, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer process2DTextureGrayscaleFromImage(QImage&& srcImage, const std::string& srcImageName, bool isInvertedPixels, gpu::TexturePointer process2DTextureGrayscaleFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress,
const std::atomic<bool>& abortProcessing); bool isInvertedPixels, const std::atomic<bool>& abortProcessing);
gpu::TexturePointer processCubeTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool generateIrradiance, gpu::TexturePointer processCubeTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress,
const std::atomic<bool>& abortProcessing); bool generateIrradiance, const std::atomic<bool>& abortProcessing);
} // namespace TextureUsage } // namespace TextureUsage
const QStringList getSupportedFormats(); const QStringList getSupportedFormats();
bool isColorTexturesCompressionEnabled(); gpu::TexturePointer processImage(std::shared_ptr<QIODevice> content, const std::string& url,
bool isNormalTexturesCompressionEnabled();
bool isGrayscaleTexturesCompressionEnabled();
bool isCubeTexturesCompressionEnabled();
void setColorTexturesCompressionEnabled(bool enabled);
void setNormalTexturesCompressionEnabled(bool enabled);
void setGrayscaleTexturesCompressionEnabled(bool enabled);
void setCubeTexturesCompressionEnabled(bool enabled);
gpu::TexturePointer processImage(QByteArray&& content, const std::string& url,
int maxNumPixels, TextureUsage::Type textureType, int maxNumPixels, TextureUsage::Type textureType,
const std::atomic<bool>& abortProcessing = false); bool compress = false, const std::atomic<bool>& abortProcessing = false);
} // namespace image } // namespace image

View file

@ -33,6 +33,9 @@ bool TextureMeta::deserialize(const QByteArray& data, TextureMeta* meta) {
if (root.contains("original")) { if (root.contains("original")) {
meta->original = root["original"].toString(); meta->original = root["original"].toString();
} }
if (root.contains("uncompressed")) {
meta->uncompressed = root["uncompressed"].toString();
}
if (root.contains("compressed")) { if (root.contains("compressed")) {
auto compressed = root["compressed"].toObject(); auto compressed = root["compressed"].toObject();
for (auto it = compressed.constBegin(); it != compressed.constEnd(); it++) { for (auto it = compressed.constBegin(); it != compressed.constEnd(); it++) {
@ -57,6 +60,7 @@ QByteArray TextureMeta::serialize() {
compressed[name] = kv.second.toString(); compressed[name] = kv.second.toString();
} }
root["original"] = original.toString(); root["original"] = original.toString();
root["uncompressed"] = uncompressed.toString();
root["compressed"] = compressed; root["compressed"] = compressed;
doc.setObject(root); doc.setObject(root);

View file

@ -35,6 +35,7 @@ struct TextureMeta {
QByteArray serialize(); QByteArray serialize();
QUrl original; QUrl original;
QUrl uncompressed;
std::unordered_map<khronos::gl::texture::InternalFormat, QUrl> availableTextureTypes; std::unordered_map<khronos::gl::texture::InternalFormat, QUrl> availableTextureTypes;
}; };

View file

@ -50,6 +50,8 @@
#include <TextureMeta.h> #include <TextureMeta.h>
#include <OwningBuffer.h>
Q_LOGGING_CATEGORY(trace_resource_parse_image, "trace.resource.parse.image") Q_LOGGING_CATEGORY(trace_resource_parse_image, "trace.resource.parse.image")
Q_LOGGING_CATEGORY(trace_resource_parse_image_raw, "trace.resource.parse.image.raw") Q_LOGGING_CATEGORY(trace_resource_parse_image_raw, "trace.resource.parse.image.raw")
Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.ktx") Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.ktx")
@ -277,7 +279,7 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path, image::Te
return nullptr; return nullptr;
} }
auto loader = image::TextureUsage::getTextureLoaderForType(type, options); auto loader = image::TextureUsage::getTextureLoaderForType(type, options);
return gpu::TexturePointer(loader(std::move(image), path.toStdString(), false)); return gpu::TexturePointer(loader(std::move(image), path.toStdString(), false, false));
} }
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, QSharedPointer<Resource> TextureCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
@ -964,7 +966,6 @@ void NetworkTexture::loadMetaContent(const QByteArray& content) {
return; return;
} }
auto& backend = DependencyManager::get<TextureCache>()->getGPUContext()->getBackend(); auto& backend = DependencyManager::get<TextureCache>()->getGPUContext()->getBackend();
for (auto pair : meta.availableTextureTypes) { for (auto pair : meta.availableTextureTypes) {
gpu::Element elFormat; gpu::Element elFormat;
@ -990,6 +991,21 @@ void NetworkTexture::loadMetaContent(const QByteArray& content) {
} }
} }
#ifndef Q_OS_ANDROID
if (!meta.uncompressed.isEmpty()) {
_currentlyLoadingResourceType = ResourceType::KTX;
_activeUrl = _activeUrl.resolved(meta.uncompressed);
auto textureCache = DependencyManager::get<TextureCache>();
auto self = _self.lock();
if (!self) {
return;
}
QMetaObject::invokeMethod(this, "attemptRequest", Qt::QueuedConnection);
return;
}
#endif
if (!meta.original.isEmpty()) { if (!meta.original.isEmpty()) {
_currentlyLoadingResourceType = ResourceType::ORIGINAL; _currentlyLoadingResourceType = ResourceType::ORIGINAL;
_activeUrl = _activeUrl.resolved(meta.original); _activeUrl = _activeUrl.resolved(meta.original);
@ -1143,7 +1159,8 @@ void ImageReader::read() {
PROFILE_RANGE_EX(resource_parse_image_raw, __FUNCTION__, 0xffff0000, 0); PROFILE_RANGE_EX(resource_parse_image_raw, __FUNCTION__, 0xffff0000, 0);
// IMPORTANT: _content is empty past this point // IMPORTANT: _content is empty past this point
texture = image::processImage(std::move(_content), _url.toString().toStdString(), _maxNumPixels, networkTexture->getTextureType()); auto buffer = std::shared_ptr<QIODevice>((QIODevice*)new OwningBuffer(std::move(_content)));
texture = image::processImage(std::move(buffer), _url.toString().toStdString(), _maxNumPixels, networkTexture->getTextureType());
if (!texture) { if (!texture) {
qCWarning(modelnetworking) << "Could not process:" << _url; qCWarning(modelnetworking) << "Could not process:" << _url;

View file

@ -0,0 +1,94 @@
//
// ApplicationVersion.cpp
// libraries/shared/src
//
// Created by Stephen Birarda on 6/8/18.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ApplicationVersion.h"
#include <cassert>
#include <QtCore/QDebug>
#include <QtCore/QRegExp>
#include <QtCore/QStringList>
ApplicationVersion::ApplicationVersion(const QString& versionString) :
versionString(versionString)
{
// attempt to regex out a semantic version from the string
// handling both x.y.z and x.y formats
QRegExp semanticRegex("([\\d]+)\\.([\\d]+)(?:\\.([\\d]+))?");
int pos = semanticRegex.indexIn(versionString);
if (pos != -1) {
isSemantic = true;
auto captures = semanticRegex.capturedTexts();
major = captures[1].toInt();
minor = captures[2].toInt();
if (captures.length() > 3) {
patch = captures[3].toInt();
} else {
// the patch is implictly 0 if it was not included
patch = 0;
}
} else {
// if we didn't have a sematic style, we assume that we just have a build number
build = versionString.toInt();
}
}
bool ApplicationVersion::operator==(const ApplicationVersion& other) const {
if (isSemantic && other.isSemantic) {
return major == other.major && minor == other.minor && patch == other.patch;
} else if (!isSemantic && !other.isSemantic) {
return build == other.build;
} else {
assert(isSemantic == other.isSemantic);
return false;
}
}
bool ApplicationVersion::operator<(const ApplicationVersion& other) const {
if (isSemantic && other.isSemantic) {
if (major == other.major) {
if (minor == other.minor) {
return patch < other.patch;
} else {
return minor < other.minor;
}
} else {
return major < other.major;
}
} else if (!isSemantic && !other.isSemantic) {
return build < other.build;
} else {
assert(isSemantic == other.isSemantic);
return false;
}
}
bool ApplicationVersion::operator>(const ApplicationVersion& other) const {
if (isSemantic && other.isSemantic) {
if (major == other.major) {
if (minor == other.minor) {
return patch > other.patch;
} else {
return minor > other.minor;
}
} else {
return major > other.major;
}
} else if (!isSemantic && !other.isSemantic) {
return build > other.build;
} else {
assert(isSemantic == other.isSemantic);
return false;
}
}

View file

@ -0,0 +1,41 @@
//
// ApplicationVersion.h
// libraries/shared/src
//
// Created by Stephen Birarda on 6/8/18.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ApplicationVersion_h
#define hifi_ApplicationVersion_h
#include <QtCore/QString>
class ApplicationVersion {
public:
ApplicationVersion(const QString& versionString);
bool operator==(const ApplicationVersion& other) const;
bool operator!=(const ApplicationVersion& other) const { return !(*this == other); }
bool operator <(const ApplicationVersion& other) const;
bool operator >(const ApplicationVersion& other) const;
bool operator >=(const ApplicationVersion& other) const { return (*this == other) || (*this > other); }
bool operator <=(const ApplicationVersion& other) const { return (*this == other) || (*this < other); }
int major = -1;
int minor = -1;
int patch = -1;
int build = -1;
bool isSemantic { false };
QString versionString;
};
#endif // hifi_ApplicationVersion_h

View file

@ -0,0 +1,29 @@
//
// OwningBuffer.h
// shared/src
//
// Created by Ryan Huffman on 5/31/2018.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_OwningBuffer_h
#define hifi_OwningBuffer_h
#include <QBuffer>
class OwningBuffer : public QBuffer {
public:
OwningBuffer(const QByteArray& content) : _content(content) {
setData(_content);
}
OwningBuffer(QByteArray&& content) : _content(std::move(content)) {
setData(_content);
}
private:
QByteArray _content;
};
#endif // hifi_OwningBuffer_h

View file

@ -777,34 +777,27 @@ function onContentLoaded() {
// maybeShowSplash(); // maybeShowSplash();
if (buildInfo.releaseType == 'PRODUCTION' && !argv.noUpdater) { if (buildInfo.releaseType == 'PRODUCTION' && !argv.noUpdater) {
var currentVersion = null;
try {
currentVersion = parseInt(buildInfo.buildIdentifier);
} catch (e) {
}
if (currentVersion !== null) { const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30;
const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30; var hasShownUpdateNotification = false;
var hasShownUpdateNotification = false; const updateChecker = new updater.UpdateChecker(buildInfo, CHECK_FOR_UPDATES_INTERVAL_SECONDS);
const updateChecker = new updater.UpdateChecker(currentVersion, CHECK_FOR_UPDATES_INTERVAL_SECONDS); updateChecker.on('update-available', function(latestVersion, url) {
updateChecker.on('update-available', function(latestVersion, url) { if (!hasShownUpdateNotification) {
if (!hasShownUpdateNotification) { notifier.notify({
notifier.notify({ icon: notificationIcon,
icon: notificationIcon, title: 'An update is available!',
title: 'An update is available!', message: 'High Fidelity version ' + latestVersion + ' is available',
message: 'High Fidelity version ' + latestVersion + ' is available', wait: true,
wait: true, appID: buildInfo.appUserModelId,
appID: buildInfo.appUserModelId, url: url
url: url });
}); hasShownUpdateNotification = true;
hasShownUpdateNotification = true; }
} });
}); notifier.on('click', function(notifierObject, options) {
notifier.on('click', function(notifierObject, options) { log.debug("Got click", options.url);
log.debug("Got click", options.url); shell.openExternal(options.url);
shell.openExternal(options.url); });
});
}
} }
deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX); deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX);

View file

@ -8,10 +8,48 @@ const os = require('os');
const platform = os.type() == 'Windows_NT' ? 'windows' : 'mac'; const platform = os.type() == 'Windows_NT' ? 'windows' : 'mac';
const BUILDS_URL = 'https://highfidelity.com/builds.xml'; const BUILDS_URL = 'https://highfidelity.com/builds.xml';
const DEV_BUILDS_URL = 'https://highfidelity.com/dev-builds.xml';
function UpdateChecker(currentVersion, checkForUpdatesEveryXSeconds) { // returns 1 if A is greater, 0 if equal, -1 if A is lesser
this.currentVersion = currentVersion; function semanticVersionCompare(versionA, versionB) {
log.debug('cur', currentVersion); var versionAParts = versionA.split('.');
var versionBParts = versionB.split('.');
// make sure each version has 3 parts
var partsLength = versionAParts.length;
while (partsLength < 3) {
partsLength = versionAParts.push(0);
}
partsLength = versionBParts.length;
while (partsLength < 3) {
partsLength = versionBParts.push(0);
}
// map all of the parts to numbers
versionAParts = versionAParts.map(Number);
versionBParts = versionBParts.map(Number);
for (var i = 0; i < 3; ++i) {
if (versionAParts[i] == versionBParts[i]) {
continue;
} else if (versionAParts[i] > versionBParts[i]) {
return 1;
} else {
return -1;
}
}
return 0;
}
function UpdateChecker(buildInfo, checkForUpdatesEveryXSeconds) {
this.stableBuild = (buildInfo.stableBuild == "1");
this.buildsURL = this.stableBuild ? BUILDS_URL : DEV_BUILDS_URL;
this.currentVersion = this.stableBuild ? buildInfo.buildIdentifier : parseInt(buildInfo.buildNumber);
log.debug('Current version is', this.currentVersion);
setInterval(this.checkForUpdates.bind(this), checkForUpdatesEveryXSeconds * 1000); setInterval(this.checkForUpdates.bind(this), checkForUpdatesEveryXSeconds * 1000);
this.checkForUpdates(); this.checkForUpdates();
@ -20,7 +58,7 @@ util.inherits(UpdateChecker, events.EventEmitter);
UpdateChecker.prototype = extend(UpdateChecker.prototype, { UpdateChecker.prototype = extend(UpdateChecker.prototype, {
checkForUpdates: function() { checkForUpdates: function() {
log.debug("Checking for updates"); log.debug("Checking for updates");
request(BUILDS_URL, (error, response, body) => { request(this.buildsURL, (error, response, body) => {
if (error) { if (error) {
log.debug("Error", error); log.debug("Error", error);
return; return;
@ -29,12 +67,32 @@ UpdateChecker.prototype = extend(UpdateChecker.prototype, {
try { try {
var $ = cheerio.load(body, { xmlMode: true }); var $ = cheerio.load(body, { xmlMode: true });
const latestBuild = $('project[name="interface"] platform[name="' + platform + '"]').children().first(); const latestBuild = $('project[name="interface"] platform[name="' + platform + '"]').children().first();
const latestVersion = parseInt(latestBuild.find('version').text());
log.debug("Latest version is:", latestVersion, this.currentVersion); var latestVersion = 0;
if (latestVersion > this.currentVersion) {
if (this.stableBuild) {
latestVersion = latestBuild.find('stable_version').text();
} else {
latestVersion = parseInt(latestBuild.find('version').text());
}
log.debug("Latest available update version is:", latestVersion);
updateAvailable = false;
if (this.stableBuild) {
// compare the semantic versions to see if the update is newer
updateAvailable = (semanticVersionCompare(latestVersion, this.currentVersion) == 1);
} else {
// for master builds we just compare the versions as integers
updateAvailable = latestVersion > this.currentVersion;
}
if (updateAvailable) {
const url = latestBuild.find('url').text(); const url = latestBuild.find('url').text();
this.emit('update-available', latestVersion, url); this.emit('update-available', latestVersion, url);
} }
} catch (e) { } catch (e) {
log.warn("Error when checking for updates", e); log.warn("Error when checking for updates", e);
} }

View file

@ -25,12 +25,6 @@ Oven* Oven::_staticInstance { nullptr };
Oven::Oven() { Oven::Oven() {
_staticInstance = this; _staticInstance = this;
// enable compression in image library
image::setColorTexturesCompressionEnabled(true);
image::setGrayscaleTexturesCompressionEnabled(true);
image::setNormalTexturesCompressionEnabled(true);
image::setCubeTexturesCompressionEnabled(true);
// setup our worker threads // setup our worker threads
setupWorkerThreads(QThread::idealThreadCount()); setupWorkerThreads(QThread::idealThreadCount());

View file

@ -15,6 +15,7 @@
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <image/Image.h> #include <image/Image.h>
#include <TextureBaker.h>
#include "BakerCLI.h" #include "BakerCLI.h"
@ -47,10 +48,7 @@ OvenCLIApplication::OvenCLIApplication(int argc, char* argv[]) :
if (parser.isSet(CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER)) { if (parser.isSet(CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER)) {
qDebug() << "Disabling texture compression"; qDebug() << "Disabling texture compression";
image::setColorTexturesCompressionEnabled(false); TextureBaker::setCompressionEnabled(false);
image::setGrayscaleTexturesCompressionEnabled(false);
image::setNormalTexturesCompressionEnabled(false);
image::setCubeTexturesCompressionEnabled(false);
} }
QMetaObject::invokeMethod(cli, "bakeFile", Qt::QueuedConnection, Q_ARG(QUrl, inputUrl), QMetaObject::invokeMethod(cli, "bakeFile", Qt::QueuedConnection, Q_ARG(QUrl, inputUrl),