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