26#include <ksharedptr.h>
28#include "kis_global.h"
29#include "kis_meta_registry.h"
30#include "kis_colorspace_factory_registry.h"
33#include "kis_selection.h"
34#include "kis_background.h"
35#include "kis_opengl_canvas.h"
36#include "kis_opengl_image_context.h"
40TQGLWidget *KisOpenGLImageContext::SharedContextWidget = 0;
41int KisOpenGLImageContext::SharedContextWidgetRefCount = 0;
43KisOpenGLImageContext::ImageContextMap KisOpenGLImageContext::imageContextMap;
45KisOpenGLImageContext::KisOpenGLImageContext()
52KisOpenGLImageContext::~KisOpenGLImageContext()
54 kdDebug(41001) <<
"Destroyed KisOpenGLImageContext\n";
56 --SharedContextWidgetRefCount;
57 kdDebug(41001) <<
"Shared context widget ref count now " << SharedContextWidgetRefCount << endl;
59 if (SharedContextWidgetRefCount == 0) {
61 kdDebug(41001) <<
"Deleting shared context widget\n";
62 delete SharedContextWidget;
63 SharedContextWidget = 0;
66 imageContextMap.erase(m_image);
69KisOpenGLImageContext::KisOpenGLImageContext(KisImageSP image, KisProfile *monitorProfile)
71 kdDebug(41001) <<
"Created KisOpenGLImageContext\n";
74 m_monitorProfile = monitorProfile;
76 m_displaySelection =
true;
78 if (SharedContextWidget == 0) {
79 kdDebug(41001) <<
"Creating shared context widget\n";
81 SharedContextWidget =
new TQGLWidget(KisOpenGLCanvasFormat);
84 ++SharedContextWidgetRefCount;
86 kdDebug(41001) <<
"Shared context widget ref count now " << SharedContextWidgetRefCount << endl;
88 SharedContextWidget->makeCurrent();
89 glGenTextures(1, &m_backgroundTexture);
90 generateBackgroundTexture();
92 GLint max_texture_size;
94 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
96 m_imageTextureTileWidth = TQMIN(PREFERRED_IMAGE_TEXTURE_WIDTH, max_texture_size);
97 m_imageTextureTileHeight = TQMIN(PREFERRED_IMAGE_TEXTURE_HEIGHT, max_texture_size);
99 createImageTextureTiles();
101 connect(m_image, TQ_SIGNAL(sigImageUpdated(TQRect)),
102 TQ_SLOT(slotImageUpdated(TQRect)));
103 connect(m_image, TQ_SIGNAL(sigSizeChanged(TQ_INT32, TQ_INT32)),
104 TQ_SLOT(slotImageSizeChanged(TQ_INT32, TQ_INT32)));
106 updateImageTextureTiles(m_image->bounds());
109KisOpenGLImageContextSP KisOpenGLImageContext::getImageContext(KisImageSP image, KisProfile *monitorProfile)
111 if (imageCanShareImageContext(image)) {
112 ImageContextMap::iterator it = imageContextMap.find(image);
114 if (it != imageContextMap.end()) {
116 kdDebug(41001) <<
"Sharing image context from map\n";
118 KisOpenGLImageContextSP context = (*it).second;
119 context->setMonitorProfile(monitorProfile);
123 KisOpenGLImageContext *imageContext =
new KisOpenGLImageContext(image, monitorProfile);
124 imageContextMap[image] = imageContext;
126 kdDebug(41001) <<
"Added shareable context to map\n";
131 kdDebug(41001) <<
"Creating non-shareable image context\n";
133 return new KisOpenGLImageContext(image, monitorProfile);
137bool KisOpenGLImageContext::imageCanShareImageContext(KisImageSP image)
139 if (image->colorSpace()->hasHighDynamicRange()) {
147TQGLWidget *KisOpenGLImageContext::sharedContextWidget()
const
149 return SharedContextWidget;
152void KisOpenGLImageContext::updateImageTextureTiles(
const TQRect& rect)
156 TQRect updateRect = rect & m_image->bounds();
158 if (!updateRect.isEmpty()) {
160 SharedContextWidget->makeCurrent();
162 int firstColumn = updateRect.left() / m_imageTextureTileWidth;
163 int lastColumn = updateRect.right() / m_imageTextureTileWidth;
164 int firstRow = updateRect.top() / m_imageTextureTileHeight;
165 int lastRow = updateRect.bottom() / m_imageTextureTileHeight;
167 for (
int column = firstColumn; column <= lastColumn; column++) {
168 for (
int row = firstRow; row <= lastRow; row++) {
170 TQRect tileRect(column * m_imageTextureTileWidth, row * m_imageTextureTileHeight,
171 m_imageTextureTileWidth, m_imageTextureTileHeight);
173 TQRect tileUpdateRect = tileRect & updateRect;
175 glBindTexture(GL_TEXTURE_2D, imageTextureTile(tileRect.x(), tileRect.y()));
176 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
177 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
178 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
181 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
183 TQImage tileUpdateImage = m_image->convertToTQImage(tileUpdateRect.left(), tileUpdateRect.top(),
184 tileUpdateRect.right(), tileUpdateRect.bottom(),
185 m_monitorProfile, m_exposure);
187 if (m_displaySelection) {
188 if (m_image->activeLayer() != 0) {
189 m_image->activeLayer()->paintSelection(tileUpdateImage,
190 tileUpdateRect.x(), tileUpdateRect.y(),
191 tileUpdateRect.width(), tileUpdateRect.height());
195 if (tileUpdateRect.width() == m_imageTextureTileWidth && tileUpdateRect.height() == m_imageTextureTileHeight) {
197 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_imageTextureTileWidth, m_imageTextureTileHeight, 0,
198 GL_BGRA, GL_UNSIGNED_BYTE, tileUpdateImage.bits());
200 int xOffset = tileUpdateRect.x() - tileRect.x();
201 int yOffset = tileUpdateRect.y() - tileRect.y();
203 glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, tileUpdateRect.width(), tileUpdateRect.height(),
204 GL_BGRA, GL_UNSIGNED_BYTE, tileUpdateImage.bits());
207 GLenum error = glGetError ();
209 if (error != GL_NO_ERROR)
211 kdDebug(41001) <<
"Error loading texture: " << endl;
220 return KisMetaRegistry::instance()->csRegistry()->
getColorSpace(
KisID(
"RGBA",
""),
"");
223void KisOpenGLImageContext::setMonitorProfile(KisProfile *monitorProfile)
225 if (monitorProfile != m_monitorProfile) {
226 m_monitorProfile = monitorProfile;
227 generateBackgroundTexture();
228 updateImageTextureTiles(m_image->bounds());
232void KisOpenGLImageContext::setHDRExposure(
float exposure)
234 if (exposure != m_exposure) {
235 m_exposure = exposure;
237 if (m_image->colorSpace()->hasHighDynamicRange()) {
239 updateImageTextureTiles(m_image->bounds());
244void KisOpenGLImageContext::generateBackgroundTexture()
246 SharedContextWidget->makeCurrent();
248 glBindTexture(GL_TEXTURE_2D, m_backgroundTexture);
250 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
251 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
252 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
253 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
255 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
257 TQImage backgroundImage = m_image->background()->patternTile();
260 Q_ASSERT(backgroundImage.width() == BACKGROUND_TEXTURE_WIDTH);
261 Q_ASSERT(backgroundImage.height() == BACKGROUND_TEXTURE_HEIGHT);
263 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BACKGROUND_TEXTURE_WIDTH, BACKGROUND_TEXTURE_HEIGHT, 0,
264 GL_BGRA, GL_UNSIGNED_BYTE, backgroundImage.bits());
267GLuint KisOpenGLImageContext::backgroundTexture()
const
269 return m_backgroundTexture;
272int KisOpenGLImageContext::imageTextureTileIndex(
int x,
int y)
const
274 int column = x / m_imageTextureTileWidth;
275 int row = y / m_imageTextureTileHeight;
277 return column + (row * m_numImageTextureTileColumns);
280GLuint KisOpenGLImageContext::imageTextureTile(
int pixelX,
int pixelY)
const
282 TQ_INT32 textureTileIndex = imageTextureTileIndex(pixelX, pixelY);
284 textureTileIndex = CLAMP(textureTileIndex, 0, ((TQ_INT32)m_imageTextureTiles.count()) - 1);
286 return m_imageTextureTiles[textureTileIndex];
289int KisOpenGLImageContext::imageTextureTileWidth()
const
291 return m_imageTextureTileWidth;
294int KisOpenGLImageContext::imageTextureTileHeight()
const
296 return m_imageTextureTileHeight;
299void KisOpenGLImageContext::createImageTextureTiles()
301 SharedContextWidget->makeCurrent();
303 destroyImageTextureTiles();
305 m_numImageTextureTileColumns = (m_image->width() + m_imageTextureTileWidth - 1) / m_imageTextureTileWidth;
306 int numImageTextureTileRows = (m_image->height() + m_imageTextureTileHeight - 1) / m_imageTextureTileHeight;
307 int numImageTextureTiles = m_numImageTextureTileColumns * numImageTextureTileRows;
309 m_imageTextureTiles.resize(numImageTextureTiles);
310 glGenTextures(numImageTextureTiles, &(m_imageTextureTiles[0]));
313 #define RGBA_BYTES_PER_PIXEL 4
315 TQByteArray emptyTilePixelData(m_imageTextureTileWidth * m_imageTextureTileHeight * RGBA_BYTES_PER_PIXEL);
316 emptyTilePixelData.fill(0);
318 for (
int tileIndex = 0; tileIndex < numImageTextureTiles; ++tileIndex) {
320 glBindTexture(GL_TEXTURE_2D, m_imageTextureTiles[tileIndex]);
321 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
324 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
326 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
328 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_imageTextureTileWidth, m_imageTextureTileHeight, 0,
329 GL_BGRA, GL_UNSIGNED_BYTE, &emptyTilePixelData[0]);
333void KisOpenGLImageContext::destroyImageTextureTiles()
335 if (!m_imageTextureTiles.empty()) {
336 SharedContextWidget->makeCurrent();
337 glDeleteTextures(m_imageTextureTiles.count(), &(m_imageTextureTiles[0]));
338 m_imageTextureTiles.clear();
342void KisOpenGLImageContext::update(
const TQRect& imageRect)
344 updateImageTextureTiles(imageRect);
347void KisOpenGLImageContext::setSelectionDisplayEnabled(
bool enable)
349 m_displaySelection = enable;
352void KisOpenGLImageContext::slotImageUpdated(TQRect rc)
354 TQRect r = rc & m_image->bounds();
356 updateImageTextureTiles(r);
357 emit sigImageUpdated(r);
360void KisOpenGLImageContext::slotImageSizeChanged(TQ_INT32 w, TQ_INT32 h)
362 createImageTextureTiles();
363 updateImageTextureTiles(m_image->bounds());
365 emit sigSizeChanged(w, h);
368#include "kis_opengl_image_context.moc"
KisColorSpace * getColorSpace(const KisID &csID, const TQString &profileName)
Return the colorspace + profile as named, or NULL if impossible combination.
A colorspace is the definition of a certain color model in Chalk.
Chalk has a large number of extensible resources.