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