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