cap size of textures from FBX files

This commit is contained in:
Andrew Meadows 2017-02-02 13:35:40 -08:00
parent b4cef787d9
commit 64dbfd0819
5 changed files with 54 additions and 27 deletions

View file

@ -100,22 +100,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_FBX_TEXTURE_SIZE = 1024 * 1024;
/// 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 maxSize { MAX_FBX_TEXTURE_SIZE };
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(); }

View file

@ -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.maxSize);
_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>();

View file

@ -167,16 +167,17 @@ class TextureExtra {
public: public:
NetworkTexture::Type type; NetworkTexture::Type type;
const QByteArray& content; const QByteArray& content;
int maxSize;
}; };
ScriptableResource* TextureCache::prefetch(const QUrl& url, int type) { ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxSize) {
auto byteArray = QByteArray(); auto byteArray = QByteArray();
TextureExtra extra = { (Type)type, byteArray }; TextureExtra extra = { (Type)type, byteArray, maxSize };
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 maxSize) {
TextureExtra extra = { type, content }; TextureExtra extra = { type, content, maxSize };
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 maxSize = textureExtra ? textureExtra->maxSize : ABSOLUTE_MAX_TEXTURE_SIZE;
return QSharedPointer<Resource>(new NetworkTexture(url, type, content, maxSize),
&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 maxSize) :
Resource(url), Resource(url),
_type(type) _type(type),
_maxSize(maxSize)
{ {
_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_SIZE)
{ {
_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 maxSize = ABSOLUTE_MAX_TEXTURE_SIZE);
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 _maxSize;
}; };
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, _maxSize));
} }
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 maxSize) :
_resource(resource), _resource(resource),
_url(url), _url(url),
_content(data) _content(data),
_maxSize(maxSize)
{ {
#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,21 @@ void ImageReader::run() {
} }
return; return;
} }
if (imageWidth * imageHeight > _maxSize) {
float scaleFactor = sqrtf(_maxSize / (float)(imageWidth * imageHeight));
int originalWidth = imageWidth;
int originalHeight = imageHeight;
imageWidth = (int)(scaleFactor * (float)imageWidth + 0.5f);
imageHeight = (int)(scaleFactor * (float)imageHeight + 0.5f);
//QSize newSize(imageWidth, imageHeight);
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 +429,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));
} }
} }

View file

@ -23,6 +23,8 @@
#include <ResourceCache.h> #include <ResourceCache.h>
#include <model/TextureMap.h> #include <model/TextureMap.h>
const int ABSOLUTE_MAX_TEXTURE_SIZE = 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 maxSize);
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 _maxSize { ABSOLUTE_MAX_TEXTURE_SIZE };
}; };
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 maxSize = ABSOLUTE_MAX_TEXTURE_SIZE);
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 maxSize = ABSOLUTE_MAX_TEXTURE_SIZE);
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;

View file

@ -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; }