svn merge ^/trunk/blender -r42920:42927
[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         X000X000
77         00000000
78         00X000X0
79         00000000 */
80
81
82 GLubyte stipple_quarttone[128] = { 
83         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0,
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
92
93 GLubyte stipple_diag_stripes_pos[128] = {
94     0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
95         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
96         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
97         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
98         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
99         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
100         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
101         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
102         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
103         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
104         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
105         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
106         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
107         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
108         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
109         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f};
110
111
112 GLubyte stipple_diag_stripes_neg[128] = {
113     0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
114         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
115         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
116         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
117         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
118         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
119         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
120         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
121         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
122         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
123         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
124         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
125         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
126         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
127         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
128         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80};
129
130
131 void fdrawbezier(float vec[4][3])
132 {
133         float dist;
134         float curve_res = 24, spline_step = 0.0f;
135         
136         dist= 0.5f*ABS(vec[0][0] - vec[3][0]);
137         
138         /* check direction later, for top sockets */
139         vec[1][0]= vec[0][0]+dist;
140         vec[1][1]= vec[0][1];
141         
142         vec[2][0]= vec[3][0]-dist;
143         vec[2][1]= vec[3][1];
144         /* we can reuse the dist variable here to increment the GL curve eval amount*/
145         dist = 1.0f/curve_res;
146         
147         cpack(0x0);
148         glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
149         glBegin(GL_LINE_STRIP);
150         while (spline_step < 1.000001f) {
151                 /*if(do_shaded)
152                         UI_ThemeColorBlend(th_col1, th_col2, spline_step);*/
153                 glEvalCoord1f(spline_step);
154                 spline_step += dist;
155         }
156         glEnd();
157 }
158
159 void fdrawline(float x1, float y1, float x2, float y2)
160 {
161         float v[2];
162         
163         glBegin(GL_LINE_STRIP);
164         v[0] = x1; v[1] = y1;
165         glVertex2fv(v);
166         v[0] = x2; v[1] = y2;
167         glVertex2fv(v);
168         glEnd();
169 }
170
171 void fdrawbox(float x1, float y1, float x2, float y2)
172 {
173         float v[2];
174         
175         glBegin(GL_LINE_STRIP);
176         
177         v[0] = x1; v[1] = y1;
178         glVertex2fv(v);
179         v[0] = x1; v[1] = y2;
180         glVertex2fv(v);
181         v[0] = x2; v[1] = y2;
182         glVertex2fv(v);
183         v[0] = x2; v[1] = y1;
184         glVertex2fv(v);
185         v[0] = x1; v[1] = y1;
186         glVertex2fv(v);
187         
188         glEnd();
189 }
190
191 void sdrawline(short x1, short y1, short x2, short y2)
192 {
193         short v[2];
194         
195         glBegin(GL_LINE_STRIP);
196         v[0] = x1; v[1] = y1;
197         glVertex2sv(v);
198         v[0] = x2; v[1] = y2;
199         glVertex2sv(v);
200         glEnd();
201 }
202
203 /*
204
205         x1,y2
206         |  \
207         |   \
208         |    \
209         x1,y1-- x2,y1
210
211 */
212
213 static void sdrawtripoints(short x1, short y1, short x2, short y2)
214 {
215         short v[2];
216         v[0]= x1; v[1]= y1;
217         glVertex2sv(v);
218         v[0]= x1; v[1]= y2;
219         glVertex2sv(v);
220         v[0]= x2; v[1]= y1;
221         glVertex2sv(v);
222 }
223
224 void sdrawtri(short x1, short y1, short x2, short y2)
225 {
226         glBegin(GL_LINE_STRIP);
227         sdrawtripoints(x1, y1, x2, y2);
228         glEnd();
229 }
230
231 void sdrawtrifill(short x1, short y1, short x2, short y2)
232 {
233         glBegin(GL_TRIANGLES);
234         sdrawtripoints(x1, y1, x2, y2);
235         glEnd();
236 }
237
238 void sdrawbox(short x1, short y1, short x2, short y2)
239 {
240         short v[2];
241         
242         glBegin(GL_LINE_STRIP);
243         
244         v[0] = x1; v[1] = y1;
245         glVertex2sv(v);
246         v[0] = x1; v[1] = y2;
247         glVertex2sv(v);
248         v[0] = x2; v[1] = y2;
249         glVertex2sv(v);
250         v[0] = x2; v[1] = y1;
251         glVertex2sv(v);
252         v[0] = x1; v[1] = y1;
253         glVertex2sv(v);
254         
255         glEnd();
256 }
257
258
259 /* ******************************************** */
260
261 void setlinestyle(int nr)
262 {
263         if(nr==0) {
264                 glDisable(GL_LINE_STIPPLE);
265         }
266         else {
267                 
268                 glEnable(GL_LINE_STIPPLE);
269                 glLineStipple(nr, 0xAAAA);
270         }
271 }
272
273         /* Invert line handling */
274         
275 #define glToggle(mode, onoff)   (((onoff)?glEnable:glDisable)(mode))
276
277 void set_inverted_drawing(int enable) 
278 {
279         glLogicOp(enable?GL_INVERT:GL_COPY);
280         glToggle(GL_COLOR_LOGIC_OP, enable);
281         glToggle(GL_DITHER, !enable);
282 }
283
284 void sdrawXORline(int x0, int y0, int x1, int y1)
285 {
286         if(x0==x1 && y0==y1) return;
287
288         set_inverted_drawing(1);
289         
290         glBegin(GL_LINES);
291         glVertex2i(x0, y0);
292         glVertex2i(x1, y1);
293         glEnd();
294         
295         set_inverted_drawing(0);
296 }
297
298 void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
299 {
300         static short old[4][2][2];
301         static char flags[4]= {0, 0, 0, 0};
302         
303                 /* with builtin memory, max 4 lines */
304
305         set_inverted_drawing(1);
306                 
307         glBegin(GL_LINES);
308         if(nr== -1) { /* flush */
309                 for (nr=0; nr<4; nr++) {
310                         if (flags[nr]) {
311                                 glVertex2sv(old[nr][0]);
312                                 glVertex2sv(old[nr][1]);
313                                 flags[nr]= 0;
314                         }
315                 }
316         } else {
317                 if(nr>=0 && nr<4) {
318                         if(flags[nr]) {
319                                 glVertex2sv(old[nr][0]);
320                                 glVertex2sv(old[nr][1]);
321                         }
322
323                         old[nr][0][0]= x0;
324                         old[nr][0][1]= y0;
325                         old[nr][1][0]= x1;
326                         old[nr][1][1]= y1;
327                         
328                         flags[nr]= 1;
329                 }
330                 
331                 glVertex2i(x0, y0);
332                 glVertex2i(x1, y1);
333         }
334         glEnd();
335         
336         set_inverted_drawing(0);
337 }
338
339 void fdrawXORellipse(float xofs, float yofs, float hw, float hh)
340 {
341         if(hw==0) return;
342
343         set_inverted_drawing(1);
344
345         glPushMatrix();
346         glTranslatef(xofs, yofs, 0.0);
347         glScalef(1,hh/hw,1);
348         glutil_draw_lined_arc(0.0, M_PI*2.0, hw, 20);
349         glPopMatrix();
350
351         set_inverted_drawing(0);
352 }
353 void fdrawXORcirc(float xofs, float yofs, float rad)
354 {
355         set_inverted_drawing(1);
356
357         glPushMatrix();
358         glTranslatef(xofs, yofs, 0.0);
359         glutil_draw_lined_arc(0.0, M_PI*2.0, rad, 20);
360         glPopMatrix();
361
362         set_inverted_drawing(0);
363 }
364
365 void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments)
366 {
367         int i;
368         
369         glBegin(GL_TRIANGLE_FAN);
370         glVertex2f(0.0, 0.0);
371         for (i=0; i<nsegments; i++) {
372                 float t= (float) i/(nsegments-1);
373                 float cur= start + t*angle;
374                 
375                 glVertex2f(cosf(cur)*radius, sinf(cur)*radius);
376         }
377         glEnd();
378 }
379
380 void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments)
381 {
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 {
802         float value[4];
803         int pointhack_px;
804         glGetFloatv(GL_POINT_SIZE_RANGE, value);
805         if(value[1] < 2.0f) {
806                 glGetFloatv(GL_POINT_SIZE, value);
807                 pointhack_px= floorf(value[0]+0.5f);
808                 if(pointhack_px>4) pointhack_px= 4;
809                 return pointhack_px;
810         }
811         return 0;
812 }
813
814 void bglVertex3fv(float *vec)
815 {
816         switch(curmode) {
817         case GL_POINTS:
818                 if(pointhack) {
819                         glRasterPos3fv(vec);
820                         glBitmap(pointhack, pointhack, (float)pointhack/2.0f, (float)pointhack/2.0f, 0.0, 0.0, Squaredot);
821                 }
822                 else glVertex3fv(vec);
823                 break;
824         }
825 }
826
827 void bglVertex3f(float x, float y, float z)
828 {
829         switch(curmode) {
830         case GL_POINTS:
831                 if(pointhack) {
832                         glRasterPos3f(x, y, z);
833                         glBitmap(pointhack, pointhack, (float)pointhack/2.0f, (float)pointhack/2.0f, 0.0, 0.0, Squaredot);
834                 }
835                 else glVertex3f(x, y, z);
836                 break;
837         }
838 }
839
840 void bglVertex2fv(float *vec)
841 {
842         switch(curmode) {
843         case GL_POINTS:
844                 if(pointhack) {
845                         glRasterPos2fv(vec);
846                         glBitmap(pointhack, pointhack, (float)pointhack/2, pointhack/2, 0.0, 0.0, Squaredot);
847                 }
848                 else glVertex2fv(vec);
849                 break;
850         }
851 }
852
853
854 void bglEnd(void)
855 {
856         if(pointhack) pointhack= 0;
857         else glEnd();
858         
859 }
860
861 /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
862 void bgl_get_mats(bglMats *mats)
863 {
864         const double badvalue= 1.0e-6;
865
866         glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
867         glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
868         glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
869         
870         /* Very strange code here - it seems that certain bad values in the
871            modelview matrix can cause gluUnProject to give bad results. */
872         if(mats->modelview[0] < badvalue &&
873            mats->modelview[0] > -badvalue)
874                 mats->modelview[0]= 0;
875         if(mats->modelview[5] < badvalue &&
876            mats->modelview[5] > -badvalue)
877                 mats->modelview[5]= 0;
878         
879         /* Set up viewport so that gluUnProject will give correct values */
880         mats->viewport[0] = 0;
881         mats->viewport[1] = 0;
882 }
883
884 /* *************** glPolygonOffset hack ************* */
885
886 /* dist is only for ortho now... */
887 void bglPolygonOffset(float viewdist, float dist) 
888 {
889         static float winmat[16], offset=0.0;    
890         
891         if(dist != 0.0f) {
892                 float offs;
893                 
894                 // glEnable(GL_POLYGON_OFFSET_FILL);
895                 // glPolygonOffset(-1.0, -1.0);
896
897                 /* hack below is to mimic polygon offset */
898                 glMatrixMode(GL_PROJECTION);
899                 glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
900                 
901                 /* dist is from camera to center point */
902                 
903                 if(winmat[15]>0.5f) offs= 0.00001f*dist*viewdist;  // ortho tweaking
904                 else offs= 0.0005f*dist;  // should be clipping value or so...
905                 
906                 winmat[14]-= offs;
907                 offset+= offs;
908                 
909                 glLoadMatrixf(winmat);
910                 glMatrixMode(GL_MODELVIEW);
911         }
912         else {
913
914                 glMatrixMode(GL_PROJECTION);
915                 winmat[14]+= offset;
916                 offset= 0.0;
917                 glLoadMatrixf(winmat);
918                 glMatrixMode(GL_MODELVIEW);
919         }
920 }
921
922 void bglFlush(void) 
923 {
924         glFlush();
925 #ifdef __APPLE__
926 //      if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
927 // XXX          myswapbuffers(); //hack to get mac intel graphics to show frontbuffer
928 #endif
929 }
930