📄 qgl.cpp
字号:
Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg);QGLShareRegister* qgl_share_reg(){ return _qgl_share_reg();}/*! \class QGLContext \brief The QGLContext class encapsulates an OpenGL rendering context. \ingroup multimedia An OpenGL rendering context is a complete set of OpenGL state variables. The rendering context's \l {QGL::FormatOption} {format} is set in the constructor, but it can also be set later with setFormat(). The format options that are actually set are returned by format(); the options you asked for are returned by requestedFormat(). Note that after a QGLContext object has been constructed, the actual OpenGL context must be created by explicitly calling the \link create() create()\endlink function. The makeCurrent() function makes this context the current rendering context. You can make \e no context current using doneCurrent(). The reset() function will reset the context and make it invalid. You can examine properties of the context with, e.g. isValid(), isSharing(), initialized(), windowCreated() and overlayTransparentColor(). If you're using double buffering you can swap the screen contents with the off-screen buffer using swapBuffers(). Please note that QGLContext is not thread safe.*//*! \obsolete Constructs an OpenGL context for the given paint \a device, which can be a widget or a pixmap. The \a format specifies several display options for the context. If the underlying OpenGL/Window system cannot satisfy all the features requested in \a format, the nearest subset of features will be used. After creation, the format() method will return the actual format obtained. Note that after a QGLContext object has been constructed, \l create() must be called explicitly to create the actual OpenGL context. The context will be \l {isValid()}{invalid} if it was not possible to obtain a GL context at all.*/QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device){ d_ptr = new QGLContextPrivate(this); Q_D(QGLContext); d->init(device, format);}/*! Constructs an OpenGL context with the given \a format which specifies several display options for the context. If the underlying OpenGL/Window system cannot satisfy all the features requested in \a format, the nearest subset of features will be used. After creation, the format() method will return the actual format obtained. Note that after a QGLContext object has been constructed, \l create() must be called explicitly to create the actual OpenGL context. The context will be \l {isValid()}{invalid} if it was not possible to obtain a GL context at all. \sa format(), isValid()*/QGLContext::QGLContext(const QGLFormat &format){ d_ptr = new QGLContextPrivate(this); Q_D(QGLContext); d->init(0, format);}/*! Destroys the OpenGL context and frees its resources.*/QGLContext::~QGLContext(){ Q_D(QGLContext); // remove any textures cached in this context if (qt_tex_cache) { QList<QString> keys = qt_tex_cache->keys(); for (int i = 0; i < keys.size(); ++i) { const QString &key = keys.at(i); if (qt_tex_cache->object(key)->context == this) qt_tex_cache->remove(key); } // ### thread safety if (qt_tex_cache->size() == 0) { qt_pixmap_cleanup_hook_64 = 0; qt_image_cleanup_hook_64 = 0; delete qt_tex_cache; qt_tex_cache = 0; } } QGLProxy::signalProxy()->emitAboutToDestroyContext(this); reset(); delete d;}/*! \overload Reads the DirectDrawSurface (DDS) compressed file \a fileName and generates a 2D GL texture from it. Only the DXT1, DXT3 and DXT5 DDS formats are supported. Note that this will only work if the implementation supports the \c GL_ARB_texture_compression and \c GL_EXT_texture_compression_s3tc extensions. \sa deleteTexture()*/GLuint QGLContext::bindTexture(const QString &fileName){ if (!qt_glCompressedTexImage2DARB) { qWarning("QGLContext::bindTexture(): The GL implementation does not support texture" "compression extensions."); return 0; } if (!qt_tex_cache) qt_tex_cache = new QGLTextureCache(qt_tex_cache_limit); QString key(fileName); QGLTexture *texture = qt_tex_cache->object(key); if (texture && texture->context == this) { glBindTexture(GL_TEXTURE_2D, texture->id); return texture->id; } QFile f(fileName); f.open(QIODevice::ReadOnly); char tag[4]; f.read(&tag[0], 4); if (strncmp(tag,"DDS ", 4) != 0) { qWarning("QGLContext::bindTexture(): not a DDS image file."); return 0; } DDSFormat ddsHeader; f.read((char *) &ddsHeader, sizeof(DDSFormat)); if (!ddsHeader.dwLinearSize) { qWarning("QGLContext::bindTexture() DDS image size is not valid."); return 0; } int factor = 4; int bufferSize = 0; int blockSize = 16; GLenum format; switch(ddsHeader.ddsPixelFormat.dwFourCC) { case FOURCC_DXT1: format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; factor = 2; blockSize = 8; break; case FOURCC_DXT3: format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case FOURCC_DXT5: format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; default: qWarning("QGLContext::bindTexture() DDS image format not supported."); return 0; } if (ddsHeader.dwMipMapCount > 1) bufferSize = ddsHeader.dwLinearSize * factor; else bufferSize = ddsHeader.dwLinearSize; GLubyte *pixels = (GLubyte *) malloc(bufferSize*sizeof(GLubyte)); f.seek(ddsHeader.dwSize + 4); f.read((char *) pixels, bufferSize); f.close(); GLuint tx_id; glGenTextures(1, &tx_id); glBindTexture(GL_TEXTURE_2D, tx_id);#ifndef Q_WS_QWS glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);#else glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);#endif int size; int offset = 0; int w = ddsHeader.dwWidth; int h = ddsHeader.dwHeight; // load mip-maps for(int i = 0; i < (int) ddsHeader.dwMipMapCount; ++i) { if (w == 0) w = 1; if (h == 0) h = 1; size = ((w+3)/4) * ((h+3)/4) * blockSize; qt_glCompressedTexImage2DARB(GL_TEXTURE_2D, i, format, w, h, 0, size, pixels + offset); offset += size; // half size for each mip-map level w = w/2; h = h/2; } free(pixels); int cost = bufferSize/1024; qt_tex_cache->insert(key, new QGLTexture(this, tx_id, 0), cost); return tx_id;}/* a hook that removes textures from the cache when a pixmap/image is deref'ed*/static void qt_gl_clean_cache(const QString &cacheKey){ // ### remove for 4.4 // Temporary fix to avoid QImages created in a different thread // cause crashes due to the fact that the QGLTextureCache isn't // thread-safe. if (qApp->thread() != QThread::currentThread()) return; const QList<QString> keys = qt_tex_cache->keys(); for (int i = 0; i < keys.count(); ++i) { const QString &key = keys.at(i); if (key.startsWith(cacheKey)) { if (qt_tex_cache->object(key)->clean) qt_tex_cache->remove(key); break; } }}static void qt_gl_pixmap_cleanup(qint64 key){ if (qt_tex_cache) qt_gl_clean_cache(QString().sprintf("p%016llx", key));}static void qt_gl_image_cleanup(qint64 key){ if (qt_tex_cache) qt_gl_clean_cache(QString().sprintf("i%016llx", key));}QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format){ QImage img = image; if ((force_premul && image.format() != QImage::Format_ARGB32_Premultiplied) || (!force_premul && image.format() != QImage::Format_ARGB32_Premultiplied && image.format() != QImage::Format_ARGB32)) { img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); } if (texture_format == GL_BGRA) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { // mirror + swizzle QImage res = img.copy(); for (int i=0; i < img.height(); i++) { uint *p = (uint*) img.scanLine(i); uint *q = (uint*) res.scanLine(img.height() - i - 1); uint *end = p + img.width(); while (p < end) { *q = ((*p << 24) & 0xff000000) | ((*p >> 24) & 0x000000ff) | ((*p << 8) & 0x00ff0000) | ((*p >> 8) & 0x0000ff00); p++; q++; } } return res; } else { return img.mirrored(); } } else { img = img.mirrored(); if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { for (int i=0; i < img.height(); i++) { uint *p = (uint*)img.scanLine(i); uint *end = p + img.width(); while (p < end) { *p = (*p << 8) | ((*p >> 24) & 0xFF); p++; } } } else { img = img.rgbSwapped(); } return img; }}GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, const QString &key, qint64 qt_id, bool clean){ Q_Q(QGLContext); // the GL_BGRA format is only present in GL version >= 1.2 GLenum texture_format = (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2) ? GL_BGRA : GL_RGBA; if (!qt_tex_cache) { qt_tex_cache = new QGLTextureCache(qt_tex_cache_limit); qt_pixmap_cleanup_hook_64 = qt_gl_pixmap_cleanup; qt_image_cleanup_hook_64 = qt_gl_image_cleanup; } // Scale the pixmap if needed. GL textures needs to have the // dimensions 2^n+2(border) x 2^m+2(border). QImage tx; int tx_w = qt_next_power_of_two(image.width()); int tx_h = qt_next_power_of_two(image.height()); // Note: the clean param is only true when a texture is bound // from the QOpenGLPaintEngine - in that case we have to force // a premultiplied texture format if (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())) tx = convertToGLFormat(image.scaled(tx_w, tx_h), clean, texture_format); else tx = convertToGLFormat(image, clean, texture_format); GLuint tx_id; glGenTextures(1, &tx_id); glBindTexture(target, tx_id); glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap && target == GL_TEXTURE_2D) { glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);#ifndef Q_WS_QWS glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);#else glTexParameterf(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);#endif glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } else { glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } glTexImage2D(target, 0, format, tx.width(), tx.height(), 0, texture_format, GL_UNSIGNED_BYTE, tx.bits()); // this assumes the size of a texture is always smaller than the max cache size int cost = tx.width()*tx.height()*4/1024; if (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost()) { // the cache is full - make an attempt to remove something const QList<QString> keys = qt_tex_cache->keys(); int i = 0; while (i < qt_tex_cache->count() && (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost())) { QGLTexture *tex = qt_tex_cache->object(keys.at(i)); if (tex->context == q) qt_tex_cache->remove(keys.at(i)); ++i; } } qt_tex_cache->insert(key, new QGLTexture(q, tx_id, qt_id, clean), cost); return tx_id;}bool QGLContextPrivate::textureCacheLookup(const QString &key, GLuint *id, qint64 *qt_id){ Q_Q(QGLContext); if (qt_tex_cache) { QGLTexture *texture = qt_tex_cache->object(key); if (texture && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context))) { *id = texture->id; *qt_id = texture->qt_id; return true; } } return false;}/*! \internal */GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean){ Q_Q(QGLContext); const QString key = QString(QLatin1String("%1_%2_%3")).arg(QString().sprintf("i%016llx",image.cacheKey())).arg(target).arg(format); GLuint id; qint64 qt_id; if (textureCacheLookup(key, &id, &qt_id)) { if (image.cacheKey() == qt_id) { glBindTexture(target, id); return id; } else { q->deleteTexture(id); } } return bindTexture(image, target, format, key, image.cacheKey(), clean);}/*! \internal */GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean){ Q_Q(QGLContext); const QString key = QString(QLatin1String("%1_%2_%3")).arg(QString().sprintf("p%016llx",pixmap.cacheKey())).arg(target).arg(format); GLuint id; qint64 qt_id; if (textureCacheLookup(key, &id, &qt_id)) { if (pixmap.cacheKey() == qt_id) { glBindTexture(target, id); return id; } else { q->deleteTexture(id); } } return bindTexture(pixmap.toImage(), target, format, key, pixmap.cacheKey(), clean);}/*! Generates and binds a 2D GL texture to the current context, based on \a image. The generated texture id is returned and can be used in later \c glBindTexture() calls. The \a target parameter specifies the texture target. The default target is \c GL_TEXTURE_2D. The \a format parameter sets the internal format for the texture. The default format is \c GL_RGBA8. If the GL implementation supports the \c GL_SGIS_generate_mipmap extension, mipmaps will be automatically generated for the texture. Mipmap generation is only supported for the \c GL_TEXTURE_2D target. The texture that is generated is cached, so multiple calls to bindTexture() with the same QImage will return the same texture id. \sa deleteTexture()*/GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format){ Q_D(QGLContext); return d->bindTexture(image, target, format, false);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -