code cleanup: unused functions
[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 /** Save the current OpenGL state and initialize OpenGL for 2D
763  * rendering. glaEnd2DDraw should be called on the returned structure
764  * to free it and to return OpenGL to its previous state. The
765  * scissor rectangle is set to match the viewport.
766  *
767  * See glaDefine2DArea for an explanation of why this function uses integers.
768  *
769  * \param screen_rect The screen rectangle to be used for 2D drawing.
770  * \param world_rect The world rectangle that the 2D area represented
771  * by \a screen_rect is supposed to represent. If NULL it is assumed the
772  * world has a 1 to 1 mapping to the screen.
773  */
774 gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) 
775 {
776         gla2DDrawInfo *di = MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
777         int sc_w, sc_h;
778         float wo_w, wo_h;
779
780         glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp);
781         glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc);
782         glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat);
783         glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat);
784
785         di->screen_rect = *screen_rect;
786         if (world_rect) {
787                 di->world_rect = *world_rect;
788         }
789         else {
790                 di->world_rect.xmin = di->screen_rect.xmin;
791                 di->world_rect.ymin = di->screen_rect.ymin;
792                 di->world_rect.xmax = di->screen_rect.xmax;
793                 di->world_rect.ymax = di->screen_rect.ymax;
794         }
795
796         sc_w = BLI_rcti_size_x(&di->screen_rect);
797         sc_h = BLI_rcti_size_y(&di->screen_rect);
798         wo_w = BLI_rcti_size_x(&di->world_rect);
799         wo_h = BLI_rcti_size_y(&di->world_rect);
800
801         di->wo_to_sc[0] = sc_w / wo_w;
802         di->wo_to_sc[1] = sc_h / wo_h;
803
804         glaDefine2DArea(&di->screen_rect);
805
806         return di;
807 }
808
809 /**
810  * Translate the (\a wo_x, \a wo_y) point from world coordinates into screen space.
811  */
812 void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r)
813 {
814         *sc_x_r = (wo_x - di->world_rect.xmin) * di->wo_to_sc[0];
815         *sc_y_r = (wo_y - di->world_rect.ymin) * di->wo_to_sc[1];
816 }
817
818 /**
819  * Translate the \a world point from world coordiantes into screen space.
820  */
821 void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
822 {
823         screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0];
824         screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1];
825 }
826
827 /**
828  * Restores the previous OpenGL state and free's the auxilary gla data.
829  */
830 void glaEnd2DDraw(gla2DDrawInfo *di)
831 {
832         glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
833         glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
834         glMatrixMode(GL_PROJECTION);
835         glLoadMatrixf(di->orig_projmat);
836         glMatrixMode(GL_MODELVIEW);
837         glLoadMatrixf(di->orig_viewmat);
838
839         MEM_freeN(di);
840 }
841 #endif
842
843 /* **************** GL_POINT hack ************************ */
844
845 static int curmode = 0;
846 static int pointhack = 0;
847 static GLubyte Squaredot[16] = {0xff, 0xff, 0xff, 0xff,
848                                 0xff, 0xff, 0xff, 0xff,
849                                 0xff, 0xff, 0xff, 0xff,
850                                 0xff, 0xff, 0xff, 0xff};
851
852 void bglBegin(int mode)
853 {
854         curmode = mode;
855         
856         if (mode == GL_POINTS) {
857                 float value[4];
858                 glGetFloatv(GL_POINT_SIZE_RANGE, value);
859                 if (value[1] < 2.0f) {
860                         glGetFloatv(GL_POINT_SIZE, value);
861                         pointhack = floor(value[0] + 0.5f);
862                         if (pointhack > 4) pointhack = 4;
863                 }
864                 else {
865                         glBegin(mode);
866                 }
867         }
868 }
869
870 #if 0 /* UNUSED */
871 int bglPointHack(void)
872 {
873         float value[4];
874         int pointhack_px;
875         glGetFloatv(GL_POINT_SIZE_RANGE, value);
876         if (value[1] < 2.0f) {
877                 glGetFloatv(GL_POINT_SIZE, value);
878                 pointhack_px = floorf(value[0] + 0.5f);
879                 if (pointhack_px > 4) pointhack_px = 4;
880                 return pointhack_px;
881         }
882         return 0;
883 }
884 #endif
885
886 void bglVertex3fv(const float vec[3])
887 {
888         switch (curmode) {
889                 case GL_POINTS:
890                         if (pointhack) {
891                                 glRasterPos3fv(vec);
892                                 glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
893                         }
894                         else {
895                                 glVertex3fv(vec);
896                         }
897                         break;
898         }
899 }
900
901 void bglVertex3f(float x, float y, float z)
902 {
903         switch (curmode) {
904                 case GL_POINTS:
905                         if (pointhack) {
906                                 glRasterPos3f(x, y, z);
907                                 glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
908                         }
909                         else {
910                                 glVertex3f(x, y, z);
911                         }
912                         break;
913         }
914 }
915
916 void bglVertex2fv(const float vec[2])
917 {
918         switch (curmode) {
919                 case GL_POINTS:
920                         if (pointhack) {
921                                 glRasterPos2fv(vec);
922                                 glBitmap(pointhack, pointhack, (float)pointhack / 2, pointhack / 2, 0.0, 0.0, Squaredot);
923                         }
924                         else {
925                                 glVertex2fv(vec);
926                         }
927                         break;
928         }
929 }
930
931
932 void bglEnd(void)
933 {
934         if (pointhack) pointhack = 0;
935         else glEnd();
936         
937 }
938
939 /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
940 void bgl_get_mats(bglMats *mats)
941 {
942         const double badvalue = 1.0e-6;
943
944         glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
945         glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
946         glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
947         
948         /* Very strange code here - it seems that certain bad values in the
949          * modelview matrix can cause gluUnProject to give bad results. */
950         if (mats->modelview[0] < badvalue &&
951             mats->modelview[0] > -badvalue)
952         {
953                 mats->modelview[0] = 0;
954         }
955         if (mats->modelview[5] < badvalue &&
956             mats->modelview[5] > -badvalue)
957         {
958                 mats->modelview[5] = 0;
959         }
960         
961         /* Set up viewport so that gluUnProject will give correct values */
962         mats->viewport[0] = 0;
963         mats->viewport[1] = 0;
964 }
965
966 /* *************** glPolygonOffset hack ************* */
967
968 /* dist is only for ortho now... */
969 void bglPolygonOffset(float viewdist, float dist) 
970 {
971         static float winmat[16], offset = 0.0;
972         
973         if (dist != 0.0f) {
974                 float offs;
975                 
976                 // glEnable(GL_POLYGON_OFFSET_FILL);
977                 // glPolygonOffset(-1.0, -1.0);
978
979                 /* hack below is to mimic polygon offset */
980                 glMatrixMode(GL_PROJECTION);
981                 glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
982                 
983                 /* dist is from camera to center point */
984                 
985                 if (winmat[15] > 0.5f) offs = 0.00001f * dist * viewdist;  // ortho tweaking
986                 else offs = 0.0005f * dist;  // should be clipping value or so...
987                 
988                 winmat[14] -= offs;
989                 offset += offs;
990                 
991                 glLoadMatrixf(winmat);
992                 glMatrixMode(GL_MODELVIEW);
993         }
994         else {
995
996                 glMatrixMode(GL_PROJECTION);
997                 winmat[14] += offset;
998                 offset = 0.0;
999                 glLoadMatrixf(winmat);
1000                 glMatrixMode(GL_MODELVIEW);
1001         }
1002 }
1003
1004 #if 0 /* UNUSED */
1005 void bglFlush(void) 
1006 {
1007         glFlush();
1008 #ifdef __APPLE__
1009 //      if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
1010 // XXX          myswapbuffers(); //hack to get mac intel graphics to show frontbuffer
1011 #endif
1012 }
1013 #endif
1014
1015 /* **** Color management helper functions for GLSL display/transform ***** */
1016
1017 /* Draw given image buffer on a screen using GLSL for display transform */
1018 void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter)
1019 {
1020         bool need_fallback = true;
1021
1022         /* Bytes and dithering are not supported on GLSL yet */
1023
1024         /* WORKAROUND: only use GLSL if there's no byte buffer at all,
1025          *             this is because of how render results are handled,
1026          *             they're not updating image buffer's float buffer,
1027          *             but writes data directly to it's byte buffer and
1028          *             modifies display buffer.
1029          */
1030         if (ibuf->rect == NULL && ibuf->rect_float && ibuf->dither == 0.0f) {
1031                 if (IMB_colormanagement_setup_glsl_draw_from_ctx(C)) {
1032                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1033                         glColor4f(1.0, 1.0, 1.0, 1.0);
1034
1035                         glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_FLOAT, zoomfilter, ibuf->rect_float);
1036
1037                         IMB_colormanagement_finish_glsl_draw();
1038
1039                         need_fallback = false;
1040                 }
1041         }
1042
1043         if (need_fallback) {
1044                 unsigned char *display_buffer;
1045                 void *cache_handle;
1046
1047                 display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
1048
1049                 if (display_buffer)
1050                         glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, zoomfilter, display_buffer);
1051
1052                 IMB_display_buffer_release(cache_handle);
1053         }
1054 }
1055
1056 /* Transform buffer from role to scene linear space using GLSL OCIO conversion
1057  *
1058  * See IMB_colormanagement_setup_transform_from_role_glsl description for
1059  * some more details
1060  */
1061 int glaBufferTransformFromRole_glsl(float *buffer, int width, int height, int role)
1062 {
1063         GPUOffScreen *ofs;
1064         char err_out[256];
1065         rcti display_rect;
1066
1067         ofs = GPU_offscreen_create(width, height, err_out);
1068
1069         if (!ofs)
1070                 return FALSE;
1071
1072         GPU_offscreen_bind(ofs);
1073
1074         if (!IMB_colormanagement_setup_transform_from_role_glsl(role)) {
1075                 GPU_offscreen_unbind(ofs);
1076                 GPU_offscreen_free(ofs);
1077                 return FALSE;
1078         }
1079
1080         BLI_rcti_init(&display_rect, 0, width, 0, height);
1081
1082         glMatrixMode(GL_PROJECTION);
1083         glPushMatrix();
1084         glMatrixMode(GL_MODELVIEW);
1085         glPushMatrix();
1086
1087         glaDefine2DArea(&display_rect);
1088         glLoadIdentity();
1089
1090         glaDrawPixelsTex(0, 0, width, height, GL_FLOAT, GL_NEAREST, buffer);
1091
1092         glMatrixMode(GL_PROJECTION);
1093         glPopMatrix();
1094         glMatrixMode(GL_MODELVIEW);
1095         glPopMatrix();
1096
1097         GPU_offscreen_read_pixels(ofs, GL_FLOAT, buffer);
1098
1099         IMB_colormanagement_finish_glsl_transform();
1100
1101         /* unbind */
1102         GPU_offscreen_unbind(ofs);
1103         GPU_offscreen_free(ofs);
1104
1105         return TRUE;
1106 }