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