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