Color management: add "Color Unpremultiply" option for images and render settings.
[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 void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect)
563 {
564         float xzoom= glaGetOneFloat(GL_ZOOM_X);
565         float yzoom= glaGetOneFloat(GL_ZOOM_Y);
566                 
567                 /* The pixel space coordinate of the intersection of
568                  * the [zoomed] image with the origin.
569                  */
570         float ix= -x/xzoom;
571         float iy= -y/yzoom;
572         
573                 /* The maximum pixel amounts the image can be cropped
574                  * at the lower left without exceeding the origin.
575                  */
576         int off_x= floor(MAX2(ix, 0));
577         int off_y= floor(MAX2(iy, 0));
578                 
579                 /* The zoomed space coordinate of the raster position 
580                  * (starting at the lower left most unclipped pixel).
581                  */
582         float rast_x= x + off_x*xzoom;
583         float rast_y= y + off_y*yzoom;
584
585         GLfloat scissor[4];
586         int draw_w, draw_h;
587
588                 /* Determine the smallest number of pixels we need to draw
589                  * before the image would go off the upper right corner.
590                  * 
591                  * It may seem this is just an optimization but some graphics 
592                  * cards (ATI) freak out if there is a large zoom factor and
593                  * a large number of pixels off the screen (probably at some
594                  * level the number of image pixels to draw is getting multiplied
595                  * by the zoom and then clamped). Making sure we draw the
596                  * fewest pixels possible keeps everyone mostly happy (still
597                  * fails if we zoom in on one really huge pixel so that it
598                  * covers the entire screen).
599                  */
600         glGetFloatv(GL_SCISSOR_BOX, scissor);
601         draw_w = MIN2(img_w-off_x, ceil((scissor[2]-rast_x)/xzoom));
602         draw_h = MIN2(img_h-off_y, ceil((scissor[3]-rast_y)/yzoom));
603
604         if (draw_w>0 && draw_h>0) {
605                 int old_row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
606
607                         /* Don't use safe RasterPos (slower) if we can avoid it. */
608                 if (rast_x>=0 && rast_y>=0) {
609                         glRasterPos2f(rast_x, rast_y);
610                 } else {
611                         glaRasterPosSafe2f(rast_x, rast_y, 0, 0);
612                 }
613
614                 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_w);
615                 if(format==GL_LUMINANCE || format==GL_RED) {
616                         if(type==GL_FLOAT) {
617                                 float *f_rect= (float *)rect;
618                                 glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y*row_w + off_x));
619                         }
620                         else if(type==GL_INT || type==GL_UNSIGNED_INT) {
621                                 int *i_rect= (int *)rect;
622                                 glDrawPixels(draw_w, draw_h, format, type, i_rect + (off_y*row_w + off_x));
623                         }
624                 }
625                 else { /* RGBA */
626                         if(type==GL_FLOAT) {
627                                 float *f_rect= (float *)rect;
628                                 glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y*row_w + off_x)*4);
629                         }
630                         else if(type==GL_UNSIGNED_BYTE) {
631                                 unsigned char *uc_rect= (unsigned char *) rect;
632                                 glDrawPixels(draw_w, draw_h, format, type, uc_rect + (off_y*row_w + off_x)*4);
633                         }
634                 }
635                 
636                 glPixelStorei(GL_UNPACK_ROW_LENGTH,  old_row_length);
637         }
638 }
639
640 /* 2D Drawing Assistance */
641
642 void glaDefine2DArea(rcti *screen_rect)
643 {
644         int sc_w= screen_rect->xmax - screen_rect->xmin + 1;
645         int sc_h= screen_rect->ymax - screen_rect->ymin + 1;
646
647         glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
648         glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
649
650                 /* The 0.375 magic number is to shift the matrix so that
651                  * both raster and vertex integer coordinates fall at pixel
652                  * centers properly. For a longer discussion see the OpenGL
653                  * Programming Guide, Appendix H, Correctness Tips.
654                  */
655
656         glMatrixMode(GL_PROJECTION);
657         glLoadIdentity();
658         glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1);
659         glTranslatef(0.375, 0.375, 0.0);
660
661         glMatrixMode(GL_MODELVIEW);
662         glLoadIdentity();
663 }
664
665 struct gla2DDrawInfo {
666         int orig_vp[4], orig_sc[4];
667         float orig_projmat[16], orig_viewmat[16];
668
669         rcti screen_rect;
670         rctf world_rect;
671
672         float wo_to_sc[2];
673 };
674
675 void gla2DGetMap(gla2DDrawInfo *di, rctf *rect) 
676 {
677         *rect= di->world_rect;
678 }
679
680 void gla2DSetMap(gla2DDrawInfo *di, rctf *rect) 
681 {
682         int sc_w, sc_h;
683         float wo_w, wo_h;
684
685         di->world_rect= *rect;
686         
687         sc_w= (di->screen_rect.xmax-di->screen_rect.xmin);
688         sc_h= (di->screen_rect.ymax-di->screen_rect.ymin);
689         wo_w= (di->world_rect.xmax-di->world_rect.xmin);
690         wo_h= (di->world_rect.ymax-di->world_rect.ymin);
691         
692         di->wo_to_sc[0]= sc_w/wo_w;
693         di->wo_to_sc[1]= sc_h/wo_h;
694 }
695
696
697 gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) 
698 {
699         gla2DDrawInfo *di= MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
700         int sc_w, sc_h;
701         float wo_w, wo_h;
702
703         glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp);
704         glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc);
705         glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat);
706         glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat);
707
708         di->screen_rect= *screen_rect;
709         if (world_rect) {
710                 di->world_rect= *world_rect;
711         } else {
712                 di->world_rect.xmin= di->screen_rect.xmin;
713                 di->world_rect.ymin= di->screen_rect.ymin;
714                 di->world_rect.xmax= di->screen_rect.xmax;
715                 di->world_rect.ymax= di->screen_rect.ymax;
716         }
717
718         sc_w= (di->screen_rect.xmax-di->screen_rect.xmin);
719         sc_h= (di->screen_rect.ymax-di->screen_rect.ymin);
720         wo_w= (di->world_rect.xmax-di->world_rect.xmin);
721         wo_h= (di->world_rect.ymax-di->world_rect.ymin);
722
723         di->wo_to_sc[0]= sc_w/wo_w;
724         di->wo_to_sc[1]= sc_h/wo_h;
725
726         glaDefine2DArea(&di->screen_rect);
727
728         return di;
729 }
730
731 void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r)
732 {
733         *sc_x_r= (wo_x - di->world_rect.xmin)*di->wo_to_sc[0];
734         *sc_y_r= (wo_y - di->world_rect.ymin)*di->wo_to_sc[1];
735 }
736 void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
737 {
738         screen_r[0]= (world[0] - di->world_rect.xmin)*di->wo_to_sc[0];
739         screen_r[1]= (world[1] - di->world_rect.ymin)*di->wo_to_sc[1];
740 }
741
742 void glaEnd2DDraw(gla2DDrawInfo *di)
743 {
744         glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
745         glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
746         glMatrixMode(GL_PROJECTION);
747         glLoadMatrixf(di->orig_projmat);
748         glMatrixMode(GL_MODELVIEW);
749         glLoadMatrixf(di->orig_viewmat);
750
751         MEM_freeN(di);
752 }
753
754 /* **************** glPoint hack ************************ */
755
756 static int curmode=0;
757 static int pointhack=0;
758 static GLubyte Squaredot[16] = { 0xff,0xff,0xff,0xff,
759                                                                  0xff,0xff,0xff,0xff,
760                                                                  0xff,0xff,0xff,0xff, 
761                                                                  0xff,0xff,0xff,0xff};
762
763 void bglBegin(int mode)
764 {
765         curmode= mode;
766         
767         if(mode==GL_POINTS) {
768                 float value[4];
769                 glGetFloatv(GL_POINT_SIZE_RANGE, value);
770                 if(value[1] < 2.0f) {
771                         glGetFloatv(GL_POINT_SIZE, value);
772                         pointhack= floor(value[0] + 0.5f);
773                         if(pointhack>4) pointhack= 4;
774                 }
775                 else glBegin(mode);
776         }
777 }
778
779 int bglPointHack(void)
780 {
781         float value[4];
782         int pointhack_px;
783         glGetFloatv(GL_POINT_SIZE_RANGE, value);
784         if(value[1] < 2.0f) {
785                 glGetFloatv(GL_POINT_SIZE, value);
786                 pointhack_px= floorf(value[0]+0.5f);
787                 if(pointhack_px>4) pointhack_px= 4;
788                 return pointhack_px;
789         }
790         return 0;
791 }
792
793 void bglVertex3fv(float *vec)
794 {
795         switch(curmode) {
796         case GL_POINTS:
797                 if(pointhack) {
798                         glRasterPos3fv(vec);
799                         glBitmap(pointhack, pointhack, (float)pointhack/2.0f, (float)pointhack/2.0f, 0.0, 0.0, Squaredot);
800                 }
801                 else glVertex3fv(vec);
802                 break;
803         }
804 }
805
806 void bglVertex3f(float x, float y, float z)
807 {
808         switch(curmode) {
809         case GL_POINTS:
810                 if(pointhack) {
811                         glRasterPos3f(x, y, z);
812                         glBitmap(pointhack, pointhack, (float)pointhack/2.0f, (float)pointhack/2.0f, 0.0, 0.0, Squaredot);
813                 }
814                 else glVertex3f(x, y, z);
815                 break;
816         }
817 }
818
819 void bglVertex2fv(float *vec)
820 {
821         switch(curmode) {
822         case GL_POINTS:
823                 if(pointhack) {
824                         glRasterPos2fv(vec);
825                         glBitmap(pointhack, pointhack, (float)pointhack/2, pointhack/2, 0.0, 0.0, Squaredot);
826                 }
827                 else glVertex2fv(vec);
828                 break;
829         }
830 }
831
832
833 void bglEnd(void)
834 {
835         if(pointhack) pointhack= 0;
836         else glEnd();
837         
838 }
839
840 /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
841 void bgl_get_mats(bglMats *mats)
842 {
843         const double badvalue= 1.0e-6;
844
845         glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
846         glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
847         glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
848         
849         /* Very strange code here - it seems that certain bad values in the
850            modelview matrix can cause gluUnProject to give bad results. */
851         if(mats->modelview[0] < badvalue &&
852            mats->modelview[0] > -badvalue)
853                 mats->modelview[0]= 0;
854         if(mats->modelview[5] < badvalue &&
855            mats->modelview[5] > -badvalue)
856                 mats->modelview[5]= 0;
857         
858         /* Set up viewport so that gluUnProject will give correct values */
859         mats->viewport[0] = 0;
860         mats->viewport[1] = 0;
861 }
862
863 /* *************** glPolygonOffset hack ************* */
864
865 /* dist is only for ortho now... */
866 void bglPolygonOffset(float viewdist, float dist) 
867 {
868         static float winmat[16], offset=0.0;    
869         
870         if(dist != 0.0f) {
871                 float offs;
872                 
873                 // glEnable(GL_POLYGON_OFFSET_FILL);
874                 // glPolygonOffset(-1.0, -1.0);
875
876                 /* hack below is to mimic polygon offset */
877                 glMatrixMode(GL_PROJECTION);
878                 glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
879                 
880                 /* dist is from camera to center point */
881                 
882                 if(winmat[15]>0.5f) offs= 0.00001f*dist*viewdist;  // ortho tweaking
883                 else offs= 0.0005f*dist;  // should be clipping value or so...
884                 
885                 winmat[14]-= offs;
886                 offset+= offs;
887                 
888                 glLoadMatrixf(winmat);
889                 glMatrixMode(GL_MODELVIEW);
890         }
891         else {
892
893                 glMatrixMode(GL_PROJECTION);
894                 winmat[14]+= offset;
895                 offset= 0.0;
896                 glLoadMatrixf(winmat);
897                 glMatrixMode(GL_MODELVIEW);
898         }
899 }
900
901 void bglFlush(void) 
902 {
903         glFlush();
904 #ifdef __APPLE__
905 //      if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
906 // XXX          myswapbuffers(); //hack to get mac intel graphics to show frontbuffer
907 #endif
908 }
909