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