00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 #include <config.h>
00021 #endif
00022
00023 #ifdef HAVE_GL
00024
00025 #include <kdebug.h>
00026 #include <ksharedptr.h>
00027
00028 #include "kis_global.h"
00029 #include "kis_meta_registry.h"
00030 #include "kis_colorspace_factory_registry.h"
00031 #include "kis_image.h"
00032 #include "kis_layer.h"
00033 #include "kis_selection.h"
00034 #include "kis_background.h"
00035 #include "kis_opengl_canvas.h"
00036 #include "kis_opengl_image_context.h"
00037
00038 using namespace std;
00039
00040 QGLWidget *KisOpenGLImageContext::SharedContextWidget = 0;
00041 int KisOpenGLImageContext::SharedContextWidgetRefCount = 0;
00042
00043 KisOpenGLImageContext::ImageContextMap KisOpenGLImageContext::imageContextMap;
00044
00045 KisOpenGLImageContext::KisOpenGLImageContext()
00046 {
00047 m_image = 0;
00048 m_monitorProfile = 0;
00049 m_exposure = 0;
00050 }
00051
00052 KisOpenGLImageContext::~KisOpenGLImageContext()
00053 {
00054 kdDebug(41001) << "Destroyed KisOpenGLImageContext\n";
00055
00056 --SharedContextWidgetRefCount;
00057 kdDebug(41001) << "Shared context widget ref count now " << SharedContextWidgetRefCount << endl;
00058
00059 if (SharedContextWidgetRefCount == 0) {
00060
00061 kdDebug(41001) << "Deleting shared context widget\n";
00062 delete SharedContextWidget;
00063 SharedContextWidget = 0;
00064 }
00065
00066 imageContextMap.erase(m_image);
00067 }
00068
00069 KisOpenGLImageContext::KisOpenGLImageContext(KisImageSP image, KisProfile *monitorProfile)
00070 {
00071 kdDebug(41001) << "Created KisOpenGLImageContext\n";
00072
00073 m_image = image;
00074 m_monitorProfile = monitorProfile;
00075 m_exposure = 0;
00076 m_displaySelection = true;
00077
00078 if (SharedContextWidget == 0) {
00079 kdDebug(41001) << "Creating shared context widget\n";
00080
00081 SharedContextWidget = new QGLWidget(KisOpenGLCanvasFormat);
00082 }
00083
00084 ++SharedContextWidgetRefCount;
00085
00086 kdDebug(41001) << "Shared context widget ref count now " << SharedContextWidgetRefCount << endl;
00087
00088 SharedContextWidget->makeCurrent();
00089 glGenTextures(1, &m_backgroundTexture);
00090 generateBackgroundTexture();
00091
00092 GLint max_texture_size;
00093
00094 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
00095
00096 m_imageTextureTileWidth = QMIN(PREFERRED_IMAGE_TEXTURE_WIDTH, max_texture_size);
00097 m_imageTextureTileHeight = QMIN(PREFERRED_IMAGE_TEXTURE_HEIGHT, max_texture_size);
00098
00099 createImageTextureTiles();
00100
00101 connect(m_image, SIGNAL(sigImageUpdated(QRect)),
00102 SLOT(slotImageUpdated(QRect)));
00103 connect(m_image, SIGNAL(sigSizeChanged(Q_INT32, Q_INT32)),
00104 SLOT(slotImageSizeChanged(Q_INT32, Q_INT32)));
00105
00106 updateImageTextureTiles(m_image->bounds());
00107 }
00108
00109 KisOpenGLImageContextSP KisOpenGLImageContext::getImageContext(KisImageSP image, KisProfile *monitorProfile)
00110 {
00111 if (imageCanShareImageContext(image)) {
00112 ImageContextMap::iterator it = imageContextMap.find(image);
00113
00114 if (it != imageContextMap.end()) {
00115
00116 kdDebug(41001) << "Sharing image context from map\n";
00117
00118 KisOpenGLImageContextSP context = (*it).second;
00119 context->setMonitorProfile(monitorProfile);
00120
00121 return context;
00122 } else {
00123 KisOpenGLImageContext *imageContext = new KisOpenGLImageContext(image, monitorProfile);
00124 imageContextMap[image] = imageContext;
00125
00126 kdDebug(41001) << "Added shareable context to map\n";
00127
00128 return imageContext;
00129 }
00130 } else {
00131 kdDebug(41001) << "Creating non-shareable image context\n";
00132
00133 return new KisOpenGLImageContext(image, monitorProfile);
00134 }
00135 }
00136
00137 bool KisOpenGLImageContext::imageCanShareImageContext(KisImageSP image)
00138 {
00139 if (image->colorSpace()->hasHighDynamicRange()) {
00140
00141 return false;
00142 } else {
00143 return true;
00144 }
00145 }
00146
00147 QGLWidget *KisOpenGLImageContext::sharedContextWidget() const
00148 {
00149 return SharedContextWidget;
00150 }
00151
00152 void KisOpenGLImageContext::updateImageTextureTiles(const QRect& rect)
00153 {
00154
00155
00156 QRect updateRect = rect & m_image->bounds();
00157
00158 if (!updateRect.isEmpty()) {
00159
00160 SharedContextWidget->makeCurrent();
00161
00162 int firstColumn = updateRect.left() / m_imageTextureTileWidth;
00163 int lastColumn = updateRect.right() / m_imageTextureTileWidth;
00164 int firstRow = updateRect.top() / m_imageTextureTileHeight;
00165 int lastRow = updateRect.bottom() / m_imageTextureTileHeight;
00166
00167 for (int column = firstColumn; column <= lastColumn; column++) {
00168 for (int row = firstRow; row <= lastRow; row++) {
00169
00170 QRect tileRect(column * m_imageTextureTileWidth, row * m_imageTextureTileHeight,
00171 m_imageTextureTileWidth, m_imageTextureTileHeight);
00172
00173 QRect tileUpdateRect = tileRect & updateRect;
00174
00175 glBindTexture(GL_TEXTURE_2D, imageTextureTile(tileRect.x(), tileRect.y()));
00176 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00177 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00178 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00180
00181 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00182
00183 QImage tileUpdateImage = m_image->convertToQImage(tileUpdateRect.left(), tileUpdateRect.top(),
00184 tileUpdateRect.right(), tileUpdateRect.bottom(),
00185 m_monitorProfile, m_exposure);
00186
00187 if (m_displaySelection) {
00188 if (m_image->activeLayer() != 0) {
00189 m_image->activeLayer()->paintSelection(tileUpdateImage,
00190 tileUpdateRect.x(), tileUpdateRect.y(),
00191 tileUpdateRect.width(), tileUpdateRect.height());
00192 }
00193 }
00194
00195 if (tileUpdateRect.width() == m_imageTextureTileWidth && tileUpdateRect.height() == m_imageTextureTileHeight) {
00196
00197 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_imageTextureTileWidth, m_imageTextureTileHeight, 0,
00198 GL_BGRA, GL_UNSIGNED_BYTE, tileUpdateImage.bits());
00199 } else {
00200 int xOffset = tileUpdateRect.x() - tileRect.x();
00201 int yOffset = tileUpdateRect.y() - tileRect.y();
00202
00203 glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, tileUpdateRect.width(), tileUpdateRect.height(),
00204 GL_BGRA, GL_UNSIGNED_BYTE, tileUpdateImage.bits());
00205 }
00206
00207 GLenum error = glGetError ();
00208
00209 if (error != GL_NO_ERROR)
00210 {
00211 kdDebug(41001) << "Error loading texture: " << endl;
00212 }
00213 }
00214 }
00215 }
00216 }
00217
00218 KisColorSpace* KisOpenGLImageContext::textureColorSpaceForImageColorSpace(KisColorSpace *)
00219 {
00220 return KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""), "");
00221 }
00222
00223 void KisOpenGLImageContext::setMonitorProfile(KisProfile *monitorProfile)
00224 {
00225 if (monitorProfile != m_monitorProfile) {
00226 m_monitorProfile = monitorProfile;
00227 generateBackgroundTexture();
00228 updateImageTextureTiles(m_image->bounds());
00229 }
00230 }
00231
00232 void KisOpenGLImageContext::setHDRExposure(float exposure)
00233 {
00234 if (exposure != m_exposure) {
00235 m_exposure = exposure;
00236
00237 if (m_image->colorSpace()->hasHighDynamicRange()) {
00238
00239 updateImageTextureTiles(m_image->bounds());
00240 }
00241 }
00242 }
00243
00244 void KisOpenGLImageContext::generateBackgroundTexture()
00245 {
00246 SharedContextWidget->makeCurrent();
00247
00248 glBindTexture(GL_TEXTURE_2D, m_backgroundTexture);
00249
00250 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00251 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00252 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00253 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00254
00255 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00256
00257 QImage backgroundImage = m_image->background()->patternTile();
00258
00259
00260 Q_ASSERT(backgroundImage.width() == BACKGROUND_TEXTURE_WIDTH);
00261 Q_ASSERT(backgroundImage.height() == BACKGROUND_TEXTURE_HEIGHT);
00262
00263 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BACKGROUND_TEXTURE_WIDTH, BACKGROUND_TEXTURE_HEIGHT, 0,
00264 GL_BGRA, GL_UNSIGNED_BYTE, backgroundImage.bits());
00265 }
00266
00267 GLuint KisOpenGLImageContext::backgroundTexture() const
00268 {
00269 return m_backgroundTexture;
00270 }
00271
00272 int KisOpenGLImageContext::imageTextureTileIndex(int x, int y) const
00273 {
00274 int column = x / m_imageTextureTileWidth;
00275 int row = y / m_imageTextureTileHeight;
00276
00277 return column + (row * m_numImageTextureTileColumns);
00278 }
00279
00280 GLuint KisOpenGLImageContext::imageTextureTile(int pixelX, int pixelY) const
00281 {
00282 Q_INT32 textureTileIndex = imageTextureTileIndex(pixelX, pixelY);
00283
00284 textureTileIndex = CLAMP(textureTileIndex, 0, ((Q_INT32)m_imageTextureTiles.count()) - 1);
00285
00286 return m_imageTextureTiles[textureTileIndex];
00287 }
00288
00289 int KisOpenGLImageContext::imageTextureTileWidth() const
00290 {
00291 return m_imageTextureTileWidth;
00292 }
00293
00294 int KisOpenGLImageContext::imageTextureTileHeight() const
00295 {
00296 return m_imageTextureTileHeight;
00297 }
00298
00299 void KisOpenGLImageContext::createImageTextureTiles()
00300 {
00301 SharedContextWidget->makeCurrent();
00302
00303 destroyImageTextureTiles();
00304
00305 m_numImageTextureTileColumns = (m_image->width() + m_imageTextureTileWidth - 1) / m_imageTextureTileWidth;
00306 int numImageTextureTileRows = (m_image->height() + m_imageTextureTileHeight - 1) / m_imageTextureTileHeight;
00307 int numImageTextureTiles = m_numImageTextureTileColumns * numImageTextureTileRows;
00308
00309 m_imageTextureTiles.resize(numImageTextureTiles);
00310 glGenTextures(numImageTextureTiles, &(m_imageTextureTiles[0]));
00311
00312
00313 #define RGBA_BYTES_PER_PIXEL 4
00314
00315 QByteArray emptyTilePixelData(m_imageTextureTileWidth * m_imageTextureTileHeight * RGBA_BYTES_PER_PIXEL);
00316 emptyTilePixelData.fill(0);
00317
00318 for (int tileIndex = 0; tileIndex < numImageTextureTiles; ++tileIndex) {
00319
00320 glBindTexture(GL_TEXTURE_2D, m_imageTextureTiles[tileIndex]);
00321 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00324 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00325
00326 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00327
00328 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_imageTextureTileWidth, m_imageTextureTileHeight, 0,
00329 GL_BGRA, GL_UNSIGNED_BYTE, &emptyTilePixelData[0]);
00330 }
00331 }
00332
00333 void KisOpenGLImageContext::destroyImageTextureTiles()
00334 {
00335 if (!m_imageTextureTiles.empty()) {
00336 SharedContextWidget->makeCurrent();
00337 glDeleteTextures(m_imageTextureTiles.count(), &(m_imageTextureTiles[0]));
00338 m_imageTextureTiles.clear();
00339 }
00340 }
00341
00342 void KisOpenGLImageContext::update(const QRect& imageRect)
00343 {
00344 updateImageTextureTiles(imageRect);
00345 }
00346
00347 void KisOpenGLImageContext::setSelectionDisplayEnabled(bool enable)
00348 {
00349 m_displaySelection = enable;
00350 }
00351
00352 void KisOpenGLImageContext::slotImageUpdated(QRect rc)
00353 {
00354 QRect r = rc & m_image->bounds();
00355
00356 updateImageTextureTiles(r);
00357 emit sigImageUpdated(r);
00358 }
00359
00360 void KisOpenGLImageContext::slotImageSizeChanged(Q_INT32 w, Q_INT32 h)
00361 {
00362 createImageTextureTiles();
00363 updateImageTextureTiles(m_image->bounds());
00364
00365 emit sigSizeChanged(w, h);
00366 }
00367
00368 #include "kis_opengl_image_context.moc"
00369
00370 #endif // HAVE_GL
00371