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