#pragma once
#include "common.h"
class ThirtyBitSGTexture
: public QSGTexture
{
Q_OBJECT
public:
ThirtyBitSGTexture();
virtual ~ThirtyBitSGTexture();
void setOwnsTexture(bool owns) { m_owns_texture = owns; }
bool ownsTexture() const { return m_owns_texture; }
void setTextureId(int id);
int textureId() const;
void setTextureSize(const QSize &size) { m_texture_size = size; }
QSize textureSize() const { return m_texture_size; }
void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; }
bool hasAlphaChannel() const { return m_has_alpha; }
bool hasMipmaps() const { return mipmapFiltering() != QSGTexture::None; }
void setImage(const QImage &image);
const QImage &image() { return m_image; }
virtual void bind();
static ThirtyBitSGTexture *fromImage(const QImage &image) {
ThirtyBitSGTexture *t = new ThirtyBitSGTexture();
t->setImage(image);
return t;
}
protected:
QImage m_image;
GLuint m_texture_id;
QSize m_texture_size;
QRectF m_texture_rect;
uint m_has_alpha : 1;
uint m_dirty_texture : 1;
uint m_dirty_bind_options : 1;
uint m_owns_texture : 1;
uint m_mipmaps_generated : 1;
uint m_retain_image: 1;
};
#include "common.h"
#include "ThirtyBitSGTexture.h"
#include < QtQml/private/qqmlglobal_p.h>
#include < QtQuick/private/qquickprofiler_p.h>
#include < QtQuick/private/qsgcontext_p.h>
#include < QtQuick/private/qsgmaterialshader_p.h>
#include < QtQuick/private/qsgtexture_p.h>
inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
return x == (x & -x);
}
ThirtyBitSGTexture::ThirtyBitSGTexture()
: QSGTexture()
, m_texture_id(0)
, m_has_alpha(false)
, m_dirty_texture(false)
, m_dirty_bind_options(false)
, m_owns_texture(true)
, m_mipmaps_generated(false)
, m_retain_image(false)
{
}
ThirtyBitSGTexture::~ThirtyBitSGTexture()
{
if (m_texture_id && m_owns_texture && QOpenGLContext::currentContext())
QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
}
void ThirtyBitSGTexture::setImage(const QImage &image)
{
m_image = image;
m_texture_size = image.size();
m_has_alpha = image.hasAlphaChannel();
m_dirty_texture = true;
m_dirty_bind_options = true;
m_mipmaps_generated = false;
}
int ThirtyBitSGTexture::textureId() const
{
if (m_dirty_texture) {
if (m_image.isNull()) {
// The actual texture and id will be updated/deleted in a later bind()
// or ~ThirtyBitSGTexture so just keep it minimal here.
return 0;
} else if (m_texture_id == 0){
// Generate a texture id for use later and return it.
QOpenGLContext::currentContext()->functions()->glGenTextures(1, &const_cast<ThirtyBitSGTexture *>(this)->m_texture_id);
return m_texture_id;
}
}
return m_texture_id;
}
void ThirtyBitSGTexture::setTextureId(int id)
{
if (m_texture_id && m_owns_texture)
QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
m_texture_id = id;
m_dirty_texture = false;
m_dirty_bind_options = true;
m_image = QImage();
m_mipmaps_generated = false;
}
void ThirtyBitSGTexture::bind()
{
QOpenGLContext *context = QOpenGLContext::currentContext();
QOpenGLFunctions *funcs = context->functions();
if (!m_dirty_texture) {
funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
if (mipmapFiltering() != QSGTexture::None && !m_mipmaps_generated) {
funcs->glGenerateMipmap(GL_TEXTURE_2D);
m_mipmaps_generated = true;
}
updateBindOptions(m_dirty_bind_options);
m_dirty_bind_options = false;
return;
}
m_dirty_texture = false;
if (m_image.isNull()) {
if (m_texture_id && m_owns_texture) {
funcs->glDeleteTextures(1, &m_texture_id);
}
m_texture_id = 0;
m_texture_size = QSize();
m_has_alpha = false;
return;
}
if (m_texture_id == 0)
funcs->glGenTextures(1, &m_texture_id);
funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
QImage tmp = (m_image.format() == QImage::Format_RGB30 || m_image.format() == QImage::Format_A2RGB30_Premultiplied)
? m_image
: m_image.convertToFormat(QImage::Format_A2RGB30_Premultiplied);
if (tmp.width() * 4 != tmp.bytesPerLine())
tmp = tmp.copy();
updateBindOptions(m_dirty_bind_options);
funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, m_texture_size.width(), m_texture_size.height(), 0, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, tmp.constBits());
if (mipmapFiltering() != QSGTexture::None) {
funcs->glGenerateMipmap(GL_TEXTURE_2D);
m_mipmaps_generated = true;
}
m_texture_rect = QRectF(0, 0, 1, 1);
m_dirty_bind_options = false;
if (!m_retain_image)
m_image = QImage();
}
Image::as10BpcQImage() const definition from Image.cpp:
QImage Image::as10BpcQImage() const
{
if(!m_isValid) return QImage();
const std::uint8_t* fiPixIt{reinterpret_cast<const std::uint8_t*>(m_rawData.get())};
const std::uint8_t* const fiPixEndIt{fiPixIt + m_byteCount};
std::uint8_t* qiPixIt;
QImage ret;
float aFactor;
switch(m_channelCount)
{
default:
qWarning("m_channelCount must be 4.");
break;
case 4:
{
ret = QImage(m_size, QImage::Format_A2RGB30_Premultiplied);
qiPixIt = ret.bits();
for(;;)
{
const FIRGBA16& fiPix = *reinterpret_cast<const FIRGBA16*>(fiPixIt);
aFactor = static_cast<float>(fiPix.alpha) / 0xffff;
// Should be endian safe (not tested on big endian, however)
*reinterpret_cast<std::uint32_t*>(qiPixIt) =
((static_cast<std::uint32_t>(fiPix.alpha ) >> 14) << 30) |
((static_cast<std::uint32_t>(fiPix.red * aFactor) >> 6) << 20) |
((static_cast<std::uint32_t>(fiPix.green * aFactor) >> 6) << 10) |
(static_cast<std::uint32_t>(fiPix.blue * aFactor) >> 6);
fiPixIt += 8;
if(fiPixIt >= fiPixEndIt) break;
qiPixIt += 4;
}
break;
}}
return ret;
}
July 2009 August 2009 September 2009 October 2009 November 2009 December 2009 January 2010 September 2010 December 2010 January 2011 February 2011 April 2011 June 2011 August 2011 February 2012 June 2012 July 2012 August 2012 October 2012 November 2012 January 2014 April 2014 June 2014 August 2014 September 2014 October 2014 January 2015 March 2015 April 2015 June 2015 November 2015 December 2015 January 2016 June 2016 August 2016 January 2017 March 2017 April 2018 April 2019 June 2019 January 2020
Subscribe to Posts [Atom]
Post a Comment