105c2dc88d117f111c62426c39c5e9251ada28d9
[blender.git] / source / blender / editors / screen / glutil.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/screen/glutil.c
27  *  \ingroup edscr
28  */
29
30
31 #include <stdio.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_userdef_types.h"
37 #include "DNA_vec_types.h"
38
39 #include "BLI_rect.h"
40 #include "BLI_utildefines.h"
41 #include "BLI_math.h"
42 #include "BLI_threads.h"
43
44 #include "BKE_blender.h"
45 #include "BKE_colortools.h"
46
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 * xzoom);
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 * xzoom);
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 /* 2D Drawing Assistance */
673
674 void glaDefine2DArea(rcti *screen_rect)
675 {
676         const int sc_w = BLI_rcti_size_x(screen_rect) + 1;
677         const int sc_h = BLI_rcti_size_y(screen_rect) + 1;
678
679         glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
680         glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
681
682         /* The GLA_PIXEL_OFS magic number is to shift the matrix so that
683          * both raster and vertex integer coordinates fall at pixel
684          * centers properly. For a longer discussion see the OpenGL
685          * Programming Guide, Appendix H, Correctness Tips.
686          */
687
688         glMatrixMode(GL_PROJECTION);
689         glLoadIdentity();
690         glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1);
691         glTranslatef(GLA_PIXEL_OFS, GLA_PIXEL_OFS, 0.0);
692
693         glMatrixMode(GL_MODELVIEW);
694         glLoadIdentity();
695 }
696
697 #if 0 /* UNUSED */
698
699 struct gla2DDrawInfo {
700         int orig_vp[4], orig_sc[4];
701         float orig_projmat[16], orig_viewmat[16];
702
703         rcti screen_rect;
704         rctf world_rect;
705
706         float wo_to_sc[2];
707 };
708
709 void gla2DGetMap(gla2DDrawInfo *di, rctf *rect) 
710 {
711         *rect = di->world_rect;
712 }
713
714 void gla2DSetMap(gla2DDrawInfo *di, rctf *rect) 
715 {
716         int sc_w, sc_h;
717         float wo_w, wo_h;
718
719         di->world_rect = *rect;
720         
721         sc_w = BLI_rcti_size_x(&di->screen_rect);
722         sc_h = BLI_rcti_size_y(&di->screen_rect);
723         wo_w = BLI_rcti_size_x(&di->world_rect);
724         wo_h = BLI_rcti_size_y(&di->world_rect);
725         
726         di->wo_to_sc[0] = sc_w / wo_w;
727         di->wo_to_sc[1] = sc_h / wo_h;
728 }
729
730 gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) 
731 {
732         gla2DDrawInfo *di = MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
733         int sc_w, sc_h;
734         float wo_w, wo_h;
735
736         glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp);
737         glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc);
738         glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat);
739         glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat);
740
741         di->screen_rect = *screen_rect;
742         if (world_rect) {
743                 di->world_rect = *world_rect;
744         }
745         else {
746                 di->world_rect.xmin = di->screen_rect.xmin;
747                 di->world_rect.ymin = di->screen_rect.ymin;
748                 di->world_rect.xmax = di->screen_rect.xmax;
749                 di->world_rect.ymax = di->screen_rect.ymax;
750         }
751
752         sc_w = BLI_rcti_size_x(&di->screen_rect);
753         sc_h = BLI_rcti_size_y(&di->screen_rect);
754         wo_w = BLI_rcti_size_x(&di->world_rect);
755         wo_h = BLI_rcti_size_y(&di->world_rect);
756
757         di->wo_to_sc[0] = sc_w / wo_w;
758         di->wo_to_sc[1] = sc_h / wo_h;
759
760         glaDefine2DArea(&di->screen_rect);
761
762         return di;
763 }
764
765 void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r)
766 {
767         *sc_x_r = (wo_x - di->world_rect.xmin) * di->wo_to_sc[0];
768         *sc_y_r = (wo_y - di->world_rect.ymin) * di->wo_to_sc[1];
769 }
770 void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
771 {
772         screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0];
773         screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1];
774 }
775
776 void glaEnd2DDraw(gla2DDrawInfo *di)
777 {
778         glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
779         glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
780         glMatrixMode(GL_PROJECTION);
781         glLoadMatrixf(di->orig_projmat);
782         glMatrixMode(GL_MODELVIEW);
783         glLoadMatrixf(di->orig_viewmat);
784
785         MEM_freeN(di);
786 }
787 #endif
788
789 /* **************** GL_POINT hack ************************ */
790
791 static int curmode = 0;
792 static int pointhack = 0;
793 static GLubyte Squaredot[16] = {0xff, 0xff, 0xff, 0xff,
794                                 0xff, 0xff, 0xff, 0xff,
795                                 0xff, 0xff, 0xff, 0xff,
796                                 0xff, 0xff, 0xff, 0xff};
797
798 void bglBegin(int mode)
799 {
800         curmode = mode;
801         
802         if (mode == GL_POINTS) {
803                 float value[4];
804                 glGetFloatv(GL_POINT_SIZE_RANGE, value);
805                 if (value[1] < 2.0f) {
806                         glGetFloatv(GL_POINT_SIZE, value);
807                         pointhack = floor(value[0] + 0.5f);
808                         if (pointhack > 4) pointhack = 4;
809                 }
810                 else glBegin(mode);
811         }
812 }
813
814 #if 0 /* UNUSED */
815 int bglPointHack(void)
816 {
817         float value[4];
818         int pointhack_px;
819         glGetFloatv(GL_POINT_SIZE_RANGE, value);
820         if (value[1] < 2.0f) {
821                 glGetFloatv(GL_POINT_SIZE, value);
822                 pointhack_px = floorf(value[0] + 0.5f);
823                 if (pointhack_px > 4) pointhack_px = 4;
824                 return pointhack_px;
825         }
826         return 0;
827 }
828 #endif
829
830 void bglVertex3fv(const float vec[3])
831 {
832         switch (curmode) {
833                 case GL_POINTS:
834                         if (pointhack) {
835                                 glRasterPos3fv(vec);
836                                 glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
837                         }
838                         else glVertex3fv(vec);
839                         break;
840         }
841 }
842
843 void bglVertex3f(float x, float y, float z)
844 {
845         switch (curmode) {
846                 case GL_POINTS:
847                         if (pointhack) {
848                                 glRasterPos3f(x, y, z);
849                                 glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
850                         }
851                         else glVertex3f(x, y, z);
852                         break;
853         }
854 }
855
856 void bglVertex2fv(const float vec[2])
857 {
858         switch (curmode) {
859                 case GL_POINTS:
860                         if (pointhack) {
861                                 glRasterPos2fv(vec);
862                                 glBitmap(pointhack, pointhack, (float)pointhack / 2, pointhack / 2, 0.0, 0.0, Squaredot);
863                         }
864                         else glVertex2fv(vec);
865                         break;
866         }
867 }
868
869
870 void bglEnd(void)
871 {
872         if (pointhack) pointhack = 0;
873         else glEnd();
874         
875 }
876
877 /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
878 void bgl_get_mats(bglMats *mats)
879 {
880         const double badvalue = 1.0e-6;
881
882         glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
883         glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
884         glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
885         
886         /* Very strange code here - it seems that certain bad values in the
887          * modelview matrix can cause gluUnProject to give bad results. */
888         if (mats->modelview[0] < badvalue &&
889             mats->modelview[0] > -badvalue)
890         {
891                 mats->modelview[0] = 0;
892         }
893         if (mats->modelview[5] < badvalue &&
894             mats->modelview[5] > -badvalue)
895         {
896                 mats->modelview[5] = 0;
897         }
898         
899         /* Set up viewport so that gluUnProject will give correct values */
900         mats->viewport[0] = 0;
901         mats->viewport[1] = 0;
902 }
903
904 /* *************** glPolygonOffset hack ************* */
905
906 /* dist is only for ortho now... */
907 void bglPolygonOffset(float viewdist, float dist) 
908 {
909         static float winmat[16], offset = 0.0;
910         
911         if (dist != 0.0f) {
912                 float offs;
913                 
914                 // glEnable(GL_POLYGON_OFFSET_FILL);
915                 // glPolygonOffset(-1.0, -1.0);
916
917                 /* hack below is to mimic polygon offset */
918                 glMatrixMode(GL_PROJECTION);
919                 glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
920                 
921                 /* dist is from camera to center point */
922                 
923                 if (winmat[15] > 0.5f) offs = 0.00001f * dist * viewdist;  // ortho tweaking
924                 else offs = 0.0005f * dist;  // should be clipping value or so...
925                 
926                 winmat[14] -= offs;
927                 offset += offs;
928                 
929                 glLoadMatrixf(winmat);
930                 glMatrixMode(GL_MODELVIEW);
931         }
932         else {
933
934                 glMatrixMode(GL_PROJECTION);
935                 winmat[14] += offset;
936                 offset = 0.0;
937                 glLoadMatrixf(winmat);
938                 glMatrixMode(GL_MODELVIEW);
939         }
940 }
941
942 #if 0 /* UNUSED */
943 void bglFlush(void) 
944 {
945         glFlush();
946 #ifdef __APPLE__
947 //      if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
948 // XXX          myswapbuffers(); //hack to get mac intel graphics to show frontbuffer
949 #endif
950 }
951 #endif