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