svn merge ^/trunk/blender -r55776:55813
[blender.git] / source / blender / editors / screen / glutil.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (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 Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/screen/glutil.c
27  *  \ingroup edscr
28  */
29
30
31 #include <stdio.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_userdef_types.h"
37 #include "DNA_vec_types.h"
38
39 #include "BLI_rect.h"
40 #include "BLI_utildefines.h"
41 #include "BLI_math.h"
42 #include "BLI_threads.h"
43
44 #include "BKE_blender.h"
45 #include "BKE_global.h"
46 #include "BKE_colortools.h"
47 #include "BKE_context.h"
48
49 #include "BIF_gl.h"
50 #include "BIF_glutil.h"
51
52 #include "GPU_extensions.h"
53
54 #include "IMB_colormanagement.h"
55 #include "IMB_imbuf_types.h"
56
57 #ifndef GL_CLAMP_TO_EDGE
58 #define GL_CLAMP_TO_EDGE                        0x812F
59 #endif
60
61
62 /* ******************************************** */
63
64 /* defined in BIF_gl.h */
65 const GLubyte stipple_halftone[128] = {
66         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
67         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
68         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
69         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
70         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
71         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
72         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
73         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
74         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
75         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
76         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
77         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
78         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
79         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
80         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
81         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
82
83
84 /*  repeat this pattern
85  *
86  *     X000X000
87  *     00000000
88  *     00X000X0
89  *     00000000 */
90
91
92 const GLubyte stipple_quarttone[128] = {
93         136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
94         136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
95         136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
96         136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
97         136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
98         136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
99         136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
100         136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0};
101
102
103 const GLubyte stipple_diag_stripes_pos[128] = {
104         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
105         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
106         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
107         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
108         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
109         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
110         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
111         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
112         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
113         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
114         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
115         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
116         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
117         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
118         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
119         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f};
120
121
122 const GLubyte stipple_diag_stripes_neg[128] = {
123         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
124         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
125         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
126         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
127         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
128         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
129         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
130         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
131         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
132         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
133         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
134         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
135         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
136         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
137         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
138         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80};
139
140
141 void fdrawbezier(float vec[4][3])
142 {
143         float dist;
144         float curve_res = 24, spline_step = 0.0f;
145         
146         dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
147         
148         /* check direction later, for top sockets */
149         vec[1][0] = vec[0][0] + dist;
150         vec[1][1] = vec[0][1];
151         
152         vec[2][0] = vec[3][0] - dist;
153         vec[2][1] = vec[3][1];
154         /* we can reuse the dist variable here to increment the GL curve eval amount*/
155         dist = 1.0f / curve_res;
156         
157         cpack(0x0);
158         glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
159         glBegin(GL_LINE_STRIP);
160         while (spline_step < 1.000001f) {
161 #if 0
162                 if (do_shaded)
163                         UI_ThemeColorBlend(th_col1, th_col2, spline_step);
164 #endif
165                 glEvalCoord1f(spline_step);
166                 spline_step += dist;
167         }
168         glEnd();
169 }
170
171 void fdrawline(float x1, float y1, float x2, float y2)
172 {
173         float v[2];
174         
175         glBegin(GL_LINE_STRIP);
176         v[0] = x1; v[1] = y1;
177         glVertex2fv(v);
178         v[0] = x2; v[1] = y2;
179         glVertex2fv(v);
180         glEnd();
181 }
182
183 void fdrawbox(float x1, float y1, float x2, float y2)
184 {
185         float v[2];
186         
187         glBegin(GL_LINE_STRIP);
188         
189         v[0] = x1; v[1] = y1;
190         glVertex2fv(v);
191         v[0] = x1; v[1] = y2;
192         glVertex2fv(v);
193         v[0] = x2; v[1] = y2;
194         glVertex2fv(v);
195         v[0] = x2; v[1] = y1;
196         glVertex2fv(v);
197         v[0] = x1; v[1] = y1;
198         glVertex2fv(v);
199         
200         glEnd();
201 }
202
203 void fdrawcheckerboard(float x1, float y1, float x2, float y2)
204 {
205         unsigned char col1[4] = {40, 40, 40}, col2[4] = {50, 50, 50};
206
207         GLubyte checker_stipple[32 * 32 / 8] = {
208                 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
209                 255,  0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
210                 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
211                 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
212                 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
213                 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
214                 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
215                 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255};
216         
217         glColor3ubv(col1);
218         glRectf(x1, y1, x2, y2);
219         glColor3ubv(col2);
220
221         glEnable(GL_POLYGON_STIPPLE);
222         glPolygonStipple(checker_stipple);
223         glRectf(x1, y1, x2, y2);
224         glDisable(GL_POLYGON_STIPPLE);
225 }
226
227 void sdrawline(short x1, short y1, short x2, short y2)
228 {
229         short v[2];
230         
231         glBegin(GL_LINE_STRIP);
232         v[0] = x1; v[1] = y1;
233         glVertex2sv(v);
234         v[0] = x2; v[1] = y2;
235         glVertex2sv(v);
236         glEnd();
237 }
238
239 /*
240  *     x1,y2
241  *     |  \
242  *     |   \
243  *     |    \
244  *     x1,y1-- x2,y1
245  */
246
247 static void sdrawtripoints(short x1, short y1, short x2, short y2)
248 {
249         short v[2];
250         v[0] = x1; v[1] = y1;
251         glVertex2sv(v);
252         v[0] = x1; v[1] = y2;
253         glVertex2sv(v);
254         v[0] = x2; v[1] = y1;
255         glVertex2sv(v);
256 }
257
258 void sdrawtri(short x1, short y1, short x2, short y2)
259 {
260         glBegin(GL_LINE_STRIP);
261         sdrawtripoints(x1, y1, x2, y2);
262         glEnd();
263 }
264
265 void sdrawtrifill(short x1, short y1, short x2, short y2)
266 {
267         glBegin(GL_TRIANGLES);
268         sdrawtripoints(x1, y1, x2, y2);
269         glEnd();
270 }
271
272 void sdrawbox(short x1, short y1, short x2, short y2)
273 {
274         short v[2];
275         
276         glBegin(GL_LINE_STRIP);
277         
278         v[0] = x1; v[1] = y1;
279         glVertex2sv(v);
280         v[0] = x1; v[1] = y2;
281         glVertex2sv(v);
282         v[0] = x2; v[1] = y2;
283         glVertex2sv(v);
284         v[0] = x2; v[1] = y1;
285         glVertex2sv(v);
286         v[0] = x1; v[1] = y1;
287         glVertex2sv(v);
288         
289         glEnd();
290 }
291
292
293 /* ******************************************** */
294
295 void setlinestyle(int nr)
296 {
297         if (nr == 0) {
298                 glDisable(GL_LINE_STIPPLE);
299         }
300         else {
301                 
302                 glEnable(GL_LINE_STIPPLE);
303                 if (U.pixelsize > 1.0f)
304                         glLineStipple(nr, 0xCCCC);
305                 else
306                         glLineStipple(nr, 0xAAAA);
307         }
308 }
309
310 /* Invert line handling */
311         
312 #define GL_TOGGLE(mode, onoff)  (((onoff) ? glEnable : glDisable)(mode))
313
314 void set_inverted_drawing(int enable) 
315 {
316         glLogicOp(enable ? GL_INVERT : GL_COPY);
317         GL_TOGGLE(GL_COLOR_LOGIC_OP, enable);
318         GL_TOGGLE(GL_DITHER, !enable);
319 }
320
321 void sdrawXORline(int x0, int y0, int x1, int y1)
322 {
323         if (x0 == x1 && y0 == y1) return;
324
325         set_inverted_drawing(1);
326         
327         glBegin(GL_LINES);
328         glVertex2i(x0, y0);
329         glVertex2i(x1, y1);
330         glEnd();
331         
332         set_inverted_drawing(0);
333 }
334
335 void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
336 {
337         static short old[4][2][2];
338         static char flags[4] = {0, 0, 0, 0};
339         
340         /* with builtin memory, max 4 lines */
341
342         set_inverted_drawing(1);
343                 
344         glBegin(GL_LINES);
345         if (nr == -1) { /* flush */
346                 for (nr = 0; nr < 4; nr++) {
347                         if (flags[nr]) {
348                                 glVertex2sv(old[nr][0]);
349                                 glVertex2sv(old[nr][1]);
350                                 flags[nr] = 0;
351                         }
352                 }
353         }
354         else {
355                 if (nr >= 0 && nr < 4) {
356                         if (flags[nr]) {
357                                 glVertex2sv(old[nr][0]);
358                                 glVertex2sv(old[nr][1]);
359                         }
360
361                         old[nr][0][0] = x0;
362                         old[nr][0][1] = y0;
363                         old[nr][1][0] = x1;
364                         old[nr][1][1] = y1;
365                         
366                         flags[nr] = 1;
367                 }
368                 
369                 glVertex2i(x0, y0);
370                 glVertex2i(x1, y1);
371         }
372         glEnd();
373         
374         set_inverted_drawing(0);
375 }
376
377 void fdrawXORellipse(float xofs, float yofs, float hw, float hh)
378 {
379         if (hw == 0) return;
380
381         set_inverted_drawing(1);
382
383         glPushMatrix();
384         glTranslatef(xofs, yofs, 0.0f);
385         glScalef(1.0f, hh / hw, 1.0f);
386         glutil_draw_lined_arc(0.0, M_PI * 2.0, hw, 20);
387         glPopMatrix();
388
389         set_inverted_drawing(0);
390 }
391 void fdrawXORcirc(float xofs, float yofs, float rad)
392 {
393         set_inverted_drawing(1);
394
395         glPushMatrix();
396         glTranslatef(xofs, yofs, 0.0);
397         glutil_draw_lined_arc(0.0, M_PI * 2.0, rad, 20);
398         glPopMatrix();
399
400         set_inverted_drawing(0);
401 }
402
403 void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments)
404 {
405         int i;
406         
407         glBegin(GL_TRIANGLE_FAN);
408         glVertex2f(0.0, 0.0);
409         for (i = 0; i < nsegments; i++) {
410                 float t = (float) i / (nsegments - 1);
411                 float cur = start + t * angle;
412                 
413                 glVertex2f(cosf(cur) * radius, sinf(cur) * radius);
414         }
415         glEnd();
416 }
417
418 void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments)
419 {
420         int i;
421         
422         glBegin(GL_LINE_STRIP);
423         for (i = 0; i < nsegments; i++) {
424                 float t = (float) i / (nsegments - 1);
425                 float cur = start + t * angle;
426                 
427                 glVertex2f(cosf(cur) * radius, sinf(cur) * radius);
428         }
429         glEnd();
430 }
431
432 int glaGetOneInteger(int param)
433 {
434         GLint i;
435         glGetIntegerv(param, &i);
436         return i;
437 }
438
439 float glaGetOneFloat(int param)
440 {
441         GLfloat v;
442         glGetFloatv(param, &v);
443         return v;
444 }
445
446 void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y)
447 {
448         GLubyte dummy = 0;
449
450         /* As long as known good coordinates are correct
451          * this is guaranteed to generate an ok raster
452          * position (ignoring potential (real) overflow
453          * issues).
454          */
455         glRasterPos2f(known_good_x, known_good_y);
456
457         /* Now shift the raster position to where we wanted
458          * it in the first place using the glBitmap trick.
459          */
460         glBitmap(0, 0, 0, 0, x - known_good_x, y - known_good_y, &dummy);
461 }
462
463 static int get_cached_work_texture(int *w_r, int *h_r)
464 {
465         static GLint texid = -1;
466         static int tex_w = 256;
467         static int tex_h = 256;
468
469         if (texid == -1) {
470                 GLint ltexid = glaGetOneInteger(GL_TEXTURE_2D);
471                 unsigned char *tbuf;
472
473                 glGenTextures(1, (GLuint *)&texid);
474
475                 glBindTexture(GL_TEXTURE_2D, texid);
476
477                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
478                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
479
480                 tbuf = MEM_callocN(tex_w * tex_h * 4, "tbuf");
481                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tbuf);
482                 MEM_freeN(tbuf);
483
484                 glBindTexture(GL_TEXTURE_2D, ltexid);
485         }
486
487         *w_r = tex_w;
488         *h_r = tex_h;
489         return texid;
490 }
491
492 void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY)
493 {
494         unsigned char *uc_rect = (unsigned char *) rect;
495         float *f_rect = (float *)rect;
496         float xzoom = glaGetOneFloat(GL_ZOOM_X), yzoom = glaGetOneFloat(GL_ZOOM_Y);
497         int ltexid = glaGetOneInteger(GL_TEXTURE_2D);
498         int lrowlength = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
499         int subpart_x, subpart_y, tex_w, tex_h;
500         int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
501         int texid = get_cached_work_texture(&tex_w, &tex_h);
502         int components;
503
504         /* Specify the color outside this function, and tex will modulate it.
505          * This is useful for changing alpha without using glPixelTransferf()
506          */
507         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
508         glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
509         glBindTexture(GL_TEXTURE_2D, texid);
510
511         /* don't want nasty border artifacts */
512         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
513         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
514         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter);
515
516 #ifdef __APPLE__
517         /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */
518         glPixelZoom(1.f, 1.f);
519 #endif
520         
521         /* setup seamless 2=on, 0=off */
522         seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0;
523         
524         offset_x = tex_w - seamless;
525         offset_y = tex_h - seamless;
526         
527         nsubparts_x = (img_w + (offset_x - 1)) / (offset_x);
528         nsubparts_y = (img_h + (offset_y - 1)) / (offset_y);
529
530         if (format == GL_RGBA)
531                 components = 4;
532         else if (format == GL_RGB)
533                 components = 3;
534         else if (format == GL_LUMINANCE)
535                 components = 1;
536         else {
537                 BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled");
538                 return;
539         }
540
541         if (type == GL_FLOAT) {
542                 /* need to set internal format to higher range float */
543
544                 /* NOTE: this could fail on some drivers, like mesa,
545                  *       but currently this code is only used by color
546                  *       management stuff which already checks on whether
547                  *       it's possible to use GL_RGBA16F_ARB
548                  */
549
550                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
551         }
552         else {
553                 /* switch to 8bit RGBA for byte buffer  */
554                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL);
555         }
556
557         for (subpart_y = 0; subpart_y < nsubparts_y; subpart_y++) {
558                 for (subpart_x = 0; subpart_x < nsubparts_x; subpart_x++) {
559                         int remainder_x = img_w - subpart_x * offset_x;
560                         int remainder_y = img_h - subpart_y * offset_y;
561                         int subpart_w = (remainder_x < tex_w) ? remainder_x : tex_w;
562                         int subpart_h = (remainder_y < tex_h) ? remainder_y : tex_h;
563                         int offset_left = (seamless && subpart_x != 0) ? 1 : 0;
564                         int offset_bot = (seamless && subpart_y != 0) ? 1 : 0;
565                         int offset_right = (seamless && remainder_x > tex_w) ? 1 : 0;
566                         int offset_top = (seamless && remainder_y > tex_h) ? 1 : 0;
567                         float rast_x = x + subpart_x * offset_x * xzoom;
568                         float rast_y = y + subpart_y * offset_y * yzoom;
569                         
570                         /* check if we already got these because we always get 2 more when doing seamless*/
571                         if (subpart_w <= seamless || subpart_h <= seamless)
572                                 continue;
573                         
574                         if (type == GL_FLOAT) {
575                                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
576                                 
577                                 /* add an extra border of pixels so linear looks ok at edges of full image. */
578                                 if (subpart_w < tex_w)
579                                         glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
580                                 if (subpart_h < tex_h)
581                                         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
582                                 if (subpart_w < tex_w && subpart_h < tex_h)
583                                         glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
584                         }
585                         else {
586                                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
587                                 
588                                 if (subpart_w < tex_w)
589                                         glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
590                                 if (subpart_h < tex_h)
591                                         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
592                                 if (subpart_w < tex_w && subpart_h < tex_h)
593                                         glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
594                         }
595
596                         glEnable(GL_TEXTURE_2D);
597                         glBegin(GL_QUADS);
598                         glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h);
599                         glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom);
600
601                         glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h);
602                         glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom);
603
604                         glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h);
605                         glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
606
607                         glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h);
608                         glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
609                         glEnd();
610                         glDisable(GL_TEXTURE_2D);
611                 }
612         }
613
614         glBindTexture(GL_TEXTURE_2D, ltexid);
615         glPixelStorei(GL_UNPACK_ROW_LENGTH, lrowlength);
616         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
617         
618 #ifdef __APPLE__
619         /* workaround for os x 10.5/10.6 driver bug (above) */
620         glPixelZoom(xzoom, yzoom);
621 #endif
622 }
623
624 void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect)
625 {
626         glaDrawPixelsTexScaled(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f);
627 }
628
629 void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect)
630 {
631         float xzoom = glaGetOneFloat(GL_ZOOM_X);
632         float yzoom = glaGetOneFloat(GL_ZOOM_Y);
633
634         /* The pixel space coordinate of the intersection of
635          * the [zoomed] image with the origin.
636          */
637         float ix = -x / xzoom;
638         float iy = -y / yzoom;
639                 
640         /* The maximum pixel amounts the image can be cropped
641          * at the lower left without exceeding the origin.
642          */
643         int off_x = floor(max_ff(ix, 0.0f));
644         int off_y = floor(max_ff(iy, 0.0f));
645
646         /* The zoomed space coordinate of the raster position
647          * (starting at the lower left most unclipped pixel).
648          */
649         float rast_x = x + off_x * xzoom;
650         float rast_y = y + off_y * yzoom;
651
652         GLfloat scissor[4];
653         int draw_w, draw_h;
654
655         /* Determine the smallest number of pixels we need to draw
656          * before the image would go off the upper right corner.
657          *
658          * It may seem this is just an optimization but some graphics
659          * cards (ATI) freak out if there is a large zoom factor and
660          * a large number of pixels off the screen (probably at some
661          * level the number of image pixels to draw is getting multiplied
662          * by the zoom and then clamped). Making sure we draw the
663          * fewest pixels possible keeps everyone mostly happy (still
664          * fails if we zoom in on one really huge pixel so that it
665          * covers the entire screen).
666          */
667         glGetFloatv(GL_SCISSOR_BOX, scissor);
668         draw_w = min_ii(img_w - off_x, ceil((scissor[2] - rast_x) / xzoom));
669         draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
670
671         if (draw_w > 0 && draw_h > 0) {
672                 int old_row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
673
674                 /* Don't use safe RasterPos (slower) if we can avoid it. */
675                 if (rast_x >= 0 && rast_y >= 0) {
676                         glRasterPos2f(rast_x, rast_y);
677                 }
678                 else {
679                         glaRasterPosSafe2f(rast_x, rast_y, 0, 0);
680                 }
681
682                 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_w);
683                 if (format == GL_LUMINANCE || format == GL_RED) {
684                         if (type == GL_FLOAT) {
685                                 float *f_rect = (float *)rect;
686                                 glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y * row_w + off_x));
687                         }
688                         else if (type == GL_INT || type == GL_UNSIGNED_INT) {
689                                 int *i_rect = (int *)rect;
690                                 glDrawPixels(draw_w, draw_h, format, type, i_rect + (off_y * row_w + off_x));
691                         }
692                 }
693                 else { /* RGBA */
694                         if (type == GL_FLOAT) {
695                                 float *f_rect = (float *)rect;
696                                 glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y * row_w + off_x) * 4);
697                         }
698                         else if (type == GL_UNSIGNED_BYTE) {
699                                 unsigned char *uc_rect = (unsigned char *) rect;
700                                 glDrawPixels(draw_w, draw_h, format, type, uc_rect + (off_y * row_w + off_x) * 4);
701                         }
702                 }
703                 
704                 glPixelStorei(GL_UNPACK_ROW_LENGTH,  old_row_length);
705         }
706 }
707
708 /* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */
709 void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect)
710 {
711         if (U.image_gpubuffer_limit) {
712                 /* Megapixels, use float math to prevent overflow */
713                 float img_size = ((float)img_w * (float)img_h) / (1024.0f * 1024.0f);
714                 
715                 if (U.image_gpubuffer_limit > (int)img_size) {
716                         glColor4f(1.0, 1.0, 1.0, 1.0);
717                         glaDrawPixelsTex(x, y, img_w, img_h, format, type, zoomfilter, rect);
718                         return;
719                 }
720         }
721         glaDrawPixelsSafe(x, y, img_w, img_h, img_w, format, type, rect);
722 }
723
724 /* 2D Drawing Assistance */
725
726 void glaDefine2DArea(rcti *screen_rect)
727 {
728         const int sc_w = BLI_rcti_size_x(screen_rect) + 1;
729         const int sc_h = BLI_rcti_size_y(screen_rect) + 1;
730
731         glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
732         glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
733
734         /* The GLA_PIXEL_OFS magic number is to shift the matrix so that
735          * both raster and vertex integer coordinates fall at pixel
736          * centers properly. For a longer discussion see the OpenGL
737          * Programming Guide, Appendix H, Correctness Tips.
738          */
739
740         glMatrixMode(GL_PROJECTION);
741         glLoadIdentity();
742         glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1);
743         glTranslatef(GLA_PIXEL_OFS, GLA_PIXEL_OFS, 0.0);
744
745         glMatrixMode(GL_MODELVIEW);
746         glLoadIdentity();
747 }
748
749 #if 0 /* UNUSED */
750
751 struct gla2DDrawInfo {
752         int orig_vp[4], orig_sc[4];
753         float orig_projmat[16], orig_viewmat[16];
754
755         rcti screen_rect;
756         rctf world_rect;
757
758         float wo_to_sc[2];
759 };
760
761 void gla2DGetMap(gla2DDrawInfo *di, rctf *rect) 
762 {
763         *rect = di->world_rect;
764 }
765
766 void gla2DSetMap(gla2DDrawInfo *di, rctf *rect) 
767 {
768         int sc_w, sc_h;
769         float wo_w, wo_h;
770
771         di->world_rect = *rect;
772         
773         sc_w = BLI_rcti_size_x(&di->screen_rect);
774         sc_h = BLI_rcti_size_y(&di->screen_rect);
775         wo_w = BLI_rcti_size_x(&di->world_rect);
776         wo_h = BLI_rcti_size_y(&di->world_rect);
777         
778         di->wo_to_sc[0] = sc_w / wo_w;
779         di->wo_to_sc[1] = sc_h / wo_h;
780 }
781
782 /** Save the current OpenGL state and initialize OpenGL for 2D
783  * rendering. glaEnd2DDraw should be called on the returned structure
784  * to free it and to return OpenGL to its previous state. The
785  * scissor rectangle is set to match the viewport.
786  *
787  * See glaDefine2DArea for an explanation of why this function uses integers.
788  *
789  * \param screen_rect The screen rectangle to be used for 2D drawing.
790  * \param world_rect The world rectangle that the 2D area represented
791  * by \a screen_rect is supposed to represent. If NULL it is assumed the
792  * world has a 1 to 1 mapping to the screen.
793  */
794 gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) 
795 {
796         gla2DDrawInfo *di = MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
797         int sc_w, sc_h;
798         float wo_w, wo_h;
799
800         glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp);
801         glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc);
802         glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat);
803         glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat);
804
805         di->screen_rect = *screen_rect;
806         if (world_rect) {
807                 di->world_rect = *world_rect;
808         }
809         else {
810                 di->world_rect.xmin = di->screen_rect.xmin;
811                 di->world_rect.ymin = di->screen_rect.ymin;
812                 di->world_rect.xmax = di->screen_rect.xmax;
813                 di->world_rect.ymax = di->screen_rect.ymax;
814         }
815
816         sc_w = BLI_rcti_size_x(&di->screen_rect);
817         sc_h = BLI_rcti_size_y(&di->screen_rect);
818         wo_w = BLI_rcti_size_x(&di->world_rect);
819         wo_h = BLI_rcti_size_y(&di->world_rect);
820
821         di->wo_to_sc[0] = sc_w / wo_w;
822         di->wo_to_sc[1] = sc_h / wo_h;
823
824         glaDefine2DArea(&di->screen_rect);
825
826         return di;
827 }
828
829 /**
830  * Translate the (\a wo_x, \a wo_y) point from world coordinates into screen space.
831  */
832 void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r)
833 {
834         *sc_x_r = (wo_x - di->world_rect.xmin) * di->wo_to_sc[0];
835         *sc_y_r = (wo_y - di->world_rect.ymin) * di->wo_to_sc[1];
836 }
837
838 /**
839  * Translate the \a world point from world coordiantes into screen space.
840  */
841 void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
842 {
843         screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0];
844         screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1];
845 }
846
847 /**
848  * Restores the previous OpenGL state and free's the auxilary gla data.
849  */
850 void glaEnd2DDraw(gla2DDrawInfo *di)
851 {
852         glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
853         glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
854         glMatrixMode(GL_PROJECTION);
855         glLoadMatrixf(di->orig_projmat);
856         glMatrixMode(GL_MODELVIEW);
857         glLoadMatrixf(di->orig_viewmat);
858
859         MEM_freeN(di);
860 }
861 #endif
862
863 /* **************** GL_POINT hack ************************ */
864
865 static int curmode = 0;
866 static int pointhack = 0;
867 static GLubyte Squaredot[16] = {0xff, 0xff, 0xff, 0xff,
868                                 0xff, 0xff, 0xff, 0xff,
869                                 0xff, 0xff, 0xff, 0xff,
870                                 0xff, 0xff, 0xff, 0xff};
871
872 void bglBegin(int mode)
873 {
874         curmode = mode;
875         
876         if (mode == GL_POINTS) {
877                 float value[4];
878                 glGetFloatv(GL_POINT_SIZE_RANGE, value);
879                 if (value[1] < 2.0f) {
880                         glGetFloatv(GL_POINT_SIZE, value);
881                         pointhack = floor(value[0] + 0.5f);
882                         if (pointhack > 4) pointhack = 4;
883                 }
884                 else {
885                         glBegin(mode);
886                 }
887         }
888 }
889
890 #if 0 /* UNUSED */
891 int bglPointHack(void)
892 {
893         float value[4];
894         int pointhack_px;
895         glGetFloatv(GL_POINT_SIZE_RANGE, value);
896         if (value[1] < 2.0f) {
897                 glGetFloatv(GL_POINT_SIZE, value);
898                 pointhack_px = floorf(value[0] + 0.5f);
899                 if (pointhack_px > 4) pointhack_px = 4;
900                 return pointhack_px;
901         }
902         return 0;
903 }
904 #endif
905
906 void bglVertex3fv(const float vec[3])
907 {
908         switch (curmode) {
909                 case GL_POINTS:
910                         if (pointhack) {
911                                 glRasterPos3fv(vec);
912                                 glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
913                         }
914                         else {
915                                 glVertex3fv(vec);
916                         }
917                         break;
918         }
919 }
920
921 void bglVertex3f(float x, float y, float z)
922 {
923         switch (curmode) {
924                 case GL_POINTS:
925                         if (pointhack) {
926                                 glRasterPos3f(x, y, z);
927                                 glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
928                         }
929                         else {
930                                 glVertex3f(x, y, z);
931                         }
932                         break;
933         }
934 }
935
936 void bglVertex2fv(const float vec[2])
937 {
938         switch (curmode) {
939                 case GL_POINTS:
940                         if (pointhack) {
941                                 glRasterPos2fv(vec);
942                                 glBitmap(pointhack, pointhack, (float)pointhack / 2, pointhack / 2, 0.0, 0.0, Squaredot);
943                         }
944                         else {
945                                 glVertex2fv(vec);
946                         }
947                         break;
948         }
949 }
950
951
952 void bglEnd(void)
953 {
954         if (pointhack) pointhack = 0;
955         else glEnd();
956         
957 }
958
959 /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
960 void bgl_get_mats(bglMats *mats)
961 {
962         const double badvalue = 1.0e-6;
963
964         glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
965         glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
966         glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
967         
968         /* Very strange code here - it seems that certain bad values in the
969          * modelview matrix can cause gluUnProject to give bad results. */
970         if (mats->modelview[0] < badvalue &&
971             mats->modelview[0] > -badvalue)
972         {
973                 mats->modelview[0] = 0;
974         }
975         if (mats->modelview[5] < badvalue &&
976             mats->modelview[5] > -badvalue)
977         {
978                 mats->modelview[5] = 0;
979         }
980         
981         /* Set up viewport so that gluUnProject will give correct values */
982         mats->viewport[0] = 0;
983         mats->viewport[1] = 0;
984 }
985
986 /* *************** glPolygonOffset hack ************* */
987
988 /* dist is only for ortho now... */
989 void bglPolygonOffset(float viewdist, float dist) 
990 {
991         static float winmat[16], offset = 0.0;
992         
993         if (dist != 0.0f) {
994                 float offs;
995                 
996                 // glEnable(GL_POLYGON_OFFSET_FILL);
997                 // glPolygonOffset(-1.0, -1.0);
998
999                 /* hack below is to mimic polygon offset */
1000                 glMatrixMode(GL_PROJECTION);
1001                 glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
1002                 
1003                 /* dist is from camera to center point */
1004                 
1005                 if (winmat[15] > 0.5f) offs = 0.00001f * dist * viewdist;  // ortho tweaking
1006                 else offs = 0.0005f * dist;  // should be clipping value or so...
1007                 
1008                 winmat[14] -= offs;
1009                 offset += offs;
1010                 
1011                 glLoadMatrixf(winmat);
1012                 glMatrixMode(GL_MODELVIEW);
1013         }
1014         else {
1015
1016                 glMatrixMode(GL_PROJECTION);
1017                 winmat[14] += offset;
1018                 offset = 0.0;
1019                 glLoadMatrixf(winmat);
1020                 glMatrixMode(GL_MODELVIEW);
1021         }
1022 }
1023
1024 #if 0 /* UNUSED */
1025 void bglFlush(void) 
1026 {
1027         glFlush();
1028 #ifdef __APPLE__
1029 //      if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
1030 // XXX          myswapbuffers(); //hack to get mac intel graphics to show frontbuffer
1031 #endif
1032 }
1033 #endif
1034
1035 /* **** Color management helper functions for GLSL display/transform ***** */
1036
1037 /* Draw given image buffer on a screen using GLSL for display transform */
1038 void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
1039                        ColorManagedViewSettings *view_settings,
1040                        ColorManagedDisplaySettings *display_settings)
1041 {
1042         bool force_fallback = false;
1043         bool need_fallback = true;
1044
1045         /* Early out */
1046         if (ibuf->rect == NULL && ibuf->rect_float == NULL)
1047                 return;
1048
1049         /* Dithering is not supported on GLSL yet */
1050         force_fallback = ibuf->dither != 0.0f;
1051
1052         /* Single channel images could not be transformed using GLSL yet */
1053         force_fallback = ibuf->channels == 1;
1054
1055         /* This is actually lots of crap, but currently not sure about
1056          * more clear way to bypass partial buffer update crappyness
1057          * while rendering.
1058          *
1059          * The thing is -- render engines are only updating byte and
1060          * display buffers for active render result opened in image
1061          * editor. This works fine to show render progress without
1062          * switching render layers in image editor user, but this is
1063          * completely useless for GLSL display, where we need to have
1064          * original buffer which we could color manage.
1065          *
1066          * For the time of rendering, we'll stick back to slower CPU
1067          * display buffer update. GLSL could be used as soon as some
1068          * fixes (?) are done in render itself, so we'll always have
1069          * image buffer with relevant float buffer opened while
1070          * rendering.
1071          *
1072          * On the other hand, when using Cycles, stressing GPU with
1073          * GLSL could backfire on a performance.
1074          *                                         - sergey -
1075          */
1076         if (G.is_rendering) {
1077                 /* Try to detect whether we're drawing render result,
1078                  * other images could have both rect and rect_float
1079                  * but they'll be synchronized
1080                  */
1081                 if (ibuf->rect_float && ibuf->rect &&
1082                     ((ibuf->mall & IB_rectfloat) == 0))
1083                 {
1084                         force_fallback = true;
1085                 }
1086         }
1087
1088         /* Try to draw buffer using GLSL display transform */
1089         if (force_fallback == false) {
1090                 int ok;
1091
1092                 if (ibuf->rect_float) {
1093                         if (ibuf->float_colorspace) {
1094                                 ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings,
1095                                                                                     ibuf->float_colorspace, TRUE);
1096                         }
1097                         else {
1098                                 ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, TRUE);
1099                         }
1100                 }
1101                 else {
1102                         ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings,
1103                                                                             ibuf->rect_colorspace, FALSE);
1104                 }
1105
1106                 if (ok) {
1107                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1108                         glColor4f(1.0, 1.0, 1.0, 1.0);
1109
1110                         if (ibuf->rect_float) {
1111                                 int format = 0;
1112
1113                                 if (ibuf->channels == 3)
1114                                         format = GL_RGB;
1115                                 else if (ibuf->channels == 4)
1116                                         format = GL_RGBA;
1117                                 else
1118                                         BLI_assert(!"Incompatible number of channels for GLSL display");
1119
1120                                 if (format != 0) {
1121                                         glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, format, GL_FLOAT,
1122                                                          zoomfilter, ibuf->rect_float);
1123                                 }
1124                         }
1125                         else if (ibuf->rect) {
1126                                 /* ibuf->rect is always RGBA */
1127                                 glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
1128                                                  zoomfilter, ibuf->rect);
1129                         }
1130
1131                         IMB_colormanagement_finish_glsl_draw();
1132
1133                         need_fallback = false;
1134                 }
1135         }
1136
1137         /* In case GLSL failed or not usable, fallback to glaDrawPixelsAuto */
1138         if (need_fallback) {
1139                 unsigned char *display_buffer;
1140                 void *cache_handle;
1141
1142                 display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);
1143
1144                 if (display_buffer)
1145                         glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
1146                                           zoomfilter, display_buffer);
1147
1148                 IMB_display_buffer_release(cache_handle);
1149         }
1150 }
1151
1152 void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter)
1153 {
1154         ColorManagedViewSettings *view_settings;
1155         ColorManagedDisplaySettings *display_settings;
1156
1157         IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
1158
1159         glaDrawImBuf_glsl(ibuf, x, y, zoomfilter, view_settings, display_settings);
1160 }
1161
1162 /* Transform buffer from role to scene linear space using GLSL OCIO conversion
1163  *
1164  * See IMB_colormanagement_setup_transform_from_role_glsl description for
1165  * some more details
1166  *
1167  * NOTE: this only works for RGBA buffers!
1168  */
1169 int glaBufferTransformFromRole_glsl(float *buffer, int width, int height, int role)
1170 {
1171         GPUOffScreen *ofs;
1172         char err_out[256];
1173         rcti display_rect;
1174
1175         ofs = GPU_offscreen_create(width, height, err_out);
1176
1177         if (!ofs)
1178                 return FALSE;
1179
1180         GPU_offscreen_bind(ofs);
1181
1182         if (!IMB_colormanagement_setup_transform_from_role_glsl(role, TRUE)) {
1183                 GPU_offscreen_unbind(ofs);
1184                 GPU_offscreen_free(ofs);
1185                 return FALSE;
1186         }
1187
1188         BLI_rcti_init(&display_rect, 0, width, 0, height);
1189
1190         glMatrixMode(GL_PROJECTION);
1191         glPushMatrix();
1192         glMatrixMode(GL_MODELVIEW);
1193         glPushMatrix();
1194
1195         glaDefine2DArea(&display_rect);
1196
1197         glaDrawPixelsTex(0, 0, width, height, GL_RGBA, GL_FLOAT,
1198                          GL_NEAREST, buffer);
1199
1200         glMatrixMode(GL_PROJECTION);
1201         glPopMatrix();
1202         glMatrixMode(GL_MODELVIEW);
1203         glPopMatrix();
1204
1205         GPU_offscreen_read_pixels(ofs, GL_FLOAT, buffer);
1206
1207         IMB_colormanagement_finish_glsl_transform();
1208
1209         /* unbind */
1210         GPU_offscreen_unbind(ofs);
1211         GPU_offscreen_free(ofs);
1212
1213         return TRUE;
1214 }