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