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