kwin: moving KWin::GLTexture to a separate file
This commit is contained in:
parent
538e9d1467
commit
116e024d12
5 changed files with 665 additions and 568 deletions
|
@ -5,6 +5,7 @@ set(kwin_EFFECTSLIB_SRCS
|
||||||
kwinglobals.cpp
|
kwinglobals.cpp
|
||||||
kwineffects.cpp
|
kwineffects.cpp
|
||||||
kwinglutils.cpp
|
kwinglutils.cpp
|
||||||
|
kwingltexture.cpp
|
||||||
kwinglutils_funcs.cpp
|
kwinglutils_funcs.cpp
|
||||||
kwinglplatform.cpp
|
kwinglplatform.cpp
|
||||||
kwinxrenderutils.cpp
|
kwinxrenderutils.cpp
|
||||||
|
@ -55,6 +56,7 @@ install( FILES
|
||||||
kwinglplatform.h
|
kwinglplatform.h
|
||||||
kwinglutils.h
|
kwinglutils.h
|
||||||
kwinglutils_funcs.h
|
kwinglutils_funcs.h
|
||||||
|
kwingltexture.h
|
||||||
kwinxrenderutils.h
|
kwinxrenderutils.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/kwinconfig.h
|
${CMAKE_CURRENT_BINARY_DIR}/kwinconfig.h
|
||||||
DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel)
|
DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel)
|
||||||
|
|
497
libkwineffects/kwingltexture.cpp
Normal file
497
libkwineffects/kwingltexture.cpp
Normal file
|
@ -0,0 +1,497 @@
|
||||||
|
/********************************************************************
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
|
||||||
|
Copyright (C) 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "kwinconfig.h" // KWIN_HAVE_OPENGL
|
||||||
|
|
||||||
|
#ifdef KWIN_HAVE_OPENGL
|
||||||
|
|
||||||
|
#include "kwinglplatform.h"
|
||||||
|
#include "kwineffects.h"
|
||||||
|
#include "kwinglutils_funcs.h"
|
||||||
|
#include "kwinglutils.h"
|
||||||
|
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QVector2D>
|
||||||
|
#include <QVector3D>
|
||||||
|
#include <QVector4D>
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
//****************************************
|
||||||
|
// GLTexture
|
||||||
|
//****************************************
|
||||||
|
|
||||||
|
bool GLTexture::sNPOTTextureSupported = false;
|
||||||
|
bool GLTexture::sFramebufferObjectSupported = false;
|
||||||
|
bool GLTexture::sSaturationSupported = false;
|
||||||
|
|
||||||
|
GLTexture::GLTexture()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture::GLTexture(const QImage& image, GLenum target)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
load(image, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture::GLTexture(const QPixmap& pixmap, GLenum target)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
load(pixmap, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture::GLTexture(const QString& fileName)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
load(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture::GLTexture(int width, int height)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
|
||||||
|
if (NPOTTextureSupported() || (isPowerOfTwo(width) && isPowerOfTwo(height))) {
|
||||||
|
mTarget = GL_TEXTURE_2D;
|
||||||
|
mScale.setWidth(1.0 / width);
|
||||||
|
mScale.setHeight(1.0 / height);
|
||||||
|
mSize = QSize(width, height);
|
||||||
|
can_use_mipmaps = true;
|
||||||
|
|
||||||
|
glGenTextures(1, &mTexture);
|
||||||
|
bind();
|
||||||
|
#ifdef KWIN_HAVE_OPENGLES
|
||||||
|
// format and internal format have to match in ES, GL_RGBA8 and GL_BGRA are not available
|
||||||
|
// see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml
|
||||||
|
glTexImage2D(mTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||||
|
#else
|
||||||
|
glTexImage2D(mTarget, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
|
||||||
|
#endif
|
||||||
|
unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture::~GLTexture()
|
||||||
|
{
|
||||||
|
delete m_vbo;
|
||||||
|
discard();
|
||||||
|
assert(mUnnormalizeActive == 0);
|
||||||
|
assert(mNormalizeActive == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::init()
|
||||||
|
{
|
||||||
|
mTexture = None;
|
||||||
|
mTarget = 0;
|
||||||
|
mFilter = 0;
|
||||||
|
y_inverted = false;
|
||||||
|
can_use_mipmaps = false;
|
||||||
|
has_valid_mipmaps = false;
|
||||||
|
mUnnormalizeActive = 0;
|
||||||
|
mNormalizeActive = 0;
|
||||||
|
m_vbo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::initStatic()
|
||||||
|
{
|
||||||
|
#ifdef KWIN_HAVE_OPENGLES
|
||||||
|
sNPOTTextureSupported = true;
|
||||||
|
sFramebufferObjectSupported = true;
|
||||||
|
sSaturationSupported = true;
|
||||||
|
#else
|
||||||
|
sNPOTTextureSupported = hasGLExtension("GL_ARB_texture_non_power_of_two");
|
||||||
|
sFramebufferObjectSupported = hasGLExtension("GL_EXT_framebuffer_object");
|
||||||
|
sSaturationSupported = ((hasGLExtension("GL_ARB_texture_env_crossbar")
|
||||||
|
&& hasGLExtension("GL_ARB_texture_env_dot3")) || hasGLVersion(1, 4))
|
||||||
|
&& (glTextureUnitsCount >= 4) && glActiveTexture != NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::isNull() const
|
||||||
|
{
|
||||||
|
return mTexture == None;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize GLTexture::size() const
|
||||||
|
{
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::load(const QImage& image, GLenum target)
|
||||||
|
{
|
||||||
|
if (image.isNull())
|
||||||
|
return false;
|
||||||
|
QImage img = image;
|
||||||
|
mTarget = target;
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
if (mTarget != GL_TEXTURE_RECTANGLE_ARB) {
|
||||||
|
#endif
|
||||||
|
if (!NPOTTextureSupported()
|
||||||
|
&& (!isPowerOfTwo(image.width()) || !isPowerOfTwo(image.height()))) {
|
||||||
|
// non-rectangular target requires POT texture
|
||||||
|
img = img.scaled(nearestPowerOfTwo(image.width()),
|
||||||
|
nearestPowerOfTwo(image.height()));
|
||||||
|
}
|
||||||
|
mScale.setWidth(1.0 / img.width());
|
||||||
|
mScale.setHeight(1.0 / img.height());
|
||||||
|
can_use_mipmaps = true;
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
} else {
|
||||||
|
mScale.setWidth(1.0);
|
||||||
|
mScale.setHeight(1.0);
|
||||||
|
can_use_mipmaps = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
setFilter(GL_LINEAR);
|
||||||
|
mSize = img.size();
|
||||||
|
y_inverted = false;
|
||||||
|
|
||||||
|
img = convertToGLFormat(img);
|
||||||
|
|
||||||
|
setDirty();
|
||||||
|
if (isNull())
|
||||||
|
glGenTextures(1, &mTexture);
|
||||||
|
bind();
|
||||||
|
#ifdef KWIN_HAVE_OPENGLES
|
||||||
|
// format and internal format have to match in ES, GL_RGBA8 and GL_BGRA are not available
|
||||||
|
// see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml
|
||||||
|
glTexImage2D(mTarget, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
|
||||||
|
#else
|
||||||
|
glTexImage2D(mTarget, 0, GL_RGBA8, img.width(), img.height(), 0,
|
||||||
|
GL_BGRA, GL_UNSIGNED_BYTE, img.bits());
|
||||||
|
#endif
|
||||||
|
unbind();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::load(const QPixmap& pixmap, GLenum target)
|
||||||
|
{
|
||||||
|
if (pixmap.isNull())
|
||||||
|
return false;
|
||||||
|
return load(pixmap.toImage(), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::load(const QString& fileName)
|
||||||
|
{
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
return false;
|
||||||
|
return load(QImage(fileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::discard()
|
||||||
|
{
|
||||||
|
setDirty();
|
||||||
|
if (mTexture != None)
|
||||||
|
glDeleteTextures(1, &mTexture);
|
||||||
|
mTexture = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::bind()
|
||||||
|
{
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
glEnable(mTarget);
|
||||||
|
#endif
|
||||||
|
glBindTexture(mTarget, mTexture);
|
||||||
|
enableFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::unbind()
|
||||||
|
{
|
||||||
|
glBindTexture(mTarget, 0);
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
glDisable(mTarget);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::render(QRegion region, const QRect& rect)
|
||||||
|
{
|
||||||
|
if (rect.size() != m_cachedSize) {
|
||||||
|
m_cachedSize = rect.size();
|
||||||
|
QRect r(rect);
|
||||||
|
r.moveTo(0, 0);
|
||||||
|
if (!m_vbo) {
|
||||||
|
m_vbo = new GLVertexBuffer(KWin::GLVertexBuffer::Static);
|
||||||
|
}
|
||||||
|
const float verts[ 4 * 2 ] = {
|
||||||
|
// NOTICE: r.x/y could be replaced by "0", but that would make it unreadable...
|
||||||
|
r.x(), r.y(),
|
||||||
|
r.x(), r.y() + rect.height(),
|
||||||
|
r.x() + rect.width(), r.y(),
|
||||||
|
r.x() + rect.width(), r.y() + rect.height()
|
||||||
|
};
|
||||||
|
const float texcoords[ 4 * 2 ] = {
|
||||||
|
0.0f, y_inverted ? 0.0f : 1.0f, // y needs to be swapped (normalized coords)
|
||||||
|
0.0f, y_inverted ? 1.0f : 0.0f,
|
||||||
|
1.0f, y_inverted ? 0.0f : 1.0f,
|
||||||
|
1.0f, y_inverted ? 1.0f : 0.0f
|
||||||
|
};
|
||||||
|
m_vbo->setData(4, 2, verts, texcoords);
|
||||||
|
}
|
||||||
|
QMatrix4x4 translation;
|
||||||
|
translation.translate(rect.x(), rect.y());
|
||||||
|
if (ShaderManager::instance()->isShaderBound()) {
|
||||||
|
GLShader *shader = ShaderManager::instance()->getBoundShader();
|
||||||
|
shader->setUniform(GLShader::Offset, QVector2D(rect.x(), rect.y()));
|
||||||
|
shader->setUniform(GLShader::WindowTransformation, translation);
|
||||||
|
} else {
|
||||||
|
pushMatrix(translation);
|
||||||
|
}
|
||||||
|
m_vbo->render(region, GL_TRIANGLE_STRIP);
|
||||||
|
if (ShaderManager::instance()->isShaderBound()) {
|
||||||
|
GLShader *shader = ShaderManager::instance()->getBoundShader();
|
||||||
|
shader->setUniform(GLShader::WindowTransformation, QMatrix4x4());
|
||||||
|
} else {
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::enableUnnormalizedTexCoords()
|
||||||
|
{
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
assert(mNormalizeActive == 0);
|
||||||
|
if (mUnnormalizeActive++ != 0)
|
||||||
|
return;
|
||||||
|
// update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
|
||||||
|
glMatrixMode(GL_TEXTURE);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
glScalef(mScale.width(), mScale.height(), 1);
|
||||||
|
if (!y_inverted) {
|
||||||
|
// Modify texture matrix so that we could always use non-opengl
|
||||||
|
// coordinates for textures
|
||||||
|
glScalef(1, -1, 1);
|
||||||
|
glTranslatef(0, -mSize.height(), 0);
|
||||||
|
}
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::disableUnnormalizedTexCoords()
|
||||||
|
{
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
if (--mUnnormalizeActive != 0)
|
||||||
|
return;
|
||||||
|
// Restore texture matrix
|
||||||
|
glMatrixMode(GL_TEXTURE);
|
||||||
|
glPopMatrix();
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::enableNormalizedTexCoords()
|
||||||
|
{
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
assert(mUnnormalizeActive == 0);
|
||||||
|
if (mNormalizeActive++ != 0)
|
||||||
|
return;
|
||||||
|
// update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
|
||||||
|
glMatrixMode(GL_TEXTURE);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
glScalef(mSize.width() * mScale.width(), mSize.height() * mScale.height(), 1);
|
||||||
|
if (y_inverted) {
|
||||||
|
// Modify texture matrix so that we could always use non-opengl
|
||||||
|
// coordinates for textures
|
||||||
|
glScalef(1, -1, 1);
|
||||||
|
glTranslatef(0, -1, 0);
|
||||||
|
}
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::disableNormalizedTexCoords()
|
||||||
|
{
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
if (--mNormalizeActive != 0)
|
||||||
|
return;
|
||||||
|
// Restore texture matrix
|
||||||
|
glMatrixMode(GL_TEXTURE);
|
||||||
|
glPopMatrix();
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint GLTexture::texture() const
|
||||||
|
{
|
||||||
|
return mTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum GLTexture::target() const
|
||||||
|
{
|
||||||
|
return mTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum GLTexture::filter() const
|
||||||
|
{
|
||||||
|
return mFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::isDirty() const
|
||||||
|
{
|
||||||
|
return has_valid_mipmaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::setTexture(GLuint texture)
|
||||||
|
{
|
||||||
|
discard();
|
||||||
|
mTexture = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::setTarget(GLenum target)
|
||||||
|
{
|
||||||
|
mTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::setFilter(GLenum filter)
|
||||||
|
{
|
||||||
|
mFilter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::setWrapMode(GLenum mode)
|
||||||
|
{
|
||||||
|
bind();
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_WRAP_S, mode);
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_WRAP_T, mode);
|
||||||
|
unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::setDirty()
|
||||||
|
{
|
||||||
|
has_valid_mipmaps = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLTexture::enableFilter()
|
||||||
|
{
|
||||||
|
if (mFilter == GL_LINEAR_MIPMAP_LINEAR) {
|
||||||
|
// trilinear filtering requested, but is it possible?
|
||||||
|
if (NPOTTextureSupported()
|
||||||
|
&& framebufferObjectSupported()
|
||||||
|
&& can_use_mipmaps) {
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
if (!has_valid_mipmaps) {
|
||||||
|
glGenerateMipmap(mTarget);
|
||||||
|
has_valid_mipmaps = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// can't use trilinear, so use bilinear
|
||||||
|
setFilter(GL_LINEAR);
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
}
|
||||||
|
} else if (mFilter == GL_LINEAR) {
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
} else {
|
||||||
|
// if neither trilinear nor bilinear, default to fast filtering
|
||||||
|
setFilter(GL_NEAREST);
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
|
||||||
|
{
|
||||||
|
#ifdef KWIN_HAVE_OPENGLES
|
||||||
|
Q_UNUSED(texture_format)
|
||||||
|
#endif
|
||||||
|
// Copied from Qt
|
||||||
|
Q_ASSERT(dst.size() == img.size());
|
||||||
|
Q_ASSERT(dst.depth() == 32);
|
||||||
|
Q_ASSERT(img.depth() == 32);
|
||||||
|
|
||||||
|
const int width = img.width();
|
||||||
|
const int height = img.height();
|
||||||
|
const uint *p = (const uint*) img.scanLine(img.height() - 1);
|
||||||
|
uint *q = (uint*) dst.scanLine(0);
|
||||||
|
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
if (texture_format == GL_BGRA) {
|
||||||
|
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
|
||||||
|
// mirror + swizzle
|
||||||
|
for (int i = 0; i < height; ++i) {
|
||||||
|
const uint *end = p + width;
|
||||||
|
while (p < end) {
|
||||||
|
*q = ((*p << 24) & 0xff000000)
|
||||||
|
| ((*p >> 24) & 0x000000ff)
|
||||||
|
| ((*p << 8) & 0x00ff0000)
|
||||||
|
| ((*p >> 8) & 0x0000ff00);
|
||||||
|
p++;
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
p -= 2 * width;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const uint bytesPerLine = img.bytesPerLine();
|
||||||
|
for (int i = 0; i < height; ++i) {
|
||||||
|
memcpy(q, p, bytesPerLine);
|
||||||
|
q += width;
|
||||||
|
p -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
|
||||||
|
for (int i = 0; i < height; ++i) {
|
||||||
|
const uint *end = p + width;
|
||||||
|
while (p < end) {
|
||||||
|
*q = (*p << 8) | ((*p >> 24) & 0xFF);
|
||||||
|
p++;
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
p -= 2 * width;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < height; ++i) {
|
||||||
|
const uint *end = p + width;
|
||||||
|
while (p < end) {
|
||||||
|
*q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
|
||||||
|
p++;
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
p -= 2 * width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef KWIN_HAVE_OPENGLES
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage GLTexture::convertToGLFormat(const QImage& img) const
|
||||||
|
{
|
||||||
|
// Copied from Qt's QGLWidget::convertToGLFormat()
|
||||||
|
QImage res(img.size(), QImage::Format_ARGB32);
|
||||||
|
#ifdef KWIN_HAVE_OPENGLES
|
||||||
|
convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32_Premultiplied), GL_RGBA);
|
||||||
|
#else
|
||||||
|
convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32_Premultiplied), GL_BGRA);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace KWin
|
||||||
|
|
||||||
|
#endif
|
164
libkwineffects/kwingltexture.h
Normal file
164
libkwineffects/kwingltexture.h
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/********************************************************************
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
|
||||||
|
Copyright (C) 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef KWIN_GLTEXTURE_H
|
||||||
|
#define KWIN_GLTEXTURE_H
|
||||||
|
|
||||||
|
#include "kwinconfig.h" // KWIN_HAVE_OPENGL
|
||||||
|
#include "kwinglobals.h"
|
||||||
|
|
||||||
|
#ifdef KWIN_HAVE_OPENGL
|
||||||
|
|
||||||
|
#include <QtCore/QSize>
|
||||||
|
#include <QtCore/QSharedData>
|
||||||
|
|
||||||
|
class QImage;
|
||||||
|
class QPixmap;
|
||||||
|
|
||||||
|
/** @addtogroup kwineffects */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
class GLVertexBuffer;
|
||||||
|
|
||||||
|
class KWIN_EXPORT GLTexture
|
||||||
|
: public QSharedData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GLTexture();
|
||||||
|
explicit GLTexture(const QImage& image, GLenum target = GL_TEXTURE_2D);
|
||||||
|
explicit GLTexture(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D);
|
||||||
|
GLTexture(const QString& fileName);
|
||||||
|
GLTexture(int width, int height);
|
||||||
|
virtual ~GLTexture();
|
||||||
|
|
||||||
|
bool isNull() const;
|
||||||
|
QSize size() const;
|
||||||
|
int width() const {
|
||||||
|
return mSize.width(); /// @since 4.5
|
||||||
|
}
|
||||||
|
int height() const {
|
||||||
|
return mSize.height(); /// @since 4.5
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool load(const QImage& image, GLenum target = GL_TEXTURE_2D);
|
||||||
|
virtual bool load(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D);
|
||||||
|
virtual bool load(const QString& fileName);
|
||||||
|
virtual void discard();
|
||||||
|
virtual void bind();
|
||||||
|
virtual void unbind();
|
||||||
|
void render(QRegion region, const QRect& rect);
|
||||||
|
/**
|
||||||
|
* Set up texture transformation matrix to automatically map unnormalized
|
||||||
|
* texture coordinates (i.e. 0 to width, 0 to height, (0,0) is top-left)
|
||||||
|
* to OpenGL coordinates. Automatically adjusts for different texture
|
||||||
|
* types. This can be done only for one texture at a time, repeated
|
||||||
|
* calls for the same texture are allowed though, requiring the same
|
||||||
|
* amount of calls to disableUnnormalizedTexCoords().
|
||||||
|
*
|
||||||
|
* In OpenGL ES this method is a no-op. In core profile a shader should be used
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
void enableUnnormalizedTexCoords();
|
||||||
|
/**
|
||||||
|
* Disables transformation set up using enableUnnormalizedTexCoords().
|
||||||
|
*
|
||||||
|
* In OpenGL ES this method is a no-op. In core profile a shader should be used
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
void disableUnnormalizedTexCoords();
|
||||||
|
/**
|
||||||
|
* Set up texture transformation matrix to automatically map normalized
|
||||||
|
* texture coordinates (i.e. 0 to 1, 0 to 1, (0,0) is bottom-left)
|
||||||
|
* to OpenGL coordinates. Automatically adjusts for different texture
|
||||||
|
* types. This can be done only for one texture at a time, repeated
|
||||||
|
* calls for the same texture are allowed though, requiring the same
|
||||||
|
* amount of calls to disableNormalizedTexCoords().
|
||||||
|
*
|
||||||
|
* In OpenGL ES this method is a no-op. In core profile a shader should be used
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
void enableNormalizedTexCoords();
|
||||||
|
/**
|
||||||
|
* Disables transformation set up using enableNormalizedTexCoords().
|
||||||
|
*
|
||||||
|
* In OpenGL ES this method is a no-op. In core profile a shader should be used
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
void disableNormalizedTexCoords();
|
||||||
|
|
||||||
|
GLuint texture() const;
|
||||||
|
GLenum target() const;
|
||||||
|
GLenum filter() const;
|
||||||
|
virtual bool isDirty() const;
|
||||||
|
void setTexture(GLuint texture);
|
||||||
|
void setTarget(GLenum target);
|
||||||
|
void setFilter(GLenum filter);
|
||||||
|
void setWrapMode(GLenum mode);
|
||||||
|
virtual void setDirty();
|
||||||
|
|
||||||
|
static void initStatic();
|
||||||
|
static bool NPOTTextureSupported() {
|
||||||
|
return sNPOTTextureSupported;
|
||||||
|
}
|
||||||
|
static bool framebufferObjectSupported() {
|
||||||
|
return sFramebufferObjectSupported;
|
||||||
|
}
|
||||||
|
static bool saturationSupported() {
|
||||||
|
return sSaturationSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void enableFilter();
|
||||||
|
QImage convertToGLFormat(const QImage& img) const;
|
||||||
|
|
||||||
|
GLuint mTexture;
|
||||||
|
GLenum mTarget;
|
||||||
|
GLenum mFilter;
|
||||||
|
QSize mSize;
|
||||||
|
QSizeF mScale; // to un-normalize GL_TEXTURE_2D
|
||||||
|
bool y_inverted; // texture has y inverted
|
||||||
|
bool can_use_mipmaps;
|
||||||
|
bool has_valid_mipmaps;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
int mUnnormalizeActive; // 0 - no, otherwise refcount
|
||||||
|
int mNormalizeActive; // 0 - no, otherwise refcount
|
||||||
|
GLVertexBuffer* m_vbo;
|
||||||
|
QSize m_cachedSize;
|
||||||
|
|
||||||
|
static bool sNPOTTextureSupported;
|
||||||
|
static bool sFramebufferObjectSupported;
|
||||||
|
static bool sSaturationSupported;
|
||||||
|
Q_DISABLE_COPY(GLTexture)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif
|
|
@ -241,460 +241,6 @@ void popMatrix()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//****************************************
|
|
||||||
// GLTexture
|
|
||||||
//****************************************
|
|
||||||
|
|
||||||
bool GLTexture::sNPOTTextureSupported = false;
|
|
||||||
bool GLTexture::sFramebufferObjectSupported = false;
|
|
||||||
bool GLTexture::sSaturationSupported = false;
|
|
||||||
|
|
||||||
GLTexture::GLTexture()
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
GLTexture::GLTexture(const QImage& image, GLenum target)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
load(image, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLTexture::GLTexture(const QPixmap& pixmap, GLenum target)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
load(pixmap, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLTexture::GLTexture(const QString& fileName)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
load(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLTexture::GLTexture(int width, int height)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
if (NPOTTextureSupported() || (isPowerOfTwo(width) && isPowerOfTwo(height))) {
|
|
||||||
mTarget = GL_TEXTURE_2D;
|
|
||||||
mScale.setWidth(1.0 / width);
|
|
||||||
mScale.setHeight(1.0 / height);
|
|
||||||
mSize = QSize(width, height);
|
|
||||||
can_use_mipmaps = true;
|
|
||||||
|
|
||||||
glGenTextures(1, &mTexture);
|
|
||||||
bind();
|
|
||||||
#ifdef KWIN_HAVE_OPENGLES
|
|
||||||
// format and internal format have to match in ES, GL_RGBA8 and GL_BGRA are not available
|
|
||||||
// see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml
|
|
||||||
glTexImage2D(mTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
|
||||||
#else
|
|
||||||
glTexImage2D(mTarget, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
|
|
||||||
#endif
|
|
||||||
unbind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GLTexture::~GLTexture()
|
|
||||||
{
|
|
||||||
delete m_vbo;
|
|
||||||
discard();
|
|
||||||
assert(mUnnormalizeActive == 0);
|
|
||||||
assert(mNormalizeActive == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::init()
|
|
||||||
{
|
|
||||||
mTexture = None;
|
|
||||||
mTarget = 0;
|
|
||||||
mFilter = 0;
|
|
||||||
y_inverted = false;
|
|
||||||
can_use_mipmaps = false;
|
|
||||||
has_valid_mipmaps = false;
|
|
||||||
mUnnormalizeActive = 0;
|
|
||||||
mNormalizeActive = 0;
|
|
||||||
m_vbo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::initStatic()
|
|
||||||
{
|
|
||||||
#ifdef KWIN_HAVE_OPENGLES
|
|
||||||
sNPOTTextureSupported = true;
|
|
||||||
sFramebufferObjectSupported = true;
|
|
||||||
sSaturationSupported = true;
|
|
||||||
#else
|
|
||||||
sNPOTTextureSupported = hasGLExtension("GL_ARB_texture_non_power_of_two");
|
|
||||||
sFramebufferObjectSupported = hasGLExtension("GL_EXT_framebuffer_object");
|
|
||||||
sSaturationSupported = ((hasGLExtension("GL_ARB_texture_env_crossbar")
|
|
||||||
&& hasGLExtension("GL_ARB_texture_env_dot3")) || hasGLVersion(1, 4))
|
|
||||||
&& (glTextureUnitsCount >= 4) && glActiveTexture != NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLTexture::isNull() const
|
|
||||||
{
|
|
||||||
return mTexture == None;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSize GLTexture::size() const
|
|
||||||
{
|
|
||||||
return mSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLTexture::load(const QImage& image, GLenum target)
|
|
||||||
{
|
|
||||||
if (image.isNull())
|
|
||||||
return false;
|
|
||||||
QImage img = image;
|
|
||||||
mTarget = target;
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
if (mTarget != GL_TEXTURE_RECTANGLE_ARB) {
|
|
||||||
#endif
|
|
||||||
if (!NPOTTextureSupported()
|
|
||||||
&& (!isPowerOfTwo(image.width()) || !isPowerOfTwo(image.height()))) {
|
|
||||||
// non-rectangular target requires POT texture
|
|
||||||
img = img.scaled(nearestPowerOfTwo(image.width()),
|
|
||||||
nearestPowerOfTwo(image.height()));
|
|
||||||
}
|
|
||||||
mScale.setWidth(1.0 / img.width());
|
|
||||||
mScale.setHeight(1.0 / img.height());
|
|
||||||
can_use_mipmaps = true;
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
} else {
|
|
||||||
mScale.setWidth(1.0);
|
|
||||||
mScale.setHeight(1.0);
|
|
||||||
can_use_mipmaps = false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
setFilter(GL_LINEAR);
|
|
||||||
mSize = img.size();
|
|
||||||
y_inverted = false;
|
|
||||||
|
|
||||||
img = convertToGLFormat(img);
|
|
||||||
|
|
||||||
setDirty();
|
|
||||||
if (isNull())
|
|
||||||
glGenTextures(1, &mTexture);
|
|
||||||
bind();
|
|
||||||
#ifdef KWIN_HAVE_OPENGLES
|
|
||||||
// format and internal format have to match in ES, GL_RGBA8 and GL_BGRA are not available
|
|
||||||
// see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml
|
|
||||||
glTexImage2D(mTarget, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
|
|
||||||
#else
|
|
||||||
glTexImage2D(mTarget, 0, GL_RGBA8, img.width(), img.height(), 0,
|
|
||||||
GL_BGRA, GL_UNSIGNED_BYTE, img.bits());
|
|
||||||
#endif
|
|
||||||
unbind();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLTexture::load(const QPixmap& pixmap, GLenum target)
|
|
||||||
{
|
|
||||||
if (pixmap.isNull())
|
|
||||||
return false;
|
|
||||||
return load(pixmap.toImage(), target);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLTexture::load(const QString& fileName)
|
|
||||||
{
|
|
||||||
if (fileName.isEmpty())
|
|
||||||
return false;
|
|
||||||
return load(QImage(fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::discard()
|
|
||||||
{
|
|
||||||
setDirty();
|
|
||||||
if (mTexture != None)
|
|
||||||
glDeleteTextures(1, &mTexture);
|
|
||||||
mTexture = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::bind()
|
|
||||||
{
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
glEnable(mTarget);
|
|
||||||
#endif
|
|
||||||
glBindTexture(mTarget, mTexture);
|
|
||||||
enableFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::unbind()
|
|
||||||
{
|
|
||||||
glBindTexture(mTarget, 0);
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
glDisable(mTarget);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::render(QRegion region, const QRect& rect)
|
|
||||||
{
|
|
||||||
if (rect.size() != m_cachedSize) {
|
|
||||||
m_cachedSize = rect.size();
|
|
||||||
QRect r(rect);
|
|
||||||
r.moveTo(0, 0);
|
|
||||||
if (!m_vbo) {
|
|
||||||
m_vbo = new GLVertexBuffer(KWin::GLVertexBuffer::Static);
|
|
||||||
}
|
|
||||||
const float verts[ 4 * 2 ] = {
|
|
||||||
// NOTICE: r.x/y could be replaced by "0", but that would make it unreadable...
|
|
||||||
r.x(), r.y(),
|
|
||||||
r.x(), r.y() + rect.height(),
|
|
||||||
r.x() + rect.width(), r.y(),
|
|
||||||
r.x() + rect.width(), r.y() + rect.height()
|
|
||||||
};
|
|
||||||
const float texcoords[ 4 * 2 ] = {
|
|
||||||
0.0f, y_inverted ? 0.0f : 1.0f, // y needs to be swapped (normalized coords)
|
|
||||||
0.0f, y_inverted ? 1.0f : 0.0f,
|
|
||||||
1.0f, y_inverted ? 0.0f : 1.0f,
|
|
||||||
1.0f, y_inverted ? 1.0f : 0.0f
|
|
||||||
};
|
|
||||||
m_vbo->setData(4, 2, verts, texcoords);
|
|
||||||
}
|
|
||||||
QMatrix4x4 translation;
|
|
||||||
translation.translate(rect.x(), rect.y());
|
|
||||||
if (ShaderManager::instance()->isShaderBound()) {
|
|
||||||
GLShader *shader = ShaderManager::instance()->getBoundShader();
|
|
||||||
shader->setUniform(GLShader::Offset, QVector2D(rect.x(), rect.y()));
|
|
||||||
shader->setUniform(GLShader::WindowTransformation, translation);
|
|
||||||
} else {
|
|
||||||
pushMatrix(translation);
|
|
||||||
}
|
|
||||||
m_vbo->render(region, GL_TRIANGLE_STRIP);
|
|
||||||
if (ShaderManager::instance()->isShaderBound()) {
|
|
||||||
GLShader *shader = ShaderManager::instance()->getBoundShader();
|
|
||||||
shader->setUniform(GLShader::WindowTransformation, QMatrix4x4());
|
|
||||||
} else {
|
|
||||||
popMatrix();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::enableUnnormalizedTexCoords()
|
|
||||||
{
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
assert(mNormalizeActive == 0);
|
|
||||||
if (mUnnormalizeActive++ != 0)
|
|
||||||
return;
|
|
||||||
// update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
|
|
||||||
glMatrixMode(GL_TEXTURE);
|
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
glScalef(mScale.width(), mScale.height(), 1);
|
|
||||||
if (!y_inverted) {
|
|
||||||
// Modify texture matrix so that we could always use non-opengl
|
|
||||||
// coordinates for textures
|
|
||||||
glScalef(1, -1, 1);
|
|
||||||
glTranslatef(0, -mSize.height(), 0);
|
|
||||||
}
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::disableUnnormalizedTexCoords()
|
|
||||||
{
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
if (--mUnnormalizeActive != 0)
|
|
||||||
return;
|
|
||||||
// Restore texture matrix
|
|
||||||
glMatrixMode(GL_TEXTURE);
|
|
||||||
glPopMatrix();
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::enableNormalizedTexCoords()
|
|
||||||
{
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
assert(mUnnormalizeActive == 0);
|
|
||||||
if (mNormalizeActive++ != 0)
|
|
||||||
return;
|
|
||||||
// update texture matrix to handle GL_TEXTURE_2D and GL_TEXTURE_RECTANGLE
|
|
||||||
glMatrixMode(GL_TEXTURE);
|
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
glScalef(mSize.width() * mScale.width(), mSize.height() * mScale.height(), 1);
|
|
||||||
if (y_inverted) {
|
|
||||||
// Modify texture matrix so that we could always use non-opengl
|
|
||||||
// coordinates for textures
|
|
||||||
glScalef(1, -1, 1);
|
|
||||||
glTranslatef(0, -1, 0);
|
|
||||||
}
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::disableNormalizedTexCoords()
|
|
||||||
{
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
if (--mNormalizeActive != 0)
|
|
||||||
return;
|
|
||||||
// Restore texture matrix
|
|
||||||
glMatrixMode(GL_TEXTURE);
|
|
||||||
glPopMatrix();
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint GLTexture::texture() const
|
|
||||||
{
|
|
||||||
return mTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLenum GLTexture::target() const
|
|
||||||
{
|
|
||||||
return mTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLenum GLTexture::filter() const
|
|
||||||
{
|
|
||||||
return mFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLTexture::isDirty() const
|
|
||||||
{
|
|
||||||
return has_valid_mipmaps;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::setTexture(GLuint texture)
|
|
||||||
{
|
|
||||||
discard();
|
|
||||||
mTexture = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::setTarget(GLenum target)
|
|
||||||
{
|
|
||||||
mTarget = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::setFilter(GLenum filter)
|
|
||||||
{
|
|
||||||
mFilter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::setWrapMode(GLenum mode)
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_WRAP_S, mode);
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_WRAP_T, mode);
|
|
||||||
unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTexture::setDirty()
|
|
||||||
{
|
|
||||||
has_valid_mipmaps = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void GLTexture::enableFilter()
|
|
||||||
{
|
|
||||||
if (mFilter == GL_LINEAR_MIPMAP_LINEAR) {
|
|
||||||
// trilinear filtering requested, but is it possible?
|
|
||||||
if (NPOTTextureSupported()
|
|
||||||
&& framebufferObjectSupported()
|
|
||||||
&& can_use_mipmaps) {
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
if (!has_valid_mipmaps) {
|
|
||||||
glGenerateMipmap(mTarget);
|
|
||||||
has_valid_mipmaps = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// can't use trilinear, so use bilinear
|
|
||||||
setFilter(GL_LINEAR);
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
}
|
|
||||||
} else if (mFilter == GL_LINEAR) {
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
} else {
|
|
||||||
// if neither trilinear nor bilinear, default to fast filtering
|
|
||||||
setFilter(GL_NEAREST);
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
|
|
||||||
{
|
|
||||||
#ifdef KWIN_HAVE_OPENGLES
|
|
||||||
Q_UNUSED(texture_format)
|
|
||||||
#endif
|
|
||||||
// Copied from Qt
|
|
||||||
Q_ASSERT(dst.size() == img.size());
|
|
||||||
Q_ASSERT(dst.depth() == 32);
|
|
||||||
Q_ASSERT(img.depth() == 32);
|
|
||||||
|
|
||||||
const int width = img.width();
|
|
||||||
const int height = img.height();
|
|
||||||
const uint *p = (const uint*) img.scanLine(img.height() - 1);
|
|
||||||
uint *q = (uint*) dst.scanLine(0);
|
|
||||||
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
if (texture_format == GL_BGRA) {
|
|
||||||
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
|
|
||||||
// mirror + swizzle
|
|
||||||
for (int i = 0; i < height; ++i) {
|
|
||||||
const uint *end = p + width;
|
|
||||||
while (p < end) {
|
|
||||||
*q = ((*p << 24) & 0xff000000)
|
|
||||||
| ((*p >> 24) & 0x000000ff)
|
|
||||||
| ((*p << 8) & 0x00ff0000)
|
|
||||||
| ((*p >> 8) & 0x0000ff00);
|
|
||||||
p++;
|
|
||||||
q++;
|
|
||||||
}
|
|
||||||
p -= 2 * width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const uint bytesPerLine = img.bytesPerLine();
|
|
||||||
for (int i = 0; i < height; ++i) {
|
|
||||||
memcpy(q, p, bytesPerLine);
|
|
||||||
q += width;
|
|
||||||
p -= width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
|
|
||||||
for (int i = 0; i < height; ++i) {
|
|
||||||
const uint *end = p + width;
|
|
||||||
while (p < end) {
|
|
||||||
*q = (*p << 8) | ((*p >> 24) & 0xFF);
|
|
||||||
p++;
|
|
||||||
q++;
|
|
||||||
}
|
|
||||||
p -= 2 * width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < height; ++i) {
|
|
||||||
const uint *end = p + width;
|
|
||||||
while (p < end) {
|
|
||||||
*q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
|
|
||||||
p++;
|
|
||||||
q++;
|
|
||||||
}
|
|
||||||
p -= 2 * width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef KWIN_HAVE_OPENGLES
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage GLTexture::convertToGLFormat(const QImage& img) const
|
|
||||||
{
|
|
||||||
// Copied from Qt's QGLWidget::convertToGLFormat()
|
|
||||||
QImage res(img.size(), QImage::Format_ARGB32);
|
|
||||||
#ifdef KWIN_HAVE_OPENGLES
|
|
||||||
convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32_Premultiplied), GL_RGBA);
|
|
||||||
#else
|
|
||||||
convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32_Premultiplied), GL_BGRA);
|
|
||||||
#endif
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
//****************************************
|
//****************************************
|
||||||
// GLShader
|
// GLShader
|
||||||
//****************************************
|
//****************************************
|
||||||
|
|
|
@ -34,6 +34,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <QtCore/QSharedData>
|
#include <QtCore/QSharedData>
|
||||||
#include <QtCore/QStack>
|
#include <QtCore/QStack>
|
||||||
|
|
||||||
|
#include "kwingltexture.h"
|
||||||
|
|
||||||
/** @addtogroup kwineffects */
|
/** @addtogroup kwineffects */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
|
|
||||||
|
@ -130,120 +132,6 @@ KWIN_EXPORT void loadMatrix(const QMatrix4x4 &matrix);
|
||||||
**/
|
**/
|
||||||
KWIN_EXPORT void popMatrix();
|
KWIN_EXPORT void popMatrix();
|
||||||
|
|
||||||
|
|
||||||
class KWIN_EXPORT GLTexture
|
|
||||||
: public QSharedData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GLTexture();
|
|
||||||
explicit GLTexture(const QImage& image, GLenum target = GL_TEXTURE_2D);
|
|
||||||
explicit GLTexture(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D);
|
|
||||||
GLTexture(const QString& fileName);
|
|
||||||
GLTexture(int width, int height);
|
|
||||||
virtual ~GLTexture();
|
|
||||||
|
|
||||||
bool isNull() const;
|
|
||||||
QSize size() const;
|
|
||||||
int width() const {
|
|
||||||
return mSize.width(); /// @since 4.5
|
|
||||||
}
|
|
||||||
int height() const {
|
|
||||||
return mSize.height(); /// @since 4.5
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool load(const QImage& image, GLenum target = GL_TEXTURE_2D);
|
|
||||||
virtual bool load(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D);
|
|
||||||
virtual bool load(const QString& fileName);
|
|
||||||
virtual void discard();
|
|
||||||
virtual void bind();
|
|
||||||
virtual void unbind();
|
|
||||||
void render(QRegion region, const QRect& rect);
|
|
||||||
/**
|
|
||||||
* Set up texture transformation matrix to automatically map unnormalized
|
|
||||||
* texture coordinates (i.e. 0 to width, 0 to height, (0,0) is top-left)
|
|
||||||
* to OpenGL coordinates. Automatically adjusts for different texture
|
|
||||||
* types. This can be done only for one texture at a time, repeated
|
|
||||||
* calls for the same texture are allowed though, requiring the same
|
|
||||||
* amount of calls to disableUnnormalizedTexCoords().
|
|
||||||
*
|
|
||||||
* In OpenGL ES this method is a no-op. In core profile a shader should be used
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
void enableUnnormalizedTexCoords();
|
|
||||||
/**
|
|
||||||
* Disables transformation set up using enableUnnormalizedTexCoords().
|
|
||||||
*
|
|
||||||
* In OpenGL ES this method is a no-op. In core profile a shader should be used
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
void disableUnnormalizedTexCoords();
|
|
||||||
/**
|
|
||||||
* Set up texture transformation matrix to automatically map normalized
|
|
||||||
* texture coordinates (i.e. 0 to 1, 0 to 1, (0,0) is bottom-left)
|
|
||||||
* to OpenGL coordinates. Automatically adjusts for different texture
|
|
||||||
* types. This can be done only for one texture at a time, repeated
|
|
||||||
* calls for the same texture are allowed though, requiring the same
|
|
||||||
* amount of calls to disableNormalizedTexCoords().
|
|
||||||
*
|
|
||||||
* In OpenGL ES this method is a no-op. In core profile a shader should be used
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
void enableNormalizedTexCoords();
|
|
||||||
/**
|
|
||||||
* Disables transformation set up using enableNormalizedTexCoords().
|
|
||||||
*
|
|
||||||
* In OpenGL ES this method is a no-op. In core profile a shader should be used
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
void disableNormalizedTexCoords();
|
|
||||||
|
|
||||||
GLuint texture() const;
|
|
||||||
GLenum target() const;
|
|
||||||
GLenum filter() const;
|
|
||||||
virtual bool isDirty() const;
|
|
||||||
void setTexture(GLuint texture);
|
|
||||||
void setTarget(GLenum target);
|
|
||||||
void setFilter(GLenum filter);
|
|
||||||
void setWrapMode(GLenum mode);
|
|
||||||
virtual void setDirty();
|
|
||||||
|
|
||||||
static void initStatic();
|
|
||||||
static bool NPOTTextureSupported() {
|
|
||||||
return sNPOTTextureSupported;
|
|
||||||
}
|
|
||||||
static bool framebufferObjectSupported() {
|
|
||||||
return sFramebufferObjectSupported;
|
|
||||||
}
|
|
||||||
static bool saturationSupported() {
|
|
||||||
return sSaturationSupported;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void enableFilter();
|
|
||||||
QImage convertToGLFormat(const QImage& img) const;
|
|
||||||
|
|
||||||
GLuint mTexture;
|
|
||||||
GLenum mTarget;
|
|
||||||
GLenum mFilter;
|
|
||||||
QSize mSize;
|
|
||||||
QSizeF mScale; // to un-normalize GL_TEXTURE_2D
|
|
||||||
bool y_inverted; // texture has y inverted
|
|
||||||
bool can_use_mipmaps;
|
|
||||||
bool has_valid_mipmaps;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void init();
|
|
||||||
int mUnnormalizeActive; // 0 - no, otherwise refcount
|
|
||||||
int mNormalizeActive; // 0 - no, otherwise refcount
|
|
||||||
GLVertexBuffer* m_vbo;
|
|
||||||
QSize m_cachedSize;
|
|
||||||
|
|
||||||
static bool sNPOTTextureSupported;
|
|
||||||
static bool sFramebufferObjectSupported;
|
|
||||||
static bool sSaturationSupported;
|
|
||||||
Q_DISABLE_COPY(GLTexture)
|
|
||||||
};
|
|
||||||
|
|
||||||
class KWIN_EXPORT GLShader
|
class KWIN_EXPORT GLShader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue