This commit is contained in:
2023-02-07 10:11:27 +03:00
6 changed files with 161 additions and 94 deletions

View File

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

View File

@@ -19,9 +19,10 @@
#ifndef GLMATERIAL_H
#define GLMATERIAL_H
#include "chunkstream.h"
#include "glshaders_types.h"
#include <chunkstream.h>
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();

View File

@@ -41,6 +41,7 @@ public:
GLuint ID() const { return texture_; }
bool isInit() const { return texture_ != 0; }
int layersCount() const { return layers_; }
private:
GLenum target_;

View File

@@ -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<uint, QImage> 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);
}

View File

@@ -19,6 +19,7 @@
#ifndef GLTEXTUREMANAGER_H
#define GLTEXTUREMANAGER_H
#include "glmaterial.h"
#include "qglengine_core_export.h"
#include <QDir>
@@ -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<QString, GLuint> tex_ids[2];
QMap<QString, QImage> tex_im[2];
QStringList tex_pathes;
QOpenGLExtraFunctions * f;
QMap<uint, GLuint> cache_loaded;
QMap<uint, QImage> cache_image;
QMap<uint, int> array_layers;
QStringList tex_pathes;
};

View File

@@ -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;
}
@@ -110,7 +110,7 @@ void RendererBase::setUniformCamera(QOpenGLShaderProgram * prog, Camera * cam, b
void RendererBase::setUniformViewCorners(QOpenGLShaderProgram * prog, Camera * cam, QSize viewport) {
double w = view->width(), h = view->height();
double w = view->pixelWidth(), h = view->pixelHeight();
if (viewport.isValid()) {
w = viewport.width();
h = viewport.height();
@@ -147,41 +147,21 @@ void RendererBase::fillSelectionsBuffer(QVector<uchar> & buffer, bool yes, int s
void RendererBase::reloadMaterials(Scene & scene) {
// qDebug() << "reloadMaterias";
QList<Map *> maps[2];
QList<Map *> maps;
QMap<QString, int> 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<QString, int> 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;