changeset 3 | 41300fa6a67c |
parent 0 | 1918ee327afb |
child 4 | 3b1da2848fc7 |
child 7 | f7bc934e204c |
child 18 | 2f34d5167611 |
2:56cd8111b7f7 | 3:41300fa6a67c |
---|---|
125 Q_GLOBAL_STATIC(QGLDefaultOverlayFormat, defaultOverlayFormatInstance) |
125 Q_GLOBAL_STATIC(QGLDefaultOverlayFormat, defaultOverlayFormatInstance) |
126 |
126 |
127 QGLExtensions::Extensions QGLExtensions::glExtensions = 0; |
127 QGLExtensions::Extensions QGLExtensions::glExtensions = 0; |
128 bool QGLExtensions::nvidiaFboNeedsFinish = false; |
128 bool QGLExtensions::nvidiaFboNeedsFinish = false; |
129 |
129 |
130 #ifndef APIENTRY |
|
131 # define APIENTRY |
|
132 #endif |
|
133 typedef void (APIENTRY *pfn_glCompressedTexImage2DARB) (GLenum, GLint, GLenum, GLsizei, |
|
134 GLsizei, GLint, GLsizei, const GLvoid *); |
|
135 static pfn_glCompressedTexImage2DARB qt_glCompressedTexImage2DARB = 0; |
|
136 |
|
137 |
|
138 #ifndef APIENTRY |
|
139 #define APIENTRY |
|
140 #endif |
|
141 |
|
142 Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy) |
130 Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy) |
143 QGLSignalProxy *QGLSignalProxy::instance() |
131 QGLSignalProxy *QGLSignalProxy::instance() |
144 { |
132 { |
145 return theSignalProxy(); |
133 return theSignalProxy(); |
146 } |
134 } |
182 // No user-set engine - use the defaults |
170 // No user-set engine - use the defaults |
183 #if defined(QT_OPENGL_ES_2) |
171 #if defined(QT_OPENGL_ES_2) |
184 engineType = QPaintEngine::OpenGL2; |
172 engineType = QPaintEngine::OpenGL2; |
185 #else |
173 #else |
186 // We can't do this in the constructor for this object because it |
174 // We can't do this in the constructor for this object because it |
187 // needs to be called *before* the QApplication constructor |
175 // needs to be called *before* the QApplication constructor. |
176 // Also check for the FragmentShader extension in conjunction with |
|
177 // the 2.0 version flag, to cover the case where we export the display |
|
178 // from an old GL 1.1 server to a GL 2.x client. In that case we can't |
|
179 // use GL 2.0. |
|
188 if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) |
180 if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) |
181 && (QGLExtensions::glExtensions & QGLExtensions::FragmentShader) |
|
189 && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty()) |
182 && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty()) |
190 engineType = QPaintEngine::OpenGL2; |
183 engineType = QPaintEngine::OpenGL2; |
191 else |
184 else |
192 engineType = QPaintEngine::OpenGL; |
185 engineType = QPaintEngine::OpenGL; |
193 #endif |
186 #endif |
402 \i \link setStencil() Stencil buffer:\endlink Enabled. |
395 \i \link setStencil() Stencil buffer:\endlink Enabled. |
403 \i \link setStereo() Stereo:\endlink Disabled. |
396 \i \link setStereo() Stereo:\endlink Disabled. |
404 \i \link setDirectRendering() Direct rendering:\endlink Enabled. |
397 \i \link setDirectRendering() Direct rendering:\endlink Enabled. |
405 \i \link setOverlay() Overlay:\endlink Disabled. |
398 \i \link setOverlay() Overlay:\endlink Disabled. |
406 \i \link setPlane() Plane:\endlink 0 (i.e., normal plane). |
399 \i \link setPlane() Plane:\endlink 0 (i.e., normal plane). |
407 \i \link setSampleBuffers() Multisample buffers:\endlink Enabled on |
400 \i \link setSampleBuffers() Multisample buffers:\endlink Disabled. |
408 OpenGL/ES 2.0, disabled on other platforms. |
|
409 \endlist |
401 \endlist |
410 */ |
402 */ |
411 |
403 |
412 QGLFormat::QGLFormat() |
404 QGLFormat::QGLFormat() |
413 { |
405 { |
1488 sharing = false; |
1480 sharing = false; |
1489 max_texture_size = -1; |
1481 max_texture_size = -1; |
1490 version_flags_cached = false; |
1482 version_flags_cached = false; |
1491 version_flags = QGLFormat::OpenGL_Version_None; |
1483 version_flags = QGLFormat::OpenGL_Version_None; |
1492 current_fbo = 0; |
1484 current_fbo = 0; |
1485 default_fbo = 0; |
|
1493 active_engine = 0; |
1486 active_engine = 0; |
1494 } |
1487 } |
1495 |
1488 |
1496 QGLContext* QGLContext::currentCtx = 0; |
1489 QGLContext* QGLContext::currentCtx = 0; |
1497 |
1490 |
1771 Please note that QGLContext is not thread safe. |
1764 Please note that QGLContext is not thread safe. |
1772 */ |
1765 */ |
1773 |
1766 |
1774 /*! |
1767 /*! |
1775 \enum QGLContext::BindOption |
1768 \enum QGLContext::BindOption |
1769 \since 4.6 |
|
1770 |
|
1776 A set of options to decide how to bind a texture using bindTexture(). |
1771 A set of options to decide how to bind a texture using bindTexture(). |
1777 |
1772 |
1778 \value NoBindOption Don't do anything, pass the texture straight |
1773 \value NoBindOption Don't do anything, pass the texture straight |
1779 thru. |
1774 through. |
1780 |
1775 |
1781 \value InvertedYBindOption Specifies that the texture should be flipped |
1776 \value InvertedYBindOption Specifies that the texture should be flipped |
1782 over the X axis so that the texture coordinate 0,0 corresponds to |
1777 over the X axis so that the texture coordinate 0,0 corresponds to |
1783 the top left corner. Inverting the texture implies a deep copy |
1778 the top left corner. Inverting the texture implies a deep copy |
1784 prior to upload. |
1779 prior to upload. |
1877 |
1872 |
1878 void QGLContextPrivate::cleanup() |
1873 void QGLContextPrivate::cleanup() |
1879 { |
1874 { |
1880 } |
1875 } |
1881 |
1876 |
1882 typedef QHash<QString, GLuint> QGLDDSCache; |
|
1883 Q_GLOBAL_STATIC(QGLDDSCache, qgl_dds_cache) |
|
1884 |
|
1885 /*! |
1877 /*! |
1886 \overload |
1878 \overload |
1887 |
1879 |
1888 Reads the DirectDrawSurface (DDS) compressed file \a fileName and |
1880 Reads the compressed texture file \a fileName and generates a 2D GL |
1889 generates a 2D GL texture from it. |
1881 texture from it. |
1890 |
1882 |
1891 Only the DXT1, DXT3 and DXT5 DDS formats are supported. |
1883 This function can load DirectDrawSurface (DDS) textures in the |
1892 |
1884 DXT1, DXT3 and DXT5 DDS formats if the \c GL_ARB_texture_compression |
1893 Note that this will only work if the implementation supports the |
1885 and \c GL_EXT_texture_compression_s3tc extensions are supported. |
1894 \c GL_ARB_texture_compression and \c GL_EXT_texture_compression_s3tc |
1886 |
1895 extensions. |
1887 Since 4.6.1, textures in the ETC1 format can be loaded if the |
1888 \c GL_OES_compressed_ETC1_RGB8_texture extension is supported |
|
1889 and the ETC1 texture has been encapsulated in the PVR container format. |
|
1890 Also, textures in the PVRTC2 and PVRTC4 formats can be loaded |
|
1891 if the \c GL_IMG_texture_compression_pvrtc extension is supported. |
|
1896 |
1892 |
1897 \sa deleteTexture() |
1893 \sa deleteTexture() |
1898 */ |
1894 */ |
1899 |
1895 |
1900 GLuint QGLContext::bindTexture(const QString &fileName) |
1896 GLuint QGLContext::bindTexture(const QString &fileName) |
1901 { |
1897 { |
1902 if (!qt_glCompressedTexImage2DARB) { |
1898 Q_D(QGLContext); |
1903 qWarning("QGLContext::bindTexture(): The GL implementation does not support texture" |
1899 QGLDDSCache *dds_cache = &(d->group->m_dds_cache); |
1904 "compression extensions."); |
1900 QGLDDSCache::const_iterator it = dds_cache->constFind(fileName); |
1905 return 0; |
1901 if (it != dds_cache->constEnd()) { |
1906 } |
|
1907 |
|
1908 QGLDDSCache::const_iterator it = qgl_dds_cache()->constFind(fileName); |
|
1909 if (it != qgl_dds_cache()->constEnd()) { |
|
1910 glBindTexture(GL_TEXTURE_2D, it.value()); |
1902 glBindTexture(GL_TEXTURE_2D, it.value()); |
1911 return it.value(); |
1903 return it.value(); |
1912 } |
1904 } |
1913 |
1905 |
1914 QFile f(fileName); |
1906 QGLTexture texture(this); |
1915 f.open(QIODevice::ReadOnly); |
1907 QSize size = texture.bindCompressedTexture(fileName); |
1916 |
1908 if (!size.isValid()) |
1917 char tag[4]; |
|
1918 f.read(&tag[0], 4); |
|
1919 if (strncmp(tag,"DDS ", 4) != 0) { |
|
1920 qWarning("QGLContext::bindTexture(): not a DDS image file."); |
|
1921 return 0; |
1909 return 0; |
1922 } |
1910 |
1923 |
1911 dds_cache->insert(fileName, texture.id); |
1924 DDSFormat ddsHeader; |
1912 return texture.id; |
1925 f.read((char *) &ddsHeader, sizeof(DDSFormat)); |
|
1926 |
|
1927 if (!ddsHeader.dwLinearSize) { |
|
1928 qWarning("QGLContext::bindTexture() DDS image size is not valid."); |
|
1929 return 0; |
|
1930 } |
|
1931 |
|
1932 int factor = 4; |
|
1933 int bufferSize = 0; |
|
1934 int blockSize = 16; |
|
1935 GLenum format; |
|
1936 |
|
1937 switch(ddsHeader.ddsPixelFormat.dwFourCC) { |
|
1938 case FOURCC_DXT1: |
|
1939 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; |
|
1940 factor = 2; |
|
1941 blockSize = 8; |
|
1942 break; |
|
1943 case FOURCC_DXT3: |
|
1944 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; |
|
1945 break; |
|
1946 case FOURCC_DXT5: |
|
1947 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; |
|
1948 break; |
|
1949 default: |
|
1950 qWarning("QGLContext::bindTexture() DDS image format not supported."); |
|
1951 return 0; |
|
1952 } |
|
1953 |
|
1954 if (ddsHeader.dwMipMapCount > 1) |
|
1955 bufferSize = ddsHeader.dwLinearSize * factor; |
|
1956 else |
|
1957 bufferSize = ddsHeader.dwLinearSize; |
|
1958 |
|
1959 GLubyte *pixels = (GLubyte *) malloc(bufferSize*sizeof(GLubyte)); |
|
1960 f.seek(ddsHeader.dwSize + 4); |
|
1961 f.read((char *) pixels, bufferSize); |
|
1962 f.close(); |
|
1963 |
|
1964 GLuint tx_id; |
|
1965 glGenTextures(1, &tx_id); |
|
1966 glBindTexture(GL_TEXTURE_2D, tx_id); |
|
1967 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
|
1968 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
|
1969 |
|
1970 int size; |
|
1971 int offset = 0; |
|
1972 int w = ddsHeader.dwWidth; |
|
1973 int h = ddsHeader.dwHeight; |
|
1974 |
|
1975 // load mip-maps |
|
1976 for(int i = 0; i < (int) ddsHeader.dwMipMapCount; ++i) { |
|
1977 if (w == 0) w = 1; |
|
1978 if (h == 0) h = 1; |
|
1979 |
|
1980 size = ((w+3)/4) * ((h+3)/4) * blockSize; |
|
1981 qt_glCompressedTexImage2DARB(GL_TEXTURE_2D, i, format, w, h, 0, |
|
1982 size, pixels + offset); |
|
1983 offset += size; |
|
1984 |
|
1985 // half size for each mip-map level |
|
1986 w = w/2; |
|
1987 h = h/2; |
|
1988 } |
|
1989 |
|
1990 free(pixels); |
|
1991 |
|
1992 qgl_dds_cache()->insert(fileName, tx_id); |
|
1993 return tx_id; |
|
1994 } |
1913 } |
1995 |
1914 |
1996 static inline QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format) |
1915 static inline QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format) |
1997 { |
1916 { |
1998 if (texture_format == GL_BGRA) { |
1917 if (texture_format == GL_BGRA) { |
2135 texture = bindTexture(image, target, format, key, options); |
2054 texture = bindTexture(image, target, format, key, options); |
2136 // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null |
2055 // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null |
2137 Q_ASSERT(texture); |
2056 Q_ASSERT(texture); |
2138 |
2057 |
2139 if (texture->id > 0) |
2058 if (texture->id > 0) |
2140 const_cast<QImage &>(image).data_ptr()->is_cached = true; |
2059 QImagePixmapCleanupHooks::enableCleanupHooks(image); |
2141 |
2060 |
2142 return texture; |
2061 return texture; |
2143 } |
2062 } |
2144 |
2063 |
2145 // #define QGL_BIND_TEXTURE_DEBUG |
2064 // #define QGL_BIND_TEXTURE_DEBUG |
2065 |
|
2066 // map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout |
|
2067 static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) |
|
2068 { |
|
2069 const int width = img.width(); |
|
2070 const int height = img.height(); |
|
2071 |
|
2072 if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV |
|
2073 || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) |
|
2074 { |
|
2075 for (int i = 0; i < height; ++i) { |
|
2076 uint *p = (uint *) img.scanLine(i); |
|
2077 for (int x = 0; x < width; ++x) |
|
2078 p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); |
|
2079 } |
|
2080 } else { |
|
2081 for (int i = 0; i < height; ++i) { |
|
2082 uint *p = (uint *) img.scanLine(i); |
|
2083 for (int x = 0; x < width; ++x) |
|
2084 p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); |
|
2085 } |
|
2086 } |
|
2087 } |
|
2146 |
2088 |
2147 QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat, |
2089 QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat, |
2148 const qint64 key, QGLContext::BindOptions options) |
2090 const qint64 key, QGLContext::BindOptions options) |
2149 { |
2091 { |
2150 Q_Q(QGLContext); |
2092 Q_Q(QGLContext); |
2154 image.width(), image.height(), internalFormat, int(options)); |
2096 image.width(), image.height(), internalFormat, int(options)); |
2155 QTime time; |
2097 QTime time; |
2156 time.start(); |
2098 time.start(); |
2157 #endif |
2099 #endif |
2158 |
2100 |
2101 #ifndef QT_NO_DEBUG |
|
2102 // Reset the gl error stack...git |
|
2103 while (glGetError() != GL_NO_ERROR) ; |
|
2104 #endif |
|
2105 |
|
2159 // Scale the pixmap if needed. GL textures needs to have the |
2106 // Scale the pixmap if needed. GL textures needs to have the |
2160 // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL |
2107 // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL |
2161 // 2.0 or use the GL_TEXTURE_RECTANGLE texture target |
2108 // 2.0 or use the GL_TEXTURE_RECTANGLE texture target |
2162 int tx_w = qt_next_power_of_two(image.width()); |
2109 int tx_w = qt_next_power_of_two(image.width()); |
2163 int tx_h = qt_next_power_of_two(image.height()); |
2110 int tx_h = qt_next_power_of_two(image.height()); |
2164 |
2111 |
2165 QImage img = image; |
2112 QImage img = image; |
2166 if (( !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) && |
2113 if (!(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) |
2167 !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0) ) |
2114 && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0) |
2168 && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height()))) |
2115 && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height()))) |
2169 { |
2116 { |
2170 img = img.scaled(tx_w, tx_h); |
2117 img = img.scaled(tx_w, tx_h); |
2171 #ifdef QGL_BIND_TEXTURE_DEBUG |
2118 #ifdef QGL_BIND_TEXTURE_DEBUG |
2172 printf(" - upscaled to %dx%d (%d ms)\n", tx_w, tx_h, time.elapsed()); |
2119 printf(" - upscaled to %dx%d (%d ms)\n", tx_w, tx_h, time.elapsed()); |
2183 |
2130 |
2184 #if defined(QT_OPENGL_ES_2) |
2131 #if defined(QT_OPENGL_ES_2) |
2185 bool genMipmap = false; |
2132 bool genMipmap = false; |
2186 #endif |
2133 #endif |
2187 if (glFormat.directRendering() |
2134 if (glFormat.directRendering() |
2188 && QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap |
2135 && (QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap) |
2189 && target == GL_TEXTURE_2D |
2136 && target == GL_TEXTURE_2D |
2190 && options & QGLContext::MipmapBindOption) |
2137 && (options & QGLContext::MipmapBindOption)) |
2191 { |
2138 { |
2192 #ifdef QGL_BIND_TEXTURE_DEBUG |
2139 #ifdef QGL_BIND_TEXTURE_DEBUG |
2193 printf(" - generating mipmaps (%d ms)\n", time.elapsed()); |
2140 printf(" - generating mipmaps (%d ms)\n", time.elapsed()); |
2194 #endif |
2141 #endif |
2195 #if !defined(QT_OPENGL_ES_2) |
2142 #if !defined(QT_OPENGL_ES_2) |
2211 |
2158 |
2212 QImage::Format target_format = img.format(); |
2159 QImage::Format target_format = img.format(); |
2213 bool premul = options & QGLContext::PremultipliedAlphaBindOption; |
2160 bool premul = options & QGLContext::PremultipliedAlphaBindOption; |
2214 GLenum externalFormat; |
2161 GLenum externalFormat; |
2215 GLuint pixel_type; |
2162 GLuint pixel_type; |
2216 if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2) { |
2163 if (QGLExtensions::glExtensions & QGLExtensions::BGRATextureFormat) { |
2217 externalFormat = GL_BGRA; |
2164 externalFormat = GL_BGRA; |
2218 pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV; |
2165 pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV; |
2219 } else { |
2166 } else { |
2220 externalFormat = GL_RGBA; |
2167 externalFormat = GL_RGBA; |
2221 pixel_type = GL_UNSIGNED_BYTE; |
2168 pixel_type = GL_UNSIGNED_BYTE; |
2263 |
2210 |
2264 if (options & QGLContext::InvertedYBindOption) { |
2211 if (options & QGLContext::InvertedYBindOption) { |
2265 #ifdef QGL_BIND_TEXTURE_DEBUG |
2212 #ifdef QGL_BIND_TEXTURE_DEBUG |
2266 printf(" - flipping bits over y (%d ms)\n", time.elapsed()); |
2213 printf(" - flipping bits over y (%d ms)\n", time.elapsed()); |
2267 #endif |
2214 #endif |
2268 int ipl = img.bytesPerLine() / 4; |
2215 if (img.isDetached()) { |
2269 int h = img.height(); |
2216 int ipl = img.bytesPerLine() / 4; |
2270 for (int y=0; y<h/2; ++y) { |
2217 int h = img.height(); |
2271 int *a = (int *) img.scanLine(y); |
2218 for (int y=0; y<h/2; ++y) { |
2272 int *b = (int *) img.scanLine(h - y - 1); |
2219 int *a = (int *) img.scanLine(y); |
2273 for (int x=0; x<ipl; ++x) |
2220 int *b = (int *) img.scanLine(h - y - 1); |
2274 qSwap(a[x], b[x]); |
2221 for (int x=0; x<ipl; ++x) |
2222 qSwap(a[x], b[x]); |
|
2223 } |
|
2224 } else { |
|
2225 // Create a new image and copy across. If we use the |
|
2226 // above in-place code then a full copy of the image is |
|
2227 // made before the lines are swapped, which processes the |
|
2228 // data twice. This version should only do it once. |
|
2229 img = img.mirrored(); |
|
2275 } |
2230 } |
2276 } |
2231 } |
2277 |
2232 |
2278 if (externalFormat == GL_RGBA) { |
2233 if (externalFormat == GL_RGBA) { |
2279 #ifdef QGL_BIND_TEXTURE_DEBUG |
2234 #ifdef QGL_BIND_TEXTURE_DEBUG |
2281 #endif |
2236 #endif |
2282 // The only case where we end up with a depth different from |
2237 // The only case where we end up with a depth different from |
2283 // 32 in the switch above is for the RGB16 case, where we set |
2238 // 32 in the switch above is for the RGB16 case, where we set |
2284 // the format to GL_RGB |
2239 // the format to GL_RGB |
2285 Q_ASSERT(img.depth() == 32); |
2240 Q_ASSERT(img.depth() == 32); |
2286 const int width = img.width(); |
2241 qgl_byteSwapImage(img, pixel_type); |
2287 const int height = img.height(); |
2242 } |
2288 |
2243 #ifdef QT_OPENGL_ES |
2289 if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV |
2244 // OpenGL/ES requires that the internal and external formats be identical. |
2290 || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) { |
2245 // This is typically used to convert GL_RGBA into GL_BGRA. |
2291 for (int i=0; i < height; ++i) { |
2246 // Also, we need to use GL_UNSIGNED_BYTE when the format is GL_BGRA. |
2292 uint *p = (uint *) img.scanLine(i); |
2247 internalFormat = externalFormat; |
2293 for (int x=0; x<width; ++x) |
2248 if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV) |
2294 p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); |
2249 pixel_type = GL_UNSIGNED_BYTE; |
2295 } |
2250 #endif |
2296 } else { |
|
2297 for (int i=0; i < height; ++i) { |
|
2298 uint *p = (uint *) img.scanLine(i); |
|
2299 for (int x=0; x<width; ++x) |
|
2300 p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); |
|
2301 } |
|
2302 } |
|
2303 } |
|
2304 #ifdef QGL_BIND_TEXTURE_DEBUG |
2251 #ifdef QGL_BIND_TEXTURE_DEBUG |
2305 printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n", |
2252 printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n", |
2306 img.format(), externalFormat, internalFormat, pixel_type); |
2253 img.format(), externalFormat, internalFormat, pixel_type); |
2307 #endif |
2254 #endif |
2308 |
2255 |
2389 texture = bindTexture(pixmap.toImage(), target, format, key, options); |
2336 texture = bindTexture(pixmap.toImage(), target, format, key, options); |
2390 // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null |
2337 // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null |
2391 Q_ASSERT(texture); |
2338 Q_ASSERT(texture); |
2392 |
2339 |
2393 if (texture->id > 0) |
2340 if (texture->id > 0) |
2394 const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = true; |
2341 QImagePixmapCleanupHooks::enableCleanupHooks(pixmap); |
2395 |
2342 |
2396 return texture; |
2343 return texture; |
2397 } |
2344 } |
2398 |
2345 |
2399 /*! \internal */ |
2346 /*! \internal */ |
2438 |
2385 |
2439 \overload |
2386 \overload |
2440 */ |
2387 */ |
2441 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) |
2388 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) |
2442 { |
2389 { |
2390 if (image.isNull()) |
|
2391 return 0; |
|
2392 |
|
2443 Q_D(QGLContext); |
2393 Q_D(QGLContext); |
2444 QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption); |
2394 QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption); |
2445 return texture->id; |
2395 return texture->id; |
2446 } |
2396 } |
2447 |
2397 |
2470 |
2420 |
2471 \sa deleteTexture() |
2421 \sa deleteTexture() |
2472 */ |
2422 */ |
2473 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options) |
2423 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options) |
2474 { |
2424 { |
2425 if (image.isNull()) |
|
2426 return 0; |
|
2427 |
|
2475 Q_D(QGLContext); |
2428 Q_D(QGLContext); |
2476 QGLTexture *texture = d->bindTexture(image, target, format, false, options); |
2429 QGLTexture *texture = d->bindTexture(image, target, format, false, options); |
2477 return texture->id; |
2430 return texture->id; |
2478 } |
2431 } |
2479 |
2432 |
2480 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS |
2433 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS |
2481 /*! \internal */ |
2434 /*! \internal */ |
2482 GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) |
2435 GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) |
2483 { |
2436 { |
2437 if (image.isNull()) |
|
2438 return 0; |
|
2439 |
|
2484 Q_D(QGLContext); |
2440 Q_D(QGLContext); |
2485 QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption); |
2441 QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption); |
2486 return texture->id; |
2442 return texture->id; |
2487 } |
2443 } |
2488 |
2444 |
2489 /*! \internal */ |
2445 /*! \internal */ |
2490 GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, |
2446 GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, |
2491 BindOptions options) |
2447 BindOptions options) |
2492 { |
2448 { |
2449 if (image.isNull()) |
|
2450 return 0; |
|
2451 |
|
2493 Q_D(QGLContext); |
2452 Q_D(QGLContext); |
2494 QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options); |
2453 QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options); |
2495 return texture->id; |
2454 return texture->id; |
2496 } |
2455 } |
2497 #endif |
2456 #endif |
2500 |
2459 |
2501 Generates and binds a 2D GL texture based on \a pixmap. |
2460 Generates and binds a 2D GL texture based on \a pixmap. |
2502 */ |
2461 */ |
2503 GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) |
2462 GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) |
2504 { |
2463 { |
2464 if (pixmap.isNull()) |
|
2465 return 0; |
|
2466 |
|
2505 Q_D(QGLContext); |
2467 Q_D(QGLContext); |
2506 QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption); |
2468 QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption); |
2507 return texture->id; |
2469 return texture->id; |
2508 } |
2470 } |
2509 |
2471 |
2514 Generates and binds a 2D GL texture to the current context, based |
2476 Generates and binds a 2D GL texture to the current context, based |
2515 on \a pixmap. |
2477 on \a pixmap. |
2516 */ |
2478 */ |
2517 GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options) |
2479 GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options) |
2518 { |
2480 { |
2481 if (pixmap.isNull()) |
|
2482 return 0; |
|
2483 |
|
2519 Q_D(QGLContext); |
2484 Q_D(QGLContext); |
2520 QGLTexture *texture = d->bindTexture(pixmap, target, format, options); |
2485 QGLTexture *texture = d->bindTexture(pixmap, target, format, options); |
2521 return texture->id; |
2486 return texture->id; |
2522 } |
2487 } |
2523 |
2488 |
2524 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS |
2489 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS |
2525 /*! \internal */ |
2490 /*! \internal */ |
2526 GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format) |
2491 GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format) |
2527 { |
2492 { |
2493 if (pixmap.isNull()) |
|
2494 return 0; |
|
2495 |
|
2528 Q_D(QGLContext); |
2496 Q_D(QGLContext); |
2529 QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption); |
2497 QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption); |
2530 return texture->id; |
2498 return texture->id; |
2531 } |
2499 } |
2532 /*! \internal */ |
2500 /*! \internal */ |
2533 GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format, |
2501 GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format, |
2534 BindOptions options) |
2502 BindOptions options) |
2535 { |
2503 { |
2504 if (pixmap.isNull()) |
|
2505 return 0; |
|
2506 |
|
2536 Q_D(QGLContext); |
2507 Q_D(QGLContext); |
2537 QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options); |
2508 QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options); |
2538 return texture->id; |
2509 return texture->id; |
2539 } |
2510 } |
2540 #endif |
2511 #endif |
2546 |
2517 |
2547 \sa bindTexture() |
2518 \sa bindTexture() |
2548 */ |
2519 */ |
2549 void QGLContext::deleteTexture(GLuint id) |
2520 void QGLContext::deleteTexture(GLuint id) |
2550 { |
2521 { |
2522 Q_D(QGLContext); |
|
2523 |
|
2551 if (QGLTextureCache::instance()->remove(this, id)) |
2524 if (QGLTextureCache::instance()->remove(this, id)) |
2552 return; |
2525 return; |
2553 |
2526 |
2554 // check the DDS cache if the texture wasn't found in the pixmap/image |
2527 // check the DDS cache if the texture wasn't found in the pixmap/image |
2555 // cache |
2528 // cache |
2556 QList<QString> ddsKeys = qgl_dds_cache()->keys(); |
2529 QGLDDSCache *dds_cache = &(d->group->m_dds_cache); |
2530 QList<QString> ddsKeys = dds_cache->keys(); |
|
2557 for (int i = 0; i < ddsKeys.size(); ++i) { |
2531 for (int i = 0; i < ddsKeys.size(); ++i) { |
2558 GLuint texture = qgl_dds_cache()->value(ddsKeys.at(i)); |
2532 GLuint texture = dds_cache->value(ddsKeys.at(i)); |
2559 if (id == texture) { |
2533 if (id == texture) { |
2560 glDeleteTextures(1, &texture); |
2534 glDeleteTextures(1, &texture); |
2561 qgl_dds_cache()->remove(ddsKeys.at(i)); |
2535 dds_cache->remove(ddsKeys.at(i)); |
2562 return; |
2536 return; |
2563 } |
2537 } |
2564 } |
2538 } |
2565 } |
2539 } |
2566 |
2540 |
2997 } |
2971 } |
2998 |
2972 |
2999 bool QGLContext::isSharing() const |
2973 bool QGLContext::isSharing() const |
3000 { |
2974 { |
3001 Q_D(const QGLContext); |
2975 Q_D(const QGLContext); |
3002 return d->sharing; |
2976 return d->group->isSharing(); |
3003 } |
2977 } |
3004 |
2978 |
3005 QGLFormat QGLContext::format() const |
2979 QGLFormat QGLContext::format() const |
3006 { |
2980 { |
3007 Q_D(const QGLContext); |
2981 Q_D(const QGLContext); |
3834 // ### recreating the overlay isn't supported atm |
3808 // ### recreating the overlay isn't supported atm |
3835 } |
3809 } |
3836 } |
3810 } |
3837 |
3811 |
3838 #if defined(QT_OPENGL_ES) |
3812 #if defined(QT_OPENGL_ES) |
3813 // A re-parent is likely to destroy the X11 window and re-create it. It is important |
|
3814 // that we free the EGL surface _before_ the winID changes - otherwise we can leak. |
|
3815 if (e->type() == QEvent::ParentAboutToChange) |
|
3816 d->glcx->d_func()->destroyEglSurfaceForDevice(); |
|
3817 |
|
3839 if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) { |
3818 if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) { |
3840 // The window may have been re-created during re-parent or state change - if so, the EGL |
3819 // The window may have been re-created during re-parent or state change - if so, the EGL |
3841 // surface will need to be re-created. |
3820 // surface will need to be re-created. |
3842 d->recreateEglSurface(false); |
3821 d->recreateEglSurface(false); |
3843 } |
3822 } |
4045 #if defined (Q_WS_WIN) && !defined(QT_OPENGL_ES) |
4024 #if defined (Q_WS_WIN) && !defined(QT_OPENGL_ES) |
4046 res = QImage(w, h, QImage::Format_Indexed8); |
4025 res = QImage(w, h, QImage::Format_Indexed8); |
4047 glReadPixels(0, 0, w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, res.bits()); |
4026 glReadPixels(0, 0, w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, res.bits()); |
4048 const QVector<QColor> pal = QColormap::instance().colormap(); |
4027 const QVector<QColor> pal = QColormap::instance().colormap(); |
4049 if (pal.size()) { |
4028 if (pal.size()) { |
4050 res.setNumColors(pal.size()); |
4029 res.setColorCount(pal.size()); |
4051 for (int i = 0; i < pal.size(); i++) |
4030 for (int i = 0; i < pal.size(); i++) |
4052 res.setColor(i, pal.at(i).rgb()); |
4031 res.setColor(i, pal.at(i).rgb()); |
4053 } |
4032 } |
4054 res = res.mirrored(); |
4033 res = res.mirrored(); |
4055 #endif |
4034 #endif |
4124 #else |
4103 #else |
4125 Q_D(const QGLWidget); |
4104 Q_D(const QGLWidget); |
4126 const QGLContext *ctx = QGLContext::currentContext(); |
4105 const QGLContext *ctx = QGLContext::currentContext(); |
4127 if (ctx) { |
4106 if (ctx) { |
4128 if (ctx->format().rgba()) |
4107 if (ctx->format().rgba()) |
4129 glColor4ub(c.red(), c.green(), c.blue(), c.alpha()); |
4108 glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF()); |
4130 else if (!d->cmap.isEmpty()) { // QGLColormap in use? |
4109 else if (!d->cmap.isEmpty()) { // QGLColormap in use? |
4131 int i = d->cmap.find(c.rgb()); |
4110 int i = d->cmap.find(c.rgb()); |
4132 if (i < 0) |
4111 if (i < 0) |
4133 i = d->cmap.findNearest(c.rgb()); |
4112 i = d->cmap.findNearest(c.rgb()); |
4134 glIndexi(i); |
4113 glIndexi(i); |
4321 |
4300 |
4322 glShadeModel(GL_FLAT); |
4301 glShadeModel(GL_FLAT); |
4323 glDisable(GL_CULL_FACE); |
4302 glDisable(GL_CULL_FACE); |
4324 glDisable(GL_LIGHTING); |
4303 glDisable(GL_LIGHTING); |
4325 glDisable(GL_STENCIL_TEST); |
4304 glDisable(GL_STENCIL_TEST); |
4305 glDisable(GL_DEPTH_TEST); |
|
4326 glEnable(GL_BLEND); |
4306 glEnable(GL_BLEND); |
4327 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); |
4307 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); |
4328 } |
4308 } |
4329 |
4309 |
4330 static void qt_restore_gl_state() |
4310 static void qt_restore_gl_state() |
4374 future version of Qt. |
4354 future version of Qt. |
4375 |
4355 |
4376 \note This function clears the stencil buffer. |
4356 \note This function clears the stencil buffer. |
4377 |
4357 |
4378 \note This function is not supported on OpenGL/ES systems. |
4358 \note This function is not supported on OpenGL/ES systems. |
4359 |
|
4360 \note This function temporarily disables depth-testing when the |
|
4361 text is drawn. |
|
4362 |
|
4379 \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. |
4363 \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. |
4380 */ |
4364 */ |
4381 |
4365 |
4382 void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int) |
4366 void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int) |
4383 { |
4367 { |
4464 relative to the currently set projection and model matrices. This |
4448 relative to the currently set projection and model matrices. This |
4465 can be useful if you want to annotate models with text labels and |
4449 can be useful if you want to annotate models with text labels and |
4466 have the labels move with the model as it is rotated etc. |
4450 have the labels move with the model as it is rotated etc. |
4467 |
4451 |
4468 \note This function is not supported on OpenGL/ES systems. |
4452 \note This function is not supported on OpenGL/ES systems. |
4453 |
|
4454 \note If depth testing is enabled before this function is called, |
|
4455 then the drawn text will be depth-tested against the models that |
|
4456 have already been drawn in the scene. Use \c{glDisable(GL_DEPTH_TEST)} |
|
4457 before calling this function to annotate the models without |
|
4458 depth-testing the text. |
|
4459 |
|
4469 \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. |
4460 \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. |
4470 */ |
4461 */ |
4471 void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int) |
4462 void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int) |
4472 { |
4463 { |
4473 #ifndef QT_OPENGL_ES |
4464 #ifndef QT_OPENGL_ES |
4588 |
4579 |
4589 \sa deleteTexture() |
4580 \sa deleteTexture() |
4590 */ |
4581 */ |
4591 GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format) |
4582 GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format) |
4592 { |
4583 { |
4584 if (image.isNull()) |
|
4585 return 0; |
|
4586 |
|
4593 Q_D(QGLWidget); |
4587 Q_D(QGLWidget); |
4594 return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption); |
4588 return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption); |
4595 } |
4589 } |
4596 |
4590 |
4597 /*! |
4591 /*! |
4601 The binding \a options are a set of options used to decide how to |
4595 The binding \a options are a set of options used to decide how to |
4602 bind the texture to the context. |
4596 bind the texture to the context. |
4603 */ |
4597 */ |
4604 GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options) |
4598 GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options) |
4605 { |
4599 { |
4600 if (image.isNull()) |
|
4601 return 0; |
|
4602 |
|
4606 Q_D(QGLWidget); |
4603 Q_D(QGLWidget); |
4607 return d->glcx->bindTexture(image, target, format, options); |
4604 return d->glcx->bindTexture(image, target, format, options); |
4608 } |
4605 } |
4609 |
4606 |
4610 |
4607 |
4611 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS |
4608 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS |
4612 /*! \internal */ |
4609 /*! \internal */ |
4613 GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) |
4610 GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) |
4614 { |
4611 { |
4612 if (image.isNull()) |
|
4613 return 0; |
|
4614 |
|
4615 Q_D(QGLWidget); |
4615 Q_D(QGLWidget); |
4616 return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption); |
4616 return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption); |
4617 } |
4617 } |
4618 |
4618 |
4619 GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, |
4619 GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, |
4620 QGLContext::BindOptions options) |
4620 QGLContext::BindOptions options) |
4621 { |
4621 { |
4622 if (image.isNull()) |
|
4623 return 0; |
|
4624 |
|
4622 Q_D(QGLWidget); |
4625 Q_D(QGLWidget); |
4623 return d->glcx->bindTexture(image, GLenum(target), GLint(format), options); |
4626 return d->glcx->bindTexture(image, GLenum(target), GLint(format), options); |
4624 } |
4627 } |
4625 #endif |
4628 #endif |
4626 |
4629 |
4630 |
4633 |
4631 \sa deleteTexture() |
4634 \sa deleteTexture() |
4632 */ |
4635 */ |
4633 GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) |
4636 GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) |
4634 { |
4637 { |
4638 if (pixmap.isNull()) |
|
4639 return 0; |
|
4640 |
|
4635 Q_D(QGLWidget); |
4641 Q_D(QGLWidget); |
4636 return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption); |
4642 return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption); |
4637 } |
4643 } |
4638 |
4644 |
4639 /*! |
4645 /*! |
4838 |
4844 |
4839 #endif // QT3_SUPPORT |
4845 #endif // QT3_SUPPORT |
4840 |
4846 |
4841 void QGLExtensions::init_extensions() |
4847 void QGLExtensions::init_extensions() |
4842 { |
4848 { |
4843 QString extensions = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); |
4849 QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); |
4844 if (extensions.contains(QLatin1String("texture_rectangle"))) |
4850 |
4851 if (extensions.match("GL_ARB_texture_rectangle")) |
|
4845 glExtensions |= TextureRectangle; |
4852 glExtensions |= TextureRectangle; |
4846 if (extensions.contains(QLatin1String("multisample"))) |
4853 if (extensions.match("GL_ARB_multisample")) |
4847 glExtensions |= SampleBuffers; |
4854 glExtensions |= SampleBuffers; |
4848 if (extensions.contains(QLatin1String("generate_mipmap"))) |
4855 if (extensions.match("GL_SGIS_generate_mipmap")) |
4849 glExtensions |= GenerateMipmap; |
4856 glExtensions |= GenerateMipmap; |
4850 if (extensions.contains(QLatin1String("texture_compression_s3tc"))) |
4857 if (extensions.match("GL_ARB_texture_compression")) |
4851 glExtensions |= TextureCompression; |
4858 glExtensions |= TextureCompression; |
4852 if (extensions.contains(QLatin1String("ARB_fragment_program"))) |
4859 if (extensions.match("GL_EXT_texture_compression_s3tc")) |
4860 glExtensions |= DDSTextureCompression; |
|
4861 if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture")) |
|
4862 glExtensions |= ETC1TextureCompression; |
|
4863 if (extensions.match("GL_IMG_texture_compression_pvrtc")) |
|
4864 glExtensions |= PVRTCTextureCompression; |
|
4865 if (extensions.match("GL_ARB_fragment_program")) |
|
4853 glExtensions |= FragmentProgram; |
4866 glExtensions |= FragmentProgram; |
4854 if (extensions.contains(QLatin1String("mirrored_repeat"))) |
4867 if (extensions.match("GL_ARB_fragment_shader")) |
4868 glExtensions |= FragmentShader; |
|
4869 if (extensions.match("GL_ARB_texture_mirrored_repeat")) |
|
4855 glExtensions |= MirroredRepeat; |
4870 glExtensions |= MirroredRepeat; |
4856 if (extensions.contains(QLatin1String("EXT_framebuffer_object"))) |
4871 if (extensions.match("GL_EXT_framebuffer_object")) |
4857 glExtensions |= FramebufferObject; |
4872 glExtensions |= FramebufferObject; |
4858 if (extensions.contains(QLatin1String("EXT_stencil_two_side"))) |
4873 if (extensions.match("GL_EXT_stencil_two_side")) |
4859 glExtensions |= StencilTwoSide; |
4874 glExtensions |= StencilTwoSide; |
4860 if (extensions.contains(QLatin1String("EXT_stencil_wrap"))) |
4875 if (extensions.match("GL_EXT_stencil_wrap")) |
4861 glExtensions |= StencilWrap; |
4876 glExtensions |= StencilWrap; |
4862 if (extensions.contains(QLatin1String("EXT_packed_depth_stencil"))) |
4877 if (extensions.match("GL_EXT_packed_depth_stencil")) |
4863 glExtensions |= PackedDepthStencil; |
4878 glExtensions |= PackedDepthStencil; |
4864 if (extensions.contains(QLatin1String("GL_NV_float_buffer"))) |
4879 if (extensions.match("GL_NV_float_buffer")) |
4865 glExtensions |= NVFloatBuffer; |
4880 glExtensions |= NVFloatBuffer; |
4866 if (extensions.contains(QLatin1String("ARB_pixel_buffer_object"))) |
4881 if (extensions.match("GL_ARB_pixel_buffer_object")) |
4867 glExtensions |= PixelBufferObject; |
4882 glExtensions |= PixelBufferObject; |
4868 #if defined(QT_OPENGL_ES_2) |
4883 #if defined(QT_OPENGL_ES_2) |
4869 glExtensions |= FramebufferObject; |
4884 glExtensions |= FramebufferObject; |
4870 glExtensions |= GenerateMipmap; |
4885 glExtensions |= GenerateMipmap; |
4886 glExtensions |= FragmentShader; |
|
4871 #endif |
4887 #endif |
4872 #if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) |
4888 #if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) |
4873 if (extensions.contains(QLatin1String("OES_framebuffer_object"))) |
4889 if (extensions.match("GL_OES_framebuffer_object")) |
4874 glExtensions |= FramebufferObject; |
4890 glExtensions |= FramebufferObject; |
4875 #endif |
4891 #endif |
4876 #if defined(QT_OPENGL_ES) |
4892 #if defined(QT_OPENGL_ES) |
4877 if (extensions.contains(QLatin1String("OES_packed_depth_stencil"))) |
4893 if (extensions.match("GL_OES_packed_depth_stencil")) |
4878 glExtensions |= PackedDepthStencil; |
4894 glExtensions |= PackedDepthStencil; |
4879 #endif |
4895 #endif |
4880 if (extensions.contains(QLatin1String("ARB_framebuffer_object"))) { |
4896 if (extensions.match("GL_ARB_framebuffer_object")) { |
4881 // ARB_framebuffer_object also includes EXT_framebuffer_blit. |
4897 // ARB_framebuffer_object also includes EXT_framebuffer_blit. |
4882 glExtensions |= FramebufferObject; |
4898 glExtensions |= FramebufferObject; |
4883 glExtensions |= FramebufferBlit; |
4899 glExtensions |= FramebufferBlit; |
4884 } |
4900 } |
4885 if (extensions.contains(QLatin1String("EXT_framebuffer_blit"))) |
4901 |
4902 if (extensions.match("GL_EXT_framebuffer_blit")) |
|
4886 glExtensions |= FramebufferBlit; |
4903 glExtensions |= FramebufferBlit; |
4887 |
4904 |
4888 if (extensions.contains(QLatin1String("GL_ARB_texture_non_power_of_two"))) |
4905 if (extensions.match("GL_ARB_texture_non_power_of_two")) |
4889 glExtensions |= NPOTTextures; |
4906 glExtensions |= NPOTTextures; |
4890 |
4907 |
4891 QGLContext cx(QGLFormat::defaultFormat()); |
4908 if (extensions.match("GL_EXT_bgra")) |
4892 if (glExtensions & TextureCompression) { |
4909 glExtensions |= BGRATextureFormat; |
4893 qt_glCompressedTexImage2DARB = (pfn_glCompressedTexImage2DARB) cx.getProcAddress(QLatin1String("glCompressedTexImage2DARB")); |
|
4894 } |
|
4895 } |
4910 } |
4896 |
4911 |
4897 /* |
4912 /* |
4898 This is the shared initialization for all platforms. Called from QGLWidgetPrivate::init() |
4913 This is the shared initialization for all platforms. Called from QGLWidgetPrivate::init() |
4899 */ |
4914 */ |
5045 } else { |
5060 } else { |
5046 m_group = 0; |
5061 m_group = 0; |
5047 } |
5062 } |
5048 } |
5063 } |
5049 |
5064 |
5065 QSize QGLTexture::bindCompressedTexture |
|
5066 (const QString& fileName, const char *format) |
|
5067 { |
|
5068 QFile file(fileName); |
|
5069 if (!file.open(QIODevice::ReadOnly)) |
|
5070 return QSize(); |
|
5071 QByteArray contents = file.readAll(); |
|
5072 file.close(); |
|
5073 return bindCompressedTexture |
|
5074 (contents.constData(), contents.size(), format); |
|
5075 } |
|
5076 |
|
5077 // PVR header format for container files that store textures compressed |
|
5078 // with the ETC1, PVRTC2, and PVRTC4 encodings. Format information from the |
|
5079 // PowerVR SDK at http://www.imgtec.com/powervr/insider/powervr-sdk.asp |
|
5080 // "PVRTexTool Reference Manual, version 1.11f". |
|
5081 struct PvrHeader |
|
5082 { |
|
5083 quint32 headerSize; |
|
5084 quint32 height; |
|
5085 quint32 width; |
|
5086 quint32 mipMapCount; |
|
5087 quint32 flags; |
|
5088 quint32 dataSize; |
|
5089 quint32 bitsPerPixel; |
|
5090 quint32 redMask; |
|
5091 quint32 greenMask; |
|
5092 quint32 blueMask; |
|
5093 quint32 alphaMask; |
|
5094 quint32 magic; |
|
5095 quint32 surfaceCount; |
|
5096 }; |
|
5097 |
|
5098 #define PVR_MAGIC 0x21525650 // "PVR!" in little-endian |
|
5099 |
|
5100 #define PVR_FORMAT_MASK 0x000000FF |
|
5101 #define PVR_FORMAT_PVRTC2 0x00000018 |
|
5102 #define PVR_FORMAT_PVRTC4 0x00000019 |
|
5103 #define PVR_FORMAT_ETC1 0x00000036 |
|
5104 |
|
5105 #define PVR_HAS_MIPMAPS 0x00000100 |
|
5106 #define PVR_TWIDDLED 0x00000200 |
|
5107 #define PVR_NORMAL_MAP 0x00000400 |
|
5108 #define PVR_BORDER_ADDED 0x00000800 |
|
5109 #define PVR_CUBE_MAP 0x00001000 |
|
5110 #define PVR_FALSE_COLOR_MIPMAPS 0x00002000 |
|
5111 #define PVR_VOLUME_TEXTURE 0x00004000 |
|
5112 #define PVR_ALPHA_IN_TEXTURE 0x00008000 |
|
5113 #define PVR_VERTICAL_FLIP 0x00010000 |
|
5114 |
|
5115 #ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG |
|
5116 #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 |
|
5117 #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 |
|
5118 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 |
|
5119 #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 |
|
5120 #endif |
|
5121 |
|
5122 #ifndef GL_ETC1_RGB8_OES |
|
5123 #define GL_ETC1_RGB8_OES 0x8D64 |
|
5124 #endif |
|
5125 |
|
5126 bool QGLTexture::canBindCompressedTexture |
|
5127 (const char *buf, int len, const char *format, bool *hasAlpha) |
|
5128 { |
|
5129 if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) { |
|
5130 // Compressed texture loading only supported on little-endian |
|
5131 // systems such as x86 and ARM at the moment. |
|
5132 return false; |
|
5133 } |
|
5134 if (!format) { |
|
5135 // Auto-detect the format from the header. |
|
5136 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) { |
|
5137 *hasAlpha = true; |
|
5138 return true; |
|
5139 } else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) { |
|
5140 const PvrHeader *pvrHeader = |
|
5141 reinterpret_cast<const PvrHeader *>(buf); |
|
5142 *hasAlpha = (pvrHeader->alphaMask != 0); |
|
5143 return true; |
|
5144 } |
|
5145 } else { |
|
5146 // Validate the format against the header. |
|
5147 if (!qstricmp(format, "DDS")) { |
|
5148 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) { |
|
5149 *hasAlpha = true; |
|
5150 return true; |
|
5151 } |
|
5152 } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) { |
|
5153 if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) { |
|
5154 const PvrHeader *pvrHeader = |
|
5155 reinterpret_cast<const PvrHeader *>(buf); |
|
5156 *hasAlpha = (pvrHeader->alphaMask != 0); |
|
5157 return true; |
|
5158 } |
|
5159 } |
|
5160 } |
|
5161 return false; |
|
5162 } |
|
5163 |
|
5164 #define ctx QGLContext::currentContext() |
|
5165 |
|
5166 QSize QGLTexture::bindCompressedTexture |
|
5167 (const char *buf, int len, const char *format) |
|
5168 { |
|
5169 if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) { |
|
5170 // Compressed texture loading only supported on little-endian |
|
5171 // systems such as x86 and ARM at the moment. |
|
5172 return QSize(); |
|
5173 } |
|
5174 #if !defined(QT_OPENGL_ES) |
|
5175 if (!glCompressedTexImage2D) { |
|
5176 if (!(QGLExtensions::glExtensions & QGLExtensions::TextureCompression)) { |
|
5177 qWarning("QGLContext::bindTexture(): The GL implementation does " |
|
5178 "not support texture compression extensions."); |
|
5179 return QSize(); |
|
5180 } |
|
5181 glCompressedTexImage2D = (_glCompressedTexImage2DARB) ctx->getProcAddress(QLatin1String("glCompressedTexImage2DARB")); |
|
5182 if (!glCompressedTexImage2D) { |
|
5183 qWarning("QGLContext::bindTexture(): could not resolve " |
|
5184 "glCompressedTexImage2DARB."); |
|
5185 return QSize(); |
|
5186 } |
|
5187 } |
|
5188 #endif |
|
5189 if (!format) { |
|
5190 // Auto-detect the format from the header. |
|
5191 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) |
|
5192 return bindCompressedTextureDDS(buf, len); |
|
5193 else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) |
|
5194 return bindCompressedTexturePVR(buf, len); |
|
5195 } else { |
|
5196 // Validate the format against the header. |
|
5197 if (!qstricmp(format, "DDS")) { |
|
5198 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) |
|
5199 return bindCompressedTextureDDS(buf, len); |
|
5200 } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) { |
|
5201 if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) |
|
5202 return bindCompressedTexturePVR(buf, len); |
|
5203 } |
|
5204 } |
|
5205 return QSize(); |
|
5206 } |
|
5207 |
|
5208 QSize QGLTexture::bindCompressedTextureDDS(const char *buf, int len) |
|
5209 { |
|
5210 // We only support 2D texture loading at present. |
|
5211 if (target != GL_TEXTURE_2D) |
|
5212 return QSize(); |
|
5213 |
|
5214 // Bail out if the necessary extension is not present. |
|
5215 if (!(QGLExtensions::glExtensions & QGLExtensions::DDSTextureCompression)) { |
|
5216 qWarning("QGLContext::bindTexture(): DDS texture compression is not supported."); |
|
5217 return QSize(); |
|
5218 } |
|
5219 |
|
5220 const DDSFormat *ddsHeader = reinterpret_cast<const DDSFormat *>(buf + 4); |
|
5221 if (!ddsHeader->dwLinearSize) { |
|
5222 qWarning("QGLContext::bindTexture(): DDS image size is not valid."); |
|
5223 return QSize(); |
|
5224 } |
|
5225 |
|
5226 int blockSize = 16; |
|
5227 GLenum format; |
|
5228 |
|
5229 switch(ddsHeader->ddsPixelFormat.dwFourCC) { |
|
5230 case FOURCC_DXT1: |
|
5231 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; |
|
5232 blockSize = 8; |
|
5233 break; |
|
5234 case FOURCC_DXT3: |
|
5235 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; |
|
5236 break; |
|
5237 case FOURCC_DXT5: |
|
5238 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; |
|
5239 break; |
|
5240 default: |
|
5241 qWarning("QGLContext::bindTexture(): DDS image format not supported."); |
|
5242 return QSize(); |
|
5243 } |
|
5244 |
|
5245 const GLubyte *pixels = |
|
5246 reinterpret_cast<const GLubyte *>(buf + ddsHeader->dwSize + 4); |
|
5247 |
|
5248 glGenTextures(1, &id); |
|
5249 glBindTexture(GL_TEXTURE_2D, id); |
|
5250 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
|
5251 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
|
5252 |
|
5253 int size; |
|
5254 int offset = 0; |
|
5255 int available = len - int(ddsHeader->dwSize + 4); |
|
5256 int w = ddsHeader->dwWidth; |
|
5257 int h = ddsHeader->dwHeight; |
|
5258 |
|
5259 // load mip-maps |
|
5260 for(int i = 0; i < (int) ddsHeader->dwMipMapCount; ++i) { |
|
5261 if (w == 0) w = 1; |
|
5262 if (h == 0) h = 1; |
|
5263 |
|
5264 size = ((w+3)/4) * ((h+3)/4) * blockSize; |
|
5265 if (size > available) |
|
5266 break; |
|
5267 glCompressedTexImage2D(GL_TEXTURE_2D, i, format, w, h, 0, |
|
5268 size, pixels + offset); |
|
5269 offset += size; |
|
5270 available -= size; |
|
5271 |
|
5272 // half size for each mip-map level |
|
5273 w = w/2; |
|
5274 h = h/2; |
|
5275 } |
|
5276 |
|
5277 // DDS images are not inverted. |
|
5278 options &= ~QGLContext::InvertedYBindOption; |
|
5279 |
|
5280 return QSize(ddsHeader->dwWidth, ddsHeader->dwHeight); |
|
5281 } |
|
5282 |
|
5283 QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len) |
|
5284 { |
|
5285 // We only support 2D texture loading at present. Cube maps later. |
|
5286 if (target != GL_TEXTURE_2D) |
|
5287 return QSize(); |
|
5288 |
|
5289 // Determine which texture format we will be loading. |
|
5290 const PvrHeader *pvrHeader = reinterpret_cast<const PvrHeader *>(buf); |
|
5291 GLenum textureFormat; |
|
5292 quint32 minWidth, minHeight; |
|
5293 switch (pvrHeader->flags & PVR_FORMAT_MASK) { |
|
5294 case PVR_FORMAT_PVRTC2: |
|
5295 if (pvrHeader->alphaMask) |
|
5296 textureFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; |
|
5297 else |
|
5298 textureFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; |
|
5299 minWidth = 16; |
|
5300 minHeight = 8; |
|
5301 break; |
|
5302 |
|
5303 case PVR_FORMAT_PVRTC4: |
|
5304 if (pvrHeader->alphaMask) |
|
5305 textureFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; |
|
5306 else |
|
5307 textureFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; |
|
5308 minWidth = 8; |
|
5309 minHeight = 8; |
|
5310 break; |
|
5311 |
|
5312 case PVR_FORMAT_ETC1: |
|
5313 textureFormat = GL_ETC1_RGB8_OES; |
|
5314 minWidth = 4; |
|
5315 minHeight = 4; |
|
5316 break; |
|
5317 |
|
5318 default: |
|
5319 qWarning("QGLContext::bindTexture(): PVR image format 0x%x not supported.", int(pvrHeader->flags & PVR_FORMAT_MASK)); |
|
5320 return QSize(); |
|
5321 } |
|
5322 |
|
5323 // Bail out if the necessary extension is not present. |
|
5324 if (textureFormat == GL_ETC1_RGB8_OES) { |
|
5325 if (!(QGLExtensions::glExtensions & |
|
5326 QGLExtensions::ETC1TextureCompression)) { |
|
5327 qWarning("QGLContext::bindTexture(): ETC1 texture compression is not supported."); |
|
5328 return QSize(); |
|
5329 } |
|
5330 } else { |
|
5331 if (!(QGLExtensions::glExtensions & |
|
5332 QGLExtensions::PVRTCTextureCompression)) { |
|
5333 qWarning("QGLContext::bindTexture(): PVRTC texture compression is not supported."); |
|
5334 return QSize(); |
|
5335 } |
|
5336 } |
|
5337 |
|
5338 // Boundary check on the buffer size. |
|
5339 quint32 bufferSize = pvrHeader->headerSize + pvrHeader->dataSize; |
|
5340 if (bufferSize > quint32(len)) { |
|
5341 qWarning("QGLContext::bindTexture(): PVR image size is not valid."); |
|
5342 return QSize(); |
|
5343 } |
|
5344 |
|
5345 // Create the texture. |
|
5346 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
|
5347 glGenTextures(1, &id); |
|
5348 glBindTexture(GL_TEXTURE_2D, id); |
|
5349 if (pvrHeader->mipMapCount) { |
|
5350 if ((options & QGLContext::LinearFilteringBindOption) != 0) { |
|
5351 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
|
5352 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
|
5353 } else { |
|
5354 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
5355 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
|
5356 } |
|
5357 } else if ((options & QGLContext::LinearFilteringBindOption) != 0) { |
|
5358 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
|
5359 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
|
5360 } else { |
|
5361 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
5362 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
5363 } |
|
5364 |
|
5365 // Load the compressed mipmap levels. |
|
5366 const GLubyte *buffer = |
|
5367 reinterpret_cast<const GLubyte *>(buf + pvrHeader->headerSize); |
|
5368 bufferSize = pvrHeader->dataSize; |
|
5369 quint32 level = 0; |
|
5370 quint32 width = pvrHeader->width; |
|
5371 quint32 height = pvrHeader->height; |
|
5372 while (bufferSize > 0 && level < pvrHeader->mipMapCount) { |
|
5373 quint32 size = |
|
5374 (qMax(width, minWidth) * qMax(height, minHeight) * |
|
5375 pvrHeader->bitsPerPixel) / 8; |
|
5376 if (size > bufferSize) |
|
5377 break; |
|
5378 glCompressedTexImage2D(GL_TEXTURE_2D, GLint(level), textureFormat, |
|
5379 GLsizei(width), GLsizei(height), 0, |
|
5380 GLsizei(size), buffer); |
|
5381 width /= 2; |
|
5382 height /= 2; |
|
5383 buffer += size; |
|
5384 ++level; |
|
5385 } |
|
5386 |
|
5387 // Restore the default pixel alignment for later texture uploads. |
|
5388 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); |
|
5389 |
|
5390 // Set the invert flag for the texture. The "vertical flip" |
|
5391 // flag in PVR is the opposite sense to our sense of inversion. |
|
5392 if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0) |
|
5393 options &= ~QGLContext::InvertedYBindOption; |
|
5394 else |
|
5395 options |= QGLContext::InvertedYBindOption; |
|
5396 |
|
5397 return QSize(pvrHeader->width, pvrHeader->height); |
|
5398 } |
|
5399 |
|
5400 #undef ctx |
|
5401 |
|
5050 QT_END_NAMESPACE |
5402 QT_END_NAMESPACE |