Blender  V2.59
glutil.c
Go to the documentation of this file.
00001 /*
00002  * $Id: glutil.c 38978 2011-08-03 09:28:16Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * Contributor(s): Blender Foundation
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <stdio.h>
00034 #include <string.h>
00035 
00036 #include "MEM_guardedalloc.h"
00037 
00038 #include "DNA_vec_types.h"
00039 
00040 #include "BLI_utildefines.h"
00041 
00042 #include "BKE_colortools.h"
00043 
00044 #include "BLI_math.h"
00045 #include "BLI_threads.h"
00046 
00047 #include "BIF_gl.h"
00048 #include "BIF_glutil.h"
00049 
00050 #ifndef GL_CLAMP_TO_EDGE
00051 #define GL_CLAMP_TO_EDGE                        0x812F
00052 #endif
00053 
00054 
00055 /* ******************************************** */
00056 
00057 /* defined in BIF_gl.h */
00058 GLubyte stipple_halftone[128] = {
00059         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00060         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00061         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
00062         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00063         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00064         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
00065         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00066         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00067         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
00068         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00069         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00070         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
00071         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00072         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
00073         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
00074         0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
00075 
00076 
00077 /*  repeat this pattern
00078         X000X000
00079         00000000
00080         00X000X0
00081         00000000 */
00082 
00083 
00084 GLubyte stipple_quarttone[128] = { 
00085         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0,
00086         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0,
00087         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0,
00088         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0,
00089         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0,
00090         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0,
00091         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0,
00092         136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0};
00093 
00094 
00095 GLubyte stipple_diag_stripes_pos[128] = {
00096     0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
00097         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
00098         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
00099         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
00100         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
00101         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
00102         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
00103         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
00104         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
00105         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
00106         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
00107         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
00108         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
00109         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
00110         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
00111         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f};
00112 
00113 
00114 GLubyte stipple_diag_stripes_neg[128] = {
00115     0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
00116         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
00117         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
00118         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
00119         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
00120         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
00121         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
00122         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
00123         0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
00124         0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
00125         0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
00126         0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
00127         0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
00128         0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
00129         0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
00130         0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80};
00131 
00132 
00133 void fdrawbezier(float vec[4][3])
00134 {
00135         float dist;
00136         float curve_res = 24, spline_step = 0.0f;
00137         
00138         dist= 0.5f*ABS(vec[0][0] - vec[3][0]);
00139         
00140         /* check direction later, for top sockets */
00141         vec[1][0]= vec[0][0]+dist;
00142         vec[1][1]= vec[0][1];
00143         
00144         vec[2][0]= vec[3][0]-dist;
00145         vec[2][1]= vec[3][1];
00146         /* we can reuse the dist variable here to increment the GL curve eval amount*/
00147         dist = 1.0f/curve_res;
00148         
00149         cpack(0x0);
00150         glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
00151         glBegin(GL_LINE_STRIP);
00152         while (spline_step < 1.000001f) {
00153                 /*if(do_shaded)
00154                         UI_ThemeColorBlend(th_col1, th_col2, spline_step);*/
00155                 glEvalCoord1f(spline_step);
00156                 spline_step += dist;
00157         }
00158         glEnd();
00159 }
00160 
00161 void fdrawline(float x1, float y1, float x2, float y2)
00162 {
00163         float v[2];
00164         
00165         glBegin(GL_LINE_STRIP);
00166         v[0] = x1; v[1] = y1;
00167         glVertex2fv(v);
00168         v[0] = x2; v[1] = y2;
00169         glVertex2fv(v);
00170         glEnd();
00171 }
00172 
00173 void fdrawbox(float x1, float y1, float x2, float y2)
00174 {
00175         float v[2];
00176         
00177         glBegin(GL_LINE_STRIP);
00178         
00179         v[0] = x1; v[1] = y1;
00180         glVertex2fv(v);
00181         v[0] = x1; v[1] = y2;
00182         glVertex2fv(v);
00183         v[0] = x2; v[1] = y2;
00184         glVertex2fv(v);
00185         v[0] = x2; v[1] = y1;
00186         glVertex2fv(v);
00187         v[0] = x1; v[1] = y1;
00188         glVertex2fv(v);
00189         
00190         glEnd();
00191 }
00192 
00193 void sdrawline(short x1, short y1, short x2, short y2)
00194 {
00195         short v[2];
00196         
00197         glBegin(GL_LINE_STRIP);
00198         v[0] = x1; v[1] = y1;
00199         glVertex2sv(v);
00200         v[0] = x2; v[1] = y2;
00201         glVertex2sv(v);
00202         glEnd();
00203 }
00204 
00205 /*
00206 
00207         x1,y2
00208         |  \
00209         |   \
00210         |    \
00211         x1,y1-- x2,y1
00212 
00213 */
00214 
00215 static void sdrawtripoints(short x1, short y1, short x2, short y2)
00216 {
00217         short v[2];
00218         v[0]= x1; v[1]= y1;
00219         glVertex2sv(v);
00220         v[0]= x1; v[1]= y2;
00221         glVertex2sv(v);
00222         v[0]= x2; v[1]= y1;
00223         glVertex2sv(v);
00224 }
00225 
00226 void sdrawtri(short x1, short y1, short x2, short y2)
00227 {
00228         glBegin(GL_LINE_STRIP);
00229         sdrawtripoints(x1, y1, x2, y2);
00230         glEnd();
00231 }
00232 
00233 void sdrawtrifill(short x1, short y1, short x2, short y2)
00234 {
00235         glBegin(GL_TRIANGLES);
00236         sdrawtripoints(x1, y1, x2, y2);
00237         glEnd();
00238 }
00239 
00240 void sdrawbox(short x1, short y1, short x2, short y2)
00241 {
00242         short v[2];
00243         
00244         glBegin(GL_LINE_STRIP);
00245         
00246         v[0] = x1; v[1] = y1;
00247         glVertex2sv(v);
00248         v[0] = x1; v[1] = y2;
00249         glVertex2sv(v);
00250         v[0] = x2; v[1] = y2;
00251         glVertex2sv(v);
00252         v[0] = x2; v[1] = y1;
00253         glVertex2sv(v);
00254         v[0] = x1; v[1] = y1;
00255         glVertex2sv(v);
00256         
00257         glEnd();
00258 }
00259 
00260 
00261 /* ******************************************** */
00262 
00263 void setlinestyle(int nr)
00264 {
00265         if(nr==0) {
00266                 glDisable(GL_LINE_STIPPLE);
00267         }
00268         else {
00269                 
00270                 glEnable(GL_LINE_STIPPLE);
00271                 glLineStipple(nr, 0xAAAA);
00272         }
00273 }
00274 
00275         /* Invert line handling */
00276         
00277 #define glToggle(mode, onoff)   (((onoff)?glEnable:glDisable)(mode))
00278 
00279 void set_inverted_drawing(int enable) 
00280 {
00281         glLogicOp(enable?GL_INVERT:GL_COPY);
00282 
00283         /* Use GL_BLEND_EQUATION_EXT on sgi (if we have it),
00284          * apparently GL_COLOR_LOGIC_OP doesn't work on O2?
00285          * Is this an sgi bug or our bug?
00286          */
00287 #if defined(__sgi) && defined(GL_BLEND_EQUATION_EXT)
00288         glBlendEquationEXT(enable?GL_LOGIC_OP:GL_FUNC_ADD_EXT);
00289         glToggle(GL_BLEND, enable);
00290 #else
00291         glToggle(GL_COLOR_LOGIC_OP, enable);
00292 #endif
00293 
00294         glToggle(GL_DITHER, !enable);
00295 }
00296 
00297 void sdrawXORline(int x0, int y0, int x1, int y1)
00298 {
00299         if(x0==x1 && y0==y1) return;
00300 
00301         set_inverted_drawing(1);
00302         
00303         glBegin(GL_LINES);
00304         glVertex2i(x0, y0);
00305         glVertex2i(x1, y1);
00306         glEnd();
00307         
00308         set_inverted_drawing(0);
00309 }
00310 
00311 void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
00312 {
00313         static short old[4][2][2];
00314         static char flags[4]= {0, 0, 0, 0};
00315         
00316                 /* with builtin memory, max 4 lines */
00317 
00318         set_inverted_drawing(1);
00319                 
00320         glBegin(GL_LINES);
00321         if(nr== -1) { /* flush */
00322                 for (nr=0; nr<4; nr++) {
00323                         if (flags[nr]) {
00324                                 glVertex2sv(old[nr][0]);
00325                                 glVertex2sv(old[nr][1]);
00326                                 flags[nr]= 0;
00327                         }
00328                 }
00329         } else {
00330                 if(nr>=0 && nr<4) {
00331                         if(flags[nr]) {
00332                                 glVertex2sv(old[nr][0]);
00333                                 glVertex2sv(old[nr][1]);
00334                         }
00335 
00336                         old[nr][0][0]= x0;
00337                         old[nr][0][1]= y0;
00338                         old[nr][1][0]= x1;
00339                         old[nr][1][1]= y1;
00340                         
00341                         flags[nr]= 1;
00342                 }
00343                 
00344                 glVertex2i(x0, y0);
00345                 glVertex2i(x1, y1);
00346         }
00347         glEnd();
00348         
00349         set_inverted_drawing(0);
00350 }
00351 
00352 void fdrawXORellipse(float xofs, float yofs, float hw, float hh)
00353 {
00354         if(hw==0) return;
00355 
00356         set_inverted_drawing(1);
00357 
00358         glPushMatrix();
00359         glTranslatef(xofs, yofs, 0.0);
00360         glScalef(1,hh/hw,1);
00361         glutil_draw_lined_arc(0.0, M_PI*2.0, hw, 20);
00362         glPopMatrix();
00363 
00364         set_inverted_drawing(0);
00365 }
00366 void fdrawXORcirc(float xofs, float yofs, float rad)
00367 {
00368         set_inverted_drawing(1);
00369 
00370         glPushMatrix();
00371         glTranslatef(xofs, yofs, 0.0);
00372         glutil_draw_lined_arc(0.0, M_PI*2.0, rad, 20);
00373         glPopMatrix();
00374 
00375         set_inverted_drawing(0);
00376 }
00377 
00378 void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments) {
00379         int i;
00380         
00381         glBegin(GL_TRIANGLE_FAN);
00382         glVertex2f(0.0, 0.0);
00383         for (i=0; i<nsegments; i++) {
00384                 float t= (float) i/(nsegments-1);
00385                 float cur= start + t*angle;
00386                 
00387                 glVertex2f(cosf(cur)*radius, sinf(cur)*radius);
00388         }
00389         glEnd();
00390 }
00391 
00392 void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments) {
00393         int i;
00394         
00395         glBegin(GL_LINE_STRIP);
00396         for (i=0; i<nsegments; i++) {
00397                 float t= (float) i/(nsegments-1);
00398                 float cur= start + t*angle;
00399                 
00400                 glVertex2f(cosf(cur)*radius, sinf(cur)*radius);
00401         }
00402         glEnd();
00403 }
00404 
00405 int glaGetOneInteger(int param)
00406 {
00407         GLint i;
00408         glGetIntegerv(param, &i);
00409         return i;
00410 }
00411 
00412 float glaGetOneFloat(int param)
00413 {
00414         GLfloat v;
00415         glGetFloatv(param, &v);
00416         return v;
00417 }
00418 
00419 void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y)
00420 {
00421         GLubyte dummy= 0;
00422 
00423                 /* As long as known good coordinates are correct
00424                  * this is guarenteed to generate an ok raster
00425                  * position (ignoring potential (real) overflow
00426                  * issues).
00427                  */
00428         glRasterPos2f(known_good_x, known_good_y);
00429 
00430                 /* Now shift the raster position to where we wanted
00431                  * it in the first place using the glBitmap trick.
00432                  */
00433         glBitmap(0, 0, 0, 0, x - known_good_x, y - known_good_y, &dummy);
00434 }
00435 
00436 static int get_cached_work_texture(int *w_r, int *h_r)
00437 {
00438         static GLint texid= -1;
00439         static int tex_w= 256;
00440         static int tex_h= 256;
00441 
00442         if (texid==-1) {
00443                 GLint ltexid= glaGetOneInteger(GL_TEXTURE_2D);
00444                 unsigned char *tbuf;
00445 
00446                 glGenTextures(1, (GLuint *)&texid);
00447 
00448                 glBindTexture(GL_TEXTURE_2D, texid);
00449 
00450                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00451                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00452 
00453                 tbuf= MEM_callocN(tex_w*tex_h*4, "tbuf");
00454                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tbuf);
00455                 MEM_freeN(tbuf);
00456 
00457                 glBindTexture(GL_TEXTURE_2D, ltexid);
00458         }
00459 
00460         *w_r= tex_w;
00461         *h_r= tex_h;
00462         return texid;
00463 }
00464 
00465 void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, void *rect, float scaleX, float scaleY)
00466 {
00467         unsigned char *uc_rect= (unsigned char*) rect;
00468         float *f_rect= (float *)rect;
00469         float xzoom= glaGetOneFloat(GL_ZOOM_X), yzoom= glaGetOneFloat(GL_ZOOM_Y);
00470         int ltexid= glaGetOneInteger(GL_TEXTURE_2D);
00471         int lrowlength= glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
00472         int subpart_x, subpart_y, tex_w, tex_h;
00473         int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
00474         int texid= get_cached_work_texture(&tex_w, &tex_h);
00475         
00476         /* Specify the color outside this function, and tex will modulate it.
00477          * This is useful for changing alpha without using glPixelTransferf()
00478          */
00479         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00480         glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
00481         glBindTexture(GL_TEXTURE_2D, texid);
00482 
00483         /* don't want nasty border artifacts */
00484         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00485         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00486 
00487 #ifdef __APPLE__
00488         /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */
00489         glPixelZoom(1.f, 1.f);
00490 #endif
00491         
00492         /* setup seamless 2=on, 0=off */
00493         seamless= ((tex_w<img_w || tex_h<img_h) && tex_w>2 && tex_h>2)? 2: 0;
00494         
00495         offset_x= tex_w - seamless;
00496         offset_y= tex_h - seamless;
00497         
00498         nsubparts_x= (img_w + (offset_x - 1))/(offset_x);
00499         nsubparts_y= (img_h + (offset_y - 1))/(offset_y);
00500 
00501         for (subpart_y=0; subpart_y<nsubparts_y; subpart_y++) {
00502                 for (subpart_x=0; subpart_x<nsubparts_x; subpart_x++) {
00503                         int remainder_x= img_w-subpart_x*offset_x;
00504                         int remainder_y= img_h-subpart_y*offset_y;
00505                         int subpart_w= (remainder_x<tex_w)? remainder_x: tex_w;
00506                         int subpart_h= (remainder_y<tex_h)? remainder_y: tex_h;
00507                         int offset_left= (seamless && subpart_x!=0)? 1: 0;
00508                         int offset_bot= (seamless && subpart_y!=0)? 1: 0;
00509                         int offset_right= (seamless && remainder_x>tex_w)? 1: 0;
00510                         int offset_top= (seamless && remainder_y>tex_h)? 1: 0;
00511                         float rast_x= x+subpart_x*offset_x*xzoom;
00512                         float rast_y= y+subpart_y*offset_y*yzoom;
00513                         
00514                         /* check if we already got these because we always get 2 more when doing seamless*/
00515                         if(subpart_w<=seamless || subpart_h<=seamless)
00516                                 continue;
00517                         
00518                         if(format==GL_FLOAT) {
00519                                 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]);
00520                                 
00521                                 /* add an extra border of pixels so linear looks ok at edges of full image. */
00522                                 if(subpart_w<tex_w)
00523                                         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]);
00524                                 if(subpart_h<tex_h)
00525                                         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]);
00526                                 if(subpart_w<tex_w && subpart_h<tex_h)
00527                                         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]);
00528                         }
00529                         else {
00530                                 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]);
00531                                 
00532                                 if(subpart_w<tex_w)
00533                                         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]);
00534                                 if(subpart_h<tex_h)
00535                                         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]);
00536                                 if(subpart_w<tex_w && subpart_h<tex_h)
00537                                         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]);
00538                         }
00539 
00540                         glEnable(GL_TEXTURE_2D);
00541                         glBegin(GL_QUADS);
00542                         glTexCoord2f((float)(0 + offset_left)/tex_w, (float)(0 + offset_bot)/tex_h);
00543                         glVertex2f(rast_x + (float)offset_left*xzoom, rast_y + (float)offset_bot*xzoom);
00544 
00545                         glTexCoord2f((float)(subpart_w - offset_right)/tex_w, (float)(0 + offset_bot)/tex_h);
00546                         glVertex2f(rast_x + (float)(subpart_w - offset_right)*xzoom*scaleX, rast_y + (float)offset_bot*xzoom);
00547 
00548                         glTexCoord2f((float)(subpart_w - offset_right)/tex_w, (float)(subpart_h - offset_top)/tex_h);
00549                         glVertex2f(rast_x + (float)(subpart_w - offset_right)*xzoom*scaleX, rast_y + (float)(subpart_h - offset_top)*yzoom*scaleY);
00550 
00551                         glTexCoord2f((float)(0 + offset_left)/tex_w, (float)(subpart_h - offset_top)/tex_h);
00552                         glVertex2f(rast_x + (float)offset_left*xzoom, rast_y + (float)(subpart_h - offset_top)*yzoom*scaleY);
00553                         glEnd();
00554                         glDisable(GL_TEXTURE_2D);
00555                 }
00556         }
00557 
00558         glBindTexture(GL_TEXTURE_2D, ltexid);
00559         glPixelStorei(GL_UNPACK_ROW_LENGTH, lrowlength);
00560         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00561         
00562 #ifdef __APPLE__
00563         /* workaround for os x 10.5/10.6 driver bug (above) */
00564         glPixelZoom(xzoom, yzoom);
00565 #endif
00566 }
00567 
00568 void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void *rect)
00569 {
00570         glaDrawPixelsTexScaled(x, y, img_w, img_h, format, rect, 1.0f, 1.0f);
00571 }
00572 
00573 /* row_w is unused but kept for completeness */
00574 void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int UNUSED(row_w), float *rectf, int do_gamma_correct)
00575 {
00576         unsigned char *rect32;
00577         
00578         /* copy imgw-imgh to a temporal 32 bits rect */
00579         if(img_w<1 || img_h<1) return;
00580         
00581         rect32= MEM_mallocN(img_w*img_h*sizeof(int), "temp 32 bits");
00582         
00583         if (do_gamma_correct) {
00584                 floatbuf_to_srgb_byte(rectf, rect32, 0, img_w, 0, img_h, img_w);
00585         } else {
00586                 floatbuf_to_byte(rectf, rect32, 0, img_w, 0, img_h, img_w);
00587          }
00588         
00589         glaDrawPixelsSafe(fx, fy, img_w, img_h, img_w, GL_RGBA, GL_UNSIGNED_BYTE, rect32);
00590 
00591         MEM_freeN(rect32);
00592 }
00593 
00594 void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect)
00595 {
00596         float xzoom= glaGetOneFloat(GL_ZOOM_X);
00597         float yzoom= glaGetOneFloat(GL_ZOOM_Y);
00598                 
00599                 /* The pixel space coordinate of the intersection of
00600                  * the [zoomed] image with the origin.
00601                  */
00602         float ix= -x/xzoom;
00603         float iy= -y/yzoom;
00604         
00605                 /* The maximum pixel amounts the image can be cropped
00606                  * at the lower left without exceeding the origin.
00607                  */
00608         int off_x= floor(MAX2(ix, 0));
00609         int off_y= floor(MAX2(iy, 0));
00610                 
00611                 /* The zoomed space coordinate of the raster position 
00612                  * (starting at the lower left most unclipped pixel).
00613                  */
00614         float rast_x= x + off_x*xzoom;
00615         float rast_y= y + off_y*yzoom;
00616 
00617         GLfloat scissor[4];
00618         int draw_w, draw_h;
00619 
00620                 /* Determine the smallest number of pixels we need to draw
00621                  * before the image would go off the upper right corner.
00622                  * 
00623                  * It may seem this is just an optimization but some graphics 
00624                  * cards (ATI) freak out if there is a large zoom factor and
00625                  * a large number of pixels off the screen (probably at some
00626                  * level the number of image pixels to draw is getting multiplied
00627                  * by the zoom and then clamped). Making sure we draw the
00628                  * fewest pixels possible keeps everyone mostly happy (still
00629                  * fails if we zoom in on one really huge pixel so that it
00630                  * covers the entire screen).
00631                  */
00632         glGetFloatv(GL_SCISSOR_BOX, scissor);
00633         draw_w = MIN2(img_w-off_x, ceil((scissor[2]-rast_x)/xzoom));
00634         draw_h = MIN2(img_h-off_y, ceil((scissor[3]-rast_y)/yzoom));
00635 
00636         if (draw_w>0 && draw_h>0) {
00637                 int old_row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
00638 
00639                         /* Don't use safe RasterPos (slower) if we can avoid it. */
00640                 if (rast_x>=0 && rast_y>=0) {
00641                         glRasterPos2f(rast_x, rast_y);
00642                 } else {
00643                         glaRasterPosSafe2f(rast_x, rast_y, 0, 0);
00644                 }
00645 
00646                 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_w);
00647                 if(format==GL_LUMINANCE || format==GL_RED) {
00648                         if(type==GL_FLOAT) {
00649                                 float *f_rect= (float *)rect;
00650                                 glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y*row_w + off_x));
00651                         }
00652                         else if(type==GL_INT || type==GL_UNSIGNED_INT) {
00653                                 int *i_rect= (int *)rect;
00654                                 glDrawPixels(draw_w, draw_h, format, type, i_rect + (off_y*row_w + off_x));
00655                         }
00656                 }
00657                 else { /* RGBA */
00658                         if(type==GL_FLOAT) {
00659                                 float *f_rect= (float *)rect;
00660                                 glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y*row_w + off_x)*4);
00661                         }
00662                         else if(type==GL_UNSIGNED_BYTE) {
00663                                 unsigned char *uc_rect= (unsigned char *) rect;
00664                                 glDrawPixels(draw_w, draw_h, format, type, uc_rect + (off_y*row_w + off_x)*4);
00665                         }
00666                 }
00667                 
00668                 glPixelStorei(GL_UNPACK_ROW_LENGTH,  old_row_length);
00669         }
00670 }
00671 
00672 /* 2D Drawing Assistance */
00673 
00674 void glaDefine2DArea(rcti *screen_rect)
00675 {
00676         int sc_w= screen_rect->xmax - screen_rect->xmin + 1;
00677         int sc_h= screen_rect->ymax - screen_rect->ymin + 1;
00678 
00679         glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
00680         glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
00681 
00682                 /* The 0.375 magic number is to shift the matrix so that
00683                  * both raster and vertex integer coordinates fall at pixel
00684                  * centers properly. For a longer discussion see the OpenGL
00685                  * Programming Guide, Appendix H, Correctness Tips.
00686                  */
00687 
00688         glMatrixMode(GL_PROJECTION);
00689         glLoadIdentity();
00690         glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1);
00691         glTranslatef(0.375, 0.375, 0.0);
00692 
00693         glMatrixMode(GL_MODELVIEW);
00694         glLoadIdentity();
00695 }
00696 
00697 struct gla2DDrawInfo {
00698         int orig_vp[4], orig_sc[4];
00699         float orig_projmat[16], orig_viewmat[16];
00700 
00701         rcti screen_rect;
00702         rctf world_rect;
00703 
00704         float wo_to_sc[2];
00705 };
00706 
00707 void gla2DGetMap(gla2DDrawInfo *di, rctf *rect) 
00708 {
00709         *rect= di->world_rect;
00710 }
00711 
00712 void gla2DSetMap(gla2DDrawInfo *di, rctf *rect) 
00713 {
00714         int sc_w, sc_h;
00715         float wo_w, wo_h;
00716 
00717         di->world_rect= *rect;
00718         
00719         sc_w= (di->screen_rect.xmax-di->screen_rect.xmin);
00720         sc_h= (di->screen_rect.ymax-di->screen_rect.ymin);
00721         wo_w= (di->world_rect.xmax-di->world_rect.xmin);
00722         wo_h= (di->world_rect.ymax-di->world_rect.ymin);
00723         
00724         di->wo_to_sc[0]= sc_w/wo_w;
00725         di->wo_to_sc[1]= sc_h/wo_h;
00726 }
00727 
00728 
00729 gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) 
00730 {
00731         gla2DDrawInfo *di= MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
00732         int sc_w, sc_h;
00733         float wo_w, wo_h;
00734 
00735         glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp);
00736         glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc);
00737         glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat);
00738         glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat);
00739 
00740         di->screen_rect= *screen_rect;
00741         if (world_rect) {
00742                 di->world_rect= *world_rect;
00743         } else {
00744                 di->world_rect.xmin= di->screen_rect.xmin;
00745                 di->world_rect.ymin= di->screen_rect.ymin;
00746                 di->world_rect.xmax= di->screen_rect.xmax;
00747                 di->world_rect.ymax= di->screen_rect.ymax;
00748         }
00749 
00750         sc_w= (di->screen_rect.xmax-di->screen_rect.xmin);
00751         sc_h= (di->screen_rect.ymax-di->screen_rect.ymin);
00752         wo_w= (di->world_rect.xmax-di->world_rect.xmin);
00753         wo_h= (di->world_rect.ymax-di->world_rect.ymin);
00754 
00755         di->wo_to_sc[0]= sc_w/wo_w;
00756         di->wo_to_sc[1]= sc_h/wo_h;
00757 
00758         glaDefine2DArea(&di->screen_rect);
00759 
00760         return di;
00761 }
00762 
00763 void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r)
00764 {
00765         *sc_x_r= (wo_x - di->world_rect.xmin)*di->wo_to_sc[0];
00766         *sc_y_r= (wo_y - di->world_rect.ymin)*di->wo_to_sc[1];
00767 }
00768 void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
00769 {
00770         screen_r[0]= (world[0] - di->world_rect.xmin)*di->wo_to_sc[0];
00771         screen_r[1]= (world[1] - di->world_rect.ymin)*di->wo_to_sc[1];
00772 }
00773 
00774 void glaEnd2DDraw(gla2DDrawInfo *di)
00775 {
00776         glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
00777         glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
00778         glMatrixMode(GL_PROJECTION);
00779         glLoadMatrixf(di->orig_projmat);
00780         glMatrixMode(GL_MODELVIEW);
00781         glLoadMatrixf(di->orig_viewmat);
00782 
00783         MEM_freeN(di);
00784 }
00785 
00786 /* **************** glPoint hack ************************ */
00787 
00788 static int curmode=0;
00789 static int pointhack=0;
00790 static GLubyte Squaredot[16] = { 0xff,0xff,0xff,0xff,
00791                                                                  0xff,0xff,0xff,0xff,
00792                                                                  0xff,0xff,0xff,0xff, 
00793                                                                  0xff,0xff,0xff,0xff};
00794 
00795 void bglBegin(int mode)
00796 {
00797         curmode= mode;
00798         
00799         if(mode==GL_POINTS) {
00800                 float value[4];
00801                 glGetFloatv(GL_POINT_SIZE_RANGE, value);
00802                 if(value[1] < 2.0f) {
00803                         glGetFloatv(GL_POINT_SIZE, value);
00804                         pointhack= floor(value[0] + 0.5f);
00805                         if(pointhack>4) pointhack= 4;
00806                 }
00807                 else glBegin(mode);
00808         }
00809 }
00810 
00811 int bglPointHack(void) {
00812         float value[4];
00813         int pointhack_px;
00814         glGetFloatv(GL_POINT_SIZE_RANGE, value);
00815         if(value[1] < 2.0f) {
00816                 glGetFloatv(GL_POINT_SIZE, value);
00817                 pointhack_px= floorf(value[0]+0.5f);
00818                 if(pointhack_px>4) pointhack_px= 4;
00819                 return pointhack_px;
00820         }
00821         return 0;
00822 }
00823 
00824 void bglVertex3fv(float *vec)
00825 {
00826         switch(curmode) {
00827         case GL_POINTS:
00828                 if(pointhack) {
00829                         glRasterPos3fv(vec);
00830                         glBitmap(pointhack, pointhack, (float)pointhack/2.0f, (float)pointhack/2.0f, 0.0, 0.0, Squaredot);
00831                 }
00832                 else glVertex3fv(vec);
00833                 break;
00834         }
00835 }
00836 
00837 void bglVertex3f(float x, float y, float z)
00838 {
00839         switch(curmode) {
00840         case GL_POINTS:
00841                 if(pointhack) {
00842                         glRasterPos3f(x, y, z);
00843                         glBitmap(pointhack, pointhack, (float)pointhack/2.0f, (float)pointhack/2.0f, 0.0, 0.0, Squaredot);
00844                 }
00845                 else glVertex3f(x, y, z);
00846                 break;
00847         }
00848 }
00849 
00850 void bglVertex2fv(float *vec)
00851 {
00852         switch(curmode) {
00853         case GL_POINTS:
00854                 if(pointhack) {
00855                         glRasterPos2fv(vec);
00856                         glBitmap(pointhack, pointhack, (float)pointhack/2, pointhack/2, 0.0, 0.0, Squaredot);
00857                 }
00858                 else glVertex2fv(vec);
00859                 break;
00860         }
00861 }
00862 
00863 
00864 void bglEnd(void)
00865 {
00866         if(pointhack) pointhack= 0;
00867         else glEnd();
00868         
00869 }
00870 
00871 /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
00872 void bgl_get_mats(bglMats *mats)
00873 {
00874         const double badvalue= 1.0e-6;
00875 
00876         glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
00877         glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
00878         glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
00879         
00880         /* Very strange code here - it seems that certain bad values in the
00881            modelview matrix can cause gluUnProject to give bad results. */
00882         if(mats->modelview[0] < badvalue &&
00883            mats->modelview[0] > -badvalue)
00884                 mats->modelview[0]= 0;
00885         if(mats->modelview[5] < badvalue &&
00886            mats->modelview[5] > -badvalue)
00887                 mats->modelview[5]= 0;
00888         
00889         /* Set up viewport so that gluUnProject will give correct values */
00890         mats->viewport[0] = 0;
00891         mats->viewport[1] = 0;
00892 }
00893 
00894 /* *************** glPolygonOffset hack ************* */
00895 
00896 /* dist is only for ortho now... */
00897 void bglPolygonOffset(float viewdist, float dist) 
00898 {
00899         static float winmat[16], offset=0.0;    
00900         
00901         if(dist != 0.0f) {
00902                 float offs;
00903                 
00904                 // glEnable(GL_POLYGON_OFFSET_FILL);
00905                 // glPolygonOffset(-1.0, -1.0);
00906 
00907                 /* hack below is to mimic polygon offset */
00908                 glMatrixMode(GL_PROJECTION);
00909                 glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
00910                 
00911                 /* dist is from camera to center point */
00912                 
00913                 if(winmat[15]>0.5f) offs= 0.00001f*dist*viewdist;  // ortho tweaking
00914                 else offs= 0.0005f*dist;  // should be clipping value or so...
00915                 
00916                 winmat[14]-= offs;
00917                 offset+= offs;
00918                 
00919                 glLoadMatrixf(winmat);
00920                 glMatrixMode(GL_MODELVIEW);
00921         }
00922         else {
00923 
00924                 glMatrixMode(GL_PROJECTION);
00925                 winmat[14]+= offset;
00926                 offset= 0.0;
00927                 glLoadMatrixf(winmat);
00928                 glMatrixMode(GL_MODELVIEW);
00929         }
00930 }
00931 
00932 void bglFlush(void) 
00933 {
00934         glFlush();
00935 #ifdef __APPLE__
00936 //      if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
00937 // XXX          myswapbuffers(); //hack to get mac intel graphics to show frontbuffer
00938 #endif
00939 }
00940