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