From 98ccefd05706ea5ec9c077bfed25c9ab382bde72 Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 7 Feb 2023 08:36:59 +0300 Subject: [PATCH] refactor texture loading, maps invert channels works --- src/core/core/glmaterial.cpp | 31 ++++-- src/core/core/glmaterial.h | 7 +- src/core/core/gltexturearray.h | 1 + src/core/render/gltexture_manager.cpp | 131 ++++++++++++++++++-------- src/core/render/gltexture_manager.h | 41 +++++--- src/core/render/renderer_base.cpp | 42 +++------ 6 files changed, 160 insertions(+), 93 deletions(-) diff --git a/src/core/core/glmaterial.cpp b/src/core/core/glmaterial.cpp index 968aaf9..2c74c26 100644 --- a/src/core/core/glmaterial.cpp +++ b/src/core/core/glmaterial.cpp @@ -17,8 +17,6 @@ */ #include "gltexture_manager.h" -#include "gltypes.h" -#include "qglview.h" using namespace QGLEngineShaders; @@ -31,17 +29,28 @@ Map::Map() { use_bitmap = false; _changed = true; _layer = 0; + _bitmap_hash = 0; } void Map::setBitmapPath(const QString & p) { - bitmap_path = p; - _changed = true; + bitmap_path = p; + _changed = true; + _bitmap_hash = 0; } void Map::load(TextureManager * tm) { - if (bitmap_id == 0) bitmap_id = tm->loadTexture(bitmap_path, true, _type == mtNormal); + _bitmap_hash = 0; + if (!bitmap_path.isEmpty()) tm->loadTextureImage(bitmap_path, _type == mtNormal, bake_options, &_bitmap_hash); +} + + +void Map::setMapLayer(TextureManager * tm) { + if (loadedBitmap()) + _layer = tm->textureLayer(_bitmap_hash); + else + _layer = 0; } @@ -49,7 +58,7 @@ void Map::copyToQGLMap(QGLMap & m) const { m.amount = color_amount; m.offset = color_offset; m.scale = QVector2D(bitmap_scale); - if (hasBitmap() && use_bitmap) { + if (loadedBitmap() && use_bitmap) { m.array_index = tarMaps; m.map_index = _layer; } else { @@ -114,6 +123,16 @@ void Material::load(TextureManager * tm) { } +void Material::setMapsLayers(TextureManager * tm) { + map_diffuse.setMapLayer(tm); + map_normal.setMapLayer(tm); + map_metalness.setMapLayer(tm); + map_roughness.setMapLayer(tm); + map_emission.setMapLayer(tm); + map_relief.setMapLayer(tm); +} + + void Material::setMapsChanged() { map_diffuse._changed = true; map_normal._changed = true; diff --git a/src/core/core/glmaterial.h b/src/core/core/glmaterial.h index b3823f9..28915f7 100644 --- a/src/core/core/glmaterial.h +++ b/src/core/core/glmaterial.h @@ -19,9 +19,10 @@ #ifndef GLMATERIAL_H #define GLMATERIAL_H -#include "chunkstream.h" #include "glshaders_types.h" +#include + struct QGLENGINE_CORE_EXPORT MapBakeOptions { uint hash() const; @@ -37,7 +38,9 @@ public: void setBitmapPath(const QString & p); void clearBitmap() { setBitmapPath(QString()); } bool hasBitmap() const { return !bitmap_path.isEmpty(); } + bool loadedBitmap() const { return _bitmap_hash != 0; } void load(TextureManager * tm); + void setMapLayer(TextureManager * tm); void copyToQGLMap(QGLEngineShaders::QGLMap & m) const; QString bitmap_path; GLuint bitmap_id; @@ -50,6 +53,7 @@ public: bool _changed; int _type, _layer; + uint _bitmap_hash; }; class QGLENGINE_CORE_EXPORT Material { @@ -60,6 +64,7 @@ public: bool isMapsChanged() const; bool isMapChanged(int type) const; void load(TextureManager * tm); + void setMapsLayers(TextureManager * tm); void setMapsChanged(); void setTypes(); void detectMaps(); diff --git a/src/core/core/gltexturearray.h b/src/core/core/gltexturearray.h index 2121561..80b2c13 100644 --- a/src/core/core/gltexturearray.h +++ b/src/core/core/gltexturearray.h @@ -41,6 +41,7 @@ public: GLuint ID() const { return texture_; } bool isInit() const { return texture_ != 0; } + int layersCount() const { return layers_; } private: GLenum target_; diff --git a/src/core/render/gltexture_manager.cpp b/src/core/render/gltexture_manager.cpp index e72b1fd..ce9d3a6 100644 --- a/src/core/render/gltexture_manager.cpp +++ b/src/core/render/gltexture_manager.cpp @@ -18,6 +18,7 @@ #include "gltexture_manager.h" +#include "gltexturearray.h" #include "gltypes.h" QStringList TextureManager::search_pathes("."); @@ -37,18 +38,20 @@ QString TextureManager::findFile(const QString & path) { return ::findFile(path, search_pathes); } - -GLuint TextureManager::loadTexture(const QString & path, bool ownership, bool bump) { +/* +GLuint TextureManager::loadTexture(const QString & path, bool is_normal, MapBakeOptions opts) { QString p = findFile(path); if (p.isEmpty()) return 0; - int tid = textureID(p, bump); + uint hash = mapHash(p, is_normal, opts); + int tid = cache_loaded.value(hash, 0); if (tid > 0) { qDebug() << "[TextureManager] Found" << path << "as" << tid; return tid; } QImage image(p); - if (bump) convertToNormal(image); - // qDebug() << p << image.width() << image.height() << image.format() << bump; + if (is_normal) convertToNormal(image); + applyBakeOption(image, opts); + // qDebug() << p << image.width() << image.height() << image.format() << is_normal; GLuint tid_ = tid; createGLTexture(f, tid_, image); tid = tid_; @@ -57,18 +60,37 @@ GLuint TextureManager::loadTexture(const QString & path, bool ownership, bool bu return tid; } qDebug() << "[TextureManager] Loaded" << p << "as" << tid; - if (ownership) { - tex_ids[bump ? 1 : 0].insert(p, tid); - tex_im[bump ? 1 : 0].insert(p, image); - } + tex_ids[is_normal ? 1 : 0].insert(p, tid); + tex_im[is_normal ? 1 : 0].insert(p, image); return tid; } +*/ +QImage TextureManager::loadTextureImage(const QString & path, bool is_normal, MapBakeOptions opts, uint * result_hash) { + if (result_hash) *result_hash = 0; + QString p = findFile(path); + if (p.isEmpty()) return QImage(); + uint hash = mapHash(p, is_normal, opts); + QImage image = cache_image.value(hash); + if (!image.isNull()) { + if (result_hash) *result_hash = hash; + return image; + } + image = QImage(p).convertToFormat(QImage::Format_ARGB32); + if (image.isNull()) return image; + if (is_normal) convertToNormal(image); + applyBakeOption(image, opts); + cache_image[hash] = image; + if (result_hash) *result_hash = hash; + return image; +} -GLuint TextureManager::loadTexture(const QImage & im, bool ownership, bool bump) { +/* +GLuint TextureManager::loadTexture(const QImage & im, bool ownership, bool is_normal, MapBakeOptions opts) { if (im.isNull()) return 0; QImage image(im); - if (bump) convertToNormal(image); + if (is_normal) convertToNormal(image); + applyBakeOption(image, opts); GLuint tid = 0; createGLTexture(f, tid, im); if (tid == 0) { @@ -80,18 +102,6 @@ GLuint TextureManager::loadTexture(const QImage & im, bool ownership, bool bump) } -QImage TextureManager::loadTextureImage(const QString & path, bool bump) { - QString p = findFile(path); - if (p.isEmpty()) return QImage(); - QImage ret = tex_im[bump ? 1 : 0].value(p); - if (!ret.isNull()) return ret; - ret = QImage(p); - if (bump) convertToNormal(ret); - tex_im[bump ? 1 : 0].insert(p, ret); - return ret; -} - - void TextureManager::reloadTexture(GLuint tid, const QString & path) { QString p = findFile(path); if (p.isEmpty() || (tid == 0)) return; @@ -111,16 +121,25 @@ void TextureManager::reloadTexture(GLuint tid, const QImage & im) { createGLTexture(f, tid, image); qDebug() << "[TextureManager] Reloaded" << tid; } +*/ + +int TextureManager::textureID(const QString & path, bool is_normal, MapBakeOptions opts) { + return cache_loaded.value(mapHash(findFile(path), is_normal, opts), 0); +} + + +QImage TextureManager::textureImage(const QString & path, bool is_normal, MapBakeOptions opts) { + return cache_image.value(mapHash(findFile(path), is_normal, opts)); +} void TextureManager::convertToNormal(QImage & im) { if (im.isNull()) return; - QImage sim = im.convertToFormat(QImage::Format_ARGB32); float sum[3] = {0., 0., 0.}; llong a = 0; - const uchar * sd = sim.constBits(); - for (int i = 0; i < sim.height(); i++) { - for (int j = 0; j < sim.width(); j++) { + const uchar * sd = im.constBits(); + for (int i = 0; i < im.height(); i++) { + for (int j = 0; j < im.width(); j++) { sum[2] += sd[a] / 255.f - 0.5f; ++a; sum[1] += sd[a] / 255.f - 0.5f; @@ -130,7 +149,7 @@ void TextureManager::convertToNormal(QImage & im) { ++a; } } - float wh = sim.width() * sim.height(); + float wh = im.width() * im.height(); sum[0] /= wh; sum[1] /= wh; sum[2] /= wh; @@ -138,26 +157,26 @@ void TextureManager::convertToNormal(QImage & im) { if ((qAbs(sum[0]) <= 0.05f) && (qAbs(sum[1]) <= 0.05f) && (sum[2] >= 0.25f)) /// already normal return; // qDebug() << "convert to normal"; - QImage dim = QImage(sim.width(), sim.height(), QImage::Format_ARGB32); - int tx, ty, w = sim.width(), h = sim.height(); + QImage dim = QImage(im.width(), im.height(), QImage::Format_ARGB32); + int tx, ty, w = im.width(), h = im.height(); a = 0; uchar * dd = dim.bits(); - for (int i = 0; i < sim.height(); i++) { - for (int j = 0; j < sim.width(); j++) { + for (int i = 0; i < im.height(); i++) { + for (int j = 0; j < im.width(); j++) { tx = j - 1; tx = tx < 0 ? w + tx : tx % w; ty = i - 1; ty = ty < 0 ? h + ty : ty % h; QVector3D p[3], res; - p[0] = colorVector(sim.pixel(j, i)); - p[1] = colorVector(sim.pixel(j, ty)); - p[2] = colorVector(sim.pixel(tx, i)); + p[0] = colorVector(im.pixel(j, i)); + p[1] = colorVector(im.pixel(j, ty)); + p[2] = colorVector(im.pixel(tx, i)); res.setY(piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f)); res.setX(piClamp(0.5f - (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f)); tx = (j + 1) % w; ty = (i + 1) % h; - p[1] = colorVector(sim.pixel(j, ty)); - p[2] = colorVector(sim.pixel(tx, i)); + p[1] = colorVector(im.pixel(j, ty)); + p[2] = colorVector(im.pixel(tx, i)); res.setY(piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f)); res.setX(piClamp(0.5f - (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f)); res.setZ(1.f); @@ -176,6 +195,25 @@ void TextureManager::convertToNormal(QImage & im) { } +void TextureManager::applyBakeOption(QImage & im, MapBakeOptions opts) { + if (im.isNull()) return; + if (!opts.invert_R && !opts.invert_G && !opts.invert_B) return; + QRgb * data = (QRgb *)im.bits(); + uint pixels = im.width() * im.height(); + for (uint i = 0; i < pixels; ++i) { + uchar * p = (uchar *)&(data[i]); + if (opts.invert_B) p[0] = 255 - p[0]; + if (opts.invert_G) p[1] = 255 - p[1]; + if (opts.invert_R) p[2] = 255 - p[2]; + } +} + + +uint TextureManager::mapHash(const QString & path, bool is_normal, MapBakeOptions opts) { + return qHash(path) ^ ((uint)is_normal << 8) ^ opts.hash(); +} + +/* bool TextureManager::loadTextures() { QFileInfoList fil; foreach(const QString & i, tex_pathes) @@ -206,9 +244,22 @@ void TextureManager::deleteTexture(const QString & name) { } } } - +*/ void TextureManager::clearImageCache() { - tex_im[0].clear(); - tex_im[1].clear(); + cache_image.clear(); +} + + +void TextureManager::loadToTexture2DArray(Texture2DArray * array, QSize map_size) { + array->resize(f, map_size, texturesCount()); + array_layers.clear(); + QMapIterator it(cache_image); + int cl = -1; + while (it.hasNext()) { + it.next(); + array->load(f, it.value(), ++cl); + array_layers[it.key()] = cl; + } + array->mipmaps(f); } diff --git a/src/core/render/gltexture_manager.h b/src/core/render/gltexture_manager.h index e8e1025..1e06696 100644 --- a/src/core/render/gltexture_manager.h +++ b/src/core/render/gltexture_manager.h @@ -19,6 +19,7 @@ #ifndef GLTEXTUREMANAGER_H #define GLTEXTUREMANAGER_H +#include "glmaterial.h" #include "qglengine_core_export.h" #include @@ -33,32 +34,42 @@ public: TextureManager(QOpenGLExtraFunctions * f_): f(f_) {} virtual ~TextureManager() {} + // GLuint loadTexture(const QString & path, bool is_normal = false, MapBakeOptions opts = {}); + // GLuint loadTexture(const QImage & image, bool ownership = true, bool is_normal = false, MapBakeOptions opts = {}); + QImage loadTextureImage(const QString & path, bool is_normal = false, MapBakeOptions opts = {}, uint * result_hash = nullptr); + // void reloadTexture(GLuint tid, const QString & path); + // void reloadTexture(GLuint tid, const QImage & image); + int textureID(const QString & path, bool is_normal = false, MapBakeOptions opts = {}); + QImage textureImage(const QString & path, bool is_normal = false, MapBakeOptions opts = {}); + QImage textureImage(uint hash) const { return cache_image.value(hash); } + int textureLayer(uint hash) const { return array_layers.value(hash); } + // void addTexture(const QString & path) { tex_pathes << path; } + // bool loadTextures(); + // void deleteTextures(); + // void deleteTexture(const QString & name); + int texturesCount() const { return cache_image.size(); } + uint texturesHash() const { return qHash(cache_image.keys()); } + void clearImageCache(); + + void loadToTexture2DArray(Texture2DArray * array, QSize map_size); + static void addSearchPath(const QString & path); static void clearSearchPathes() { search_pathes.clear(); } static QStringList searchPathes() { return search_pathes; } static QString findFile(const QString & path); - GLuint loadTexture(const QString & path, bool ownership = true, bool bump = false); - GLuint loadTexture(const QImage & image, bool ownership = true, bool bump = false); - QImage loadTextureImage(const QString & path, bool bump = false); - void reloadTexture(GLuint tid, const QString & path); - void reloadTexture(GLuint tid, const QImage & image); - int textureID(const QString & path, bool bump = false) { return tex_ids[bump ? 1 : 0][path]; } - QImage textureImage(const QString & path, bool bump = false) { return tex_im[bump ? 1 : 0][path]; } - void addTexture(const QString & path) { tex_pathes << path; } - bool loadTextures(); - void deleteTextures(); - void deleteTexture(const QString & name); - void clearImageCache(); protected: static void convertToNormal(QImage & im); + static void applyBakeOption(QImage & im, MapBakeOptions opts); + static uint mapHash(const QString & path, bool is_normal, MapBakeOptions opts); static QStringList search_pathes; - QMap tex_ids[2]; - QMap tex_im[2]; - QStringList tex_pathes; QOpenGLExtraFunctions * f; + QMap cache_loaded; + QMap cache_image; + QMap array_layers; + QStringList tex_pathes; }; diff --git a/src/core/render/renderer_base.cpp b/src/core/render/renderer_base.cpp index 783709b..e2a3700 100644 --- a/src/core/render/renderer_base.cpp +++ b/src/core/render/renderer_base.cpp @@ -38,7 +38,7 @@ RendererBase::RendererBase(QGLView * view_) , textures_empty(false) , textures_maps(true) { textures_manager = new TextureManager(view); - maps_size = QSize(512, 512); + maps_size = QSize(1024, 1024); maps_hash = 0; tex_coeff[0] = tex_coeff[1] = 0; } @@ -147,41 +147,21 @@ void RendererBase::fillSelectionsBuffer(QVector & buffer, bool yes, int s void RendererBase::reloadMaterials(Scene & scene) { // qDebug() << "reloadMaterias"; - QList maps[2]; + QList maps; QMap tex_layers[2]; - foreach(Material * m, scene.materials) { - if (m->map_diffuse.hasBitmap()) maps[0] << &(m->map_diffuse); - if (m->map_normal.hasBitmap()) maps[1] << &(m->map_normal); - if (m->map_metalness.hasBitmap()) maps[0] << &(m->map_metalness); - if (m->map_roughness.hasBitmap()) maps[0] << &(m->map_roughness); - if (m->map_emission.hasBitmap()) maps[0] << &(m->map_emission); - if (m->map_relief.hasBitmap()) maps[0] << &(m->map_relief); + for (Material * m: scene.materials) { + m->load(textures_manager); } - for (int i = 0; i < 2; ++i) { - foreach(Map * m, maps[i]) - tex_layers[i][m->bitmap_path] = 0; - } - int layers_count = tex_layers[0].size() + tex_layers[1].size(), cl = -1; - uint cur_maps_hash = qHash(tex_layers[0].keys()) ^ (qHash(tex_layers[1].keys()) + 0xF00FF00F); + uint cur_maps_hash = textures_manager->texturesHash(); if (maps_hash != cur_maps_hash) { maps_hash = cur_maps_hash; - textures_maps.resize(view, maps_size, layers_count); + // textures_maps.resize(view, maps_size, textures_manager->texturesCount()); textures_maps.bind(view); - for (int i = 0; i < 2; ++i) { - QMutableMapIterator it(tex_layers[i]); - while (it.hasNext()) { - it.next(); - QImage im = textures_manager->loadTextureImage(it.key(), i == 1); - textures_maps.load(view, im, ++cl); - it.value() = cl; - } - foreach(Map * m, maps[i]) { - m->_layer = tex_layers[i].value(m->bitmap_path); - // qDebug() << "assign" << m->bitmap_path << "layer" << m->_layer; - } - } - textures_maps.mipmaps(view); - // qDebug() << "load" << (cl+1) << "bitmaps"; + textures_manager->loadToTexture2DArray(&textures_maps, maps_size); + qDebug() << "loaded" << textures_maps.layersCount() << "bitmaps"; + } + for (Material * m: scene.materials) { + m->setMapsLayers(textures_manager); } QGLMaterial glm;