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