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