/** * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ #include #include #include #include "MEM_guardedalloc.h" #include "DNA_vec_types.h" #include "DNA_listBase.h" #include "BKE_utildefines.h" #include "BLI_arithb.h" #include "BLI_threads.h" #include "BIF_gl.h" #include "BIF_glutil.h" #include "BIF_mywindow.h" #ifndef GL_CLAMP_TO_EDGE #define GL_CLAMP_TO_EDGE 0x812F #endif /* defined in BIF_gl.h */ GLubyte stipple_halftone[128] = { 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55}; /* repeate this pattern X000X000 00000000 00X000X0 00000000 */ GLubyte stipple_quarttone[128] = { 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0}; /* Invert line handling */ #define glToggle(mode, onoff) (((onoff)?glEnable:glDisable)(mode)) void set_inverted_drawing(int enable) { glLogicOp(enable?GL_INVERT:GL_COPY); /* Use GL_BLEND_EQUATION_EXT on sgi (if we have it), * apparently GL_COLOR_LOGIC_OP doesn't work on O2? * Is this an sgi bug or our bug? */ #if defined(__sgi) && defined(GL_BLEND_EQUATION_EXT) glBlendEquationEXT(enable?GL_LOGIC_OP:GL_FUNC_ADD_EXT); glToggle(GL_BLEND, enable); #else glToggle(GL_COLOR_LOGIC_OP, enable); #endif glToggle(GL_DITHER, !enable); } void sdrawXORline(int x0, int y0, int x1, int y1) { if(x0==x1 && y0==y1) return; set_inverted_drawing(1); glBegin(GL_LINES); glVertex2i(x0, y0); glVertex2i(x1, y1); glEnd(); set_inverted_drawing(0); } void glutil_draw_front_xor_line(int x0, int y0, int x1, int y1) { glReadBuffer(GL_FRONT); glDrawBuffer(GL_FRONT); sdrawXORline(x0, y0, x1, y1); glFlush(); glReadBuffer(GL_BACK); glDrawBuffer(GL_BACK); } void sdrawXORline4(int nr, int x0, int y0, int x1, int y1) { static short old[4][2][2]; static char flags[4]= {0, 0, 0, 0}; /* with builtin memory, max 4 lines */ set_inverted_drawing(1); glBegin(GL_LINES); if(nr== -1) { /* flush */ for (nr=0; nr<4; nr++) { if (flags[nr]) { glVertex2sv(old[nr][0]); glVertex2sv(old[nr][1]); flags[nr]= 0; } } } else { if(nr>=0 && nr<4) { if(flags[nr]) { glVertex2sv(old[nr][0]); glVertex2sv(old[nr][1]); } old[nr][0][0]= x0; old[nr][0][1]= y0; old[nr][1][0]= x1; old[nr][1][1]= y1; flags[nr]= 1; } glVertex2i(x0, y0); glVertex2i(x1, y1); } glEnd(); set_inverted_drawing(0); } void fdrawXORellipse(float xofs, float yofs, float hw, float hh) { if(hw==0) return; set_inverted_drawing(1); glPushMatrix(); glTranslatef(xofs, yofs, 0.0); glScalef(1,hh/hw,1); glutil_draw_lined_arc(0.0, M_PI*2.0, hw, 20); glPopMatrix(); set_inverted_drawing(0); } void fdrawXORcirc(float xofs, float yofs, float rad) { set_inverted_drawing(1); glPushMatrix(); glTranslatef(xofs, yofs, 0.0); glutil_draw_lined_arc(0.0, M_PI*2.0, rad, 20); glPopMatrix(); set_inverted_drawing(0); } void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments) { int i; glBegin(GL_TRIANGLE_FAN); glVertex2f(0.0, 0.0); for (i=0; i=1.0f?255: (char)(255.0f*val)) void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int row_w, float *rectf) { float *rf; int x, y; char *rect32, *rc; /* copy imgw-imgh to a temporal 32 bits rect */ if(img_w<1 || img_h<1) return; rc= rect32= MEM_mallocN(img_w*img_h*sizeof(int), "temp 32 bits"); for(y=0; y0 && draw_h>0) { int old_row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH); /* Don't use safe RasterPos (slower) if we can avoid it. */ if (rast_x>=0 && rast_y>=0) { glRasterPos2f(rast_x, rast_y); } else { glaRasterPosSafe2f(rast_x, rast_y, 0, 0); } glPixelStorei(GL_UNPACK_ROW_LENGTH, row_w); if(format==GL_LUMINANCE || format==GL_RED) { if(type==GL_FLOAT) { float *f_rect= (float *)rect; glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y*row_w + off_x)); } else if(type==GL_INT || type==GL_UNSIGNED_INT) { int *i_rect= (int *)rect; glDrawPixels(draw_w, draw_h, format, type, i_rect + (off_y*row_w + off_x)); } } else { /* RGBA */ if(type==GL_FLOAT) { float *f_rect= (float *)rect; glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y*row_w + off_x)*4); } else if(type==GL_UNSIGNED_BYTE) { unsigned char *uc_rect= (unsigned char *) rect; glDrawPixels(draw_w, draw_h, format, type, uc_rect + (off_y*row_w + off_x)*4); } } glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length); } } /* 2D Drawing Assistance */ void glaDefine2DArea(rcti *screen_rect) { int sc_w= screen_rect->xmax - screen_rect->xmin; int sc_h= screen_rect->ymax - screen_rect->ymin; glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h); glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h); /* The 0.375 magic number is to shift the matrix so that * both raster and vertex integer coordinates fall at pixel * centers properly. For a longer discussion see the OpenGL * Programming Guide, Appendix H, Correctness Tips. */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1); glTranslatef(0.375, 0.375, 0.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } struct gla2DDrawInfo { int orig_vp[4], orig_sc[4]; float orig_projmat[16], orig_viewmat[16]; rcti screen_rect; rctf world_rect; float wo_to_sc[2]; }; void gla2DGetMap(gla2DDrawInfo *di, rctf *rect) { *rect= di->world_rect; } void gla2DSetMap(gla2DDrawInfo *di, rctf *rect) { int sc_w, sc_h; float wo_w, wo_h; di->world_rect= *rect; sc_w= (di->screen_rect.xmax-di->screen_rect.xmin); sc_h= (di->screen_rect.ymax-di->screen_rect.ymin); wo_w= (di->world_rect.xmax-di->world_rect.xmin); wo_h= (di->world_rect.ymax-di->world_rect.ymin); di->wo_to_sc[0]= sc_w/wo_w; di->wo_to_sc[1]= sc_h/wo_h; } gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) { gla2DDrawInfo *di= MEM_mallocN(sizeof(*di), "gla2DDrawInfo"); int sc_w, sc_h; float wo_w, wo_h; glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp); glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc); glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat); glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat); di->screen_rect= *screen_rect; if (world_rect) { di->world_rect= *world_rect; } else { di->world_rect.xmin= di->screen_rect.xmin; di->world_rect.ymin= di->screen_rect.ymin; di->world_rect.xmax= di->screen_rect.xmax; di->world_rect.ymax= di->screen_rect.ymax; } sc_w= (di->screen_rect.xmax-di->screen_rect.xmin); sc_h= (di->screen_rect.ymax-di->screen_rect.ymin); wo_w= (di->world_rect.xmax-di->world_rect.xmin); wo_h= (di->world_rect.ymax-di->world_rect.ymin); di->wo_to_sc[0]= sc_w/wo_w; di->wo_to_sc[1]= sc_h/wo_h; glaDefine2DArea(&di->screen_rect); return di; } void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r) { *sc_x_r= (wo_x - di->world_rect.xmin)*di->wo_to_sc[0]; *sc_y_r= (wo_y - di->world_rect.ymin)*di->wo_to_sc[1]; } void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2]) { screen_r[0]= (world[0] - di->world_rect.xmin)*di->wo_to_sc[0]; screen_r[1]= (world[1] - di->world_rect.ymin)*di->wo_to_sc[1]; } void glaEnd2DDraw(gla2DDrawInfo *di) { glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]); glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]); glMatrixMode(GL_PROJECTION); glLoadMatrixf(di->orig_projmat); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(di->orig_viewmat); MEM_freeN(di); } /* **************** glPoint hack ************************ */ static int curmode=0; static int pointhack=0; static GLubyte Squaredot[16] = { 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff}; void bglBegin(int mode) { curmode= mode; if(mode==GL_POINTS) { float value[4]; glGetFloatv(GL_POINT_SIZE_RANGE, value); if(value[1]<2.0) { glGetFloatv(GL_POINT_SIZE, value); pointhack= floor(value[0]+0.5); if(pointhack>4) pointhack= 4; } else glBegin(mode); } } void bglVertex3fv(float *vec) { switch(curmode) { case GL_POINTS: if(pointhack) { glRasterPos3fv(vec); glBitmap(pointhack, pointhack, (float)pointhack/2.0, (float)pointhack/2.0, 0.0, 0.0, Squaredot); } else glVertex3fv(vec); break; } } void bglVertex3f(float x, float y, float z) { switch(curmode) { case GL_POINTS: if(pointhack) { glRasterPos3f(x, y, z); glBitmap(pointhack, pointhack, (float)pointhack/2.0, (float)pointhack/2.0, 0.0, 0.0, Squaredot); } else glVertex3f(x, y, z); break; } } void bglVertex2fv(float *vec) { switch(curmode) { case GL_POINTS: if(pointhack) { glRasterPos2fv(vec); glBitmap(pointhack, pointhack, (float)pointhack/2, pointhack/2, 0.0, 0.0, Squaredot); } else glVertex2fv(vec); break; } } void bglEnd(void) { if(pointhack) pointhack= 0; else glEnd(); } /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */ void bgl_get_mats(bglMats *mats) { const double badvalue= 1.0e-6; glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview); glGetDoublev(GL_PROJECTION_MATRIX, mats->projection); glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport); /* Very strange code here - it seems that certain bad values in the modelview matrix can cause gluUnProject to give bad results. */ if(mats->modelview[0] < badvalue && mats->modelview[0] > -badvalue) mats->modelview[0]= 0; if(mats->modelview[5] < badvalue && mats->modelview[5] > -badvalue) mats->modelview[5]= 0; /* Set up viewport so that gluUnProject will give correct values */ mats->viewport[0] = 0; mats->viewport[1] = 0; } /* *************** glPolygonOffset hack ************* */ // both temporal, so here for now (ton) #include "BKE_global.h" #include "DNA_view3d_types.h" /* dist is only for ortho now... */ void bglPolygonOffset(float dist) { static float winmat[16], offset=0.0; if(dist!=0.0) { float offs; // glEnable(GL_POLYGON_OFFSET_FILL); // glPolygonOffset(-1.0, -1.0); /* hack below is to mimic polygon offset */ glMatrixMode(GL_PROJECTION); glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat); /* dist is from camera to center point */ if(winmat[15]>0.5) offs= 0.00001*dist*G.vd->dist; // ortho tweaking else offs= 0.0005*dist; // should be clipping value or so... winmat[14]-= offs; offset+= offs; glLoadMatrixf(winmat); glMatrixMode(GL_MODELVIEW); } else { glMatrixMode(GL_PROJECTION); winmat[14]+= offset; offset= 0.0; glLoadMatrixf(winmat); glMatrixMode(GL_MODELVIEW); } } int is_a_really_crappy_intel_card(void) { static int well_is_it= -1; /* Do you understand the implication? Do you? */ if (well_is_it==-1) well_is_it= (strcmp((char*) glGetString(GL_VENDOR), "Intel Inc.") == 0); return well_is_it; } void bglFlush(void) { glFlush(); #ifdef __APPLE__ if(is_a_really_crappy_intel_card()) myswapbuffers(); //hack to get mac intel graphics to show frontbuffer #endif }