/** * $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. * * Contributor(s): Blender Foundation, full recode and added functions * * ***** END GPL LICENSE BLOCK ***** */ #include #include #ifdef HAVE_CONFIG_H #include #endif #include "MEM_guardedalloc.h" #include "IMB_imbuf.h" #include "DNA_armature_types.h" #include "DNA_boid_types.h" #include "DNA_camera_types.h" #include "DNA_curve_types.h" #include "DNA_constraint_types.h" // for drawing constraint #include "DNA_effect_types.h" #include "DNA_lamp_types.h" #include "DNA_lattice_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_meta_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_object_fluidsim.h" #include "DNA_particle_types.h" #include "DNA_space_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_smoke_types.h" #include "DNA_userdef_types.h" #include "DNA_view3d_types.h" #include "DNA_world_types.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_editVert.h" #include "BLI_edgehash.h" #include "BLI_rand.h" #include "BKE_anim.h" //for the where_on_path function #include "BKE_curve.h" #include "BKE_constraint.h" // for the get_constraint_target function #include "BKE_DerivedMesh.h" #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_mesh.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_property.h" #include "BKE_smoke.h" #include "BKE_unit.h" #include "BKE_utildefines.h" #include "smoke_API.h" #include "BIF_gl.h" #include "BIF_glutil.h" #include "GPU_draw.h" #include "GPU_material.h" #include "GPU_extensions.h" #include "ED_mesh.h" #include "ED_particle.h" #include "ED_screen.h" #include "ED_types.h" #include "ED_util.h" #include "UI_resources.h" #include "UI_interface_icons.h" #include "WM_api.h" #include "BLF_api.h" #include "view3d_intern.h" // own include /* this condition has been made more complex since editmode can draw textures */ #define CHECK_OB_DRAWTEXTURE(vd, dt) \ ((vd->drawtype==OB_TEXTURE && dt>OB_SOLID) || \ (vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX)) #define CHECK_OB_DRAWFACEDOT(sce, vd, dt) \ ( (sce->toolsettings->selectmode & SCE_SELECT_FACE) && \ (vd->drawtype<=OB_SOLID) && \ (((vd->drawtype==OB_SOLID) && (dt>=OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX) && (vd->flag & V3D_ZBUF_SELECT)) == 0) \ ) static void draw_bounding_volume(Scene *scene, Object *ob); static void drawcube_size(float size); static void drawcircle_size(float size); static void draw_empty_sphere(float size); static void draw_empty_cone(float size); /* ************* only use while object drawing ************** */ static void view3d_project_short_clip(ARegion *ar, float *vec, short *adr) { RegionView3D *rv3d= ar->regiondata; float fx, fy, vec4[4]; adr[0]= IS_CLIPPED; /* clipplanes in eye space */ if(rv3d->rflag & RV3D_CLIPPING) { VECCOPY(vec4, vec); Mat4MulVecfl(rv3d->viewmatob, vec4); if(view3d_test_clipping(rv3d, vec4)) return; } VECCOPY(vec4, vec); vec4[3]= 1.0; Mat4MulVec4fl(rv3d->persmatob, vec4); /* clipplanes in window space */ if( vec4[3]>BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */ fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); if( fx>0 && fxwinx) { fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); if(fy>0.0 && fy< (float)ar->winy) { adr[0]= (short)floor(fx); adr[1]= (short)floor(fy); } } } } /* only use while object drawing */ static void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr) { RegionView3D *rv3d= ar->regiondata; float fx, fy, vec4[4]; adr[0]= IS_CLIPPED; VECCOPY(vec4, vec); vec4[3]= 1.0; Mat4MulVec4fl(rv3d->persmatob, vec4); if( vec4[3]>BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */ fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); if( fx>-32700 && fx<32700) { fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); if(fy>-32700.0 && fy<32700.0) { adr[0]= (short)floor(fx); adr[1]= (short)floor(fy); } } } } /* ************************ */ /* check for glsl drawing */ int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt) { if(!GPU_extensions_minimum_support()) return 0; if(G.f & G_PICKSEL) return 0; if(!CHECK_OB_DRAWTEXTURE(v3d, dt)) return 0; if(ob==OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT)) return 0; return (scene->gm.matmode == GAME_MAT_GLSL) && (dt >= OB_SHADED); } static int check_material_alpha(Base *base, Mesh *me, int glsl) { if(base->flag & OB_FROMDUPLI) return 0; if(G.f & G_PICKSEL) return 0; if(me->edit_mesh) return 0; return (glsl || (base->object->dtx & OB_DRAWTRANSP)); } /***/ static unsigned int colortab[24]= {0x0, 0xFF88FF, 0xFFBBFF, 0x403000, 0xFFFF88, 0xFFFFBB, 0x104040, 0x66CCCC, 0x77CCCC, 0x104010, 0x55BB55, 0x66FF66, 0xFFFFFF }; static float cube[8][3] = { {-1.0, -1.0, -1.0}, {-1.0, -1.0, 1.0}, {-1.0, 1.0, 1.0}, {-1.0, 1.0, -1.0}, { 1.0, -1.0, -1.0}, { 1.0, -1.0, 1.0}, { 1.0, 1.0, 1.0}, { 1.0, 1.0, -1.0}, }; /* ----------------- OpenGL Circle Drawing - Tables for Optimised Drawing Speed ------------------ */ /* 32 values of sin function (still same result!) */ static float sinval[32] = { 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, -0.57126821, -0.39435585, -0.20129852, 0.00000000 }; /* 32 values of cos function (still same result!) */ static float cosval[32] ={ 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, 0.82076344, 0.91895781, 0.97952994, 1.00000000 }; /* flag is same as for draw_object */ void drawaxes(float size, int flag, char drawtype) { int axis; float v1[3]= {0.0, 0.0, 0.0}; float v2[3]= {0.0, 0.0, 0.0}; float v3[3]= {0.0, 0.0, 0.0}; if(G.f & G_RENDER_SHADOW) return; switch(drawtype) { case OB_PLAINAXES: for (axis=0; axis<3; axis++) { float v1[3]= {0.0, 0.0, 0.0}; float v2[3]= {0.0, 0.0, 0.0}; glBegin(GL_LINES); v1[axis]= size; v2[axis]= -size; glVertex3fv(v1); glVertex3fv(v2); glEnd(); } break; case OB_SINGLE_ARROW: glBegin(GL_LINES); /* in positive z direction only */ v1[2]= size; glVertex3fv(v1); glVertex3fv(v2); glEnd(); /* square pyramid */ glBegin(GL_TRIANGLES); v2[0]= size*0.035; v2[1] = size*0.035; v3[0]= size*-0.035; v3[1] = size*0.035; v2[2]= v3[2]= size*0.75; for (axis=0; axis<4; axis++) { if (axis % 2 == 1) { v2[0] *= -1; v3[1] *= -1; } else { v2[1] *= -1; v3[0] *= -1; } glVertex3fv(v1); glVertex3fv(v2); glVertex3fv(v3); } glEnd(); break; case OB_CUBE: drawcube_size(size); break; case OB_CIRCLE: drawcircle_size(size); break; case OB_EMPTY_SPHERE: draw_empty_sphere(size); break; case OB_EMPTY_CONE: draw_empty_cone(size); break; case OB_ARROWS: default: for (axis=0; axis<3; axis++) { float v1[3]= {0.0, 0.0, 0.0}; float v2[3]= {0.0, 0.0, 0.0}; int arrow_axis= (axis==0)?1:0; glBegin(GL_LINES); v2[axis]= size; glVertex3fv(v1); glVertex3fv(v2); v1[axis]= size*0.8; v1[arrow_axis]= -size*0.125; glVertex3fv(v1); glVertex3fv(v2); v1[arrow_axis]= size*0.125; glVertex3fv(v1); glVertex3fv(v2); glEnd(); v2[axis]+= size*0.125; // patch for 3d cards crashing on glSelect for text drawing (IBM) if((flag & DRAW_PICKING) == 0) { if (axis==0) view3d_object_text_draw_add(v2[0], v2[1], v2[2], "x", 0); else if (axis==1) view3d_object_text_draw_add(v2[0], v2[1], v2[2], "y", 0); else view3d_object_text_draw_add(v2[0], v2[1], v2[2], "z", 0); } } break; } } void drawcircball(int mode, float *cent, float rad, float tmat[][4]) { float vec[3], vx[3], vy[3]; int a, tot=32; VECCOPY(vx, tmat[0]); VECCOPY(vy, tmat[1]); VecMulf(vx, rad); VecMulf(vy, rad); glBegin(mode); for(a=0; apersmat[0][3]*vec[0]+ rv3d->persmat[1][3]*vec[1]+ rv3d->persmat[2][3]*vec[2]+ rv3d->persmat[3][3]; size*= rv3d->pixsize*((float)U.obcenter_dia*0.5f); /* using gldepthfunc guarantees that it does write z values, but not checks for it, so centers remain visible independt order of drawing */ if(v3d->zbuf) glDepthFunc(GL_ALWAYS); glEnable(GL_BLEND); if(special_color) { if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155); else glColor4ub(0x55, 0xCC, 0xCC, 155); } else { if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80); else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80); else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80); } drawcircball(GL_POLYGON, vec, size, rv3d->viewinv); UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30); drawcircball(GL_LINE_LOOP, vec, size, rv3d->viewinv); glDisable(GL_BLEND); if(v3d->zbuf) glDepthFunc(GL_LEQUAL); } /* *********** text drawing for object ************* */ static ListBase strings= {NULL, NULL}; typedef struct ViewObjectString { struct ViewObjectString *next, *prev; float vec[3], col[4]; char str[128]; short mval[2]; short xoffs; } ViewObjectString; void view3d_object_text_draw_add(float x, float y, float z, char *str, short xoffs) { ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString"); BLI_addtail(&strings, vos); BLI_strncpy(vos->str, str, 128); vos->vec[0]= x; vos->vec[1]= y; vos->vec[2]= z; glGetFloatv(GL_CURRENT_COLOR, vos->col); vos->xoffs= xoffs; } static void view3d_object_text_draw(View3D *v3d, ARegion *ar) { ViewObjectString *vos; int tot= 0; /* project first and test */ for(vos= strings.first; vos; vos= vos->next) { view3d_project_short_clip(ar, vos->vec, vos->mval); if(vos->mval[0]!=IS_CLIPPED) tot++; } if(tot) { RegionView3D *rv3d= ar->regiondata; int a; if(rv3d->rflag & RV3D_CLIPPING) for(a=0; a<6; a++) glDisable(GL_CLIP_PLANE0+a); wmPushMatrix(); ED_region_pixelspace(ar); if(v3d->zbuf) glDisable(GL_DEPTH_TEST); for(vos= strings.first; vos; vos= vos->next) { if(vos->mval[0]!=IS_CLIPPED) { glColor3fv(vos->col); BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 0.0, vos->str); } } if(v3d->zbuf) glEnable(GL_DEPTH_TEST); wmPopMatrix(); if(rv3d->rflag & RV3D_CLIPPING) for(a=0; a<6; a++) glEnable(GL_CLIP_PLANE0+a); } if(strings.first) BLI_freelistN(&strings); } static void drawcube(void) { glBegin(GL_LINE_STRIP); glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]); glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[7]); glVertex3fv(cube[4]); glEnd(); glBegin(GL_LINE_STRIP); glVertex3fv(cube[1]); glVertex3fv(cube[5]); glEnd(); glBegin(GL_LINE_STRIP); glVertex3fv(cube[2]); glVertex3fv(cube[6]); glEnd(); glBegin(GL_LINE_STRIP); glVertex3fv(cube[3]); glVertex3fv(cube[7]); glEnd(); } /* draws a cube on given the scaling of the cube, assuming that * all required matrices have been set (used for drawing empties) */ static void drawcube_size(float size) { glBegin(GL_LINE_STRIP); glVertex3f(-size,-size,-size); glVertex3f(-size,-size,size);glVertex3f(-size,size,size); glVertex3f(-size,size,-size); glVertex3f(-size,-size,-size); glVertex3f(size,-size,-size);glVertex3f(size,-size,size); glVertex3f(size,size,size); glVertex3f(size,size,-size); glVertex3f(size,-size,-size); glEnd(); glBegin(GL_LINE_STRIP); glVertex3f(-size,-size,size); glVertex3f(size,-size,size); glEnd(); glBegin(GL_LINE_STRIP); glVertex3f(-size,size,size); glVertex3f(size,size,size); glEnd(); glBegin(GL_LINE_STRIP); glVertex3f(-size,size,-size); glVertex3f(size,size,-size); glEnd(); } /* this is an unused (old) cube-drawing function based on a given size */ #if 0 static void drawcube_size(float *size) { glPushMatrix(); glScalef(size[0], size[1], size[2]); glBegin(GL_LINE_STRIP); glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]); glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[7]); glVertex3fv(cube[4]); glEnd(); glBegin(GL_LINE_STRIP); glVertex3fv(cube[1]); glVertex3fv(cube[5]); glEnd(); glBegin(GL_LINE_STRIP); glVertex3fv(cube[2]); glVertex3fv(cube[6]); glEnd(); glBegin(GL_LINE_STRIP); glVertex3fv(cube[3]); glVertex3fv(cube[7]); glEnd(); glPopMatrix(); } #endif static void drawshadbuflimits(Lamp *la, float mat[][4]) { float sta[3], end[3], lavec[3]; lavec[0]= -mat[2][0]; lavec[1]= -mat[2][1]; lavec[2]= -mat[2][2]; Normalize(lavec); sta[0]= mat[3][0]+ la->clipsta*lavec[0]; sta[1]= mat[3][1]+ la->clipsta*lavec[1]; sta[2]= mat[3][2]+ la->clipsta*lavec[2]; end[0]= mat[3][0]+ la->clipend*lavec[0]; end[1]= mat[3][1]+ la->clipend*lavec[1]; end[2]= mat[3][2]+ la->clipend*lavec[2]; glBegin(GL_LINE_STRIP); glVertex3fv(sta); glVertex3fv(end); glEnd(); glPointSize(3.0); bglBegin(GL_POINTS); bglVertex3fv(sta); bglVertex3fv(end); bglEnd(); glPointSize(1.0); } static void spotvolume(float *lvec, float *vvec, float inp) { /* camera is at 0,0,0 */ float temp[3],plane[3],mat1[3][3],mat2[3][3],mat3[3][3],mat4[3][3],q[4],co,si,angle; Normalize(lvec); Normalize(vvec); /* is this the correct vector ? */ Crossf(temp,vvec,lvec); /* equation for a plane through vvec en lvec */ Crossf(plane,lvec,temp); /* a plane perpendicular to this, parrallel with lvec */ Normalize(plane); /* now we've got two equations: one of a cone and one of a plane, but we have three unknowns. We remove one unkown by rotating the plane to z=0 (the plane normal) */ /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */ /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/ /* translating this comment to english didnt really help me understanding the math! :-) (ton) */ q[1] = plane[1] ; q[2] = -plane[0] ; q[3] = 0 ; Normalize(&q[1]); angle = saacos(plane[2])/2.0; co = cos(angle); si = sqrt(1-co*co); q[0] = co; q[1] *= si; q[2] *= si; q[3] = 0; QuatToMat3(q,mat1); /* rotate lamp vector now over acos(inp) degrees */ vvec[0] = lvec[0] ; vvec[1] = lvec[1] ; vvec[2] = lvec[2] ; Mat3One(mat2); co = inp; si = sqrt(1-inp*inp); mat2[0][0] = co; mat2[1][0] = -si; mat2[0][1] = si; mat2[1][1] = co; Mat3MulMat3(mat3,mat2,mat1); mat2[1][0] = si; mat2[0][1] = -si; Mat3MulMat3(mat4,mat2,mat1); Mat3Transp(mat1); Mat3MulMat3(mat2,mat1,mat3); Mat3MulVecfl(mat2,lvec); Mat3MulMat3(mat2,mat1,mat4); Mat3MulVecfl(mat2,vvec); return; } static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob) { Lamp *la; float vec[3], lvec[3], vvec[3], circrad, x,y,z; float pixsize, lampsize; float imat[4][4], curcol[4]; char col[4]; if(G.f & G_RENDER_SHADOW) return; la= ob->data; /* we first draw only the screen aligned & fixed scale stuff */ glPushMatrix(); wmLoadMatrix(rv3d->viewmat); /* lets calculate the scale: */ pixsize= rv3d->persmat[0][3]*ob->obmat[3][0]+ rv3d->persmat[1][3]*ob->obmat[3][1]+ rv3d->persmat[2][3]*ob->obmat[3][2]+ rv3d->persmat[3][3]; pixsize*= rv3d->pixsize; lampsize= pixsize*((float)U.obcenter_dia*0.5f); /* and view aligned matrix: */ Mat4CpyMat4(imat, rv3d->viewinv); Normalize(imat[0]); Normalize(imat[1]); /* for AA effects */ glGetFloatv(GL_CURRENT_COLOR, curcol); curcol[3]= 0.6; glColor4fv(curcol); if(ob->id.us>1) { if (ob==OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155); else glColor4ub(0x77, 0xCC, 0xCC, 155); } /* Inner Circle */ VECCOPY(vec, ob->obmat[3]); glEnable(GL_BLEND); drawcircball(GL_LINE_LOOP, vec, lampsize, imat); glDisable(GL_BLEND); drawcircball(GL_POLYGON, vec, lampsize, imat); /* restore */ if(ob->id.us>1) glColor4fv(curcol); /* Outer circle */ circrad = 3.0f*lampsize; drawcircball(GL_LINE_LOOP, vec, circrad, imat); setlinestyle(3); /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */ if (la->type!=LA_HEMI) { if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type==LA_SPOT)) ) { drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f*pixsize, imat); } } /* draw the pretty sun rays */ if(la->type==LA_SUN) { float v1[3], v2[3], mat[3][3]; short axis; /* setup a 45 degree rotation matrix */ VecRotToMat3(imat[2], M_PI/4.0f, mat); /* vectors */ VECCOPY(v1, imat[0]); VecMulf(v1, circrad*1.2f); VECCOPY(v2, imat[0]); VecMulf(v2, circrad*2.5f); /* center */ glTranslatef(vec[0], vec[1], vec[2]); setlinestyle(3); glBegin(GL_LINES); for (axis=0; axis<8; axis++) { glVertex3fv(v1); glVertex3fv(v2); Mat3MulVecfl(mat, v1); Mat3MulVecfl(mat, v2); } glEnd(); glTranslatef(-vec[0], -vec[1], -vec[2]); } if (la->type==LA_LOCAL) { if(la->mode & LA_SPHERE) { drawcircball(GL_LINE_LOOP, vec, la->dist, imat); } /* yafray: for photonlight also draw lightcone as for spot */ } glPopMatrix(); /* back in object space */ vec[0]= vec[1]= vec[2]= 0.0f; if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) { lvec[0]=lvec[1]= 0.0; lvec[2] = 1.0; x = rv3d->persmat[0][2]; y = rv3d->persmat[1][2]; z = rv3d->persmat[2][2]; vvec[0]= x*ob->obmat[0][0] + y*ob->obmat[0][1] + z*ob->obmat[0][2]; vvec[1]= x*ob->obmat[1][0] + y*ob->obmat[1][1] + z*ob->obmat[1][2]; vvec[2]= x*ob->obmat[2][0] + y*ob->obmat[2][1] + z*ob->obmat[2][2]; y = cos( M_PI*la->spotsize/360.0 ); spotvolume(lvec, vvec, y); x = -la->dist; lvec[0] *= x ; lvec[1] *= x ; lvec[2] *= x; vvec[0] *= x ; vvec[1] *= x ; vvec[2] *= x; /* draw the angled sides of the cone */ glBegin(GL_LINE_STRIP); glVertex3fv(vvec); glVertex3fv(vec); glVertex3fv(lvec); glEnd(); z = x*sqrt(1.0 - y*y); x *= y; /* draw the circle/square at the end of the cone */ glTranslatef(0.0, 0.0 , x); if(la->mode & LA_SQUARE) { vvec[0]= fabs(z); vvec[1]= fabs(z); vvec[2]= 0.0; glBegin(GL_LINE_LOOP); glVertex3fv(vvec); vvec[1]= -fabs(z); glVertex3fv(vvec); vvec[0]= -fabs(z); glVertex3fv(vvec); vvec[1]= fabs(z); glVertex3fv(vvec); glEnd(); } else circ(0.0, 0.0, fabs(z)); /* draw the circle/square representing spotbl */ if(la->type==LA_SPOT) { float spotblcirc = fabs(z)*(1 - pow(la->spotblend, 2)); /* make sure the line is always visible - prevent it from reaching the outer border (or 0) * values are kinda arbitrary - just what seemed to work well */ if (spotblcirc == 0) spotblcirc = 0.15; else if (spotblcirc == fabs(z)) spotblcirc = fabs(z) - 0.07; circ(0.0, 0.0, spotblcirc); } } else if ELEM(la->type, LA_HEMI, LA_SUN) { /* draw the line from the circle along the dist */ glBegin(GL_LINE_STRIP); vec[2] = -circrad; glVertex3fv(vec); vec[2]= -la->dist; glVertex3fv(vec); glEnd(); if(la->type==LA_HEMI) { /* draw the hemisphere curves */ short axis, steps, dir; float outdist, zdist, mul; vec[0]=vec[1]=vec[2]= 0.0; outdist = 0.14; mul = 1.4; dir = 1; setlinestyle(4); /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */ for (axis=0; axis<4; axis++) { float v[3]= {0.0, 0.0, 0.0}; zdist = 0.02; glBegin(GL_LINE_STRIP); for (steps=0; steps<6; steps++) { if (axis == 0 || axis == 1) { /* x axis up, x axis down */ /* make the arcs start at the edge of the energy circle */ if (steps == 0) v[0] = dir*circrad; else v[0] = v[0] + dir*(steps*outdist); } else if (axis == 2 || axis == 3) { /* y axis up, y axis down */ /* make the arcs start at the edge of the energy circle */ if (steps == 0) v[1] = dir*circrad; else v[1] = v[1] + dir*(steps*outdist); } v[2] = v[2] - steps*zdist; glVertex3fv(v); zdist = zdist * mul; } glEnd(); /* flip the direction */ dir = -dir; } } } else if(la->type==LA_AREA) { setlinestyle(3); if(la->area_shape==LA_AREA_SQUARE) fdrawbox(-la->area_size*0.5, -la->area_size*0.5, la->area_size*0.5, la->area_size*0.5); else if(la->area_shape==LA_AREA_RECT) fdrawbox(-la->area_size*0.5, -la->area_sizey*0.5, la->area_size*0.5, la->area_sizey*0.5); glBegin(GL_LINE_STRIP); glVertex3f(0.0,0.0,-circrad); glVertex3f(0.0,0.0,-la->dist); glEnd(); } /* and back to viewspace */ wmLoadMatrix(rv3d->viewmat); VECCOPY(vec, ob->obmat[3]); setlinestyle(0); if(la->type==LA_SPOT && (la->mode & LA_SHAD_BUF) ) { drawshadbuflimits(la, ob->obmat); } UI_GetThemeColor4ubv(TH_LAMP, col); glColor4ub(col[0], col[1], col[2], col[3]); glEnable(GL_BLEND); if (vec[2]>0) vec[2] -= circrad; else vec[2] += circrad; glBegin(GL_LINE_STRIP); glVertex3fv(vec); vec[2]= 0; glVertex3fv(vec); glEnd(); glPointSize(2.0); glBegin(GL_POINTS); glVertex3fv(vec); glEnd(); glPointSize(1.0); glDisable(GL_BLEND); /* restore for drawing extra stuff */ glColor3fv(curcol); } static void draw_limit_line(float sta, float end, unsigned int col) { glBegin(GL_LINES); glVertex3f(0.0, 0.0, -sta); glVertex3f(0.0, 0.0, -end); glEnd(); glPointSize(3.0); glBegin(GL_POINTS); cpack(col); glVertex3f(0.0, 0.0, -sta); glVertex3f(0.0, 0.0, -end); glEnd(); glPointSize(1.0); } /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */ /* qdn: now also enabled for Blender to set focus point for defocus composit node */ static void draw_focus_cross(float dist, float size) { glBegin(GL_LINES); glVertex3f(-size, 0.f, -dist); glVertex3f(size, 0.f, -dist); glVertex3f(0.f, -size, -dist); glVertex3f(0.f, size, -dist); glEnd(); } /* flag similar to draw_object() */ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int flag) { /* a standing up pyramid with (0,0,0) as top */ Camera *cam; World *wrld; float vec[8][4], tmat[4][4], fac, facx, facy, depth; int i; if(G.f & G_RENDER_SHADOW) return; cam= ob->data; glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); if(rv3d->persp>=2 && cam->type==CAM_ORTHO && ob==v3d->camera) { facx= 0.5*cam->ortho_scale*1.28; facy= 0.5*cam->ortho_scale*1.024; depth= -cam->clipsta-0.1; } else { fac= cam->drawsize; if(rv3d->persp>=2 && ob==v3d->camera) fac= cam->clipsta+0.1; /* that way it's always visible */ depth= - fac*cam->lens/16.0; facx= fac*1.28; facy= fac*1.024; } vec[0][0]= 0.0; vec[0][1]= 0.0; vec[0][2]= 0.001; /* GLBUG: for picking at iris Entry (well thats old!) */ vec[1][0]= facx; vec[1][1]= facy; vec[1][2]= depth; vec[2][0]= facx; vec[2][1]= -facy; vec[2][2]= depth; vec[3][0]= -facx; vec[3][1]= -facy; vec[3][2]= depth; vec[4][0]= -facx; vec[4][1]= facy; vec[4][2]= depth; glBegin(GL_LINE_LOOP); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]); glVertex3fv(vec[4]); glEnd(); if(rv3d->persp>=2 && ob==v3d->camera) return; glBegin(GL_LINE_STRIP); glVertex3fv(vec[2]); glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[4]); glVertex3fv(vec[0]); glVertex3fv(vec[3]); glEnd(); /* arrow on top */ vec[0][2]= depth; /* draw an outline arrow for inactive cameras and filled * for active cameras. We actually draw both outline+filled * for active cameras so the wire can be seen side-on */ for (i=0;i<2;i++) { if (i==0) glBegin(GL_LINE_LOOP); else if (i==1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES); else break; vec[0][0]= -0.7*cam->drawsize; vec[0][1]= 1.1*cam->drawsize; glVertex3fv(vec[0]); vec[0][0]= 0.0; vec[0][1]= 1.8*cam->drawsize; glVertex3fv(vec[0]); vec[0][0]= 0.7*cam->drawsize; vec[0][1]= 1.1*cam->drawsize; glVertex3fv(vec[0]); glEnd(); } if(flag==0) { if(cam->flag & (CAM_SHOWLIMITS+CAM_SHOWMIST)) { wmLoadMatrix(rv3d->viewmat); Mat4CpyMat4(vec, ob->obmat); Mat4Ortho(vec); wmMultMatrix(vec); Mat4SwapMat4(rv3d->persmat, tmat); wmGetSingleMatrix(rv3d->persmat); if(cam->flag & CAM_SHOWLIMITS) { draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF); /* qdn: was yafray only, now also enabled for Blender to be used with defocus composit node */ draw_focus_cross(dof_camera(ob), cam->drawsize); } wrld= scene->world; if(cam->flag & CAM_SHOWMIST) if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF); Mat4SwapMat4(rv3d->persmat, tmat); } } } static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel) { BPoint *bp = lt->def; float *co = dl?dl->verts:NULL; int u, v, w; UI_ThemeColor(sel?TH_VERTEX_SELECT:TH_VERTEX); glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); bglBegin(GL_POINTS); for(w=0; wpntsw; w++) { int wxt = (w==0 || w==lt->pntsw-1); for(v=0; vpntsv; v++) { int vxt = (v==0 || v==lt->pntsv-1); for(u=0; upntsu; u++, bp++, co+=3) { int uxt = (u==0 || u==lt->pntsu-1); if(!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) { if(bp->hide==0) { if((bp->f1 & SELECT)==sel) { bglVertex3fv(dl?co:bp->vec); } } } } } } glPointSize(1.0); bglEnd(); } void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPoint *bp, int x, int y), void *userData) { Object *obedit= vc->obedit; Lattice *lt= obedit->data; BPoint *bp = lt->editlatt->def; DispList *dl = find_displist(&obedit->disp, DL_VERTS); float *co = dl?dl->verts:NULL; int i, N = lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw; short s[2] = {IS_CLIPPED, 0}; for (i=0; ihide==0) { view3d_project_short_clip(vc->ar, dl?co:bp->vec, s); if (s[0] != IS_CLIPPED) func(userData, bp, s[0], s[1]); } } } static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol) { int index = ((w*lt->pntsv + v)*lt->pntsu) + u; if(use_wcol) { float col[3]; MDeformWeight *mdw= ED_vgroup_weight_get (lt->dvert+index, use_wcol-1); weight_to_rgb(mdw?mdw->weight:0.0f, col, col+1, col+2); glColor3fv(col); } if (dl) { glVertex3fv(&dl->verts[index*3]); } else { glVertex3fv(lt->def[index].vec); } } /* lattice color is hardcoded, now also shows weightgroup values in edit mode */ static void drawlattice(Scene *scene, View3D *v3d, Object *ob) { Lattice *lt= ob->data; DispList *dl; int u, v, w; int use_wcol= 0; /* now we default make displist, this will modifiers work for non animated case */ if(ob->disp.first==NULL) lattice_calc_modifiers(scene, ob); dl= find_displist(&ob->disp, DL_VERTS); if(lt->editlatt) { cpack(0x004000); if(ob->defbase.first && lt->dvert) { use_wcol= ob->actdef; glShadeModel(GL_SMOOTH); } } if(lt->editlatt) lt= lt->editlatt; glBegin(GL_LINES); for(w=0; wpntsw; w++) { int wxt = (w==0 || w==lt->pntsw-1); for(v=0; vpntsv; v++) { int vxt = (v==0 || v==lt->pntsv-1); for(u=0; upntsu; u++) { int uxt = (u==0 || u==lt->pntsu-1); if(w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) { drawlattice__point(lt, dl, u, v, w-1, use_wcol); drawlattice__point(lt, dl, u, v, w, use_wcol); } if(v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) { drawlattice__point(lt, dl, u, v-1, w, use_wcol); drawlattice__point(lt, dl, u, v, w, use_wcol); } if(u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) { drawlattice__point(lt, dl, u-1, v, w, use_wcol); drawlattice__point(lt, dl, u, v, w, use_wcol); } } } } glEnd(); /* restoration for weight colors */ if(use_wcol) glShadeModel(GL_FLAT); if( ((Lattice *)ob->data)->editlatt ) { if(v3d->zbuf) glDisable(GL_DEPTH_TEST); lattice_draw_verts(lt, dl, 0); lattice_draw_verts(lt, dl, 1); if(v3d->zbuf) glEnable(GL_DEPTH_TEST); } } /* ***************** ******************** */ static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData; EditVert *eve = EM_get_vert_for_index(index); if (eve->h==0) { short s[2]= {IS_CLIPPED, 0}; if (data->clipVerts) { view3d_project_short_clip(data->vc.ar, co, s); } else { view3d_project_short_noclip(data->vc.ar, co, s); } if (s[0]!=IS_CLIPPED) data->func(data->userData, eve, s[0], s[1], index); } } void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts) { struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data; DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; data.clipVerts = clipVerts; EM_init_index_arrays(vc->em, 1, 0, 0); dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data); EM_free_index_arrays(); dm->release(dm); } static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co) { struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData; EditEdge *eed = EM_get_edge_for_index(index); short s[2][2]; if (eed->h==0) { if (data->clipVerts==1) { view3d_project_short_clip(data->vc.ar, v0co, s[0]); view3d_project_short_clip(data->vc.ar, v1co, s[1]); } else { view3d_project_short_noclip(data->vc.ar, v0co, s[0]); view3d_project_short_noclip(data->vc.ar, v1co, s[1]); if (data->clipVerts==2) { if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]vc.ar->winx && s[0][1]vc.ar->winy)) if (!(s[1][0]>=0 && s[1][1]>= 0 && s[1][0]vc.ar->winx && s[1][1]vc.ar->winy)) return; } } data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index); } } void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts) { struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } data; DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; data.clipVerts = clipVerts; EM_init_index_arrays(vc->em, 0, 1, 0); dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data); EM_free_index_arrays(); dm->release(dm); } static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *no) { struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData; EditFace *efa = EM_get_face_for_index(index); short s[2]; if (efa && efa->h==0 && efa->fgonf!=EM_FGON) { view3d_project_short_clip(data->vc.ar, cent, s); data->func(data->userData, efa, s[0], s[1], index); } } void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData) { struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data; DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; EM_init_index_arrays(vc->em, 0, 0, 1); dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data); EM_free_index_arrays(); dm->release(dm); } void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y), void *userData) { Curve *cu= vc->obedit->data; short s[2] = {IS_CLIPPED, 0}; Nurb *nu; int i; for (nu= cu->editnurb->first; nu; nu=nu->next) { if(nu->type == CU_BEZIER) { for (i=0; ipntsu; i++) { BezTriple *bezt = &nu->bezt[i]; if(bezt->hide==0) { if(cu->drawflag & CU_HIDE_HANDLES) { view3d_project_short_clip(vc->ar, bezt->vec[1], s); if (s[0] != IS_CLIPPED) func(userData, nu, NULL, bezt, 1, s[0], s[1]); } else { view3d_project_short_clip(vc->ar, bezt->vec[0], s); if (s[0] != IS_CLIPPED) func(userData, nu, NULL, bezt, 0, s[0], s[1]); view3d_project_short_clip(vc->ar, bezt->vec[1], s); if (s[0] != IS_CLIPPED) func(userData, nu, NULL, bezt, 1, s[0], s[1]); view3d_project_short_clip(vc->ar, bezt->vec[2], s); if (s[0] != IS_CLIPPED) func(userData, nu, NULL, bezt, 2, s[0], s[1]); } } } } else { for (i=0; ipntsu*nu->pntsv; i++) { BPoint *bp = &nu->bp[i]; if(bp->hide==0) { view3d_project_short_clip(vc->ar, bp->vec, s); if (s[0] != IS_CLIPPED) func(userData, nu, bp, NULL, -1, s[0], s[1]); } } } } } /* ************** DRAW MESH ****************** */ /* First section is all the "simple" draw routines, * ones that just pass some sort of primitive to GL, * with perhaps various options to control lighting, * color, etc. * * These routines should not have user interface related * logic!!! */ static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no) { ToolSettings *ts= ((Scene *)userData)->toolsettings; EditFace *efa = EM_get_face_for_index(index); if (efa->h==0 && efa->fgonf!=EM_FGON) { glVertex3fv(cent); glVertex3f( cent[0] + no[0]*ts->normalsize, cent[1] + no[1]*ts->normalsize, cent[2] + no[2]*ts->normalsize); } } static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm) { glBegin(GL_LINES); dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene); glEnd(); } static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *no) { EditFace *efa = EM_get_face_for_index(index); int sel = *((int*) userData); if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) { bglVertex3fv(cent); } } static void draw_dm_face_centers(DerivedMesh *dm, int sel) { bglBegin(GL_POINTS); dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel); bglEnd(); } static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { Scene *scene= (Scene *)userData; ToolSettings *ts= scene->toolsettings; EditVert *eve = EM_get_vert_for_index(index); if (eve->h==0) { glVertex3fv(co); if (no_f) { glVertex3f( co[0] + no_f[0]*ts->normalsize, co[1] + no_f[1]*ts->normalsize, co[2] + no_f[2]*ts->normalsize); } else { glVertex3f( co[0] + no_s[0]*ts->normalsize/32767.0f, co[1] + no_s[1]*ts->normalsize/32767.0f, co[2] + no_s[2]*ts->normalsize/32767.0f); } } } static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm) { glBegin(GL_LINES); dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene); glEnd(); } /* Draw verts with color set based on selection */ static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { struct { int sel; EditVert *eve_act; } * data = userData; EditVert *eve = EM_get_vert_for_index(index); if (eve->h==0 && (eve->f&SELECT)==data->sel) { /* draw active larger - need to stop/start point drawing for this :/ */ if (eve==data->eve_act) { float size = UI_GetThemeValuef(TH_VERTEX_SIZE); UI_ThemeColor4(TH_EDITMESH_ACTIVE); bglEnd(); glPointSize(size); bglBegin(GL_POINTS); bglVertex3fv(co); bglEnd(); UI_ThemeColor4(data->sel?TH_VERTEX_SELECT:TH_VERTEX); glPointSize(size); bglBegin(GL_POINTS); } else { bglVertex3fv(co); } } } static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act) { struct { int sel; EditVert *eve_act; } data; data.sel = sel; data.eve_act = eve_act; bglBegin(GL_POINTS); dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data); bglEnd(); } /* Draw edges with color set based on selection */ static int draw_dm_edges_sel__setDrawOptions(void *userData, int index) { EditEdge *eed = EM_get_edge_for_index(index); //unsigned char **cols = userData, *col; struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData; unsigned char *col; if (eed->h==0) { if (eed==data->eed_act) { glColor4ubv(data->actCol); } else { if (eed->f&SELECT) { col = data->selCol; } else { col = data->baseCol; } /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */ if (col[3]==0) return 0; glColor4ubv(col); } return 1; } else { return 0; } } static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act) { struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data; data.baseCol = baseCol; data.selCol = selCol; data.actCol = actCol; data.eed_act = eed_act; dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data); } /* Draw edges */ static int draw_dm_edges__setDrawOptions(void *userData, int index) { return EM_get_edge_for_index(index)->h==0; } static void draw_dm_edges(DerivedMesh *dm) { dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL); } /* Draw edges with color interpolated based on selection */ static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index) { return EM_get_edge_for_index(index)->h==0; } static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t) { EditEdge *eed = EM_get_edge_for_index(index); unsigned char **cols = userData; unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0]; unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0]; glColor4ub( col0[0] + (col1[0]-col0[0])*t, col0[1] + (col1[1]-col0[1])*t, col0[2] + (col1[2]-col0[2])*t, col0[3] + (col1[3]-col0[3])*t); } static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol) { unsigned char *cols[2]; cols[0] = baseCol; cols[1] = selCol; dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols); } /* Draw only seam edges */ static int draw_dm_edges_seams__setDrawOptions(void *userData, int index) { EditEdge *eed = EM_get_edge_for_index(index); return (eed->h==0 && eed->seam); } static void draw_dm_edges_seams(DerivedMesh *dm) { dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL); } /* Draw only sharp edges */ static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index) { EditEdge *eed = EM_get_edge_for_index(index); return (eed->h==0 && eed->sharp); } static void draw_dm_edges_sharp(DerivedMesh *dm) { dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL); } /* Draw faces with color set based on selection * return 2 for the active face so it renders with stipple enabled */ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *drawSmooth_r) { struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData; EditFace *efa = EM_get_face_for_index(index); unsigned char *col; if (efa->h==0) { if (efa == data->efa_act) { glColor4ubv(data->cols[2]); return 2; /* stipple */ } else { col = data->cols[(efa->f&SELECT)?1:0]; if (col[3]==0) return 0; glColor4ubv(col); return 1; } } return 0; } /* also draws the active face */ static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act) { struct { unsigned char *cols[3]; EditFace *efa_act; } data; data.cols[0] = baseCol; data.cols[1] = selCol; data.cols[2] = actCol; data.efa_act = efa_act; dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0); } static int draw_dm_creases__setDrawOptions(void *userData, int index) { EditEdge *eed = EM_get_edge_for_index(index); if (eed->h==0 && eed->crease!=0.0) { UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->crease); return 1; } else { return 0; } } static void draw_dm_creases(DerivedMesh *dm) { glLineWidth(3.0); dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL); glLineWidth(1.0); } static int draw_dm_bweights__setDrawOptions(void *userData, int index) { EditEdge *eed = EM_get_edge_for_index(index); if (eed->h==0 && eed->bweight!=0.0) { UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight); return 1; } else { return 0; } } static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { EditVert *eve = EM_get_vert_for_index(index); if (eve->h==0 && eve->bweight!=0.0) { UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight); bglVertex3fv(co); } } static void draw_dm_bweights(Scene *scene, DerivedMesh *dm) { ToolSettings *ts= scene->toolsettings; if (ts->selectmode & SCE_SELECT_VERTEX) { glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2); bglBegin(GL_POINTS); dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL); bglEnd(); } else { glLineWidth(3.0); dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL); glLineWidth(1.0); } } /* Second section of routines: Combine first sets to form fancy * drawing routines (for example rendering twice to get overlays). * * Also includes routines that are basic drawing but are too * specialized to be split out (like drawing creases or measurements). */ /* EditMesh drawing routines*/ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, EditMesh *em, DerivedMesh *cageDM, EditVert *eve_act) { ToolSettings *ts= scene->toolsettings; int sel; if(v3d->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select for (sel=0; sel<2; sel++) { char col[4], fcol[4]; int pass; UI_GetThemeColor3ubv(sel?TH_VERTEX_SELECT:TH_VERTEX, col); UI_GetThemeColor3ubv(sel?TH_FACE_DOT:TH_WIRE, fcol); for (pass=0; pass<2; pass++) { float size = UI_GetThemeValuef(TH_VERTEX_SIZE); float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE); if (pass==0) { if(v3d->zbuf && !(v3d->flag&V3D_ZBUF_SELECT)) { glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); } else { continue; } size = (size>2.1?size/2.0:size); fsize = (fsize>2.1?fsize/2.0:fsize); col[3] = fcol[3] = 100; } else { col[3] = fcol[3] = 255; } if(ts->selectmode & SCE_SELECT_VERTEX) { glPointSize(size); glColor4ubv((GLubyte *)col); draw_dm_verts(cageDM, sel, eve_act); } if( CHECK_OB_DRAWFACEDOT(scene, v3d, obedit->dt) ) { glPointSize(fsize); glColor4ubv((GLubyte *)fcol); draw_dm_face_centers(cageDM, sel); } if (pass==0) { glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); } } } if(v3d->zbuf) glDepthMask(1); glPointSize(1.0); } static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act) { ToolSettings *ts= scene->toolsettings; int pass; unsigned char wireCol[4], selCol[4], actCol[4]; /* since this function does transparant... */ UI_GetThemeColor4ubv(TH_EDGE_SELECT, (char *)selCol); UI_GetThemeColor4ubv(TH_WIRE, (char *)wireCol); UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, (char *)actCol); /* when sel only is used, dont render wire, only selected, this is used for * textured draw mode when the 'edges' option is disabled */ if (sel_only) wireCol[3] = 0; for (pass=0; pass<2; pass++) { /* show wires in transparant when no zbuf clipping for select */ if (pass==0) { if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0) { glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); selCol[3] = 85; if (!sel_only) wireCol[3] = 85; } else { continue; } } else { selCol[3] = 255; if (!sel_only) wireCol[3] = 255; } if(ts->selectmode == SCE_SELECT_FACE) { draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); } else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) { if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) { glShadeModel(GL_SMOOTH); draw_dm_edges_sel_interp(cageDM, wireCol, selCol); glShadeModel(GL_FLAT); } else { draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); } } else { if (!sel_only) { glColor4ubv(wireCol); draw_dm_edges(cageDM); } } if (pass==0) { glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); } } } static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, UnitSettings *unit) { Mesh *me= ob->data; EditEdge *eed; EditFace *efa; float v1[3], v2[3], v3[3], v4[3], x, y, z; float fvec[3]; char val[32]; /* Stores the measurement display text here */ char conv_float[5]; /* Use a float conversion matching the grid size */ float area, col[3]; /* area of the face, color of the text to draw */ float grid= unit->system ? unit->scale_length : v3d->grid; int do_split= unit->flag & USER_UNIT_OPT_SPLIT; if(G.f & (G_RENDER_OGL|G_RENDER_SHADOW)) return; /* make the precission of the pronted value proportionate to the gridsize */ if (grid < 0.01f) strcpy(conv_float, "%.6f"); else if (grid < 0.1f) strcpy(conv_float, "%.5f"); else if (grid < 1.0f) strcpy(conv_float, "%.4f"); else if (grid < 10.0f) strcpy(conv_float, "%.3f"); else strcpy(conv_float, "%.2f"); if(v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0) glDisable(GL_DEPTH_TEST); if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0f); if(me->drawflag & ME_DRAW_EDGELEN) { UI_GetThemeColor3fv(TH_TEXT, col); /* make color a bit more red */ if(col[0]> 0.5f) {col[1]*=0.7f; col[2]*= 0.7f;} else col[0]= col[0]*0.7f + 0.3f; glColor3fv(col); for(eed= em->edges.first; eed; eed= eed->next) { /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */ if((eed->h != EM_FGON) && ((eed->f & SELECT) || (G.moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) { VECCOPY(v1, eed->v1->co); VECCOPY(v2, eed->v2->co); x= 0.5f*(v1[0]+v2[0]); y= 0.5f*(v1[1]+v2[1]); z= 0.5f*(v1[2]+v2[2]); if(v3d->flag & V3D_GLOBAL_STATS) { Mat4MulVecfl(ob->obmat, v1); Mat4MulVecfl(ob->obmat, v2); } if(unit->system) bUnit_AsString(val, sizeof(val), VecLenf(v1, v2)*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); else sprintf(val, conv_float, VecLenf(v1, v2)); view3d_object_text_draw_add(x, y, z, val, 0); } } } if(me->drawflag & ME_DRAW_FACEAREA) { // XXX extern int faceselectedOR(EditFace *efa, int flag); // editmesh.h shouldn't be in this file... ok for now? UI_GetThemeColor3fv(TH_TEXT, col); /* make color a bit more green */ if(col[1]> 0.5f) {col[0]*=0.7f; col[2]*= 0.7f;} else col[1]= col[1]*0.7f + 0.3f; glColor3fv(col); for(efa= em->faces.first; efa; efa= efa->next) { if((efa->f & SELECT)) { // XXX || (G.moving && faceselectedOR(efa, SELECT)) ) { VECCOPY(v1, efa->v1->co); VECCOPY(v2, efa->v2->co); VECCOPY(v3, efa->v3->co); if (efa->v4) { VECCOPY(v4, efa->v4->co); } if(v3d->flag & V3D_GLOBAL_STATS) { Mat4MulVecfl(ob->obmat, v1); Mat4MulVecfl(ob->obmat, v2); Mat4MulVecfl(ob->obmat, v3); if (efa->v4) Mat4MulVecfl(ob->obmat, v4); } if (efa->v4) area= AreaQ3Dfl(v1, v2, v3, v4); else area = AreaT3Dfl(v1, v2, v3); if(unit->system) bUnit_AsString(val, sizeof(val), area*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); // XXX should be B_UNIT_AREA else sprintf(val, conv_float, area); view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); } } } if(me->drawflag & ME_DRAW_EDGEANG) { EditEdge *e1, *e2, *e3, *e4; UI_GetThemeColor3fv(TH_TEXT, col); /* make color a bit more blue */ if(col[2]> 0.5f) {col[0]*=0.7f; col[1]*= 0.7f;} else col[2]= col[2]*0.7f + 0.3f; glColor3fv(col); for(efa= em->faces.first; efa; efa= efa->next) { VECCOPY(v1, efa->v1->co); VECCOPY(v2, efa->v2->co); VECCOPY(v3, efa->v3->co); if(efa->v4) { VECCOPY(v4, efa->v4->co); } else { VECCOPY(v4, v3); } if(v3d->flag & V3D_GLOBAL_STATS) { Mat4MulVecfl(ob->obmat, v1); Mat4MulVecfl(ob->obmat, v2); Mat4MulVecfl(ob->obmat, v3); Mat4MulVecfl(ob->obmat, v4); } e1= efa->e1; e2= efa->e2; e3= efa->e3; if(efa->e4) e4= efa->e4; else e4= e3; /* Calculate the angles */ if( (e4->f & e1->f & SELECT) || (G.moving && (efa->v1->f & SELECT)) ) { /* Vec 1 */ sprintf(val,"%.3f", VecAngle3(v4, v1, v2)); VecLerpf(fvec, efa->cent, efa->v1->co, 0.8f); view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); } if( (e1->f & e2->f & SELECT) || (G.moving && (efa->v2->f & SELECT)) ) { /* Vec 2 */ sprintf(val,"%.3f", VecAngle3(v1, v2, v3)); VecLerpf(fvec, efa->cent, efa->v2->co, 0.8f); view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } if( (e2->f & e3->f & SELECT) || (G.moving && (efa->v3->f & SELECT)) ) { /* Vec 3 */ if(efa->v4) sprintf(val,"%.3f", VecAngle3(v2, v3, v4)); else sprintf(val,"%.3f", VecAngle3(v2, v3, v1)); VecLerpf(fvec, efa->cent, efa->v3->co, 0.8f); view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } /* Vec 4 */ if(efa->v4) { if( (e3->f & e4->f & SELECT) || (G.moving && (efa->v4->f & SELECT)) ) { sprintf(val,"%.3f", VecAngle3(v3, v4, v1)); VecLerpf(fvec, efa->cent, efa->v4->co, 0.8f); view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } } } } if(v3d->zbuf) { glEnable(GL_DEPTH_TEST); bglPolygonOffset(rv3d->dist, 0.0f); } } static int draw_em_fancy__setFaceOpts(void *userData, int index, int *drawSmooth_r) { EditFace *efa = EM_get_face_for_index(index); if (efa->h==0) { GPU_enable_material(efa->mat_nr+1, NULL); return 1; } else return 0; } static int draw_em_fancy__setGLSLFaceOpts(void *userData, int index) { EditFace *efa = EM_get_face_for_index(index); return (efa->h==0); } static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt) { Mesh *me = ob->data; EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */ EditEdge *eed_act = NULL; EditVert *eve_act = NULL; if (em->selected.last) { EditSelection *ese = em->selected.last; /* face is handeled above */ /*if (ese->type == EDITFACE ) { efa_act = (EditFace *)ese->data; } else */ if ( ese->type == EDITEDGE ) { eed_act = (EditEdge *)ese->data; } else if ( ese->type == EDITVERT ) { eve_act = (EditVert *)ese->data; } } EM_init_index_arrays(em, 1, 1, 1); if(dt>OB_WIRE) { if(CHECK_OB_DRAWTEXTURE(v3d, dt)) { if(draw_glsl_material(scene, ob, v3d, dt)) { glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material, draw_em_fancy__setGLSLFaceOpts, NULL); GPU_disable_material(); glFrontFace(GL_CCW); } else { draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0); } } else { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED); glEnable(GL_LIGHTING); glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0); glFrontFace(GL_CCW); glDisable(GL_LIGHTING); } // Setup for drawing wire over, disable zbuffer // write to show selected edge wires better UI_ThemeColor(TH_WIRE); bglPolygonOffset(rv3d->dist, 1.0); glDepthMask(0); } else { if (cageDM!=finalDM) { UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7); finalDM->drawEdges(finalDM, 1); } } if((me->drawflag & (ME_DRAWFACES)) || paint_facesel_test(ob)) { /* transp faces */ unsigned char col1[4], col2[4], col3[4]; UI_GetThemeColor4ubv(TH_FACE, (char *)col1); UI_GetThemeColor4ubv(TH_FACE_SELECT, (char *)col2); UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, (char *)col3); glEnable(GL_BLEND); glDepthMask(0); // disable write in zbuffer, needed for nice transp /* dont draw unselected faces, only selected, this is MUCH nicer when texturing */ if CHECK_OB_DRAWTEXTURE(v3d, dt) col1[3] = 0; draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act); glDisable(GL_BLEND); glDepthMask(1); // restore write in zbuffer } else if (efa_act) { /* even if draw faces is off it would be nice to draw the stipple face * Make all other faces zero alpha except for the active * */ unsigned char col1[4], col2[4], col3[4]; col1[3] = col2[3] = 0; /* dont draw */ UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, (char *)col3); glEnable(GL_BLEND); glDepthMask(0); // disable write in zbuffer, needed for nice transp draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act); glDisable(GL_BLEND); glDepthMask(1); // restore write in zbuffer } /* here starts all fancy draw-extra over */ if((me->drawflag & ME_DRAWEDGES)==0 && CHECK_OB_DRAWTEXTURE(v3d, dt)) { /* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */ /* only draw selected edges otherwise there is no way of telling if a face is selected */ draw_em_fancy_edges(scene, v3d, me, cageDM, 1, eed_act); } else { if(me->drawflag & ME_DRAWSEAMS) { UI_ThemeColor(TH_EDGE_SEAM); glLineWidth(2); draw_dm_edges_seams(cageDM); glColor3ub(0,0,0); glLineWidth(1); } if(me->drawflag & ME_DRAWSHARP) { UI_ThemeColor(TH_EDGE_SHARP); glLineWidth(2); draw_dm_edges_sharp(cageDM); glColor3ub(0,0,0); glLineWidth(1); } if(me->drawflag & ME_DRAWCREASES) { draw_dm_creases(cageDM); } if(me->drawflag & ME_DRAWBWEIGHTS) { draw_dm_bweights(scene, cageDM); } draw_em_fancy_edges(scene, v3d, me, cageDM, 0, eed_act); } if(em) { // XXX retopo_matrix_update(v3d); draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act); if(me->drawflag & ME_DRAWNORMALS) { UI_ThemeColor(TH_NORMAL); draw_dm_face_normals(scene, cageDM); } if(me->drawflag & ME_DRAW_VNORMALS) { UI_ThemeColor(TH_NORMAL); draw_dm_vert_normals(scene, cageDM); } if(me->drawflag & (ME_DRAW_EDGELEN|ME_DRAW_FACEAREA|ME_DRAW_EDGEANG)) draw_em_measure_stats(v3d, rv3d, ob, em, &scene->unit); } if(dt>OB_WIRE) { glDepthMask(1); bglPolygonOffset(rv3d->dist, 0.0); GPU_disable_material(); } EM_free_index_arrays(); } /* Mesh drawing routines */ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) { if(v3d->transp==0) { // not when we draw the transparent pass glLineWidth(2.0); glDepthMask(0); /* if transparent, we cannot draw the edges for solid select... edges have no material info. drawFacesSolid() doesn't draw the transparent faces */ if(ob->dtx & OB_DRAWTRANSP) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); dm->drawFacesSolid(dm, GPU_enable_material); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); GPU_disable_material(); } else { dm->drawEdges(dm, 0); } glLineWidth(1.0); glDepthMask(1); } } static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r) { *drawSmooth_r = 1; return 1; } static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag) { Object *ob= base->object; Mesh *me = ob->data; Material *ma= give_current_material(ob, 1); int hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO)); int draw_wire = 0; int totvert, totedge, totface; DispList *dl; DerivedMesh *dm= mesh_get_derived_final(scene, ob, v3d->customdata_mask); if(!dm) return; if (ob->dtx&OB_DRAWWIRE) { draw_wire = 2; /* draw wire after solid using zoffset and depth buffer adjusment */ } totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); totface = dm->getNumFaces(dm); /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */ if(dt!=OB_SHADED) glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); // Unwanted combination. if (ob==OBACT && paint_facesel_test(ob)) draw_wire = 0; if(dt==OB_BOUNDBOX) { draw_bounding_volume(scene, ob); } else if(hasHaloMat || (totface==0 && totedge==0)) { glPointSize(1.5); dm->drawVerts(dm); glPointSize(1.0); } else if(dt==OB_WIRE || totface==0) { draw_wire = 1; /* draw wire only, no depth buffer stuff */ } else if( (ob==OBACT && (ob->mode & OB_MODE_TEXTURE_PAINT || paint_facesel_test(ob))) || CHECK_OB_DRAWTEXTURE(v3d, dt)) { int faceselect= (ob==OBACT && paint_facesel_test(ob)); if ((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !(G.f&G_PICKSEL || paint_facesel_test(ob)) && !draw_wire) { draw_mesh_object_outline(v3d, ob, dm); } if(draw_glsl_material(scene, ob, v3d, dt)) { glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); dm->drawFacesGLSL(dm, GPU_enable_material); // if(get_ob_property(ob, "Text")) // XXX draw_mesh_text(ob, 1); GPU_disable_material(); glFrontFace(GL_CCW); } else { draw_mesh_textured(scene, v3d, rv3d, ob, dm, faceselect); } if(!faceselect) { if(base->flag & SELECT) UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT); else UI_ThemeColor(TH_WIRE); dm->drawLooseEdges(dm); } } else if(dt==OB_SOLID) { if((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire) draw_mesh_object_outline(v3d, ob, dm); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED ); glEnable(GL_LIGHTING); glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); dm->drawFacesSolid(dm, GPU_enable_material); GPU_disable_material(); glFrontFace(GL_CCW); glDisable(GL_LIGHTING); if(base->flag & SELECT) { UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT); } else { UI_ThemeColor(TH_WIRE); } dm->drawLooseEdges(dm); } else if(dt==OB_SHADED) { int do_draw= 1; /* to resolve all G.f settings below... */ if(ob==OBACT) { do_draw= 0; if(ob && ob->mode & OB_MODE_WEIGHT_PAINT) { /* enforce default material settings */ GPU_enable_material(0, NULL); /* but set default spec */ glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); glEnable(GL_COLOR_MATERIAL); /* according manpages needed */ glColor3ub(120, 120, 120); glDisable(GL_COLOR_MATERIAL); /* diffuse */ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1); glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); GPU_disable_material(); } else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) { if(me->mcol) dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1); else { glColor3f(1.0f, 1.0f, 1.0f); dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0); } } else do_draw= 1; } if(do_draw) { dl = ob->disp.first; if (!dl || !dl->col1) { /* release and reload derivedmesh because it might be freed in shadeDispList due to a different datamask */ dm->release(dm); shadeDispList(scene, base); dl = find_displist(&ob->disp, DL_VERTCOL); dm= mesh_get_derived_final(scene, ob, v3d->customdata_mask); } if ((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire) { draw_mesh_object_outline(v3d, ob, dm); } /* False for dupliframe objects */ if (dl) { unsigned int *obCol1 = dl->col1; unsigned int *obCol2 = dl->col2; dm->drawFacesColored(dm, me->flag&ME_TWOSIDED, (unsigned char*) obCol1, (unsigned char*) obCol2); } if(base->flag & SELECT) { UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT); } else { UI_ThemeColor(TH_WIRE); } dm->drawLooseEdges(dm); } } /* set default draw color back for wire or for draw-extra later on */ if (dt!=OB_WIRE) { if(base->flag & SELECT) { if(ob==OBACT && ob->flag & OB_FROMGROUP) UI_ThemeColor(TH_GROUP_ACTIVE); else if(ob->flag & OB_FROMGROUP) UI_ThemeColorShade(TH_GROUP_ACTIVE, -16); else if(flag!=DRAW_CONSTCOLOR) UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT); else glColor3ub(80,80,80); } else { if (ob->flag & OB_FROMGROUP) UI_ThemeColor(TH_GROUP); else { if(ob->dtx & OB_DRAWWIRE && flag==DRAW_CONSTCOLOR) glColor3ub(80,80,80); else UI_ThemeColor(TH_WIRE); } } } if (draw_wire) { /* If drawing wire and drawtype is not OB_WIRE then we are * overlaying the wires. * * UPDATE bug #10290 - With this wire-only objects can draw * behind other objects depending on their order in the scene. 2x if 0's below. undo'ing zr's commit: r4059 * * if draw wire is 1 then just drawing wire, no need for depth buffer stuff, * otherwise this wire is to overlay solid mode faces so do some depth buffer tricks. */ if (dt!=OB_WIRE && draw_wire==2) { bglPolygonOffset(rv3d->dist, 1.0); glDepthMask(0); // disable write in zbuffer, selected edge wires show better } dm->drawEdges(dm, (dt==OB_WIRE || totface==0)); if (dt!=OB_WIRE && draw_wire==2) { glDepthMask(1); bglPolygonOffset(rv3d->dist, 0.0); } } dm->release(dm); } /* returns 1 if nothing was drawn, for detecting to draw an object center */ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag) { Object *ob= base->object; Object *obedit= scene->obedit; Mesh *me= ob->data; EditMesh *em= me->edit_mesh; int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha; if(obedit && ob!=obedit && ob->data==obedit->data) { if(ob_get_key(ob)); else drawlinked= 1; } if(ob==obedit || drawlinked) { DerivedMesh *finalDM, *cageDM; if (obedit!=ob) finalDM = cageDM = editmesh_get_derived_base(ob, em); else cageDM = editmesh_get_derived_cage_and_final(scene, ob, em, &finalDM, v3d->customdata_mask); if(dt>OB_WIRE) { // no transp in editmode, the fancy draw over goes bad then glsl = draw_glsl_material(scene, ob, v3d, dt); GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); } draw_em_fancy(scene, v3d, rv3d, ob, em, cageDM, finalDM, dt); GPU_end_object_materials(); if (obedit!=ob && finalDM) finalDM->release(finalDM); } // else if(!em && (G.f & G_SCULPTMODE) &&(scene->sculptdata.flags & SCULPT_DRAW_FAST) && // OBACT==ob && !sculpt_modifiers_active(ob)) { // XXX sculptmode_draw_mesh(0); // } else { /* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */ if(me->totface<=4 || boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) { glsl = draw_glsl_material(scene, ob, v3d, dt); check_alpha = check_material_alpha(base, me, glsl); if(dt==OB_SOLID || glsl) { GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, (check_alpha)? &do_alpha_pass: NULL); } draw_mesh_fancy(scene, v3d, rv3d, base, dt, flag); GPU_end_object_materials(); if(me->totvert==0) retval= 1; } } /* GPU_begin_object_materials checked if this is needed */ if(do_alpha_pass) add_view3d_after(v3d, base, V3D_TRANSP, flag); return retval; } /* ************** DRAW DISPLIST ****************** */ static int draw_index_wire= 1; static int index3_nors_incr= 1; /* returns 1 when nothing was drawn */ static int drawDispListwire(ListBase *dlbase) { DispList *dl; int parts, nr; float *data; if(dlbase==NULL) return 1; glDisableClientState(GL_NORMAL_ARRAY); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); for(dl= dlbase->first; dl; dl= dl->next) { if(dl->parts==0 || dl->nr==0) continue; data= dl->verts; switch(dl->type) { case DL_SEGM: glVertexPointer(3, GL_FLOAT, 0, data); for(parts=0; partsparts; parts++) glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr); break; case DL_POLY: glVertexPointer(3, GL_FLOAT, 0, data); for(parts=0; partsparts; parts++) glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr); break; case DL_SURF: glVertexPointer(3, GL_FLOAT, 0, data); for(parts=0; partsparts; parts++) { if(dl->flag & DL_CYCL_U) glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr); else glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr); } for(nr=0; nrnr; nr++) { int ofs= 3*dl->nr; data= ( dl->verts )+3*nr; parts= dl->parts; if(dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP); else glBegin(GL_LINE_STRIP); while(parts--) { glVertex3fv(data); data+=ofs; } glEnd(); /* (ton) this code crashes for me when resolv is 86 or higher... no clue */ // glVertexPointer(3, GL_FLOAT, sizeof(float)*3*dl->nr, data + 3*nr); // if(dl->flag & DL_CYCL_V) // glDrawArrays(GL_LINE_LOOP, 0, dl->parts); // else // glDrawArrays(GL_LINE_STRIP, 0, dl->parts); } break; case DL_INDEX3: if(draw_index_wire) { glVertexPointer(3, GL_FLOAT, 0, dl->verts); glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index); } break; case DL_INDEX4: if(draw_index_wire) { glVertexPointer(3, GL_FLOAT, 0, dl->verts); glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index); } break; } } glEnableClientState(GL_NORMAL_ARRAY); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); return 0; } static void drawDispListsolid(ListBase *lb, Object *ob, int glsl) { DispList *dl; GPUVertexAttribs gattribs; float *data, curcol[4]; float *ndata; if(lb==NULL) return; /* for drawing wire */ glGetFloatv(GL_CURRENT_COLOR, curcol); glEnable(GL_LIGHTING); if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); else glFrontFace(GL_CCW); if(ob->type==OB_MBALL) { // mball always smooth shaded glShadeModel(GL_SMOOTH); } dl= lb->first; while(dl) { data= dl->verts; ndata= dl->nors; switch(dl->type) { case DL_SEGM: if(ob->type==OB_SURF) { int nr; glDisable(GL_LIGHTING); glColor3fv(curcol); // glVertexPointer(3, GL_FLOAT, 0, dl->verts); // glDrawArrays(GL_LINE_STRIP, 0, dl->nr); glBegin(GL_LINE_STRIP); for(nr= dl->nr; nr; nr--, data+=3) glVertex3fv(data); glEnd(); glEnable(GL_LIGHTING); } break; case DL_POLY: if(ob->type==OB_SURF) { int nr; UI_ThemeColor(TH_WIRE); glDisable(GL_LIGHTING); /* for some reason glDrawArrays crashes here in half of the platforms (not osx) */ //glVertexPointer(3, GL_FLOAT, 0, dl->verts); //glDrawArrays(GL_LINE_LOOP, 0, dl->nr); glBegin(GL_LINE_LOOP); for(nr= dl->nr; nr; nr--, data+=3) glVertex3fv(data); glEnd(); glEnable(GL_LIGHTING); break; } case DL_SURF: if(dl->index) { GPU_enable_material(dl->col+1, (glsl)? &gattribs: NULL); if(dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH); else glShadeModel(GL_FLAT); glVertexPointer(3, GL_FLOAT, 0, dl->verts); glNormalPointer(GL_FLOAT, 0, dl->nors); glDrawElements(GL_QUADS, 4*dl->totindex, GL_UNSIGNED_INT, dl->index); } break; case DL_INDEX3: GPU_enable_material(dl->col+1, (glsl)? &gattribs: NULL); glVertexPointer(3, GL_FLOAT, 0, dl->verts); /* voor polys only one normal needed */ if(index3_nors_incr==0) { glDisableClientState(GL_NORMAL_ARRAY); glNormal3fv(ndata); } else glNormalPointer(GL_FLOAT, 0, dl->nors); glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index); if(index3_nors_incr==0) glEnableClientState(GL_NORMAL_ARRAY); break; case DL_INDEX4: GPU_enable_material(dl->col+1, (glsl)? &gattribs: NULL); glVertexPointer(3, GL_FLOAT, 0, dl->verts); glNormalPointer(GL_FLOAT, 0, dl->nors); glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index); break; } dl= dl->next; } glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); glFrontFace(GL_CCW); } static void drawDispListshaded(ListBase *lb, Object *ob) { DispList *dl, *dlob; unsigned int *cdata; if(lb==NULL) return; glShadeModel(GL_SMOOTH); glDisableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); dl= lb->first; dlob= ob->disp.first; while(dl && dlob) { cdata= dlob->col1; if(cdata==NULL) break; switch(dl->type) { case DL_SURF: if(dl->index) { glVertexPointer(3, GL_FLOAT, 0, dl->verts); glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata); glDrawElements(GL_QUADS, 4*dl->totindex, GL_UNSIGNED_INT, dl->index); } break; case DL_INDEX3: glVertexPointer(3, GL_FLOAT, 0, dl->verts); glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata); glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index); break; case DL_INDEX4: glVertexPointer(3, GL_FLOAT, 0, dl->verts); glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata); glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index); break; } dl= dl->next; dlob= dlob->next; } glShadeModel(GL_FLAT); glEnableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } /* returns 1 when nothing was drawn */ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt) { Object *ob= base->object; ListBase *lb=0; DispList *dl; Curve *cu; int solid, retval= 0; solid= (dt > OB_WIRE); switch(ob->type) { case OB_FONT: case OB_CURVE: cu= ob->data; lb= &cu->disp; if(solid) { dl= lb->first; if(dl==NULL) return 1; if(dl->nors==0) addnormalsDispList(ob, lb); index3_nors_incr= 0; if( displist_has_faces(lb)==0) { draw_index_wire= 0; drawDispListwire(lb); draw_index_wire= 1; } else { if(draw_glsl_material(scene, ob, v3d, dt)) { GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL); drawDispListsolid(lb, ob, 1); GPU_end_object_materials(); } else if(dt == OB_SHADED) { if(ob->disp.first==0) shadeDispList(scene, base); drawDispListshaded(lb, ob); } else { GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); drawDispListsolid(lb, ob, 0); GPU_end_object_materials(); } if(cu->editnurb && cu->bevobj==NULL && cu->taperobj==NULL && cu->ext1 == 0.0 && cu->ext2 == 0.0) { cpack(0); draw_index_wire= 0; drawDispListwire(lb); draw_index_wire= 1; } } index3_nors_incr= 1; } else { draw_index_wire= 0; retval= drawDispListwire(lb); draw_index_wire= 1; } break; case OB_SURF: lb= &((Curve *)ob->data)->disp; if(solid) { dl= lb->first; if(dl==NULL) return 1; if(dl->nors==NULL) addnormalsDispList(ob, lb); if(draw_glsl_material(scene, ob, v3d, dt)) { GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL); drawDispListsolid(lb, ob, 1); GPU_end_object_materials(); } else if(dt==OB_SHADED) { if(ob->disp.first==NULL) shadeDispList(scene, base); drawDispListshaded(lb, ob); } else { GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); drawDispListsolid(lb, ob, 0); GPU_end_object_materials(); } } else { retval= drawDispListwire(lb); } break; case OB_MBALL: if( is_basis_mball(ob)) { lb= &ob->disp; if(lb->first==NULL) makeDispListMBall(scene, ob); if(lb->first==NULL) return 1; if(solid) { if(draw_glsl_material(scene, ob, v3d, dt)) { GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL); drawDispListsolid(lb, ob, 1); GPU_end_object_materials(); } else if(dt == OB_SHADED) { dl= lb->first; if(dl && dl->col1==0) shadeDispList(scene, base); drawDispListshaded(lb, ob); } else { GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); drawDispListsolid(lb, ob, 0); GPU_end_object_materials(); } } else{ /* MetaBalls use DL_INDEX4 type of DispList */ retval= drawDispListwire(lb); } } break; } return retval; } /* *********** text drawing for particles ************* */ static ListBase pstrings= {NULL, NULL}; typedef struct ViewParticleString { struct ViewParticleString *next, *prev; float vec[3], col[4]; char str[128]; short mval[2]; short xoffs; } ViewParticleString; void view3d_particle_text_draw_add(float x, float y, float z, char *str, short xoffs) { ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString"); BLI_addtail(&pstrings, vos); BLI_strncpy(vos->str, str, 128); vos->vec[0]= x; vos->vec[1]= y; vos->vec[2]= z; glGetFloatv(GL_CURRENT_COLOR, vos->col); vos->xoffs= xoffs; } static void view3d_particle_text_draw(View3D *v3d, ARegion *ar) { ViewObjectString *vos; int tot= 0; /* project first and test */ for(vos= pstrings.first; vos; vos= vos->next) { project_short(ar, vos->vec, vos->mval); if(vos->mval[0]!=IS_CLIPPED) tot++; } if(tot) { RegionView3D *rv3d= ar->regiondata; int a; if(rv3d->rflag & RV3D_CLIPPING) for(a=0; a<6; a++) glDisable(GL_CLIP_PLANE0+a); wmPushMatrix(); ED_region_pixelspace(ar); if(v3d->zbuf) glDepthMask(0); for(vos= pstrings.first; vos; vos= vos->next) { if(vos->mval[0]!=IS_CLIPPED) { glColor3fv(vos->col); BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 2.0, vos->str); } } if(v3d->zbuf) glDepthMask(1); wmPopMatrix(); if(rv3d->rflag & RV3D_CLIPPING) for(a=0; a<6; a++) glEnable(GL_CLIP_PLANE0+a); } if(pstrings.first) BLI_freelistN(&pstrings); } typedef struct ParticleDrawData { float *vdata, *vd; float *ndata, *nd; float *cdata, *cd; float *vedata, *ved; float *ma_r, *ma_g, *ma_b; } ParticleDrawData; static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, float imat[4][4], float *draw_line, ParticleBillboardData *bb, ParticleDrawData *pdd) { float vec[3], vec2[3]; float *vd = pdd->vd; float *cd = pdd->cd; float ma_r=0.0f; float ma_g=0.0f; float ma_b=0.0f; if(pdd->ma_r) { ma_r = *pdd->ma_r; ma_g = *pdd->ma_g; ma_b = *pdd->ma_b; } switch(draw_as){ case PART_DRAW_DOT: { if(vd) { VECCOPY(vd,state->co) pdd->vd+=3; } if(cd) { cd[0]=ma_r; cd[1]=ma_g; cd[2]=ma_b; pdd->cd+=3; } break; } case PART_DRAW_CROSS: case PART_DRAW_AXIS: { vec[0]=2.0f*pixsize; vec[1]=vec[2]=0.0; QuatMulVecf(state->rot,vec); if(draw_as==PART_DRAW_AXIS) { cd[1]=cd[2]=cd[4]=cd[5]=0.0; cd[0]=cd[3]=1.0; cd[6]=cd[8]=cd[9]=cd[11]=0.0; cd[7]=cd[10]=1.0; cd[13]=cd[12]=cd[15]=cd[16]=0.0; cd[14]=cd[17]=1.0; cd+=18; VECCOPY(vec2,state->co); } else { if(cd) { cd[0]=cd[3]=cd[6]=cd[9]=cd[12]=cd[15]=ma_r; cd[1]=cd[4]=cd[7]=cd[10]=cd[13]=cd[16]=ma_g; cd[2]=cd[5]=cd[8]=cd[11]=cd[14]=cd[17]=ma_b; pdd->cd+=18; } VECSUB(vec2,state->co,vec); } VECADD(vec,state->co,vec); VECCOPY(pdd->vd,vec); pdd->vd+=3; VECCOPY(pdd->vd,vec2); pdd->vd+=3; vec[1]=2.0f*pixsize; vec[0]=vec[2]=0.0; QuatMulVecf(state->rot,vec); if(draw_as==PART_DRAW_AXIS){ VECCOPY(vec2,state->co); } else VECSUB(vec2,state->co,vec); VECADD(vec,state->co,vec); VECCOPY(pdd->vd,vec); pdd->vd+=3; VECCOPY(pdd->vd,vec2); pdd->vd+=3; vec[2]=2.0f*pixsize; vec[0]=vec[1]=0.0; QuatMulVecf(state->rot,vec); if(draw_as==PART_DRAW_AXIS){ VECCOPY(vec2,state->co); } else VECSUB(vec2,state->co,vec); VECADD(vec,state->co,vec); VECCOPY(pdd->vd,vec); pdd->vd+=3; VECCOPY(pdd->vd,vec2); pdd->vd+=3; break; } case PART_DRAW_LINE: { VECCOPY(vec,state->vel); Normalize(vec); if(draw & PART_DRAW_VEL_LENGTH) VecMulf(vec,VecLength(state->vel)); VECADDFAC(pdd->vd,state->co,vec,-draw_line[0]); pdd->vd+=3; VECADDFAC(pdd->vd,state->co,vec,draw_line[1]); pdd->vd+=3; if(cd) { cd[0]=cd[3]=ma_r; cd[1]=cd[4]=ma_g; cd[2]=cd[5]=ma_b; pdd->cd+=6; } break; } case PART_DRAW_CIRC: { if(pdd->ma_r) glColor3f(ma_r,ma_g,ma_b); drawcircball(GL_LINE_LOOP, state->co, pixsize, imat); break; } case PART_DRAW_BB: { float xvec[3], yvec[3], zvec[3], bb_center[3]; if(cd) { cd[0]=cd[3]=cd[6]=cd[9]=ma_r; cd[1]=cd[4]=cd[7]=cd[10]=ma_g; cd[2]=cd[5]=cd[8]=cd[11]=ma_b; pdd->cd+=12; } VECCOPY(bb->vec, state->co); VECCOPY(bb->vel, state->vel); psys_make_billboard(bb, xvec, yvec, zvec, bb_center); VECADD(pdd->vd,bb_center,xvec); VECADD(pdd->vd,pdd->vd,yvec); pdd->vd+=3; VECSUB(pdd->vd,bb_center,xvec); VECADD(pdd->vd,pdd->vd,yvec); pdd->vd+=3; VECSUB(pdd->vd,bb_center,xvec); VECSUB(pdd->vd,pdd->vd,yvec); pdd->vd+=3; VECADD(pdd->vd,bb_center,xvec); VECSUB(pdd->vd,pdd->vd,yvec); pdd->vd+=3; VECCOPY(pdd->nd, zvec); pdd->nd+=3; VECCOPY(pdd->nd, zvec); pdd->nd+=3; VECCOPY(pdd->nd, zvec); pdd->nd+=3; VECCOPY(pdd->nd, zvec); pdd->nd+=3; break; } } } /* unified drawing of all new particle systems draw types except dupli ob & group */ /* mostly tries to use vertex arrays for speed */ /* 1. check that everything is ok & updated */ /* 2. start initialising things */ /* 3. initialize according to draw type */ /* 4. allocate drawing data arrays */ /* 5. start filling the arrays */ /* 6. draw the arrays */ /* 7. clean up */ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, ParticleSystem *psys, int ob_dt) { Object *ob=base->object; ParticleSystemModifierData *psmd; ParticleEditSettings *pset = PE_settings(scene); ParticleSettings *part; ParticleData *pars, *pa; ParticleKey state, *states=0; ParticleBillboardData bb; ParticleDrawData pdd; Material *ma; float vel[3], imat[4][4]; float timestep, pixsize=1.0, pa_size, r_tilt, r_length; float pa_time, pa_birthtime, pa_dietime, pa_health; float cfra= bsystem_time(scene, ob,(float)CFRA,0.0); float ma_r=0.0f, ma_g=0.0f, ma_b=0.0f; int a, totpart, totpoint=0, totve=0, drawn, draw_as, totchild=0; int select=ob->flag&SELECT, create_cdata=0, need_v=0; GLint polygonmode[2]; char val[32]; /* 1. */ if(psys==0) return; part=psys->part; pars=psys->particles; if(part==0 || !psys_check_enabled(ob, psys)) return; if(pars==0) return; /* don't draw normal paths in edit mode */ if(psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART)==0) return; if(part->draw_as==PART_DRAW_NOT) return; /* 2. */ if(part->phystype==PART_PHYS_KEYED){ if(psys->flag&PSYS_KEYED){ psys_count_keyed_targets(ob,psys); if(psys->totkeyed==0) return; } } if(select){ select=0; if(psys_get_current(ob)==psys) select=1; } psys->flag|=PSYS_DRAWING; if(part->type==PART_HAIR && !psys->childcache) totchild=0; else totchild=psys->totchild*part->disp/100; memset(&pdd, 0, sizeof(ParticleDrawData)); ma= give_current_material(ob,part->omat); if(v3d->zbuf) glDepthMask(1); if(select) cpack(0xFFFFFF); else if((ma) && (part->draw&PART_DRAW_MAT_COL)) { glColor3f(ma->r,ma->g,ma->b); ma_r = ma->r; ma_g = ma->g; ma_b = ma->b; pdd.ma_r = &ma_r; pdd.ma_g = &ma_g; pdd.ma_b = &ma_b; create_cdata = 1; } else cpack(0); psmd= psys_get_modifier(ob,psys); timestep= psys_get_timestep(part); if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) { float mat[4][4]; Mat4MulMat4(mat, psys->imat, ob->obmat); wmMultMatrix(mat); } totpart=psys->totpart; if(part->draw_as==PART_DRAW_REND) draw_as = part->ren_as; else draw_as = part->draw_as; //if(part->flag&PART_GLOB_TIME) cfra=bsystem_time(scene, 0, (float)CFRA, 0.0f); if(draw_as==PART_DRAW_PATH && psys->pathcache==NULL) draw_as=PART_DRAW_DOT; /* 3. */ switch(draw_as){ case PART_DRAW_DOT: if(part->draw_size) glPointSize(part->draw_size); else glPointSize(2.0); /* default dot size */ break; case PART_DRAW_CIRC: /* calculate view aligned matrix: */ Mat4CpyMat4(imat, rv3d->viewinv); Normalize(imat[0]); Normalize(imat[1]); /* no break! */ case PART_DRAW_CROSS: case PART_DRAW_AXIS: /* lets calculate the scale: */ pixsize= rv3d->persmat[0][3]*ob->obmat[3][0]+ rv3d->persmat[1][3]*ob->obmat[3][1]+ rv3d->persmat[2][3]*ob->obmat[3][2]+ rv3d->persmat[3][3]; pixsize*= rv3d->pixsize; if(part->draw_size==0.0) pixsize*=2.0; else pixsize*=part->draw_size; break; case PART_DRAW_OB: if(part->dup_ob==0) draw_as=PART_DRAW_DOT; else draw_as=0; break; case PART_DRAW_GR: if(part->dup_group==0) draw_as=PART_DRAW_DOT; else draw_as=0; break; case PART_DRAW_BB: if(v3d->camera==0 && part->bb_ob==0){ printf("Billboards need an active camera or a target object!\n"); draw_as=part->draw_as=PART_DRAW_DOT; if(part->draw_size) glPointSize(part->draw_size); else glPointSize(2.0); /* default dot size */ } else if(part->bb_ob) bb.ob=part->bb_ob; else bb.ob=v3d->camera; bb.align = part->bb_align; bb.anim = part->bb_anim; bb.lock = part->draw & PART_DRAW_BB_LOCK; bb.offset[0] = part->bb_offset[0]; bb.offset[1] = part->bb_offset[1]; break; case PART_DRAW_PATH: break; case PART_DRAW_LINE: need_v=1; break; } if(part->draw & PART_DRAW_SIZE && part->draw_as!=PART_DRAW_CIRC){ Mat4CpyMat4(imat, rv3d->viewinv); Normalize(imat[0]); Normalize(imat[1]); } /* 4. */ if(draw_as && draw_as!=PART_DRAW_PATH) { int tot_vec_size = (totpart + totchild) * 3 * sizeof(float); if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) { tot_vec_size *= part->trail_count; psys_make_temp_pointcache(ob, psys); } if(draw_as!=PART_DRAW_CIRC) { switch(draw_as) { case PART_DRAW_AXIS: case PART_DRAW_CROSS: if(draw_as != PART_DRAW_CROSS || create_cdata) pdd.cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata"); pdd.vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata"); break; case PART_DRAW_LINE: if(create_cdata) pdd.cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata"); pdd.vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata"); break; case PART_DRAW_BB: if(create_cdata) pdd.cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata"); pdd.vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); pdd.ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); break; default: if(create_cdata) pdd.cdata=MEM_callocN(tot_vec_size, "particle_cdata"); pdd.vdata=MEM_callocN(tot_vec_size, "particle_vdata"); } } if(part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) { pdd.vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata"); need_v = 1; } pdd.vd= pdd.vdata; pdd.ved= pdd.vedata; pdd.cd= pdd.cdata; pdd.nd= pdd.ndata; psys->lattice= psys_get_lattice(scene, ob, psys); } if(draw_as){ /* 5. */ for(a=0,pa=pars; adraw&PART_DRAW_PARENT)==0) continue; if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue; pa_time=(cfra-pa->time)/pa->lifetime; pa_birthtime=pa->time; pa_dietime = pa->dietime; pa_size=pa->size; if(part->phystype==PART_PHYS_BOIDS) { pa_health = pa->boid->data.health; } else pa_health = -1.0; #if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0){ if(ma && ma->ipo){ IpoCurve *icu; /* correction for lifetime */ calc_ipo(ma->ipo, 100.0f*pa_time); for(icu = ma->ipo->curve.first; icu; icu=icu->next) { if(icu->adrcode == MA_COL_R) ma_r = icu->curval; else if(icu->adrcode == MA_COL_G) ma_g = icu->curval; else if(icu->adrcode == MA_COL_B) ma_b = icu->curval; } } if(part->ipo) { IpoCurve *icu; /* correction for lifetime */ calc_ipo(part->ipo, 100*pa_time); for(icu = part->ipo->curve.first; icu; icu=icu->next) { if(icu->adrcode == PART_SIZE) pa_size = icu->curval; } } } #endif // XXX old animation system BLI_srandom(psys->seed+a); r_tilt = 2.0f*(BLI_frand() - 0.5f); r_length = BLI_frand(); } else{ ChildParticle *cpa= &psys->child[a-totpart]; pa_time=psys_get_child_time(psys,cpa,cfra,&pa_birthtime,&pa_dietime); #if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0) { if(ma && ma->ipo){ IpoCurve *icu; /* correction for lifetime */ calc_ipo(ma->ipo, 100.0f*pa_time); for(icu = ma->ipo->curve.first; icu; icu=icu->next) { if(icu->adrcode == MA_COL_R) ma_r = icu->curval; else if(icu->adrcode == MA_COL_G) ma_g = icu->curval; else if(icu->adrcode == MA_COL_B) ma_b = icu->curval; } } } #endif // XXX old animation system pa_size=psys_get_child_size(psys,cpa,cfra,0); pa_health = -1.0; r_tilt = 2.0f * cpa->rand[2]; r_length = cpa->rand[1]; } if(draw_as!=PART_DRAW_PATH){ drawn = 0; if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) { float length = part->path_end * (1.0 - part->randlength * r_length); int trail_count = part->trail_count * (1.0 - part->randlength * r_length); float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length; float dt = length / (trail_count ? (float)trail_count : 1.0f); int i=0; ct+=dt; for(i=0; i < trail_count; i++, ct += dt) { if(part->draw & PART_ABS_PATH_TIME) { if(ct < pa_birthtime || ct > pa_dietime) continue; } else if(ct < 0.0f || ct > 1.0f) continue; state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime)); psys_get_particle_on_path(scene,ob,psys,a,&state,need_v); if(psys->parent) Mat4MulVecfl(psys->parent->obmat, state.co); /* create actiual particle data */ if(draw_as == PART_DRAW_BB) { bb.size = pa_size; bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); bb.time = ct; } draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd); totpoint++; drawn = 1; } } else { state.time=cfra; if(psys_get_particle_state(scene,ob,psys,a,&state,0)){ if(psys->parent) Mat4MulVecfl(psys->parent->obmat, state.co); /* create actiual particle data */ if(draw_as == PART_DRAW_BB) { bb.size = pa_size; bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); bb.time = pa_time; } draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd); totpoint++; drawn = 1; } } if(drawn) { /* additional things to draw for each particle */ /* (velocity, size and number) */ if(pdd.vedata){ VECCOPY(pdd.ved,state.co); pdd.ved+=3; VECCOPY(vel,state.vel); VecMulf(vel,timestep); VECADD(pdd.ved,state.co,vel); pdd.ved+=3; totve++; } if(part->draw & PART_DRAW_SIZE){ setlinestyle(3); drawcircball(GL_LINE_LOOP, state.co, pa_size, imat); setlinestyle(0); } if((part->draw&PART_DRAW_NUM || part->draw&PART_DRAW_HEALTH) && !(G.f & G_RENDER_SHADOW)){ val[0]= '\0'; if(part->draw&PART_DRAW_NUM) sprintf(val, " %i", a); if(part->draw&PART_DRAW_NUM && part->draw&PART_DRAW_HEALTH) sprintf(val, "%s:", val); if(part->draw&PART_DRAW_HEALTH && a < totpart && part->phystype==PART_PHYS_BOIDS) sprintf(val, "%s %.2f", val, pa_health); /* in path drawing state.co is the end point */ view3d_particle_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0); } } } } /* 6. */ glGetIntegerv(GL_POLYGON_MODE, polygonmode); glDisableClientState(GL_NORMAL_ARRAY); if(draw_as==PART_DRAW_PATH){ ParticleCacheKey **cache, *path; float *cd2=0,*cdata2=0; glEnableClientState(GL_VERTEX_ARRAY); /* setup gl flags */ if(ob_dt > OB_WIRE) { glEnableClientState(GL_NORMAL_ARRAY); if(part->draw&PART_DRAW_MAT_COL) glEnableClientState(GL_COLOR_ARRAY); glEnable(GL_LIGHTING); glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); } else { glDisableClientState(GL_NORMAL_ARRAY); glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); UI_ThemeColor(TH_WIRE); } if(totchild && (part->draw&PART_DRAW_PARENT)==0) totpart=0; /* draw actual/parent particles */ cache=psys->pathcache; for(a=0, pa=psys->particles; asteps > 0) { glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); if(ob_dt > OB_WIRE) { glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); if(part->draw&PART_DRAW_MAT_COL) glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); } glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); } } /* draw child particles */ cache=psys->childcache; for(a=0; aco); if(ob_dt > OB_WIRE) { glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); if(part->draw&PART_DRAW_MAT_COL) glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); } glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); } /* restore & clean up */ if(ob_dt > OB_WIRE) { if(part->draw&PART_DRAW_MAT_COL) glDisable(GL_COLOR_ARRAY); glDisable(GL_COLOR_MATERIAL); } if(cdata2) MEM_freeN(cdata2); cd2=cdata2=0; glLineWidth(1.0f); } else if(draw_as!=PART_DRAW_CIRC){ glDisableClientState(GL_COLOR_ARRAY); /* setup created data arrays */ if(pdd.vdata){ glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, pdd.vdata); } else glDisableClientState(GL_VERTEX_ARRAY); /* billboards are drawn this way */ if(pdd.ndata && ob_dt>OB_WIRE){ glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, 0, pdd.ndata); glEnable(GL_LIGHTING); } else{ glDisableClientState(GL_NORMAL_ARRAY); glDisable(GL_LIGHTING); } if(pdd.cdata){ glEnableClientState(GL_COLOR_ARRAY); glColorPointer(3, GL_FLOAT, 0, pdd.cdata); } /* draw created data arrays */ switch(draw_as){ case PART_DRAW_AXIS: case PART_DRAW_CROSS: glDrawArrays(GL_LINES, 0, 6*totpoint); break; case PART_DRAW_LINE: glDrawArrays(GL_LINES, 0, 2*totpoint); break; case PART_DRAW_BB: if(ob_dt<=OB_WIRE) glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); glDrawArrays(GL_QUADS, 0, 4*totpoint); break; default: glDrawArrays(GL_POINTS, 0, totpoint); break; } } if(pdd.vedata){ glDisableClientState(GL_COLOR_ARRAY); cpack(0xC0C0C0); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, pdd.vedata); glDrawArrays(GL_LINES, 0, 2*totve); } glPolygonMode(GL_FRONT, polygonmode[0]); glPolygonMode(GL_BACK, polygonmode[1]); } /* 7. */ glDisable(GL_LIGHTING); glDisableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); if(states) MEM_freeN(states); if(pdd.vdata) MEM_freeN(pdd.vdata); if(pdd.vedata) MEM_freeN(pdd.vedata); if(pdd.cdata) MEM_freeN(pdd.cdata); if(pdd.ndata) MEM_freeN(pdd.ndata); psys->flag &= ~PSYS_DRAWING; if(psys->lattice){ end_latt_deform(psys->lattice); psys->lattice= NULL; } if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) wmLoadMatrix(rv3d->viewmat); } static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, PTCacheEdit *edit, int dt) { ParticleCacheKey **cache, *path, *pkey; PTCacheEditPoint *point; PTCacheEditKey *key; ParticleEditSettings *pset = PE_settings(scene); int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0; int steps; char nosel[4], sel[4]; float sel_col[3]; float nosel_col[3]; float *pathcol = NULL, *pcol; if(edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) { PE_update_object(scene, ob, 0); edit->psys->flag &= ~PSYS_HAIR_UPDATED; } /* create path and child path cache if it doesn't exist already */ if(edit->pathcache==0) psys_cache_edit_paths(scene, ob, edit, CFRA); if(edit->pathcache==0) return; PE_hide_keys_time(scene, edit, CFRA); /* opengl setup */ if((v3d->flag & V3D_ZBUF_SELECT)==0) glDisable(GL_DEPTH_TEST); /* get selection theme colors */ UI_GetThemeColor3ubv(TH_VERTEX_SELECT, sel); UI_GetThemeColor3ubv(TH_VERTEX, nosel); sel_col[0]=(float)sel[0]/255.0f; sel_col[1]=(float)sel[1]/255.0f; sel_col[2]=(float)sel[2]/255.0f; nosel_col[0]=(float)nosel[0]/255.0f; nosel_col[1]=(float)nosel[1]/255.0f; nosel_col[2]=(float)nosel[2]/255.0f; /* draw paths */ if(timed) { glEnable(GL_BLEND); steps = (*edit->pathcache)->steps + 1; pathcol = MEM_callocN(steps*4*sizeof(float), "particle path color data"); } glEnableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); cache=edit->pathcache; for(i=0; ico); if(timed) { for(k=0, pcol=pathcol, pkey=path; kcol); pcol[3] = 1.0f - fabs((float)CFRA - pkey->time)/(float)pset->fade_frames; } glColorPointer(4, GL_FLOAT, 4*sizeof(float), pathcol); } else glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); } if(pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; } /* draw edit vertices */ if(pset->selectmode!=SCE_SELECT_PATH){ glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); if(pset->selectmode==SCE_SELECT_POINT){ float *pd=0,*pdata=0; float *cd=0,*cdata=0; int totkeys = 0; for (i=0, point=edit->points; iflag & PEP_HIDE)) totkeys += point->totkey; if(!(edit->points->keys->flag & PEK_USE_WCO)) pd=pdata=MEM_callocN(totkeys*3*sizeof(float), "particle edit point data"); cd=cdata=MEM_callocN(totkeys*(timed?4:3)*sizeof(float), "particle edit color data"); for(i=0, point=edit->points; iflag & PEP_HIDE) continue; for(k=0, key=point->keys; ktotkey; k++, key++){ if(pd) { VECCOPY(pd, key->co); pd += 3; } if(key->flag&PEK_SELECT){ VECCOPY(cd,sel_col); } else{ VECCOPY(cd,nosel_col); } if(timed) *(cd+3) = 1.0f - fabs((float)CFRA - *key->time)/(float)pset->fade_frames; cd += (timed?4:3); } } cd=cdata; pd=pdata; for(i=0, point=edit->points; iflag & PEP_HIDE) continue; if(point->keys->flag & PEK_USE_WCO) glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co); else glVertexPointer(3, GL_FLOAT, 3*sizeof(float), pd); glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd); glDrawArrays(GL_POINTS, 0, point->totkey); pd += pd ? 3 * point->totkey : 0; cd += (timed?4:3) * point->totkey; } if(pdata) { MEM_freeN(pdata); pd=pdata=0; } if(cdata) { MEM_freeN(cdata); cd=cdata=0; } } else if(pset->selectmode == SCE_SELECT_END){ for(i=0, point=edit->points; iflag & PEP_HIDE)==0){ key = point->keys + point->totkey - 1; if(key->flag & PEK_SELECT) glColor3fv(sel_col); else glColor3fv(nosel_col); /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/ glBegin(GL_POINTS); glVertex3fv(key->flag & PEK_USE_WCO ? key->world_co : key->co); glEnd(); } } } } glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glDisableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnable(GL_DEPTH_TEST); glLineWidth(1.0f); glPointSize(1.0); } unsigned int nurbcol[8]= { 0, 0x9090, 0x409030, 0x603080, 0, 0x40fff0, 0x40c033, 0xA090F0 }; static void tekenhandlesN(Nurb *nu, short sel, short hide_handles) { BezTriple *bezt; float *fp; unsigned int *col; int a; if(nu->hide || hide_handles) return; glBegin(GL_LINES); if(nu->type == CU_BEZIER) { if(sel) col= nurbcol+4; else col= nurbcol; bezt= nu->bezt; a= nu->pntsu; while(a--) { if(bezt->hide==0) { if( (bezt->f2 & SELECT)==sel) { fp= bezt->vec[0]; cpack(col[(int)bezt->h1]); glVertex3fv(fp); glVertex3fv(fp+3); cpack(col[(int)bezt->h2]); glVertex3fv(fp+3); glVertex3fv(fp+6); } else if( (bezt->f1 & SELECT)==sel) { fp= bezt->vec[0]; cpack(col[(int)bezt->h1]); glVertex3fv(fp); glVertex3fv(fp+3); } else if( (bezt->f3 & SELECT)==sel) { fp= bezt->vec[1]; cpack(col[(int)bezt->h2]); glVertex3fv(fp); glVertex3fv(fp+3); } } bezt++; } } glEnd(); } static void tekenvertsN(Nurb *nu, short sel, short hide_handles) { BezTriple *bezt; BPoint *bp; float size; int a; if(nu->hide) return; if(sel) UI_ThemeColor(TH_VERTEX_SELECT); else UI_ThemeColor(TH_VERTEX); size= UI_GetThemeValuef(TH_VERTEX_SIZE); glPointSize(size); bglBegin(GL_POINTS); if(nu->type == CU_BEZIER) { bezt= nu->bezt; a= nu->pntsu; while(a--) { if(bezt->hide==0) { if (hide_handles) { if((bezt->f2 & SELECT)==sel) bglVertex3fv(bezt->vec[1]); } else { if((bezt->f1 & SELECT)==sel) bglVertex3fv(bezt->vec[0]); if((bezt->f2 & SELECT)==sel) bglVertex3fv(bezt->vec[1]); if((bezt->f3 & SELECT)==sel) bglVertex3fv(bezt->vec[2]); } } bezt++; } } else { bp= nu->bp; a= nu->pntsu*nu->pntsv; while(a--) { if(bp->hide==0) { if((bp->f1 & SELECT)==sel) bglVertex3fv(bp->vec); } bp++; } } bglEnd(); glPointSize(1.0); } static void draw_editnurb(Object *ob, Nurb *nurb, int sel) { Nurb *nu; BPoint *bp, *bp1; int a, b, ofs; nu= nurb; while(nu) { if(nu->hide==0) { switch(nu->type) { case CU_POLY: cpack(nurbcol[3]); bp= nu->bp; for(b=0; bpntsv; b++) { if(nu->flagu & 1) glBegin(GL_LINE_LOOP); else glBegin(GL_LINE_STRIP); for(a=0; apntsu; a++, bp++) { glVertex3fv(bp->vec); } glEnd(); } break; case CU_NURBS: bp= nu->bp; for(b=0; bpntsv; b++) { bp1= bp; bp++; for(a=nu->pntsu-1; a>0; a--, bp++) { if(bp->hide==0 && bp1->hide==0) { if(sel) { if( (bp->f1 & SELECT) && ( bp1->f1 & SELECT ) ) { cpack(nurbcol[5]); glBegin(GL_LINE_STRIP); glVertex3fv(bp->vec); glVertex3fv(bp1->vec); glEnd(); } } else { if( (bp->f1 & SELECT) && ( bp1->f1 & SELECT) ); else { cpack(nurbcol[1]); glBegin(GL_LINE_STRIP); glVertex3fv(bp->vec); glVertex3fv(bp1->vec); glEnd(); } } } bp1= bp; } } if(nu->pntsv > 1) { /* surface */ ofs= nu->pntsu; for(b=0; bpntsu; b++) { bp1= nu->bp+b; bp= bp1+ofs; for(a=nu->pntsv-1; a>0; a--, bp+=ofs) { if(bp->hide==0 && bp1->hide==0) { if(sel) { if( (bp->f1 & SELECT) && ( bp1->f1 & SELECT) ) { cpack(nurbcol[7]); glBegin(GL_LINE_STRIP); glVertex3fv(bp->vec); glVertex3fv(bp1->vec); glEnd(); } } else { if( (bp->f1 & SELECT) && ( bp1->f1 & SELECT) ); else { cpack(nurbcol[3]); glBegin(GL_LINE_STRIP); glVertex3fv(bp->vec); glVertex3fv(bp1->vec); glEnd(); } } } bp1= bp; } } } break; } } nu= nu->next; } } static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb, int dt) { ToolSettings *ts= scene->toolsettings; Object *ob= base->object; Curve *cu = ob->data; Nurb *nu; BevList *bl; short hide_handles = (cu->drawflag & CU_HIDE_HANDLES); // XXX retopo_matrix_update(v3d); /* DispList */ UI_ThemeColor(TH_WIRE); drawDispList(scene, v3d, rv3d, base, dt); if(v3d->zbuf) glDisable(GL_DEPTH_TEST); /* first non-selected handles */ for(nu=nurb; nu; nu=nu->next) { if(nu->type == CU_BEZIER) { tekenhandlesN(nu, 0, hide_handles); } } draw_editnurb(ob, nurb, 0); draw_editnurb(ob, nurb, 1); /* selected handles */ for(nu=nurb; nu; nu=nu->next) { if(nu->type == CU_BEZIER && (cu->drawflag & CU_HIDE_HANDLES)==0) tekenhandlesN(nu, 1, hide_handles); tekenvertsN(nu, 0, hide_handles); } if(v3d->zbuf) glEnable(GL_DEPTH_TEST); /* direction vectors for 3d curve paths when at its lowest, dont render normals */ if(cu->flag & CU_3D && ts->normalsize > 0.0015 && (cu->drawflag & CU_HIDE_NORMALS)==0) { UI_ThemeColor(TH_WIRE); for (bl=cu->bev.first,nu=nurb; nu && bl; bl=bl->next,nu=nu->next) { BevPoint *bevp= (BevPoint *)(bl+1); int nr= bl->nr; int skip= nu->resolu/16; while (nr-->0) { /* accounts for empty bevel lists */ float fac= bevp->radius * ts->normalsize; float vec_a[3] = { fac,0, 0}; // Offset perpendicular to the curve float vec_b[3] = {-fac,0, 0}; // Delta along the curve QuatMulVecf(bevp->quat, vec_a); QuatMulVecf(bevp->quat, vec_b); VecAddf(vec_a, vec_a, bevp->vec); VecAddf(vec_b, vec_b, bevp->vec); VECSUBFAC(vec_a, vec_a, bevp->dir, fac); VECSUBFAC(vec_b, vec_b, bevp->dir, fac); glBegin(GL_LINE_STRIP); glVertex3fv(vec_a); glVertex3fv(bevp->vec); glVertex3fv(vec_b); glEnd(); bevp += skip+1; nr -= skip; } } } if(v3d->zbuf) glDisable(GL_DEPTH_TEST); for(nu=nurb; nu; nu=nu->next) { tekenvertsN(nu, 1, hide_handles); } if(v3d->zbuf) glEnable(GL_DEPTH_TEST); } /* draw a sphere for use as an empty drawtype */ static void draw_empty_sphere (float size) { static GLuint displist=0; if (displist == 0) { GLUquadricObj *qobj; displist= glGenLists(1); glNewList(displist, GL_COMPILE_AND_EXECUTE); glPushMatrix(); qobj = gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); gluDisk(qobj, 0.0, 1, 16, 1); glRotatef(90, 0, 1, 0); gluDisk(qobj, 0.0, 1, 16, 1); glRotatef(90, 1, 0, 0); gluDisk(qobj, 0.0, 1, 16, 1); gluDeleteQuadric(qobj); glPopMatrix(); glEndList(); } glScalef(size, size, size); glCallList(displist); glScalef(1/size, 1/size, 1/size); } /* draw a cone for use as an empty drawtype */ static void draw_empty_cone (float size) { float cent=0; float radius; GLUquadricObj *qobj = gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); glPushMatrix(); radius = size; glTranslatef(cent,cent, cent); glScalef(radius, 2.0*size, radius); glRotatef(-90., 1.0, 0.0, 0.0); gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1); glPopMatrix(); gluDeleteQuadric(qobj); } /* draw points on curve speed handles */ static void curve_draw_speed(Scene *scene, Object *ob) { #if 0 // XXX old animation system stuff Curve *cu= ob->data; IpoCurve *icu; BezTriple *bezt; float loc[4], dir[3]; int a; if(cu->ipo==NULL) return; icu= cu->ipo->curve.first; if(icu==NULL || icu->totvert<2) return; glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) ); bglBegin(GL_POINTS); for(a=0, bezt= icu->bezt; atotvert; a++, bezt++) { if( where_on_path(ob, bezt->vec[1][1], loc, dir)) { UI_ThemeColor((bezt->f2 & SELECT) && ob==OBACT?TH_VERTEX_SELECT:TH_VERTEX); bglVertex3fv(loc); } } glPointSize(1.0); bglEnd(); #endif // XXX old animation system stuff } static void draw_textcurs(float textcurs[][2]) { cpack(0); set_inverted_drawing(1); glBegin(GL_QUADS); glVertex2fv(textcurs[0]); glVertex2fv(textcurs[1]); glVertex2fv(textcurs[2]); glVertex2fv(textcurs[3]); glEnd(); set_inverted_drawing(0); } static void drawspiral(float *cent, float rad, float tmat[][4], int start) { float vec[3], vx[3], vy[3]; int a, tot=32; char inverse=0; if (start < 0) { inverse = 1; start *= -1; } VECCOPY(vx, tmat[0]); VECCOPY(vy, tmat[1]); VecMulf(vx, rad); VecMulf(vy, rad); VECCOPY(vec, cent); if (inverse==0) { for(a=0; a31) start=-a + 1; glBegin(GL_LINES); glVertex3fv(vec); vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)a/(float)tot) + *(cosval+a+start) * (vy[0] * (float)a/(float)tot); vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)a/(float)tot) + *(cosval+a+start) * (vy[1] * (float)a/(float)tot); vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)a/(float)tot) + *(cosval+a+start) * (vy[2] * (float)a/(float)tot); glVertex3fv(vec); glEnd(); } } else { a=0; vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[0] * (float)(-a+31)/(float)tot); vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[1] * (float)(-a+31)/(float)tot); vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[2] * (float)(-a+31)/(float)tot); for(a=0; a31) start=-a + 1; glBegin(GL_LINES); glVertex3fv(vec); vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[0] * (float)(-a+31)/(float)tot); vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[1] * (float)(-a+31)/(float)tot); vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[2] * (float)(-a+31)/(float)tot); glVertex3fv(vec); glEnd(); } } } /* draws a circle on x-z plane given the scaling of the circle, assuming that * all required matrices have been set (used for drawing empties) */ static void drawcircle_size(float size) { float x, y; short degrees; glBegin(GL_LINE_LOOP); /* coordinates are: cos(degrees*11.25)=x, sin(degrees*11.25)=y, 0.0f=z */ for (degrees=0; degrees<32; degrees++) { x= *(cosval + degrees); y= *(sinval + degrees); glVertex3f(x*size, 0.0f, y*size); } glEnd(); } /* needs fixing if non-identity matrice used */ static void drawtube(float *vec, float radius, float height, float tmat[][4]) { float cur[3]; drawcircball(GL_LINE_LOOP, vec, radius, tmat); VecCopyf(cur,vec); cur[2]+=height; drawcircball(GL_LINE_LOOP, cur, radius, tmat); glBegin(GL_LINES); glVertex3f(vec[0]+radius,vec[1],vec[2]); glVertex3f(cur[0]+radius,cur[1],cur[2]); glVertex3f(vec[0]-radius,vec[1],vec[2]); glVertex3f(cur[0]-radius,cur[1],cur[2]); glVertex3f(vec[0],vec[1]+radius,vec[2]); glVertex3f(cur[0],cur[1]+radius,cur[2]); glVertex3f(vec[0],vec[1]-radius,vec[2]); glVertex3f(cur[0],cur[1]-radius,cur[2]); glEnd(); } /* needs fixing if non-identity matrice used */ static void drawcone(float *vec, float radius, float height, float tmat[][4]) { float cur[3]; VecCopyf(cur,vec); cur[2]+=height; drawcircball(GL_LINE_LOOP, cur, radius, tmat); glBegin(GL_LINES); glVertex3f(vec[0],vec[1],vec[2]); glVertex3f(cur[0]+radius,cur[1],cur[2]); glVertex3f(vec[0],vec[1],vec[2]); glVertex3f(cur[0]-radius,cur[1],cur[2]); glVertex3f(vec[0],vec[1],vec[2]); glVertex3f(cur[0],cur[1]+radius,cur[2]); glVertex3f(vec[0],vec[1],vec[2]); glVertex3f(cur[0],cur[1]-radius,cur[2]); glEnd(); } /* return 1 if nothing was drawn */ static int drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt) { Object *ob= base->object; MetaBall *mb; MetaElem *ml; float imat[4][4], tmat[4][4]; int code= 1; mb= ob->data; if(mb->editelems) { UI_ThemeColor(TH_WIRE); if((G.f & G_PICKSEL)==0 ) drawDispList(scene, v3d, rv3d, base, dt); ml= mb->editelems->first; } else { if((base->flag & OB_FROMDUPLI)==0) drawDispList(scene, v3d, rv3d, base, dt); ml= mb->elems.first; } if(ml==NULL) return 1; /* in case solid draw, reset wire colors */ if(ob->flag & SELECT) { if(ob==OBACT) UI_ThemeColor(TH_ACTIVE); else UI_ThemeColor(TH_SELECT); } else UI_ThemeColor(TH_WIRE); wmGetMatrix(tmat); Mat4Invert(imat, tmat); Normalize(imat[0]); Normalize(imat[1]); while(ml) { /* draw radius */ if(mb->editelems) { if((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) cpack(0xA0A0F0); else cpack(0x3030A0); if(G.f & G_PICKSEL) { ml->selcol1= code; glLoadName(code++); } } drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat); /* draw stiffness */ if(mb->editelems) { if((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) cpack(0xA0F0A0); else cpack(0x30A030); if(G.f & G_PICKSEL) { ml->selcol2= code; glLoadName(code++); } drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad*atan(ml->s)/M_PI_2, imat); } ml= ml->next; } return 0; } static void draw_forcefield(Scene *scene, Object *ob) { PartDeflect *pd= ob->pd; float imat[4][4], tmat[4][4]; float vec[3]= {0.0, 0.0, 0.0}; int curcol; float size; if(G.f & G_RENDER_SHADOW) return; /* XXX why? */ if(ob!=scene->obedit && (ob->flag & SELECT)) { if(ob==OBACT) curcol= TH_ACTIVE; else curcol= TH_SELECT; } else curcol= TH_WIRE; /* scale size of circle etc with the empty drawsize */ if (ob->type == OB_EMPTY) size = ob->empty_drawsize; else size = 1.0; /* calculus here, is reused in PFIELD_FORCE */ wmGetMatrix(tmat); Mat4Invert(imat, tmat); // Normalize(imat[0]); // we don't do this because field doesnt scale either... apart from wind! // Normalize(imat[1]); if (pd->forcefield == PFIELD_WIND) { float force_val; Mat4One(tmat); UI_ThemeColorBlend(curcol, TH_BACK, 0.5); //if (has_ipo_code(ob->ipo, OB_PD_FSTR)) // force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra); //else force_val = pd->f_strength; force_val*= 0.1; drawcircball(GL_LINE_LOOP, vec, size, tmat); vec[2]= 0.5*force_val; drawcircball(GL_LINE_LOOP, vec, size, tmat); vec[2]= 1.0*force_val; drawcircball(GL_LINE_LOOP, vec, size, tmat); vec[2]= 1.5*force_val; drawcircball(GL_LINE_LOOP, vec, size, tmat); vec[2] = 0; /* reset vec for max dist circle */ } else if (pd->forcefield == PFIELD_FORCE) { float ffall_val; //if (has_ipo_code(ob->ipo, OB_PD_FFALL)) // ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra); //else ffall_val = pd->f_power; UI_ThemeColorBlend(curcol, TH_BACK, 0.5); drawcircball(GL_LINE_LOOP, vec, size, imat); UI_ThemeColorBlend(curcol, TH_BACK, 0.9 - 0.4 / pow(1.5, (double)ffall_val)); drawcircball(GL_LINE_LOOP, vec, size*1.5, imat); UI_ThemeColorBlend(curcol, TH_BACK, 0.9 - 0.4 / pow(2.0, (double)ffall_val)); drawcircball(GL_LINE_LOOP, vec, size*2.0, imat); } else if (pd->forcefield == PFIELD_VORTEX) { float ffall_val, force_val; Mat4One(tmat); //if (has_ipo_code(ob->ipo, OB_PD_FFALL)) // ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra); //else ffall_val = pd->f_power; //if (has_ipo_code(ob->ipo, OB_PD_FSTR)) // force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra); //else force_val = pd->f_strength; UI_ThemeColorBlend(curcol, TH_BACK, 0.7); if (force_val < 0) { drawspiral(vec, size*1.0, tmat, 1); drawspiral(vec, size*1.0, tmat, 16); } else { drawspiral(vec, size*1.0, tmat, -1); drawspiral(vec, size*1.0, tmat, -16); } } else if (pd->forcefield == PFIELD_GUIDE && ob->type==OB_CURVE) { Curve *cu= ob->data; if((cu->flag & CU_PATH) && cu->path && cu->path->data) { float mindist, guidevec1[4], guidevec2[3]; //if (has_ipo_code(ob->ipo, OB_PD_FSTR)) // mindist = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra); //else mindist = pd->f_strength; /*path end*/ setlinestyle(3); where_on_path(ob, 1.0f, guidevec1, guidevec2); UI_ThemeColorBlend(curcol, TH_BACK, 0.5); drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat); /*path beginning*/ setlinestyle(0); where_on_path(ob, 0.0f, guidevec1, guidevec2); UI_ThemeColorBlend(curcol, TH_BACK, 0.5); drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat); VECCOPY(vec, guidevec1); /* max center */ } } setlinestyle(3); UI_ThemeColorBlend(curcol, TH_BACK, 0.5); if(pd->falloff==PFIELD_FALL_SPHERE){ /* as last, guide curve alters it */ if(pd->flag & PFIELD_USEMAX) drawcircball(GL_LINE_LOOP, vec, pd->maxdist, imat); if(pd->flag & PFIELD_USEMIN) drawcircball(GL_LINE_LOOP, vec, pd->mindist, imat); } else if(pd->falloff==PFIELD_FALL_TUBE){ float radius,distance; Mat4One(tmat); vec[0]=vec[1]=0.0f; radius=(pd->flag&PFIELD_USEMAXR)?pd->maxrad:1.0f; distance=(pd->flag&PFIELD_USEMAX)?pd->maxdist:0.0f; vec[2]=distance; distance=(pd->flag&PFIELD_POSZ)?-distance:-2.0f*distance; if(pd->flag & (PFIELD_USEMAX|PFIELD_USEMAXR)) drawtube(vec,radius,distance,tmat); radius=(pd->flag&PFIELD_USEMINR)?pd->minrad:1.0f; distance=(pd->flag&PFIELD_USEMIN)?pd->mindist:0.0f; vec[2]=distance; distance=(pd->flag&PFIELD_POSZ)?-distance:-2.0f*distance; if(pd->flag & (PFIELD_USEMIN|PFIELD_USEMINR)) drawtube(vec,radius,distance,tmat); } else if(pd->falloff==PFIELD_FALL_CONE){ float radius,distance; Mat4One(tmat); radius=(pd->flag&PFIELD_USEMAXR)?pd->maxrad:1.0f; radius*=(float)M_PI/180.0f; distance=(pd->flag&PFIELD_USEMAX)?pd->maxdist:0.0f; if(pd->flag & (PFIELD_USEMAX|PFIELD_USEMAXR)){ drawcone(vec,distance*sin(radius),distance*cos(radius),tmat); if((pd->flag & PFIELD_POSZ)==0) drawcone(vec,distance*sin(radius),-distance*cos(radius),tmat); } radius=(pd->flag&PFIELD_USEMINR)?pd->minrad:1.0f; radius*=(float)M_PI/180.0f; distance=(pd->flag&PFIELD_USEMIN)?pd->mindist:0.0f; if(pd->flag & (PFIELD_USEMIN|PFIELD_USEMINR)){ drawcone(vec,distance*sin(radius),distance*cos(radius),tmat); if((pd->flag & PFIELD_POSZ)==0) drawcone(vec,distance*sin(radius),-distance*cos(radius),tmat); } } setlinestyle(0); } static void draw_box(float vec[8][3]) { glBegin(GL_LINE_STRIP); glVertex3fv(vec[0]); glVertex3fv(vec[1]);glVertex3fv(vec[2]); glVertex3fv(vec[3]); glVertex3fv(vec[0]); glVertex3fv(vec[4]);glVertex3fv(vec[5]); glVertex3fv(vec[6]); glVertex3fv(vec[7]); glVertex3fv(vec[4]); glEnd(); glBegin(GL_LINES); glVertex3fv(vec[1]); glVertex3fv(vec[5]); glVertex3fv(vec[2]); glVertex3fv(vec[6]); glVertex3fv(vec[3]); glVertex3fv(vec[7]); glEnd(); } /* uses boundbox, function used by Ketsji */ void get_local_bounds(Object *ob, float *center, float *size) { BoundBox *bb= object_get_boundbox(ob); if(bb==NULL) { center[0]= center[1]= center[2]= 0.0; VECCOPY(size, ob->size); } else { size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]); size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]); size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]); center[0]= (bb->vec[0][0] + bb->vec[4][0])/2.0; center[1]= (bb->vec[0][1] + bb->vec[2][1])/2.0; center[2]= (bb->vec[0][2] + bb->vec[1][2])/2.0; } } static void draw_bb_quadric(BoundBox *bb, short type) { float size[3], cent[3]; GLUquadricObj *qobj = gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]); size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]); size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]); cent[0]= (bb->vec[0][0] + bb->vec[4][0])/2.0; cent[1]= (bb->vec[0][1] + bb->vec[2][1])/2.0; cent[2]= (bb->vec[0][2] + bb->vec[1][2])/2.0; glPushMatrix(); if(type==OB_BOUND_SPHERE) { glTranslatef(cent[0], cent[1], cent[2]); glScalef(size[0], size[1], size[2]); gluSphere(qobj, 1.0, 8, 5); } else if(type==OB_BOUND_CYLINDER) { float radius = size[0] > size[1] ? size[0] : size[1]; glTranslatef(cent[0], cent[1], cent[2]-size[2]); glScalef(radius, radius, 2.0*size[2]); gluCylinder(qobj, 1.0, 1.0, 1.0, 8, 1); } else if(type==OB_BOUND_CONE) { float radius = size[0] > size[1] ? size[0] : size[1]; glTranslatef(cent[0], cent[2]-size[2], cent[1]); glScalef(radius, 2.0*size[2], radius); glRotatef(-90., 1.0, 0.0, 0.0); gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1); } glPopMatrix(); gluDeleteQuadric(qobj); } static void draw_bounding_volume(Scene *scene, Object *ob) { BoundBox *bb=0; if(ob->type==OB_MESH) { bb= mesh_get_bb(ob); } else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) { bb= ( (Curve *)ob->data )->bb; } else if(ob->type==OB_MBALL) { bb= ob->bb; if(bb==0) { makeDispListMBall(scene, ob); bb= ob->bb; } } else { drawcube(); return; } if(bb==0) return; if(ob->boundtype==OB_BOUND_BOX) draw_box(bb->vec); else draw_bb_quadric(bb, ob->boundtype); } static void drawtexspace(Object *ob) { float vec[8][3], loc[3], size[3]; if(ob->type==OB_MESH) { mesh_get_texspace(ob->data, loc, NULL, size); } else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) { Curve *cu= ob->data; VECCOPY(size, cu->size); VECCOPY(loc, cu->loc); } else if(ob->type==OB_MBALL) { MetaBall *mb= ob->data; VECCOPY(size, mb->size); VECCOPY(loc, mb->loc); } else return; vec[0][0]=vec[1][0]=vec[2][0]=vec[3][0]= loc[0]-size[0]; vec[4][0]=vec[5][0]=vec[6][0]=vec[7][0]= loc[0]+size[0]; vec[0][1]=vec[1][1]=vec[4][1]=vec[5][1]= loc[1]-size[1]; vec[2][1]=vec[3][1]=vec[6][1]=vec[7][1]= loc[1]+size[1]; vec[0][2]=vec[3][2]=vec[4][2]=vec[7][2]= loc[2]-size[2]; vec[1][2]=vec[2][2]=vec[5][2]=vec[6][2]= loc[2]+size[2]; setlinestyle(2); draw_box(vec); setlinestyle(0); } /* draws wire outline */ static void drawSolidSelect(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) { Object *ob= base->object; glLineWidth(2.0); glDepthMask(0); if(ELEM3(ob->type, OB_FONT,OB_CURVE, OB_SURF)) { Curve *cu = ob->data; if (displist_has_faces(&cu->disp) && boundbox_clip(rv3d, ob->obmat, cu->bb)) { draw_index_wire= 0; drawDispListwire(&cu->disp); draw_index_wire= 1; } } else if (ob->type==OB_MBALL) { if((base->flag & OB_FROMDUPLI)==0) drawDispListwire(&ob->disp); } else if(ob->type==OB_ARMATURE) { if(!(ob->mode & OB_MODE_POSE)) draw_armature(scene, v3d, rv3d, base, OB_WIRE, 0); } glLineWidth(1.0); glDepthMask(1); } static void drawWireExtra(Scene *scene, RegionView3D *rv3d, Object *ob) { if(ob!=scene->obedit && (ob->flag & SELECT)) { if(ob==OBACT) { if(ob->flag & OB_FROMGROUP) UI_ThemeColor(TH_GROUP_ACTIVE); else UI_ThemeColor(TH_ACTIVE); } else if(ob->flag & OB_FROMGROUP) UI_ThemeColorShade(TH_GROUP_ACTIVE, -16); else UI_ThemeColor(TH_SELECT); } else { if(ob->flag & OB_FROMGROUP) UI_ThemeColor(TH_GROUP); else { if(ob->dtx & OB_DRAWWIRE) { glColor3ub(80,80,80); } else { UI_ThemeColor(TH_WIRE); } } } bglPolygonOffset(rv3d->dist, 1.0); glDepthMask(0); // disable write in zbuffer, selected edge wires show better if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; if (boundbox_clip(rv3d, ob->obmat, cu->bb)) { if (ob->type==OB_CURVE) draw_index_wire= 0; drawDispListwire(&cu->disp); if (ob->type==OB_CURVE) draw_index_wire= 1; } } else if (ob->type==OB_MBALL) { drawDispListwire(&ob->disp); } glDepthMask(1); bglPolygonOffset(rv3d->dist, 0.0); } /* should be called in view space */ static void draw_hooks(Object *ob) { ModifierData *md; float vec[3]; for (md=ob->modifiers.first; md; md=md->next) { if (md->type==eModifierType_Hook) { HookModifierData *hmd = (HookModifierData*) md; VecMat4MulVecfl(vec, ob->obmat, hmd->cent); if(hmd->object) { setlinestyle(3); glBegin(GL_LINES); glVertex3fv(hmd->object->obmat[3]); glVertex3fv(vec); glEnd(); setlinestyle(0); } glPointSize(3.0); bglBegin(GL_POINTS); bglVertex3fv(vec); bglEnd(); glPointSize(1.0); } } } // void drawRBpivot(bRigidBodyJointConstraint *data) { float radsPerDeg = 6.283185307179586232f / 360.f; int axis; float v1[3]= {data->pivX, data->pivY, data->pivZ}; float eu[3]= {radsPerDeg*data->axX, radsPerDeg*data->axY, radsPerDeg*data->axZ}; float mat[4][4]; if(G.f & G_RENDER_SHADOW) return; EulToMat4(eu,mat); glLineWidth (4.0f); setlinestyle(2); for (axis=0; axis<3; axis++) { float dir[3] = {0,0,0}; float v[3]= {data->pivX, data->pivY, data->pivZ}; dir[axis] = 1.f; glBegin(GL_LINES); Mat4MulVecfl(mat,dir); v[0] += dir[0]; v[1] += dir[1]; v[2] += dir[2]; glVertex3fv(v1); glVertex3fv(v); glEnd(); if (axis==0) view3d_object_text_draw_add(v[0], v[1], v[2], "px", 0); else if (axis==1) view3d_object_text_draw_add(v[0], v[1], v[2], "py", 0); else view3d_object_text_draw_add(v[0], v[1], v[2], "pz", 0); } glLineWidth (1.0f); setlinestyle(0); } /* flag can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET */ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) { static int warning_recursive= 0; ModifierData *md = NULL; Object *ob; Curve *cu; RegionView3D *rv3d= ar->regiondata; //float cfraont; float vec1[3], vec2[3]; unsigned int col=0; int /*sel, drawtype,*/ colindex= 0; int i, selstart, selend, empty_object=0; short dt, dtx, zbufoff= 0; /* only once set now, will be removed too, should become a global standard */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ob= base->object; if (ob!=scene->obedit) { if (ob->restrictflag & OB_RESTRICT_VIEW) return; } /* xray delay? */ if((flag & DRAW_PICKING)==0 && (base->flag & OB_FROMDUPLI)==0) { /* don't do xray in particle mode, need the z-buffer */ if(!(ob->mode & OB_MODE_PARTICLE_EDIT)) { /* xray and transp are set when it is drawing the 2nd/3rd pass */ if(!v3d->xray && !v3d->transp && (ob->dtx & OB_DRAWXRAY) && !(ob->dtx & OB_DRAWTRANSP)) { add_view3d_after(v3d, base, V3D_XRAY, flag); return; } } } /* draw keys? */ #if 0 // XXX old animation system if(base==(scene->basact) || (base->flag & (SELECT+BA_WAS_SEL))) { if(flag==0 && warning_recursive==0 && ob!=scene->obedit) { if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) { ListBase elems; CfraElem *ce; float temp[7][3]; warning_recursive= 1; elems.first= elems.last= 0; // warning: no longer checks for certain ob-keys only... (so does this need to use the proper ipokeys then?) make_cfra_list(ob->ipo, &elems); cfraont= (scene->r.cfra); drawtype= v3d->drawtype; if(drawtype>OB_WIRE) v3d->drawtype= OB_WIRE; sel= base->flag; memcpy(temp, &ob->loc, 7*3*sizeof(float)); ipoflag= ob->ipoflag; ob->ipoflag &= ~OB_OFFS_OB; set_no_parent_ipo(1); disable_speed_curve(1); if ((ob->ipoflag & OB_DRAWKEYSEL)==0) { ce= elems.first; while(ce) { if(!ce->sel) { (scene->r.cfra)= ce->cfra/scene->r.framelen; base->flag= 0; where_is_object_time(scene, ob, (scene->r.cfra)); draw_object(scene, ar, v3d, base, 0); } ce= ce->next; } } ce= elems.first; while(ce) { if(ce->sel) { (scene->r.cfra)= ce->cfra/scene->r.framelen; base->flag= SELECT; where_is_object_time(scene, ob, (scene->r.cfra)); draw_object(scene, ar, v3d, base, 0); } ce= ce->next; } set_no_parent_ipo(0); disable_speed_curve(0); base->flag= sel; ob->ipoflag= ipoflag; /* restore icu->curval */ (scene->r.cfra)= cfraont; memcpy(&ob->loc, temp, 7*3*sizeof(float)); where_is_object(scene, ob); v3d->drawtype= drawtype; BLI_freelistN(&elems); warning_recursive= 0; } } } #endif // XXX old animation system /* patch? children objects with a timeoffs change the parents. How to solve! */ /* if( ((int)ob->ctime) != F_(scene->r.cfra)) where_is_object(scene, ob); */ /* draw paths... */ // TODO... /* multiply view with object matrix */ wmMultMatrix(ob->obmat); /* local viewmat and persmat, to calculate projections */ wmGetMatrix(rv3d->viewmatob); wmGetSingleMatrix(rv3d->persmatob); /* which wire color */ if((flag & DRAW_CONSTCOLOR) == 0) { project_short(ar, ob->obmat[3], &base->sx); if((G.moving & G_TRANSFORM_OBJ) && (base->flag & (SELECT+BA_WAS_SEL))) UI_ThemeColor(TH_TRANSFORM); else { if(ob->type==OB_LAMP) UI_ThemeColor(TH_LAMP); else UI_ThemeColor(TH_WIRE); if((scene->basact)==base) { if(base->flag & (SELECT+BA_WAS_SEL)) UI_ThemeColor(TH_ACTIVE); } else { if(base->flag & (SELECT+BA_WAS_SEL)) UI_ThemeColor(TH_SELECT); } // no theme yet if(ob->id.lib) { if(base->flag & (SELECT+BA_WAS_SEL)) colindex = 4; else colindex = 3; } else if(warning_recursive==1) { if(base->flag & (SELECT+BA_WAS_SEL)) { if(scene->basact==base) colindex = 8; else colindex= 7; } else colindex = 6; } else if(ob->flag & OB_FROMGROUP) { if(base->flag & (SELECT+BA_WAS_SEL)) { if(scene->basact==base) UI_ThemeColor(TH_GROUP_ACTIVE); else UI_ThemeColorShade(TH_GROUP_ACTIVE, -16); } else UI_ThemeColor(TH_GROUP); colindex= 0; } } if(colindex) { col= colortab[colindex]; cpack(col); } } /* maximum drawtype */ dt= MIN2(v3d->drawtype, ob->dt); if(v3d->zbuf==0 && dt>OB_WIRE) dt= OB_WIRE; dtx= 0; /* faceselect exception: also draw solid when dt==wire, except in editmode */ if(ob==OBACT && (ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))) { if(ob->type==OB_MESH) { if(ob==scene->obedit); else { if(dt=OB_BOUNDBOX ) { dtx= ob->dtx; if(scene->obedit==ob) { // the only 2 extra drawtypes alowed in editmode dtx= dtx & (OB_DRAWWIRE|OB_TEXSPACE); } } /* bad exception, solve this! otherwise outline shows too late */ if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { cu= ob->data; /* still needed for curves hidden in other layers. depgraph doesnt handle that yet */ if (cu->disp.first==NULL) makeDispListCurveTypes(scene, ob, 0); } /* draw outline for selected solid objects, mesh does itself */ if((v3d->flag & V3D_SELECT_OUTLINE) && ob->type!=OB_MESH) { if(dt>OB_WIRE && dtobedit && (flag && DRAW_SCENESET)==0) { if (!(ob->dtx&OB_DRAWWIRE) && (ob->flag&SELECT) && !(flag&DRAW_PICKING)) { drawSolidSelect(scene, v3d, rv3d, base); } } } switch( ob->type) { case OB_MESH: if (!(base->flag&OB_RADIO)) { empty_object= draw_mesh_object(scene, v3d, rv3d, base, dt, flag); if(flag!=DRAW_CONSTCOLOR) dtx &= ~OB_DRAWWIRE; // mesh draws wire itself } break; case OB_FONT: cu= ob->data; if(cu->editfont) { draw_textcurs(cu->editfont->textcurs); if (cu->flag & CU_FAST) { cpack(0xFFFFFF); set_inverted_drawing(1); drawDispList(scene, v3d, rv3d, base, OB_WIRE); set_inverted_drawing(0); } else { drawDispList(scene, v3d, rv3d, base, dt); } if (cu->linewidth != 0.0) { cpack(0xff44ff); UI_ThemeColor(TH_WIRE); VECCOPY(vec1, ob->orig); VECCOPY(vec2, ob->orig); vec1[0] += cu->linewidth; vec2[0] += cu->linewidth; vec1[1] += cu->linedist * cu->fsize; vec2[1] -= cu->lines * cu->linedist * cu->fsize; setlinestyle(3); glBegin(GL_LINE_STRIP); glVertex2fv(vec1); glVertex2fv(vec2); glEnd(); setlinestyle(0); } setlinestyle(3); for (i=0; itotbox; i++) { if (cu->tb[i].w != 0.0) { if (i == (cu->actbox-1)) UI_ThemeColor(TH_ACTIVE); else UI_ThemeColor(TH_WIRE); vec1[0] = cu->tb[i].x; vec1[1] = cu->tb[i].y + cu->fsize; vec1[2] = 0.001; glBegin(GL_LINE_STRIP); glVertex3fv(vec1); vec1[0] += cu->tb[i].w; glVertex3fv(vec1); vec1[1] -= cu->tb[i].h; glVertex3fv(vec1); vec1[0] -= cu->tb[i].w; glVertex3fv(vec1); vec1[1] += cu->tb[i].h; glVertex3fv(vec1); glEnd(); } } setlinestyle(0); if (BKE_font_getselection(ob, &selstart, &selend) && cu->selboxes) { float selboxw; cpack(0xffffff); set_inverted_drawing(1); for (i=0; i<(selend-selstart+1); i++) { SelBox *sb = &(cu->selboxes[i]); if (i<(selend-selstart)) { if (cu->selboxes[i+1].y == sb->y) selboxw= cu->selboxes[i+1].x - sb->x; else selboxw= sb->w; } else { selboxw= sb->w; } glBegin(GL_QUADS); glVertex3f(sb->x, sb->y, 0.001); glVertex3f(sb->x+selboxw, sb->y, 0.001); glVertex3f(sb->x+selboxw, sb->y+sb->h, 0.001); glVertex3f(sb->x, sb->y+sb->h, 0.001); glEnd(); } set_inverted_drawing(0); } } else if(dt==OB_BOUNDBOX) draw_bounding_volume(scene, ob); else if(boundbox_clip(rv3d, ob->obmat, cu->bb)) empty_object= drawDispList(scene, v3d, rv3d, base, dt); break; case OB_CURVE: case OB_SURF: cu= ob->data; if(cu->editnurb) { drawnurb(scene, v3d, rv3d, base, cu->editnurb->first, dt); } else if(dt==OB_BOUNDBOX) draw_bounding_volume(scene, ob); else if(boundbox_clip(rv3d, ob->obmat, cu->bb)) { empty_object= drawDispList(scene, v3d, rv3d, base, dt); if(cu->path) curve_draw_speed(scene, ob); } break; case OB_MBALL: { MetaBall *mb= ob->data; if(mb->editelems) drawmball(scene, v3d, rv3d, base, dt); else if(dt==OB_BOUNDBOX) draw_bounding_volume(scene, ob); else empty_object= drawmball(scene, v3d, rv3d, base, dt); break; } case OB_EMPTY: drawaxes(ob->empty_drawsize, flag, ob->empty_drawtype); break; case OB_LAMP: drawlamp(scene, v3d, rv3d, ob); if(dtx || (base->flag & SELECT)) wmMultMatrix(ob->obmat); break; case OB_CAMERA: drawcamera(scene, v3d, rv3d, ob, flag); break; case OB_LATTICE: drawlattice(scene, v3d, ob); break; case OB_ARMATURE: if(dt>OB_WIRE) GPU_enable_material(0, NULL); // we use default material empty_object= draw_armature(scene, v3d, rv3d, base, dt, flag); if(dt>OB_WIRE) GPU_disable_material(); break; default: drawaxes(1.0, flag, OB_ARROWS); } if(ob->pd && ob->pd->forcefield) draw_forcefield(scene, ob); /* code for new particle system */ if( (warning_recursive==0) && (ob->particlesystem.first) && (flag & DRAW_PICKING)==0 && (ob!=scene->obedit) ) { ParticleSystem *psys; if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */ //glDepthMask(GL_FALSE); wmLoadMatrix(rv3d->viewmat); for(psys=ob->particlesystem.first; psys; psys=psys->next) draw_new_particle_system(scene, v3d, rv3d, base, psys, dt); view3d_particle_text_draw(v3d, ar); wmMultMatrix(ob->obmat); //glDepthMask(GL_TRUE); if(col) cpack(col); } if( (warning_recursive==0) && (flag & DRAW_PICKING)==0 && (!scene->obedit) ) { if(ob->mode & OB_MODE_PARTICLE_EDIT && ob==OBACT) { PTCacheEdit *edit = PE_get_current(scene, ob); if(edit) { wmLoadMatrix(rv3d->viewmat); draw_ptcache_edit(scene, v3d, rv3d, ob, edit, dt); wmMultMatrix(ob->obmat); } } } /* draw code for smoke */ if((md = modifiers_findByType(ob, eModifierType_Smoke))) { SmokeModifierData *smd = (SmokeModifierData *)md; // draw collision objects if((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) { /*SmokeCollSettings *scs = smd->coll; if(scs->points) { size_t i; wmLoadMatrix(rv3d->viewmat); if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); glDepthMask(GL_FALSE); glEnable(GL_BLEND); // glPointSize(3.0); bglBegin(GL_POINTS); for(i = 0; i < scs->numpoints; i++) { bglVertex3fv(&scs->points[3*i]); } bglEnd(); glPointSize(1.0); wmMultMatrix(ob->obmat); glDisable(GL_BLEND); glDepthMask(GL_TRUE); if(col) cpack(col); } */ } // only draw domains if(smd->domain && smd->domain->fluid) { if(!smd->domain->wt || !(smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { smd->domain->tex = NULL; GPU_create_smoke(smd, 0); draw_volume(scene, ar, v3d, base, smd->domain->tex, smd->domain->res, smd->domain->dx, smd->domain->tex_shadow); GPU_free_smoke(smd); } else if(smd->domain->wt || (smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { smd->domain->tex = NULL; GPU_create_smoke(smd, 1); draw_volume(scene, ar, v3d, base, smd->domain->tex, smd->domain->res_wt, smd->domain->dx_wt, smd->domain->tex_shadow); GPU_free_smoke(smd); } } } { bConstraint *con; for(con=ob->constraints.first; con; con= con->next) { if(con->type==CONSTRAINT_TYPE_RIGIDBODYJOINT) { bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint*)con->data; if(data->flag&CONSTRAINT_DRAW_PIVOT) drawRBpivot(data); } } } /* draw extra: after normal draw because of makeDispList */ if(dtx && !(G.f & (G_RENDER_OGL|G_RENDER_SHADOW))) { if(dtx & OB_AXIS) { drawaxes(1.0f, flag, OB_ARROWS); } if(dtx & OB_BOUNDBOX) draw_bounding_volume(scene, ob); if(dtx & OB_TEXSPACE) drawtexspace(ob); if(dtx & OB_DRAWNAME) { /* patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing */ /* but, we also dont draw names for sets or duplicators */ if(flag == 0) { view3d_object_text_draw_add(0.0f, 0.0f, 0.0f, ob->id.name+2, 10); } } /*if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/ if((dtx & OB_DRAWWIRE) && dt>=OB_SOLID) drawWireExtra(scene, rv3d, ob); } if(dtgameflag & OB_DYNAMIC) || ((ob->gameflag & OB_BOUNDS) && (ob->boundtype == OB_BOUND_SPHERE))) { float tmat[4][4], imat[4][4], vec[3]; vec[0]= vec[1]= vec[2]= 0.0; wmGetMatrix(tmat); Mat4Invert(imat, tmat); setlinestyle(2); drawcircball(GL_LINE_LOOP, vec, ob->inertia, imat); setlinestyle(0); } } /* return warning, this is cached text draw */ view3d_object_text_draw(v3d, ar); wmLoadMatrix(rv3d->viewmat); if(zbufoff) glDisable(GL_DEPTH_TEST); if(warning_recursive) return; if(base->flag & (OB_FROMDUPLI|OB_RADIO)) return; if(G.f & G_RENDER_SHADOW) return; /* object centers, need to be drawn in viewmat space for speed, but OK for picking select */ if(ob!=OBACT || !(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))) { int do_draw_center= -1; /* defines below are zero or positive... */ if((scene->basact)==base) do_draw_center= ACTIVE; else if(base->flag & SELECT) do_draw_center= SELECT; else if(empty_object || (v3d->flag & V3D_DRAW_CENTERS)) do_draw_center= DESELECT; if(do_draw_center != -1) { if(flag & DRAW_PICKING) { /* draw a single point for opengl selection */ glBegin(GL_POINTS); glVertex3fv(ob->obmat[3]); glEnd(); } else if((flag & DRAW_CONSTCOLOR)==0) { /* we don't draw centers for duplicators and sets */ drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us>1); } } } /* not for sets, duplicators or picking */ if(flag==0 && (!(v3d->flag & V3D_HIDE_HELPLINES))) { ListBase *list; /* draw hook center and offset line */ if(ob!=scene->obedit) draw_hooks(ob); /* help lines and so */ if(ob!=scene->obedit && ob->parent && (ob->parent->lay & v3d->lay)) { setlinestyle(3); glBegin(GL_LINES); glVertex3fv(ob->obmat[3]); glVertex3fv(ob->orig); glEnd(); setlinestyle(0); } /* Drawing the constraint lines */ list = &ob->constraints; if (list) { bConstraint *curcon; bConstraintOb *cob; char col[4], col2[4]; UI_GetThemeColor3ubv(TH_GRID, col); UI_make_axis_color(col, col2, 'z'); glColor3ubv((GLubyte *)col2); cob= constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); for (curcon = list->first; curcon; curcon=curcon->next) { bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; if ((curcon->flag & CONSTRAINT_EXPAND) && (cti) && (cti->get_constraint_targets)) { cti->get_constraint_targets(curcon, &targets); for (ct= targets.first; ct; ct= ct->next) { /* calculate target's matrix */ if (cti->get_target_matrix) cti->get_target_matrix(curcon, cob, ct, bsystem_time(scene, ob, (float)(scene->r.cfra), give_timeoffset(ob))); else Mat4One(ct->matrix); setlinestyle(3); glBegin(GL_LINES); glVertex3fv(ct->matrix[3]); glVertex3fv(ob->obmat[3]); glEnd(); setlinestyle(0); } if (cti->flush_constraint_targets) cti->flush_constraint_targets(curcon, &targets, 1); } } constraints_clear_evalob(cob); } } free_old_images(); } /* ***************** BACKBUF SEL (BBS) ********* */ static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { int offset = (intptr_t) userData; EditVert *eve = EM_get_vert_for_index(index); if (eve->h==0) { WM_set_framebuffer_index_color(offset+index); bglVertex3fv(co); } } static void bbs_mesh_verts(DerivedMesh *dm, int offset) { glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) ); bglBegin(GL_POINTS); dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(intptr_t) offset); bglEnd(); glPointSize(1.0); } static int bbs_mesh_wire__setDrawOptions(void *userData, int index) { int offset = (intptr_t) userData; EditEdge *eed = EM_get_edge_for_index(index); if (eed->h==0) { WM_set_framebuffer_index_color(offset+index); return 1; } else { return 0; } } static void bbs_mesh_wire(DerivedMesh *dm, int offset) { dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(intptr_t) offset); } static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r) { if (EM_get_face_for_index(index)->h==0) { if (userData) { WM_set_framebuffer_index_color(index+1); } return 1; } else { return 0; } } static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, float *no) { EditFace *efa = EM_get_face_for_index(index); if (efa->h==0 && efa->fgonf!=EM_FGON) { WM_set_framebuffer_index_color(index+1); bglVertex3fv(cent); } } /* two options, facecolors or black */ static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh *dm, int facecol) { cpack(0); if (facecol) { dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0); if( CHECK_OB_DRAWFACEDOT(scene, v3d, ob->dt) ) { glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE)); bglBegin(GL_POINTS); dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, NULL); bglEnd(); } } else { dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0); } } static int bbs_mesh_solid__setDrawOpts(void *userData, int index, int *drawSmooth_r) { Mesh *me = userData; if (!(me->mface[index].flag&ME_HIDE)) { WM_set_framebuffer_index_color(index+1); return 1; } else { return 0; } } /* TODO remove this - since face select mode now only works with painting */ static void bbs_mesh_solid(Scene *scene, View3D *v3d, Object *ob) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, v3d->customdata_mask); Mesh *me = (Mesh*)ob->data; glColor3ub(0, 0, 0); dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0); dm->release(dm); } void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob) { ToolSettings *ts= scene->toolsettings; wmMultMatrix(ob->obmat); glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); switch( ob->type) { case OB_MESH: { if(ob == scene->obedit) { Mesh *me= ob->data; EditMesh *em= me->edit_mesh; DerivedMesh *dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); EM_init_index_arrays(em, 1, 1, 1); bbs_mesh_solid_EM(scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE); if(ts->selectmode & SCE_SELECT_FACE) em_solidoffs = 1+em->totface; else em_solidoffs= 1; bglPolygonOffset(rv3d->dist, 1.0); // we draw edges always, for loop (select) tools bbs_mesh_wire(dm, em_solidoffs); em_wireoffs= em_solidoffs + em->totedge; // we draw verts if vert select mode or if in transform (for snap). if(ts->selectmode & SCE_SELECT_VERTEX || G.moving & G_TRANSFORM_EDIT) { bbs_mesh_verts(dm, em_wireoffs); em_vertoffs= em_wireoffs + em->totvert; } else em_vertoffs= em_wireoffs; bglPolygonOffset(rv3d->dist, 0.0); dm->release(dm); EM_free_index_arrays(); } else bbs_mesh_solid(scene, v3d, ob); } break; case OB_CURVE: case OB_SURF: break; } wmLoadMatrix(rv3d->viewmat); } /* ************* draw object instances for bones, for example ****************** */ /* assumes all matrices/etc set OK */ /* helper function for drawing object instances - meshes */ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int dt, int outline) { Mesh *me= ob->data; DerivedMesh *dm=NULL, *edm=NULL; int glsl; if(ob == scene->obedit) edm= editmesh_get_derived_base(ob, me->edit_mesh); else dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); if(dt<=OB_WIRE) { if(dm) dm->drawEdges(dm, 1); else if(edm) edm->drawEdges(edm, 1); } else { if(outline) draw_mesh_object_outline(v3d, ob, dm?dm:edm); if(dm) { glsl = draw_glsl_material(scene, ob, v3d, dt); GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); } else { glEnable(GL_COLOR_MATERIAL); UI_ThemeColor(TH_BONE_SOLID); glDisable(GL_COLOR_MATERIAL); } glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); glEnable(GL_LIGHTING); if(dm) { dm->drawFacesSolid(dm, GPU_enable_material); GPU_end_object_materials(); } else if(edm) edm->drawMappedFaces(edm, NULL, NULL, 0); glDisable(GL_LIGHTING); } if(edm) edm->release(edm); if(dm) dm->release(dm); } void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int dt, int outline) { if (ob == NULL) return; switch (ob->type) { case OB_MESH: draw_object_mesh_instance(scene, v3d, rv3d, ob, dt, outline); break; case OB_EMPTY: drawaxes(ob->empty_drawsize, 0, ob->empty_drawtype); break; } }