mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 19:36:45 +02:00
Merge pull request #9594 from AndrewMeadows/cap-fbx-texture-size
Cap fbx texture size
This commit is contained in:
commit
24a3a514a4
8 changed files with 144 additions and 39 deletions
|
@ -1465,6 +1465,34 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
|
|
||||||
// Create the Material Library
|
// Create the Material Library
|
||||||
consolidateFBXMaterials(mapping);
|
consolidateFBXMaterials(mapping);
|
||||||
|
|
||||||
|
// HACK: until we get proper LOD management we're going to cap model textures
|
||||||
|
// according to how many unique textures the model uses:
|
||||||
|
// 1 - 8 textures --> 2048
|
||||||
|
// 8 - 32 textures --> 1024
|
||||||
|
// 33 - 128 textures --> 512
|
||||||
|
// etc...
|
||||||
|
QSet<QString> uniqueTextures;
|
||||||
|
for (auto& material : _fbxMaterials) {
|
||||||
|
material.getTextureNames(uniqueTextures);
|
||||||
|
}
|
||||||
|
int numTextures = uniqueTextures.size();
|
||||||
|
const int MAX_NUM_TEXTURES_AT_MAX_RESOLUTION = 8;
|
||||||
|
int maxWidth = sqrt(MAX_NUM_PIXELS_FOR_FBX_TEXTURE);
|
||||||
|
if (numTextures > MAX_NUM_TEXTURES_AT_MAX_RESOLUTION) {
|
||||||
|
int numTextureThreshold = MAX_NUM_TEXTURES_AT_MAX_RESOLUTION;
|
||||||
|
const int MIN_MIP_TEXTURE_WIDTH = 64;
|
||||||
|
do {
|
||||||
|
maxWidth /= 2;
|
||||||
|
numTextureThreshold *= 4;
|
||||||
|
} while (numTextureThreshold < numTextures && maxWidth > MIN_MIP_TEXTURE_WIDTH);
|
||||||
|
|
||||||
|
qCDebug(modelformat) << "Capped square texture width =" << maxWidth << "for model" << url << "with" << numTextures << "textures";
|
||||||
|
for (auto& material : _fbxMaterials) {
|
||||||
|
material.setMaxNumPixelsPerTexture(maxWidth * maxWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
geometry.materials = _fbxMaterials;
|
geometry.materials = _fbxMaterials;
|
||||||
|
|
||||||
// see if any materials have texture children
|
// see if any materials have texture children
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_FBXReader_h
|
#define hifi_FBXReader_h
|
||||||
|
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
#include <QSet>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVarLengthArray>
|
#include <QVarLengthArray>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
@ -100,22 +101,25 @@ public:
|
||||||
/// A single binding to a joint in an FBX document.
|
/// A single binding to a joint in an FBX document.
|
||||||
class FBXCluster {
|
class FBXCluster {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int jointIndex;
|
int jointIndex;
|
||||||
glm::mat4 inverseBindMatrix;
|
glm::mat4 inverseBindMatrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048;
|
||||||
|
|
||||||
/// A texture map in an FBX document.
|
/// A texture map in an FBX document.
|
||||||
class FBXTexture {
|
class FBXTexture {
|
||||||
public:
|
public:
|
||||||
QString name;
|
QString name;
|
||||||
QByteArray filename;
|
QByteArray filename;
|
||||||
QByteArray content;
|
QByteArray content;
|
||||||
|
|
||||||
Transform transform;
|
Transform transform;
|
||||||
|
int maxNumPixels { MAX_NUM_PIXELS_FOR_FBX_TEXTURE };
|
||||||
int texcoordSet;
|
int texcoordSet;
|
||||||
QString texcoordSetName;
|
QString texcoordSetName;
|
||||||
|
|
||||||
bool isBumpmap{ false };
|
bool isBumpmap{ false };
|
||||||
|
|
||||||
bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); }
|
bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); }
|
||||||
|
@ -143,6 +147,9 @@ public:
|
||||||
shininess(shininess),
|
shininess(shininess),
|
||||||
opacity(opacity) {}
|
opacity(opacity) {}
|
||||||
|
|
||||||
|
void getTextureNames(QSet<QString>& textureList) const;
|
||||||
|
void setMaxNumPixelsPerTexture(int maxNumPixels);
|
||||||
|
|
||||||
glm::vec3 diffuseColor{ 1.0f };
|
glm::vec3 diffuseColor{ 1.0f };
|
||||||
float diffuseFactor{ 1.0f };
|
float diffuseFactor{ 1.0f };
|
||||||
glm::vec3 specularColor{ 0.02f };
|
glm::vec3 specularColor{ 0.02f };
|
||||||
|
|
|
@ -27,6 +27,56 @@
|
||||||
|
|
||||||
#include "ModelFormatLogging.h"
|
#include "ModelFormatLogging.h"
|
||||||
|
|
||||||
|
void FBXMaterial::getTextureNames(QSet<QString>& textureList) const {
|
||||||
|
if (!normalTexture.isNull()) {
|
||||||
|
textureList.insert(normalTexture.name);
|
||||||
|
}
|
||||||
|
if (!albedoTexture.isNull()) {
|
||||||
|
textureList.insert(albedoTexture.name);
|
||||||
|
}
|
||||||
|
if (!opacityTexture.isNull()) {
|
||||||
|
textureList.insert(opacityTexture.name);
|
||||||
|
}
|
||||||
|
if (!glossTexture.isNull()) {
|
||||||
|
textureList.insert(glossTexture.name);
|
||||||
|
}
|
||||||
|
if (!roughnessTexture.isNull()) {
|
||||||
|
textureList.insert(roughnessTexture.name);
|
||||||
|
}
|
||||||
|
if (!specularTexture.isNull()) {
|
||||||
|
textureList.insert(specularTexture.name);
|
||||||
|
}
|
||||||
|
if (!metallicTexture.isNull()) {
|
||||||
|
textureList.insert(metallicTexture.name);
|
||||||
|
}
|
||||||
|
if (!emissiveTexture.isNull()) {
|
||||||
|
textureList.insert(emissiveTexture.name);
|
||||||
|
}
|
||||||
|
if (!occlusionTexture.isNull()) {
|
||||||
|
textureList.insert(occlusionTexture.name);
|
||||||
|
}
|
||||||
|
if (!scatteringTexture.isNull()) {
|
||||||
|
textureList.insert(scatteringTexture.name);
|
||||||
|
}
|
||||||
|
if (!lightmapTexture.isNull()) {
|
||||||
|
textureList.insert(lightmapTexture.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBXMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) {
|
||||||
|
normalTexture.maxNumPixels = maxNumPixels;
|
||||||
|
albedoTexture.maxNumPixels = maxNumPixels;
|
||||||
|
opacityTexture.maxNumPixels = maxNumPixels;
|
||||||
|
glossTexture.maxNumPixels = maxNumPixels;
|
||||||
|
roughnessTexture.maxNumPixels = maxNumPixels;
|
||||||
|
specularTexture.maxNumPixels = maxNumPixels;
|
||||||
|
metallicTexture.maxNumPixels = maxNumPixels;
|
||||||
|
emissiveTexture.maxNumPixels = maxNumPixels;
|
||||||
|
occlusionTexture.maxNumPixels = maxNumPixels;
|
||||||
|
scatteringTexture.maxNumPixels = maxNumPixels;
|
||||||
|
lightmapTexture.maxNumPixels = maxNumPixels;
|
||||||
|
}
|
||||||
|
|
||||||
bool FBXMaterial::needTangentSpace() const {
|
bool FBXMaterial::needTangentSpace() const {
|
||||||
return !normalTexture.isNull();
|
return !normalTexture.isNull();
|
||||||
}
|
}
|
||||||
|
@ -47,10 +97,10 @@ FBXTexture FBXReader::getTexture(const QString& textureID) {
|
||||||
texture.texcoordSet = 0;
|
texture.texcoordSet = 0;
|
||||||
if (_textureParams.contains(textureID)) {
|
if (_textureParams.contains(textureID)) {
|
||||||
auto p = _textureParams.value(textureID);
|
auto p = _textureParams.value(textureID);
|
||||||
|
|
||||||
texture.transform.setTranslation(p.translation);
|
texture.transform.setTranslation(p.translation);
|
||||||
texture.transform.setRotation(glm::quat(glm::radians(p.rotation)));
|
texture.transform.setRotation(glm::quat(glm::radians(p.rotation)));
|
||||||
|
|
||||||
auto scaling = p.scaling;
|
auto scaling = p.scaling;
|
||||||
// Protect from bad scaling which should never happen
|
// Protect from bad scaling which should never happen
|
||||||
if (scaling.x == 0.0f) {
|
if (scaling.x == 0.0f) {
|
||||||
|
@ -63,7 +113,7 @@ FBXTexture FBXReader::getTexture(const QString& textureID) {
|
||||||
scaling.z = 1.0f;
|
scaling.z = 1.0f;
|
||||||
}
|
}
|
||||||
texture.transform.setScale(scaling);
|
texture.transform.setScale(scaling);
|
||||||
|
|
||||||
if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) {
|
if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) {
|
||||||
texture.texcoordSet = 1;
|
texture.texcoordSet = 1;
|
||||||
}
|
}
|
||||||
|
@ -78,11 +128,10 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
||||||
QJsonDocument materialMapDocument = QJsonDocument::fromJson(materialMapString.toUtf8());
|
QJsonDocument materialMapDocument = QJsonDocument::fromJson(materialMapString.toUtf8());
|
||||||
QJsonObject materialMap = materialMapDocument.object();
|
QJsonObject materialMap = materialMapDocument.object();
|
||||||
|
|
||||||
// foreach (const QString& materialID, materials) {
|
|
||||||
for (QHash<QString, FBXMaterial>::iterator it = _fbxMaterials.begin(); it != _fbxMaterials.end(); it++) {
|
for (QHash<QString, FBXMaterial>::iterator it = _fbxMaterials.begin(); it != _fbxMaterials.end(); it++) {
|
||||||
FBXMaterial& material = (*it);
|
FBXMaterial& material = (*it);
|
||||||
|
|
||||||
// Maya is the exporting the shading model and we aretrying to use it
|
// Maya is the exporting the shading model and we are trying to use it
|
||||||
bool isMaterialLambert = (material.shadingModel.toLower() == "lambert");
|
bool isMaterialLambert = (material.shadingModel.toLower() == "lambert");
|
||||||
|
|
||||||
// the pure material associated with this part
|
// the pure material associated with this part
|
||||||
|
@ -127,21 +176,19 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
||||||
detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity());
|
detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FBXTexture normalTexture;
|
FBXTexture normalTexture;
|
||||||
QString bumpTextureID = bumpTextures.value(material.materialID);
|
QString bumpTextureID = bumpTextures.value(material.materialID);
|
||||||
QString normalTextureID = normalTextures.value(material.materialID);
|
QString normalTextureID = normalTextures.value(material.materialID);
|
||||||
if (!normalTextureID.isNull()) {
|
if (!normalTextureID.isNull()) {
|
||||||
normalTexture = getTexture(normalTextureID);
|
normalTexture = getTexture(normalTextureID);
|
||||||
normalTexture.isBumpmap = false;
|
normalTexture.isBumpmap = false;
|
||||||
|
|
||||||
material.normalTexture = normalTexture;
|
material.normalTexture = normalTexture;
|
||||||
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
|
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
|
||||||
} else if (!bumpTextureID.isNull()) {
|
} else if (!bumpTextureID.isNull()) {
|
||||||
normalTexture = getTexture(bumpTextureID);
|
normalTexture = getTexture(bumpTextureID);
|
||||||
normalTexture.isBumpmap = true;
|
normalTexture.isBumpmap = true;
|
||||||
|
|
||||||
material.normalTexture = normalTexture;
|
material.normalTexture = normalTexture;
|
||||||
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
|
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
|
||||||
}
|
}
|
||||||
|
@ -151,7 +198,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
||||||
if (!specularTextureID.isNull()) {
|
if (!specularTextureID.isNull()) {
|
||||||
specularTexture = getTexture(specularTextureID);
|
specularTexture = getTexture(specularTextureID);
|
||||||
detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity());
|
detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity());
|
||||||
material.specularTexture = specularTexture;
|
material.specularTexture = specularTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXTexture metallicTexture;
|
FBXTexture metallicTexture;
|
||||||
|
@ -222,7 +269,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
||||||
ambientTextureID = ambientFactorTextures.value(material.materialID);
|
ambientTextureID = ambientFactorTextures.value(material.materialID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_loadLightmaps && !ambientTextureID.isNull()) {
|
if (_loadLightmaps && !ambientTextureID.isNull()) {
|
||||||
ambientTexture = getTexture(ambientTextureID);
|
ambientTexture = getTexture(ambientTextureID);
|
||||||
detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity());
|
detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity());
|
||||||
|
|
|
@ -472,7 +472,7 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu
|
||||||
model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture,
|
model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture,
|
||||||
TextureType type, MapChannel channel) {
|
TextureType type, MapChannel channel) {
|
||||||
const auto url = getTextureUrl(baseUrl, fbxTexture);
|
const auto url = getTextureUrl(baseUrl, fbxTexture);
|
||||||
const auto texture = DependencyManager::get<TextureCache>()->getTexture(url, type, fbxTexture.content);
|
const auto texture = DependencyManager::get<TextureCache>()->getTexture(url, type, fbxTexture.content, fbxTexture.maxNumPixels);
|
||||||
_textures[channel] = Texture { fbxTexture.name, texture };
|
_textures[channel] = Texture { fbxTexture.name, texture };
|
||||||
|
|
||||||
auto map = std::make_shared<model::TextureMap>();
|
auto map = std::make_shared<model::TextureMap>();
|
||||||
|
|
|
@ -159,7 +159,7 @@ protected:
|
||||||
class Texture {
|
class Texture {
|
||||||
public:
|
public:
|
||||||
QString name;
|
QString name;
|
||||||
QSharedPointer<NetworkTexture> texture;
|
NetworkTexturePointer texture;
|
||||||
};
|
};
|
||||||
using Textures = std::vector<Texture>;
|
using Textures = std::vector<Texture>;
|
||||||
|
|
||||||
|
|
|
@ -167,16 +167,17 @@ class TextureExtra {
|
||||||
public:
|
public:
|
||||||
NetworkTexture::Type type;
|
NetworkTexture::Type type;
|
||||||
const QByteArray& content;
|
const QByteArray& content;
|
||||||
|
int maxNumPixels;
|
||||||
};
|
};
|
||||||
|
|
||||||
ScriptableResource* TextureCache::prefetch(const QUrl& url, int type) {
|
ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNumPixels) {
|
||||||
auto byteArray = QByteArray();
|
auto byteArray = QByteArray();
|
||||||
TextureExtra extra = { (Type)type, byteArray };
|
TextureExtra extra = { (Type)type, byteArray, maxNumPixels };
|
||||||
return ResourceCache::prefetch(url, &extra);
|
return ResourceCache::prefetch(url, &extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content) {
|
NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels) {
|
||||||
TextureExtra extra = { type, content };
|
TextureExtra extra = { type, content, maxNumPixels };
|
||||||
return ResourceCache::getResource(url, QUrl(), &extra).staticCast<NetworkTexture>();
|
return ResourceCache::getResource(url, QUrl(), &extra).staticCast<NetworkTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,13 +252,15 @@ QSharedPointer<Resource> TextureCache::createResource(const QUrl& url, const QSh
|
||||||
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
||||||
auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE;
|
auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE;
|
||||||
auto content = textureExtra ? textureExtra->content : QByteArray();
|
auto content = textureExtra ? textureExtra->content : QByteArray();
|
||||||
return QSharedPointer<Resource>(new NetworkTexture(url, type, content),
|
auto maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS;
|
||||||
|
return QSharedPointer<Resource>(new NetworkTexture(url, type, content, maxNumPixels),
|
||||||
&Resource::deleter);
|
&Resource::deleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content) :
|
NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels) :
|
||||||
Resource(url),
|
Resource(url),
|
||||||
_type(type)
|
_type(type),
|
||||||
|
_maxNumPixels(maxNumPixels)
|
||||||
{
|
{
|
||||||
_textureSource = std::make_shared<gpu::TextureSource>();
|
_textureSource = std::make_shared<gpu::TextureSource>();
|
||||||
|
|
||||||
|
@ -274,7 +277,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& con
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) :
|
NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) :
|
||||||
NetworkTexture(url, CUSTOM_TEXTURE, content)
|
NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_NUM_PIXELS)
|
||||||
{
|
{
|
||||||
_textureLoader = textureLoader;
|
_textureLoader = textureLoader;
|
||||||
}
|
}
|
||||||
|
@ -290,7 +293,8 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
||||||
class ImageReader : public QRunnable {
|
class ImageReader : public QRunnable {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ImageReader(const QWeakPointer<Resource>& resource, const QByteArray& data, const QUrl& url = QUrl());
|
ImageReader(const QWeakPointer<Resource>& resource, const QByteArray& data,
|
||||||
|
const QUrl& url = QUrl(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
||||||
|
|
||||||
virtual void run() override;
|
virtual void run() override;
|
||||||
|
|
||||||
|
@ -300,6 +304,7 @@ private:
|
||||||
QWeakPointer<Resource> _resource;
|
QWeakPointer<Resource> _resource;
|
||||||
QUrl _url;
|
QUrl _url;
|
||||||
QByteArray _content;
|
QByteArray _content;
|
||||||
|
int _maxNumPixels;
|
||||||
};
|
};
|
||||||
|
|
||||||
void NetworkTexture::downloadFinished(const QByteArray& data) {
|
void NetworkTexture::downloadFinished(const QByteArray& data) {
|
||||||
|
@ -308,14 +313,15 @@ void NetworkTexture::downloadFinished(const QByteArray& data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkTexture::loadContent(const QByteArray& content) {
|
void NetworkTexture::loadContent(const QByteArray& content) {
|
||||||
QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url));
|
QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxNumPixels));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QByteArray& data,
|
ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QByteArray& data,
|
||||||
const QUrl& url) :
|
const QUrl& url, int maxNumPixels) :
|
||||||
_resource(resource),
|
_resource(resource),
|
||||||
_url(url),
|
_url(url),
|
||||||
_content(data)
|
_content(data),
|
||||||
|
_maxNumPixels(maxNumPixels)
|
||||||
{
|
{
|
||||||
#if DEBUG_DUMP_TEXTURE_LOADS
|
#if DEBUG_DUMP_TEXTURE_LOADS
|
||||||
static auto start = usecTimestampNow() / USECS_PER_MSEC;
|
static auto start = usecTimestampNow() / USECS_PER_MSEC;
|
||||||
|
@ -375,10 +381,10 @@ void ImageReader::run() {
|
||||||
|
|
||||||
// Note that QImage.format is the pixel format which is different from the "format" of the image file...
|
// Note that QImage.format is the pixel format which is different from the "format" of the image file...
|
||||||
auto imageFormat = image.format();
|
auto imageFormat = image.format();
|
||||||
int originalWidth = image.width();
|
int imageWidth = image.width();
|
||||||
int originalHeight = image.height();
|
int imageHeight = image.height();
|
||||||
|
|
||||||
if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) {
|
if (imageWidth == 0 || imageHeight == 0 || imageFormat == QImage::Format_Invalid) {
|
||||||
if (filenameExtension.empty()) {
|
if (filenameExtension.empty()) {
|
||||||
qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url;
|
qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url;
|
||||||
} else {
|
} else {
|
||||||
|
@ -386,6 +392,20 @@ void ImageReader::run() {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imageWidth * imageHeight > _maxNumPixels) {
|
||||||
|
float scaleFactor = sqrtf(_maxNumPixels / (float)(imageWidth * imageHeight));
|
||||||
|
int originalWidth = imageWidth;
|
||||||
|
int originalHeight = imageHeight;
|
||||||
|
imageWidth = (int)(scaleFactor * (float)imageWidth + 0.5f);
|
||||||
|
imageHeight = (int)(scaleFactor * (float)imageHeight + 0.5f);
|
||||||
|
QImage newImage = image.scaled(QSize(imageWidth, imageHeight), Qt::IgnoreAspectRatio);
|
||||||
|
image.swap(newImage);
|
||||||
|
qCDebug(modelnetworking) << "Downscale image" << _url
|
||||||
|
<< "from" << originalWidth << "x" << originalHeight
|
||||||
|
<< "to" << imageWidth << "x" << imageHeight;
|
||||||
|
}
|
||||||
|
|
||||||
gpu::TexturePointer texture = nullptr;
|
gpu::TexturePointer texture = nullptr;
|
||||||
{
|
{
|
||||||
// Double-check the resource still exists between long operations.
|
// Double-check the resource still exists between long operations.
|
||||||
|
@ -408,7 +428,7 @@ void ImageReader::run() {
|
||||||
} else {
|
} else {
|
||||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||||
Q_ARG(gpu::TexturePointer, texture),
|
Q_ARG(gpu::TexturePointer, texture),
|
||||||
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
|
Q_ARG(int, imageWidth), Q_ARG(int, imageHeight));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include <ResourceCache.h>
|
#include <ResourceCache.h>
|
||||||
#include <model/TextureMap.h>
|
#include <model/TextureMap.h>
|
||||||
|
|
||||||
|
const int ABSOLUTE_MAX_TEXTURE_NUM_PIXELS = 8192 * 8192;
|
||||||
|
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
class Batch;
|
class Batch;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +62,7 @@ public:
|
||||||
typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName);
|
typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName);
|
||||||
using TextureLoaderFunc = std::function<TextureLoader>;
|
using TextureLoaderFunc = std::function<TextureLoader>;
|
||||||
|
|
||||||
NetworkTexture(const QUrl& url, Type type, const QByteArray& content);
|
NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels);
|
||||||
NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content);
|
NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content);
|
||||||
|
|
||||||
QString getType() const override { return "NetworkTexture"; }
|
QString getType() const override { return "NetworkTexture"; }
|
||||||
|
@ -70,7 +72,7 @@ public:
|
||||||
int getWidth() const { return _width; }
|
int getWidth() const { return _width; }
|
||||||
int getHeight() const { return _height; }
|
int getHeight() const { return _height; }
|
||||||
Type getTextureType() const { return _type; }
|
Type getTextureType() const { return _type; }
|
||||||
|
|
||||||
TextureLoaderFunc getTextureLoader() const;
|
TextureLoaderFunc getTextureLoader() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
@ -81,7 +83,7 @@ protected:
|
||||||
virtual bool isCacheable() const override { return _loaded; }
|
virtual bool isCacheable() const override { return _loaded; }
|
||||||
|
|
||||||
virtual void downloadFinished(const QByteArray& data) override;
|
virtual void downloadFinished(const QByteArray& data) override;
|
||||||
|
|
||||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||||
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
|
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
|
||||||
|
|
||||||
|
@ -92,6 +94,7 @@ private:
|
||||||
int _originalHeight { 0 };
|
int _originalHeight { 0 };
|
||||||
int _width { 0 };
|
int _width { 0 };
|
||||||
int _height { 0 };
|
int _height { 0 };
|
||||||
|
int _maxNumPixels { ABSOLUTE_MAX_TEXTURE_NUM_PIXELS };
|
||||||
};
|
};
|
||||||
|
|
||||||
using NetworkTexturePointer = QSharedPointer<NetworkTexture>;
|
using NetworkTexturePointer = QSharedPointer<NetworkTexture>;
|
||||||
|
@ -129,11 +132,11 @@ public:
|
||||||
|
|
||||||
/// Loads a texture from the specified URL.
|
/// Loads a texture from the specified URL.
|
||||||
NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE,
|
NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE,
|
||||||
const QByteArray& content = QByteArray());
|
const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Overload ResourceCache::prefetch to allow specifying texture type for loads
|
// Overload ResourceCache::prefetch to allow specifying texture type for loads
|
||||||
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type);
|
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
||||||
|
|
||||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||||
const void* extra) override;
|
const void* extra) override;
|
||||||
|
|
|
@ -86,7 +86,7 @@ private:
|
||||||
/// Wrapper to expose resources to JS/QML
|
/// Wrapper to expose resources to JS/QML
|
||||||
class ScriptableResource : public QObject {
|
class ScriptableResource : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QUrl url READ getUrl)
|
Q_PROPERTY(QUrl url READ getURL)
|
||||||
Q_PROPERTY(int state READ getState NOTIFY stateChanged)
|
Q_PROPERTY(int state READ getState NOTIFY stateChanged)
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -125,7 +125,7 @@ public:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void release();
|
Q_INVOKABLE void release();
|
||||||
|
|
||||||
const QUrl& getUrl() const { return _url; }
|
const QUrl& getURL() const { return _url; }
|
||||||
int getState() const { return (int)_state; }
|
int getState() const { return (int)_state; }
|
||||||
const QSharedPointer<Resource>& getResource() const { return _resource; }
|
const QSharedPointer<Resource>& getResource() const { return _resource; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue