diff --git a/imagewidget.cpp b/imagewidget.cpp index e39f94c..597f570 100644 --- a/imagewidget.cpp +++ b/imagewidget.cpp @@ -10,6 +10,7 @@ #include #include #include "imageringlist.h" +#include int FILTERING = 1; bool OpenGLES = false; @@ -110,16 +111,15 @@ void ImageWidgetGL::setImage(std::shared_ptr image, int index) m_error.clear(); makeCurrent(); m_rawImage = image; - if((int)image->width() > m_maxTextureSize || (int)image->height() > m_maxTextureSize) - { - uint32_t newW = std::min(image->width() * m_maxTextureSize / image->width(), image->width() * m_maxTextureSize / image->height()); - uint32_t newH = std::min(image->height() * m_maxTextureSize / image->width(), image->height() * m_maxTextureSize / image->height()); - m_rawImage->resize(newW, newH); - } - m_imgWidth = image->width(); m_imgHeight = image->height(); + bool tooBig = false; + if((int)image->width() > m_maxTextureSize || (int)image->height() > m_maxTextureSize) + { + tooBig = true; + m_swPaint = true; + } if(!m_image)return; @@ -133,21 +133,26 @@ void ImageWidgetGL::setImage(std::shared_ptr image, int index) m_lut->setData(0, 0, 0, LUT_SIZE, LUT_SIZE, LUT_SIZE, 0, QOpenGLTexture::RGBA, QOpenGLTexture::RGBA, QOpenGLTexture::Float16, image->getLUT().data()); } - QElapsedTimer timer; - timer.start(); - m_image->destroy(); - m_image->setAutoMipMapGenerationEnabled(false); - m_image->setFormat(rawImageType.textureFormat); - m_image->setSize(image->width(), image->height()); - m_image->setMipLevels([&](){ int c = 0; int s = std::min(m_imgWidth, m_imgHeight); while(s>>=1)c++; return c; }()); - m_image->allocateStorage(); - m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear); - m_image->setWrapMode(QOpenGLTexture::ClampToEdge); - m_image->setData(0, rawImageType.pixelFormat, rawImageType.dataType, (const void*)image->data()); - m_image->bind(); - f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - f->glGenerateMipmap(GL_TEXTURE_2D); - qDebug() << "setImage" << timer.elapsed(); + if(!tooBig) + { + while(f->glGetError() != GL_NO_ERROR); + QElapsedTimer timer; + timer.start(); + m_image->destroy(); + m_image->setAutoMipMapGenerationEnabled(false); + m_image->setFormat(rawImageType.textureFormat); + m_image->setSize(image->width(), image->height()); + m_image->setMipLevels([&](){ int c = 0; int s = std::min(m_imgWidth, m_imgHeight); while(s>>=1)c++; return c; }()); + m_image->allocateStorage(); + m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear); + m_image->setWrapMode(QOpenGLTexture::ClampToEdge); + m_image->setData(0, rawImageType.pixelFormat, rawImageType.dataType, (const void*)image->data()); + m_image->bind(); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + f->glGenerateMipmap(GL_TEXTURE_2D); + qDebug() << "setImage" << timer.elapsed(); + m_swPaint = f->glGetError() != GL_NO_ERROR; + } m_unit_scale[0] = 1.0f; m_unit_scale[1] = 0.0f; @@ -341,6 +346,123 @@ void ImageWidgetGL::showThumbnail(bool enable) setOffset(m_dx, m_dy); } +void swPaint(std::shared_ptr &rawImage, float dx, float dy, float scale, const MTFParam &mtfParams, QWidget *widget) +{ + QPainter painter(widget); + int width = widget->width(); + int height = widget->height(); + QImage img(width, height, QImage::Format_RGB32); + img.fill(Qt::gray); + int ox = dx; + int oy = dy; + + auto mtf = [&mtfParams](int i, float x) + { + x = (x - mtfParams.blackPoint[i]) / (mtfParams.whitePoint[i] - mtfParams.blackPoint[i]); + x = std::min(std::max(x, 0.0f), 1.0f); + return ((mtfParams.midPoint[i] - 1.0f) * x) / ((2.0f * mtfParams.midPoint[i] - 1.0f) * x - mtfParams.midPoint[i]); + }; + + int imgWidth = rawImage->width(); + int imgHeight = rawImage->height(); + + auto convert = [&](auto *src) + { + float s = 1.0f; + if constexpr(std::numeric_limits>::is_integer) + s = (float)std::numeric_limits>::max(); + + float iscale = 1.0f / scale; + float r[4]; + float g[4]; + float b[4]; + for(int y = std::max(0, -oy); y < height; y++) + { + uint32_t *pixels = (uint32_t*)(img.scanLine(y)); + float iptr; + float fy = std::modf((y + oy) * iscale - 0.5f, &iptr); + int py = iptr; + uint32_t w = py * rawImage->widthBytes(); + uint32_t w2 = w; + if(py+1 < imgHeight)w2 += rawImage->widthBytes(); + if(py >= imgHeight)break; + + for(int x = std::max(0, -ox); x < width; x++) + { + float fx = std::modf((x + ox) * iscale - 0.5f, &iptr); + int px = iptr; + int px2 = px + 1 < imgWidth ? px + 1 : px; + if(px >= imgWidth)break; + + + if(rawImage->channels() > 1) + { + r[0] = src[w + px * 4 + 0]; + g[0] = src[w + px * 4 + 1]; + b[0] = src[w + px * 4 + 2]; + r[1] = src[w + px2 * 4 + 0]; + g[1] = src[w + px2 * 4 + 1]; + b[1] = src[w + px2 * 4 + 2]; + r[2] = src[w2 + px * 4 + 0]; + g[2] = src[w2 + px * 4 + 1]; + b[2] = src[w2 + px * 4 + 2]; + r[3] = src[w2 + px2 * 4 + 0]; + g[3] = src[w2 + px2 * 4 + 1]; + b[3] = src[w2 + px2 * 4 + 2]; + } + else + { + r[0] = src[w + px]; + r[2] = src[w2 + px]; + r[1] = src[w + px2]; + r[3] = src[w2 + px2]; + } + + uint32_t rgb = 0xff000000; + if(rawImage->channels() > 1) + { + rgb |= (uint8_t)(mtf(0, ((r[3] * fx + r[2] * (1.0f - fx)) * fy + (r[1] * fx + r[0] * (1.0f - fx)) * (1.0f - fy)) / s) * 255.0f) << 16; + rgb |= (uint8_t)(mtf(1, ((g[3] * fx + g[2] * (1.0f - fx)) * fy + (g[1] * fx + g[0] * (1.0f - fx)) * (1.0f - fy)) / s) * 255.0f) << 8; + rgb |= (uint8_t)(mtf(1, ((b[3] * fx + b[2] * (1.0f - fx)) * fy + (b[1] * fx + b[0] * (1.0f - fx)) * (1.0f - fy)) / s) * 255.0f); + } + else + { + uint32_t v = (uint8_t)(mtf(0, ((r[3] * fx + r[2] * (1.0f - fx)) * fy + (r[1] * fx + r[0] * (1.0f - fx)) * (1.0f - fy)) / s) * 255.0f); + rgb = 0xff000000 | (v << 16) | (v << 8) | v; + } + pixels[x] = rgb; + } + } + }; + + if(rawImage) + { + switch(rawImage->type()) + { + case RawImage::UINT8: + convert(static_cast(rawImage->data())); + break; + case RawImage::UINT16: + convert(static_cast(rawImage->data())); + break; + case RawImage::UINT32: + convert(static_cast(rawImage->data())); + break; + case RawImage::FLOAT16: + convert(static_cast(rawImage->data())); + break; + case RawImage::FLOAT32: + convert(static_cast(rawImage->data())); + break; + case RawImage::FLOAT64: + convert(static_cast(rawImage->data())); + break; + } + } + + painter.drawImage(0, 0, img); +} + void ImageWidgetGL::paintGL() { float dx = m_dx; @@ -425,31 +547,38 @@ void ImageWidgetGL::paintGL() } else { - m_vao->bind(); - debayer(); - - if(m_superpixel && m_debayerTex) + if(m_swPaint) { - f->glActiveTexture(GL_TEXTURE0); - f->glBindTexture(GL_TEXTURE_2D, m_debayerTex); + swPaint(m_rawImage, dx, dy, m_scale, m_mtfParams, this); } else - m_image->bind(0); + { + m_vao->bind(); + debayer(); - m_program->bind(); - m_program->setUniformValue("viewport", (float)width(), (float)height()); - m_program->setUniformValue("offset", std::floor(dx), std::floor(dy)); - m_program->setUniformValueArray("mtf_param", m_mtfParams.blackPoint, 3, 3); - m_program->setUniformValue("unit_scale", m_unit_scale[0], m_unit_scale[1]); - m_program->setUniformValue("zoom", 1.0f/m_scale); - m_program->setUniformValue("bw", m_bwImg && !m_superpixel); - m_program->setUniformValue("false_color", m_falseColor && m_bwImg); - m_program->setUniformValue("invert", m_invert); - m_program->setUniformValue("filtering", m_scale > 1.0f ? FILTERING : 1); - m_program->setUniformValue("lut_table", 2); - m_program->setUniformValue("srgb", m_srgb); - f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - m_vao->release(); + if(m_superpixel && m_debayerTex) + { + f->glActiveTexture(GL_TEXTURE0); + f->glBindTexture(GL_TEXTURE_2D, m_debayerTex); + } + else + m_image->bind(0); + + m_program->bind(); + m_program->setUniformValue("viewport", (float)width(), (float)height()); + m_program->setUniformValue("offset", std::floor(dx), std::floor(dy)); + m_program->setUniformValueArray("mtf_param", m_mtfParams.blackPoint, 3, 3); + m_program->setUniformValue("unit_scale", m_unit_scale[0], m_unit_scale[1]); + m_program->setUniformValue("zoom", 1.0f/m_scale); + m_program->setUniformValue("bw", m_bwImg && !m_superpixel); + m_program->setUniformValue("false_color", m_falseColor && m_bwImg); + m_program->setUniformValue("invert", m_invert); + m_program->setUniformValue("filtering", m_scale > 1.0f ? FILTERING : 1); + m_program->setUniformValue("lut_table", 2); + m_program->setUniformValue("srgb", m_srgb); + f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + m_vao->release(); + } } } diff --git a/imagewidget.h b/imagewidget.h index f7faec4..648b3a7 100644 --- a/imagewidget.h +++ b/imagewidget.h @@ -91,6 +91,7 @@ class ImageWidgetGL : public QOpenGLWidget, public ImageWidget Database *m_database = nullptr; QPointF m_lastPos; QString m_error; + bool m_swPaint = false; public: explicit ImageWidgetGL(Database *database, QWidget *parent = nullptr); ~ImageWidgetGL() override;