chalk

kis_opengl_image_context.cpp
1/*
2 * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#ifdef HAVE_GL
24
25#include <kdebug.h>
26#include <ksharedptr.h>
27
28#include "kis_global.h"
29#include "kis_meta_registry.h"
30#include "kis_colorspace_factory_registry.h"
31#include "kis_image.h"
32#include "kis_layer.h"
33#include "kis_selection.h"
34#include "kis_background.h"
35#include "kis_opengl_canvas.h"
36#include "kis_opengl_image_context.h"
37
38using namespace std;
39
40TQGLWidget *KisOpenGLImageContext::SharedContextWidget = 0;
41int KisOpenGLImageContext::SharedContextWidgetRefCount = 0;
42
43KisOpenGLImageContext::ImageContextMap KisOpenGLImageContext::imageContextMap;
44
45KisOpenGLImageContext::KisOpenGLImageContext()
46{
47 m_image = 0;
48 m_monitorProfile = 0;
49 m_exposure = 0;
50}
51
52KisOpenGLImageContext::~KisOpenGLImageContext()
53{
54 kdDebug(41001) << "Destroyed KisOpenGLImageContext\n";
55
56 --SharedContextWidgetRefCount;
57 kdDebug(41001) << "Shared context widget ref count now " << SharedContextWidgetRefCount << endl;
58
59 if (SharedContextWidgetRefCount == 0) {
60
61 kdDebug(41001) << "Deleting shared context widget\n";
62 delete SharedContextWidget;
63 SharedContextWidget = 0;
64 }
65
66 imageContextMap.erase(m_image);
67}
68
69KisOpenGLImageContext::KisOpenGLImageContext(KisImageSP image, KisProfile *monitorProfile)
70{
71 kdDebug(41001) << "Created KisOpenGLImageContext\n";
72
73 m_image = image;
74 m_monitorProfile = monitorProfile;
75 m_exposure = 0;
76 m_displaySelection = true;
77
78 if (SharedContextWidget == 0) {
79 kdDebug(41001) << "Creating shared context widget\n";
80
81 SharedContextWidget = new TQGLWidget(KisOpenGLCanvasFormat);
82 }
83
84 ++SharedContextWidgetRefCount;
85
86 kdDebug(41001) << "Shared context widget ref count now " << SharedContextWidgetRefCount << endl;
87
88 SharedContextWidget->makeCurrent();
89 glGenTextures(1, &m_backgroundTexture);
90 generateBackgroundTexture();
91
92 GLint max_texture_size;
93
94 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
95
96 m_imageTextureTileWidth = TQMIN(PREFERRED_IMAGE_TEXTURE_WIDTH, max_texture_size);
97 m_imageTextureTileHeight = TQMIN(PREFERRED_IMAGE_TEXTURE_HEIGHT, max_texture_size);
98
99 createImageTextureTiles();
100
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)));
105
106 updateImageTextureTiles(m_image->bounds());
107}
108
109KisOpenGLImageContextSP KisOpenGLImageContext::getImageContext(KisImageSP image, KisProfile *monitorProfile)
110{
111 if (imageCanShareImageContext(image)) {
112 ImageContextMap::iterator it = imageContextMap.find(image);
113
114 if (it != imageContextMap.end()) {
115
116 kdDebug(41001) << "Sharing image context from map\n";
117
118 KisOpenGLImageContextSP context = (*it).second;
119 context->setMonitorProfile(monitorProfile);
120
121 return context;
122 } else {
123 KisOpenGLImageContext *imageContext = new KisOpenGLImageContext(image, monitorProfile);
124 imageContextMap[image] = imageContext;
125
126 kdDebug(41001) << "Added shareable context to map\n";
127
128 return imageContext;
129 }
130 } else {
131 kdDebug(41001) << "Creating non-shareable image context\n";
132
133 return new KisOpenGLImageContext(image, monitorProfile);
134 }
135}
136
137bool KisOpenGLImageContext::imageCanShareImageContext(KisImageSP image)
138{
139 if (image->colorSpace()->hasHighDynamicRange()) {
140 //XXX: and we don't have shaders...
141 return false;
142 } else {
143 return true;
144 }
145}
146
147TQGLWidget *KisOpenGLImageContext::sharedContextWidget() const
148{
149 return SharedContextWidget;
150}
151
152void KisOpenGLImageContext::updateImageTextureTiles(const TQRect& rect)
153{
154 //kdDebug() << "updateImageTextureTiles " << rect << endl;
155
156 TQRect updateRect = rect & m_image->bounds();
157
158 if (!updateRect.isEmpty()) {
159
160 SharedContextWidget->makeCurrent();
161
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;
166
167 for (int column = firstColumn; column <= lastColumn; column++) {
168 for (int row = firstRow; row <= lastRow; row++) {
169
170 TQRect tileRect(column * m_imageTextureTileWidth, row * m_imageTextureTileHeight,
171 m_imageTextureTileWidth, m_imageTextureTileHeight);
172
173 TQRect tileUpdateRect = tileRect & updateRect;
174
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);//GL_LINEAR);
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);
180
181 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
182
183 TQImage tileUpdateImage = m_image->convertToTQImage(tileUpdateRect.left(), tileUpdateRect.top(),
184 tileUpdateRect.right(), tileUpdateRect.bottom(),
185 m_monitorProfile, m_exposure);
186
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());
192 }
193 }
194
195 if (tileUpdateRect.width() == m_imageTextureTileWidth && tileUpdateRect.height() == m_imageTextureTileHeight) {
196
197 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_imageTextureTileWidth, m_imageTextureTileHeight, 0,
198 GL_BGRA, GL_UNSIGNED_BYTE, tileUpdateImage.bits());
199 } else {
200 int xOffset = tileUpdateRect.x() - tileRect.x();
201 int yOffset = tileUpdateRect.y() - tileRect.y();
202
203 glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, tileUpdateRect.width(), tileUpdateRect.height(),
204 GL_BGRA, GL_UNSIGNED_BYTE, tileUpdateImage.bits());
205 }
206
207 GLenum error = glGetError ();
208
209 if (error != GL_NO_ERROR)
210 {
211 kdDebug(41001) << "Error loading texture: " << endl;
212 }
213 }
214 }
215 }
216}
217
218KisColorSpace* KisOpenGLImageContext::textureColorSpaceForImageColorSpace(KisColorSpace */*imageColorSpace*/)
219{
220 return KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""), "");
221}
222
223void KisOpenGLImageContext::setMonitorProfile(KisProfile *monitorProfile)
224{
225 if (monitorProfile != m_monitorProfile) {
226 m_monitorProfile = monitorProfile;
227 generateBackgroundTexture();
228 updateImageTextureTiles(m_image->bounds());
229 }
230}
231
232void KisOpenGLImageContext::setHDRExposure(float exposure)
233{
234 if (exposure != m_exposure) {
235 m_exposure = exposure;
236
237 if (m_image->colorSpace()->hasHighDynamicRange()) {
238 //XXX: and we are not using shaders...
239 updateImageTextureTiles(m_image->bounds());
240 }
241 }
242}
243
244void KisOpenGLImageContext::generateBackgroundTexture()
245{
246 SharedContextWidget->makeCurrent();
247
248 glBindTexture(GL_TEXTURE_2D, m_backgroundTexture);
249
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);
254
255 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
256
257 TQImage backgroundImage = m_image->background()->patternTile();
258
259 // XXX: temp.
260 Q_ASSERT(backgroundImage.width() == BACKGROUND_TEXTURE_WIDTH);
261 Q_ASSERT(backgroundImage.height() == BACKGROUND_TEXTURE_HEIGHT);
262
263 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BACKGROUND_TEXTURE_WIDTH, BACKGROUND_TEXTURE_HEIGHT, 0,
264 GL_BGRA, GL_UNSIGNED_BYTE, backgroundImage.bits());
265}
266
267GLuint KisOpenGLImageContext::backgroundTexture() const
268{
269 return m_backgroundTexture;
270}
271
272int KisOpenGLImageContext::imageTextureTileIndex(int x, int y) const
273{
274 int column = x / m_imageTextureTileWidth;
275 int row = y / m_imageTextureTileHeight;
276
277 return column + (row * m_numImageTextureTileColumns);
278}
279
280GLuint KisOpenGLImageContext::imageTextureTile(int pixelX, int pixelY) const
281{
282 TQ_INT32 textureTileIndex = imageTextureTileIndex(pixelX, pixelY);
283
284 textureTileIndex = CLAMP(textureTileIndex, 0, ((TQ_INT32)m_imageTextureTiles.count()) - 1);
285
286 return m_imageTextureTiles[textureTileIndex];
287}
288
289int KisOpenGLImageContext::imageTextureTileWidth() const
290{
291 return m_imageTextureTileWidth;
292}
293
294int KisOpenGLImageContext::imageTextureTileHeight() const
295{
296 return m_imageTextureTileHeight;
297}
298
299void KisOpenGLImageContext::createImageTextureTiles()
300{
301 SharedContextWidget->makeCurrent();
302
303 destroyImageTextureTiles();
304
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;
308
309 m_imageTextureTiles.resize(numImageTextureTiles);
310 glGenTextures(numImageTextureTiles, &(m_imageTextureTiles[0]));
311
312 //XXX: will be float/half with shaders
313 #define RGBA_BYTES_PER_PIXEL 4
314
315 TQByteArray emptyTilePixelData(m_imageTextureTileWidth * m_imageTextureTileHeight * RGBA_BYTES_PER_PIXEL);
316 emptyTilePixelData.fill(0);
317
318 for (int tileIndex = 0; tileIndex < numImageTextureTiles; ++tileIndex) {
319
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);
325
326 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
327
328 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_imageTextureTileWidth, m_imageTextureTileHeight, 0,
329 GL_BGRA, GL_UNSIGNED_BYTE, &emptyTilePixelData[0]);
330 }
331}
332
333void KisOpenGLImageContext::destroyImageTextureTiles()
334{
335 if (!m_imageTextureTiles.empty()) {
336 SharedContextWidget->makeCurrent();
337 glDeleteTextures(m_imageTextureTiles.count(), &(m_imageTextureTiles[0]));
338 m_imageTextureTiles.clear();
339 }
340}
341
342void KisOpenGLImageContext::update(const TQRect& imageRect)
343{
344 updateImageTextureTiles(imageRect);
345}
346
347void KisOpenGLImageContext::setSelectionDisplayEnabled(bool enable)
348{
349 m_displaySelection = enable;
350}
351
352void KisOpenGLImageContext::slotImageUpdated(TQRect rc)
353{
354 TQRect r = rc & m_image->bounds();
355
356 updateImageTextureTiles(r);
357 emit sigImageUpdated(r);
358}
359
360void KisOpenGLImageContext::slotImageSizeChanged(TQ_INT32 w, TQ_INT32 h)
361{
362 createImageTextureTiles();
363 updateImageTextureTiles(m_image->bounds());
364
365 emit sigSizeChanged(w, h);
366}
367
368#include "kis_opengl_image_context.moc"
369
370#endif // HAVE_GL
371
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.
Definition kis_id.h:57