diff options
Diffstat (limited to 'source/blender/editors/space_view3d/drawobject.c')
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 5475 |
1 files changed, 5475 insertions, 0 deletions
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c new file mode 100644 index 00000000000..f5a2cd9df00 --- /dev/null +++ b/source/blender/editors/space_view3d/drawobject.c @@ -0,0 +1,5475 @@ +/** + * $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 <string.h> +#include <math.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_guardedalloc.h" + +#include "BMF_Api.h" + +#include "IMB_imbuf.h" + + +#include "MTC_matrixops.h" + +#include "DNA_armature_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_ipo_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_particle_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" +#include "DNA_view3d_types.h" +#include "DNA_world_types.h" +// FSPARTICLE +#include "DNA_object_fluidsim.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_context.h" +#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_ipo.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_particle.h" +#include "BKE_property.h" +#include "BKE_utildefines.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_draw.h" +#include "GPU_material.h" +#include "GPU_extensions.h" + +#include "ED_types.h" +#include "ED_util.h" + +#include "UI_resources.h" +#include "UI_interface_icons.h" + +#include "WM_api.h" + +#include "view3d_intern.h" // own include + + +/* pretty stupid */ +/* extern Lattice *editLatt; already in BKE_lattice.h */ +/* editcurve.c */ +extern ListBase editNurb; +/* editmball.c */ +extern ListBase editelems; + +static void draw_bounding_volume(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); + +EditVert *EM_get_vert_for_index(int x) {return 0;} // XXX +EditEdge *EM_get_edge_for_index(int x) {return 0;} // XXX +EditFace *EM_get_face_for_index(int x) {return 0;} // XXX +void EM_init_index_arrays(int x, int y, int z) {} // XXX +void EM_free_index_arrays(void) {} // XXX +#define EM_FGON 0 +EditFace *EM_get_actFace(int x) {return NULL;} // XXX +int draw_armature(Base *base, int x, int y) {return 0;} // XXX +int em_solidoffs; // XXX +int em_wireoffs; +int em_vertoffs; + +/* 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 && (G.f & G_WEIGHTPAINT)) + return 0; + + return ((G.fileflags & G_FILE_GAME_MAT) && + (G.fileflags & G_FILE_GAME_MAT_GLSL) && (dt >= OB_SHADED)); +} + +static int check_material_alpha(Base *base, Object *ob, int glsl) +{ + if(base->flag & OB_FROMDUPLI) + return 0; + + if(G.f & G_PICKSEL) + return 0; + + if(G.obedit && G.obedit->data==ob->data) + return 0; + + return (glsl || (ob->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; + glRasterPos3fv(v2); + + // patch for 3d cards crashing on glSelect for text drawing (IBM) + if((flag & DRAW_PICKING) == 0) { + if (axis==0) + BMF_DrawString(G.font, "x"); + else if (axis==1) + BMF_DrawString(G.font, "y"); + else + BMF_DrawString(G.font, "z"); + } + } + 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; a<tot; a++) { + vec[0]= cent[0] + *(sinval+a) * vx[0] + *(cosval+a) * vy[0]; + vec[1]= cent[1] + *(sinval+a) * vx[1] + *(cosval+a) * vy[1]; + vec[2]= cent[2] + *(sinval+a) * vx[2] + *(cosval+a) * vy[2]; + glVertex3fv(vec); + } + glEnd(); +} + +/* circle for object centers, special_color is for library or ob users */ +static void drawcentercircle(View3D *v3d, float *vec, int selstate, int special_color) +{ + float size; + + size= v3d->persmat[0][3]*vec[0]+ v3d->persmat[1][3]*vec[1]+ v3d->persmat[2][3]*vec[2]+ v3d->persmat[3][3]; + size*= v3d->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, v3d->viewinv); + + UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30); + drawcircball(GL_LINE_LOOP, vec, size, v3d->viewinv); + + glDisable(GL_BLEND); + if(v3d->zbuf) glDepthFunc(GL_LEQUAL); +} + + +void drawsolidcube(float size) +{ + float n[3]; + + glPushMatrix(); + glScalef(size, size, size); + + n[0]=0; n[1]=0; n[2]=0; + glBegin(GL_QUADS); + n[0]= -1.0; + glNormal3fv(n); + glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); + n[0]=0; + glEnd(); + + glBegin(GL_QUADS); + n[1]= -1.0; + glNormal3fv(n); + glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]); + n[1]=0; + glEnd(); + + glBegin(GL_QUADS); + n[0]= 1.0; + glNormal3fv(n); + glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]); + n[0]=0; + glEnd(); + + glBegin(GL_QUADS); + n[1]= 1.0; + glNormal3fv(n); + glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]); + n[1]=0; + glEnd(); + + glBegin(GL_QUADS); + n[2]= 1.0; + glNormal3fv(n); + glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]); + n[2]=0; + glEnd(); + + glBegin(GL_QUADS); + n[2]= -1.0; + glNormal3fv(n); + glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]); + glEnd(); + + glPopMatrix(); +} + +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(const bContext *C, Scene *scene, View3D *v3d, 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(CTX_wm_window(C), v3d->viewmat); + + /* lets calculate the scale: */ + pixsize= v3d->persmat[0][3]*ob->obmat[3][0]+ v3d->persmat[1][3]*ob->obmat[3][1]+ v3d->persmat[2][3]*ob->obmat[3][2]+ v3d->persmat[3][3]; + pixsize*= v3d->pixsize; + lampsize= pixsize*((float)U.obcenter_dia*0.5f); + + /* and view aligned matrix: */ + Mat4CpyMat4(imat, v3d->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 = v3d->persmat[0][2]; + y = v3d->persmat[1][2]; + z = v3d->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(CTX_wm_window(C), v3d->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(const bContext *C, Scene *scene, View3D *v3d, 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(v3d->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(v3d->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(v3d->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(CTX_wm_window(C), v3d->viewmat); + Mat4CpyMat4(vec, ob->obmat); + Mat4Ortho(vec); + wmMultMatrix(CTX_wm_window(C), vec); + + MTC_Mat4SwapMat4(v3d->persmat, tmat); + wmGetSingleMatrix(CTX_wm_window(C), v3d->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); + + MTC_Mat4SwapMat4(v3d->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; w<lt->pntsw; w++) { + int wxt = (w==0 || w==lt->pntsw-1); + for(v=0; v<lt->pntsv; v++) { + int vxt = (v==0 || v==lt->pntsv-1); + for(u=0; u<lt->pntsu; 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(void (*func)(void *userData, BPoint *bp, int x, int y), void *userData) +{ + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + BPoint *bp = editLatt->def; + DispList *dl = find_displist(&G.obedit->disp, DL_VERTS); + float *co = dl?dl->verts:NULL; + float pmat[4][4], vmat[4][4]; + int i, N = editLatt->pntsu*editLatt->pntsv*editLatt->pntsw; + short s[2]; + + view3d_get_object_project_mat(v3d, G.obedit, pmat, vmat); + + for (i=0; i<N; i++, bp++, co+=3) { + if (bp->hide==0) { + view3d_project_short_clip(ar, v3d, dl?co:bp->vec, s, pmat, vmat); + 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) { +#if 0 + XXX + float col[3]; + MDeformWeight *mdw= get_defweight (lt->dvert+index, use_wcol-1); + + weight_to_rgb(mdw?mdw->weight:0.0f, col, col+1, col+2); + glColor3fv(col); +#endif + } + + 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(View3D *v3d, Object *ob) +{ + Lattice *lt; + DispList *dl; + int u, v, w; + int use_wcol= 0; + + lt= (ob==G.obedit)?editLatt:ob->data; + + /* now we default make displist, this will modifiers work for non animated case */ + if(ob->disp.first==NULL) + lattice_calc_modifiers(ob); + dl= find_displist(&ob->disp, DL_VERTS); + + if(ob==G.obedit) { + cpack(0x004000); + + if(ob->defbase.first && lt->dvert) { + use_wcol= ob->actdef; + glShadeModel(GL_SMOOTH); + } + } + + glBegin(GL_LINES); + for(w=0; w<lt->pntsw; w++) { + int wxt = (w==0 || w==lt->pntsw-1); + for(v=0; v<lt->pntsv; v++) { + int vxt = (v==0 || v==lt->pntsv-1); + for(u=0; u<lt->pntsu; 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(ob==G.obedit) { + 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; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData; + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + EditVert *eve = EM_get_vert_for_index(index); + short s[2]; + + if (eve->h==0) { + if (data->clipVerts) { + view3d_project_short_clip(ar, v3d, co, s, data->pmat, data->vmat); + } else { + view3d_project_short_noclip(ar, co, s, data->pmat); + } + + data->func(data->userData, eve, s[0], s[1], index); + } +} +void mesh_foreachScreenVert(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; int clipVerts; float pmat[4][4], vmat[4][4]; } data; + View3D *v3d= NULL; // XXX + DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + + data.func = func; + data.userData = userData; + data.clipVerts = clipVerts; + + view3d_get_object_project_mat(v3d, G.obedit, data.pmat, data.vmat); + + EM_init_index_arrays(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; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData; + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + EditEdge *eed = EM_get_edge_for_index(index); + short s[2][2]; + + if (eed->h==0) { + if (data->clipVerts==1) { + view3d_project_short_clip(ar, v3d, v0co, s[0], data->pmat, data->vmat); + view3d_project_short_clip(ar, v3d, v1co, s[1], data->pmat, data->vmat); + } else { + view3d_project_short_noclip(ar, v0co, s[0], data->pmat); + view3d_project_short_noclip(ar, v1co, s[1], data->pmat); + + if (data->clipVerts==2) { + if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<ar->winx && s[0][1]<ar->winy)) + if (!(s[1][0]>=0 && s[1][1]>= 0 && s[1][0]<ar->winx && s[1][1]<ar->winy)) + return; + } + } + + data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index); + } +} +void mesh_foreachScreenEdge(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; int clipVerts; float pmat[4][4], vmat[4][4]; } data; + View3D *v3d= NULL; // XXX + DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + + data.func = func; + data.userData = userData; + data.clipVerts = clipVerts; + + view3d_get_object_project_mat(v3d, G.obedit, data.pmat, data.vmat); + + EM_init_index_arrays(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; float pmat[4][4], vmat[4][4]; } *data = userData; + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + EditFace *efa = EM_get_face_for_index(index); + short s[2]; + + if (efa && efa->h==0 && efa->fgonf!=EM_FGON) { + view3d_project_short_clip(ar, v3d, cent, s, data->pmat, data->vmat); + + data->func(data->userData, efa, s[0], s[1], index); + } +} +void mesh_foreachScreenFace(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; float pmat[4][4], vmat[4][4]; } data; + DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + View3D *v3d= NULL; // XXX + + data.func = func; + data.userData = userData; + + view3d_get_object_project_mat(v3d, G.obedit, data.pmat, data.vmat); + + EM_init_index_arrays(0, 0, 1); + dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data); + EM_free_index_arrays(); + + dm->release(dm); +} + +void nurbs_foreachScreenVert(void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y), void *userData) +{ + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + float pmat[4][4], vmat[4][4]; + short s[2]; + Nurb *nu; + int i; + + view3d_get_object_project_mat(v3d, G.obedit, pmat, vmat); + + for (nu= editNurb.first; nu; nu=nu->next) { + if((nu->type & 7)==CU_BEZIER) { + for (i=0; i<nu->pntsu; i++) { + BezTriple *bezt = &nu->bezt[i]; + + if(bezt->hide==0) { + if (G.f & G_HIDDENHANDLES) { + view3d_project_short_clip(ar, v3d, bezt->vec[1], s, pmat, vmat); + if (s[0] != IS_CLIPPED) + func(userData, nu, NULL, bezt, 1, s[0], s[1]); + } else { + view3d_project_short_clip(ar, v3d, bezt->vec[0], s, pmat, vmat); + if (s[0] != IS_CLIPPED) + func(userData, nu, NULL, bezt, 0, s[0], s[1]); + view3d_project_short_clip(ar, v3d, bezt->vec[1], s, pmat, vmat); + if (s[0] != IS_CLIPPED) + func(userData, nu, NULL, bezt, 1, s[0], s[1]); + view3d_project_short_clip(ar, v3d, bezt->vec[2], s, pmat, vmat); + if (s[0] != IS_CLIPPED) + func(userData, nu, NULL, bezt, 2, s[0], s[1]); + } + } + } + } + else { + for (i=0; i<nu->pntsu*nu->pntsv; i++) { + BPoint *bp = &nu->bp[i]; + + if(bp->hide==0) { + view3d_project_short_clip(ar, v3d, bp->vec, s, pmat, vmat); + 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) +{ + Scene *scene= NULL; // XXX + EditFace *efa = EM_get_face_for_index(index); + + if (efa->h==0 && efa->fgonf!=EM_FGON) { + glVertex3fv(cent); + glVertex3f( cent[0] + no[0]*scene->editbutsize, + cent[1] + no[1]*scene->editbutsize, + cent[2] + no[2]*scene->editbutsize); + } +} +static void draw_dm_face_normals(DerivedMesh *dm) { + glBegin(GL_LINES); + dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, 0); + 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= NULL; // XXX + EditVert *eve = EM_get_vert_for_index(index); + + if (eve->h==0) { + glVertex3fv(co); + + if (no_f) { + glVertex3f( co[0] + no_f[0]*scene->editbutsize, + co[1] + no_f[1]*scene->editbutsize, + co[2] + no_f[2]*scene->editbutsize); + } else { + glVertex3f( co[0] + no_s[0]*scene->editbutsize/32767.0f, + co[1] + no_s[1]*scene->editbutsize/32767.0f, + co[2] + no_s[2]*scene->editbutsize/32767.0f); + } + } +} +static void draw_dm_vert_normals(DerivedMesh *dm) { + glBegin(GL_LINES); + dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, NULL); + 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) +{ + if (scene->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, EditMesh *em, DerivedMesh *cageDM, EditVert *eve_act) +{ + 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(scene->selectmode & SCE_SELECT_VERTEX) { + glPointSize(size); + glColor4ubv((GLubyte *)col); + draw_dm_verts(cageDM, sel, eve_act); + } + + if( CHECK_OB_DRAWFACEDOT(scene, v3d, G.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, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act) +{ + 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(scene->selectmode == SCE_SELECT_FACE) { + draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); + } + else if( (G.f & G_DRAWEDGES) || (scene->selectmode & SCE_SELECT_EDGE) ) { + if(cageDM->drawMappedEdgesInterp && (scene->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, Object *ob, EditMesh *em) +{ + EditEdge *eed; + EditFace *efa; + float v1[3], v2[3], v3[3], v4[3]; + 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 */ + + if(G.f & (G_RENDER_OGL|G_RENDER_SHADOW)) + return; + + /* make the precission of the pronted value proportionate to the gridsize */ + if ((v3d->grid) < 0.01) + strcpy(conv_float, "%.6f"); + else if ((v3d->grid) < 0.1) + strcpy(conv_float, "%.5f"); + else if ((v3d->grid) < 1.0) + strcpy(conv_float, "%.4f"); + else if ((v3d->grid) < 10.0) + 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(5.0); + + if(G.f & G_DRAW_EDGELEN) { + UI_GetThemeColor3fv(TH_TEXT, col); + /* make color a bit more red */ + if(col[0]> 0.5) {col[1]*=0.7; col[2]*= 0.7;} + else col[0]= col[0]*0.7 + 0.3; + 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); + + glRasterPos3f( 0.5*(v1[0]+v2[0]), 0.5*(v1[1]+v2[1]), 0.5*(v1[2]+v2[2])); + + if(v3d->flag & V3D_GLOBAL_STATS) { + Mat4MulVecfl(ob->obmat, v1); + Mat4MulVecfl(ob->obmat, v2); + } + + sprintf(val, conv_float, VecLenf(v1, v2)); + BMF_DrawString( G.fonts, val); + } + } + } + + if(G.f & G_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.5) {col[0]*=0.7; col[2]*= 0.7;} + else col[1]= col[1]*0.7 + 0.3; + 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); + + sprintf(val, conv_float, area); + glRasterPos3fv(efa->cent); + BMF_DrawString( G.fonts, val); + } + } + } + + if(G.f & G_DRAW_EDGEANG) { + EditEdge *e1, *e2, *e3, *e4; + + UI_GetThemeColor3fv(TH_TEXT, col); + /* make color a bit more blue */ + if(col[2]> 0.5) {col[0]*=0.7; col[1]*= 0.7;} + else col[2]= col[2]*0.7 + 0.3; + 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.8); + glRasterPos3fv(fvec); + BMF_DrawString( G.fonts, val); + } + 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.8); + glRasterPos3fv(fvec); + BMF_DrawString( G.fonts, val); + } + 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.8); + glRasterPos3fv(fvec); + BMF_DrawString( G.fonts, val); + } + /* 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.8); + glRasterPos3fv(fvec); + BMF_DrawString( G.fonts, val); + } + } + } + } + + if(v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + bglPolygonOffset(0.0); + } +} + +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, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt) +{ + Mesh *me = ob->data; + EditFace *efa_act = EM_get_actFace(0); /* annoying but active faces is stored differently */ + EditEdge *eed_act = NULL; + EditVert *eve_act = NULL; + + if (G.editMesh->selected.last) { + EditSelection *ese = G.editMesh->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(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, 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(1.0); + glDepthMask(0); + } + else { + if (cageDM!=finalDM) { + UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7); + finalDM->drawEdges(finalDM, 1); + } + } + + if((G.f & (G_DRAWFACES)) || FACESEL_PAINT_TEST) { /* 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((G.f & G_DRAWEDGES)==0 && CHECK_OB_DRAWTEXTURE(v3d, dt)) { + /* we are drawing textures and 'G_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, cageDM, 1, eed_act); + + } else { + if(G.f & G_DRAWSEAMS) { + UI_ThemeColor(TH_EDGE_SEAM); + glLineWidth(2); + + draw_dm_edges_seams(cageDM); + + glColor3ub(0,0,0); + glLineWidth(1); + } + + if(G.f & G_DRAWSHARP) { + UI_ThemeColor(TH_EDGE_SHARP); + glLineWidth(2); + + draw_dm_edges_sharp(cageDM); + + glColor3ub(0,0,0); + glLineWidth(1); + } + + if(G.f & G_DRAWCREASES) { + draw_dm_creases(cageDM); + } + if(G.f & G_DRAWBWEIGHTS) { + draw_dm_bweights(scene, cageDM); + } + + draw_em_fancy_edges(scene, v3d, cageDM, 0, eed_act); + } + if(ob==G.obedit) { +// XXX retopo_matrix_update(v3d); + + draw_em_fancy_verts(scene, v3d, em, cageDM, eve_act); + + if(G.f & G_DRAWNORMALS) { + UI_ThemeColor(TH_NORMAL); + draw_dm_face_normals(cageDM); + } + if(G.f & G_DRAW_VNORMALS) { + UI_ThemeColor(TH_NORMAL); + draw_dm_vert_normals(cageDM); + } + + if(G.f & (G_DRAW_EDGELEN|G_DRAW_FACEAREA|G_DRAW_EDGEANG)) + draw_em_measure_stats(v3d, ob, em); + } + + if(dt>OB_WIRE) { + glDepthMask(1); + bglPolygonOffset(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, 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->mode&MA_HALO)); + int draw_wire = 0; + int totvert, totedge, totface; + DispList *dl; + DerivedMesh *dm= mesh_get_derived_final(ob, get_viewedit_datamask()); + + 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 && FACESEL_PAINT_TEST) draw_wire = 0; + + if(dt==OB_BOUNDBOX) { + draw_bounding_volume(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 && (G.f & G_TEXTUREPAINT || FACESEL_PAINT_TEST)) || + CHECK_OB_DRAWTEXTURE(v3d, dt)) + { + int faceselect= (ob==OBACT && FACESEL_PAINT_TEST); + + if ((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !(G.f&G_PICKSEL || FACESEL_PAINT_TEST) && !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, 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( (G.f & G_WEIGHTPAINT)) { + /* 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((G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) && me->mcol) { + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1); + } + else if(G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) { + 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(base); + dl = find_displist(&ob->disp, DL_VERTCOL); + dm= mesh_get_derived_final(ob, get_viewedit_datamask()); + } + + 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(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(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, Base *base, int dt, int flag) +{ + Object *ob= base->object; + Mesh *me= ob->data; + int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha; + + if(G.obedit && ob!=G.obedit && ob->data==G.obedit->data) { + if(ob_get_key(ob)); + else drawlinked= 1; + } + + if(ob==G.obedit || drawlinked) { + DerivedMesh *finalDM, *cageDM; + + if (G.obedit!=ob) + finalDM = cageDM = editmesh_get_derived_base(); + else + cageDM = editmesh_get_derived_cage_and_final(&finalDM, + get_viewedit_datamask()); + + if(dt>OB_WIRE) { + // no transp in editmode, the fancy draw over goes bad then + glsl = draw_glsl_material(scene, ob, v3d, dt); + GPU_set_object_materials(scene, ob, glsl, NULL); + } + + draw_em_fancy(scene, v3d, ob, G.editMesh, cageDM, finalDM, dt); + + if (G.obedit!=ob && finalDM) + finalDM->release(finalDM); + } +// else if(!G.obedit && (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(v3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) { + glsl = draw_glsl_material(scene, ob, v3d, dt); + check_alpha = check_material_alpha(base, ob, glsl); + + if(dt==OB_SOLID || glsl) { + GPU_set_object_materials(scene, ob, glsl, + (check_alpha)? &do_alpha_pass: NULL); + } + + draw_mesh_fancy(scene, v3d, base, dt, flag); + + if(me->totvert==0) retval= 1; + } + } + + /* GPU_set_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; parts<dl->parts; parts++) + glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr); + + break; + case DL_POLY: + + glVertexPointer(3, GL_FLOAT, 0, data); + + for(parts=0; parts<dl->parts; parts++) + glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr); + + break; + case DL_SURF: + + glVertexPointer(3, GL_FLOAT, 0, data); + + for(parts=0; parts<dl->parts; 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; nr<dl->nr; 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); + GPU_disable_material(); + } + 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); + GPU_disable_material(); + + 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); + + GPU_disable_material(); + + 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, 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_set_object_materials(scene, ob, 1, NULL); + drawDispListsolid(lb, ob, 1); + } + else if(dt == OB_SHADED) { + if(ob->disp.first==0) shadeDispList(base); + drawDispListshaded(lb, ob); + } + else { + GPU_set_object_materials(scene, ob, 0, NULL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); + drawDispListsolid(lb, ob, 0); + } + if(ob==G.obedit && 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_set_object_materials(scene, ob, 1, NULL); + drawDispListsolid(lb, ob, 1); + } + else if(dt==OB_SHADED) { + if(ob->disp.first==NULL) shadeDispList(base); + drawDispListshaded(lb, ob); + } + else { + GPU_set_object_materials(scene, ob, 0, NULL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); + + drawDispListsolid(lb, ob, 0); + } + } + else { + retval= drawDispListwire(lb); + } + break; + case OB_MBALL: + + if( is_basis_mball(ob)) { + lb= &ob->disp; + if(lb->first==NULL) makeDispListMBall(ob); + if(lb->first==NULL) return 1; + + if(solid) { + + if(draw_glsl_material(scene, ob, v3d, dt)) { + GPU_set_object_materials(scene, ob, 1, NULL); + drawDispListsolid(lb, ob, 1); + } + else if(dt == OB_SHADED) { + dl= lb->first; + if(dl && dl->col1==0) shadeDispList(base); + drawDispListshaded(lb, ob); + } + else { + GPU_set_object_materials(scene, ob, 0, NULL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); + + drawDispListsolid(lb, ob, 0); + } + } + else{ + /* MetaBalls use DL_INDEX4 type of DispList */ + retval= drawDispListwire(lb); + } + } + break; + } + + return retval; +} + +/* 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(const bContext *C, View3D *v3d, Base *base, ParticleSystem *psys, int dt) +{ + Object *ob=base->object; + ParticleSystemModifierData *psmd; + ParticleSettings *part; + ParticleData *pars, *pa; + ParticleKey state, *states=0; + ParticleCacheKey *cache=0; + Material *ma; + Object *bb_ob=0; + float vel[3], vec[3], vec2[3], imat[4][4], onevec[3]={0.0f,0.0f,0.0f}, bb_center[3]; + float timestep, pixsize=1.0, pa_size, pa_time, r_tilt; + float cfra=bsystem_time(ob,(float)CFRA,0.0); + float *vdata=0, *vedata=0, *cdata=0, *ndata=0, *vd=0, *ved=0, *cd=0, *nd=0, xvec[3], yvec[3], zvec[3]; + float ma_r=0.0f, ma_g=0.0f, ma_b=0.0f; + int a, k, k_max=0, totpart, totpoint=0, draw_as, path_nbr=0; + int path_possible=0, keys_possible=0, draw_keys=0, totchild=0; + int select=ob->flag&SELECT, create_cdata=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; + + if(!G.obedit && psys_in_edit_mode(psys) + && psys->flag & PSYS_HAIR_DONE && part->draw_as==PART_DRAW_PATH) + return; + + if(part->draw_as==PART_DRAW_NOT) return; + +/* 2. */ + if(part->phystype==PART_PHYS_KEYED){ + if(psys->flag & PSYS_FIRST_KEYED){ + if(psys->flag&PSYS_KEYED){ + select=psys_count_keyed_targets(ob,psys); + if(psys->totkeyed==0) + return; + } + } + else + 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; + + ma= give_current_material(ob,part->omat); + + if(ma) { + ma_r = ma->r; + ma_g = ma->g; + ma_b = ma->b; + } + + 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); + create_cdata = 1; + } + else + cpack(0); + + psmd= psys_get_modifier(ob,psys); + + timestep= psys_get_timestep(part); + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + + if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) { + float mat[4][4]; + Mat4MulMat4(mat, psys->imat, ob->obmat); + wmMultMatrix(CTX_wm_window(C), mat); + } + + totpart=psys->totpart; + draw_as=part->draw_as; + + if(part->flag&PART_GLOB_TIME) + cfra=bsystem_time(0,(float)CFRA,0.0); + + if(psys->pathcache){ + path_possible=1; + keys_possible=1; + } + if(draw_as==PART_DRAW_PATH && path_possible==0) + draw_as=PART_DRAW_DOT; + + if(draw_as!=PART_DRAW_PATH && keys_possible && part->draw&PART_DRAW_KEYS){ + path_nbr=part->keys_step; + draw_keys=1; + } + +/* 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, v3d->viewinv); + Normalize(imat[0]); + Normalize(imat[1]); + /* no break! */ + case PART_DRAW_CROSS: + case PART_DRAW_AXIS: + /* lets calculate the scale: */ + pixsize= v3d->persmat[0][3]*ob->obmat[3][0]+ v3d->persmat[1][3]*ob->obmat[3][1]+ v3d->persmat[2][3]*ob->obmat[3][2]+ v3d->persmat[3][3]; + pixsize*= v3d->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){ +// XXX error("Billboards need an active camera or a target object!"); + + 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; + + if(part->bb_align<PART_BB_VIEW) + onevec[part->bb_align]=1.0f; + break; + case PART_DRAW_PATH: + break; + } + if(part->draw & PART_DRAW_SIZE && part->draw_as!=PART_DRAW_CIRC){ + Mat4CpyMat4(imat, v3d->viewinv); + Normalize(imat[0]); + Normalize(imat[1]); + } + +/* 4. */ + if(draw_as && draw_as!=PART_DRAW_PATH){ + 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) + cdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*6*3*sizeof(float), "particle_cdata"); + vdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*6*3*sizeof(float), "particle_vdata"); + break; + case PART_DRAW_LINE: + if(create_cdata) + cdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*2*3*sizeof(float), "particle_cdata"); + vdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*2*3*sizeof(float), "particle_vdata"); + break; + case PART_DRAW_BB: + if(create_cdata) + cdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*4*3*sizeof(float), "particle_cdata"); + vdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*4*3*sizeof(float), "particle_vdata"); + ndata=MEM_callocN((totpart+totchild)*(path_nbr+1)*4*3*sizeof(float), "particle_vdata"); + break; + default: + if(create_cdata) + cdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*3*sizeof(float), "particle_cdata"); + vdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*3*sizeof(float), "particle_vdata"); + } + } + + if(part->draw&PART_DRAW_VEL && draw_as!=PART_DRAW_LINE) + vedata=MEM_callocN((totpart+totchild)*2*3*(path_nbr+1)*sizeof(float), "particle_vedata"); + + vd=vdata; + ved=vedata; + cd=cdata; + nd=ndata; + + psys->lattice=psys_get_lattice(ob,psys); + } + + if(draw_as){ +/* 5. */ + for(a=0,pa=pars; a<totpart+totchild; a++, pa++){ + if(a<totpart){ + if(totchild && (part->draw&PART_DRAW_PARENT)==0) continue; + if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue; + + pa_time=(cfra-pa->time)/pa->lifetime; + pa_size=pa->size; + + 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; + } + } + } + + r_tilt=1.0f+pa->r_ave[0]; + + if(path_nbr){ + cache=psys->pathcache[a]; + k_max=(int)(cache->steps); + } + } + else{ + ChildParticle *cpa= &psys->child[a-totpart]; + + pa_time=psys_get_child_time(psys,cpa,cfra); + + 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; + } + } + } + + pa_size=psys_get_child_size(psys,cpa,cfra,0); + + r_tilt=2.0f*cpa->rand[2]; + if(path_nbr){ + cache=psys->childcache[a-totpart]; + k_max=(int)(cache->steps); + } + } + + if(draw_as!=PART_DRAW_PATH){ + int next_pa=0; + for(k=0; k<=path_nbr; k++){ + if(draw_keys){ + state.time=(float)k/(float)path_nbr; + psys_get_particle_on_path(ob,psys,a,&state,1); + } + else if(path_nbr){ + if(k<=k_max){ + VECCOPY(state.co,(cache+k)->co); + VECCOPY(state.vel,(cache+k)->vel); + QUATCOPY(state.rot,(cache+k)->rot); + } + else + continue; + } + else{ + state.time=cfra; + if(psys_get_particle_state(ob,psys,a,&state,0)==0){ + next_pa=1; + break; + } + } + + switch(draw_as){ + case PART_DRAW_DOT: + if(cd) { + cd[0]=ma_r; + cd[1]=ma_g; + cd[2]=ma_b; + cd+=3; + } + if(vd){ + VECCOPY(vd,state.co) vd+=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; + cd+=18; + } + VECSUB(vec2,state.co,vec); + } + + VECADD(vec,state.co,vec); + VECCOPY(vd,vec); vd+=3; + VECCOPY(vd,vec2); 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(vd,vec); vd+=3; + VECCOPY(vd,vec2); 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(vd,vec); vd+=3; + VECCOPY(vd,vec2); vd+=3; + break; + case PART_DRAW_LINE: + VECCOPY(vec,state.vel); + Normalize(vec); + if(part->draw & PART_DRAW_VEL_LENGTH) + VecMulf(vec,VecLength(state.vel)); + VECADDFAC(vd,state.co,vec,-part->draw_line[0]); vd+=3; + VECADDFAC(vd,state.co,vec,part->draw_line[1]); vd+=3; + if(cd) { + cd[0]=cd[3]=ma_r; + cd[1]=cd[4]=ma_g; + cd[2]=cd[5]=ma_b; + cd+=3; + } + break; + case PART_DRAW_CIRC: + if(create_cdata) + glColor3f(ma_r,ma_g,ma_b); + drawcircball(GL_LINE_LOOP, state.co, pixsize, imat); + break; + case PART_DRAW_BB: + 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; + cd+=12; + } + if(part->draw&PART_DRAW_BB_LOCK && part->bb_align==PART_BB_VIEW){ + VECCOPY(xvec,bb_ob->obmat[0]); + Normalize(xvec); + VECCOPY(yvec,bb_ob->obmat[1]); + Normalize(yvec); + VECCOPY(zvec,bb_ob->obmat[2]); + Normalize(zvec); + } + else if(part->bb_align==PART_BB_VEL){ + float temp[3]; + VECCOPY(temp,state.vel); + Normalize(temp); + VECSUB(zvec,bb_ob->obmat[3],state.co); + if(part->draw&PART_DRAW_BB_LOCK){ + float fac=-Inpf(zvec,temp); + VECADDFAC(zvec,zvec,temp,fac); + } + Normalize(zvec); + Crossf(xvec,temp,zvec); + Normalize(xvec); + Crossf(yvec,zvec,xvec); + } + else{ + VECSUB(zvec,bb_ob->obmat[3],state.co); + if(part->draw&PART_DRAW_BB_LOCK) + zvec[part->bb_align]=0.0f; + Normalize(zvec); + + if(part->bb_align<PART_BB_VIEW) + Crossf(xvec,onevec,zvec); + else + Crossf(xvec,bb_ob->obmat[1],zvec); + Normalize(xvec); + Crossf(yvec,zvec,xvec); + } + + VECCOPY(vec,xvec); + VECCOPY(vec2,yvec); + + VecMulf(xvec,cos(part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt)*(float)M_PI)); + VecMulf(vec2,sin(part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt)*(float)M_PI)); + VECADD(xvec,xvec,vec2); + + VecMulf(yvec,cos(part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt)*(float)M_PI)); + VecMulf(vec,-sin(part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt)*(float)M_PI)); + VECADD(yvec,yvec,vec); + + VecMulf(xvec,pa_size); + VecMulf(yvec,pa_size); + + VECADDFAC(bb_center,state.co,xvec,part->bb_offset[0]); + VECADDFAC(bb_center,bb_center,yvec,part->bb_offset[1]); + + VECADD(vd,bb_center,xvec); + VECADD(vd,vd,yvec); vd+=3; + + VECSUB(vd,bb_center,xvec); + VECADD(vd,vd,yvec); vd+=3; + + VECSUB(vd,bb_center,xvec); + VECSUB(vd,vd,yvec); vd+=3; + + VECADD(vd,bb_center,xvec); + VECSUB(vd,vd,yvec); vd+=3; + + VECCOPY(nd, zvec); nd+=3; + VECCOPY(nd, zvec); nd+=3; + VECCOPY(nd, zvec); nd+=3; + VECCOPY(nd, zvec); nd+=3; + break; + } + + if(vedata){ + VECCOPY(ved,state.co); + ved+=3; + VECCOPY(vel,state.vel); + VecMulf(vel,timestep); + VECADD(ved,state.co,vel); + ved+=3; + } + + if(part->draw & PART_DRAW_SIZE){ + setlinestyle(3); + drawcircball(GL_LINE_LOOP, state.co, pa_size, imat); + setlinestyle(0); + } + + totpoint++; + } + if(next_pa) + continue; + if(part->draw&PART_DRAW_NUM && !(G.f & G_RENDER_SHADOW)){ + /* in path drawing state.co is the end point */ + glRasterPos3f(state.co[0], state.co[1], state.co[2]); + sprintf(val," %i",a); + BMF_DrawString(G.font, val); + } + } + } +/* 6. */ + + glGetIntegerv(GL_POLYGON_MODE, polygonmode); + glDisableClientState(GL_NORMAL_ARRAY); + + if(draw_as != PART_DRAW_CIRC){ + if(draw_as==PART_DRAW_PATH){ + ParticleCacheKey **cache, *path; + float *cd2=0,*cdata2=0; + + glEnableClientState(GL_VERTEX_ARRAY); + + if(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; + + cache=psys->pathcache; + for(a=0, pa=psys->particles; a<totpart; a++, pa++){ + path=cache[a]; + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); + + if(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); + } + + cache=psys->childcache; + for(a=0; a<totchild; a++){ + path=cache[a]; + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); + + if(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); + } + + if(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); + + /* draw particle edit mode key points*/ + } + + if(draw_as!=PART_DRAW_PATH){ + glDisableClientState(GL_COLOR_ARRAY); + + if(vdata){ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vdata); + } + else + glDisableClientState(GL_VERTEX_ARRAY); + + if(ndata && dt>OB_WIRE){ + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, ndata); + glEnable(GL_LIGHTING); + } + else{ + glDisableClientState(GL_NORMAL_ARRAY); + glDisable(GL_LIGHTING); + } + + if(cdata){ + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(3, GL_FLOAT, 0, cdata); + } + + 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(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(vedata){ + glDisableClientState(GL_COLOR_ARRAY); + cpack(0xC0C0C0); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vedata); + + glDrawArrays(GL_LINES, 0, 2*totpoint); + } + + 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(vdata) + MEM_freeN(vdata); + if(vedata) + MEM_freeN(vedata); + if(cdata) + MEM_freeN(cdata); + if(ndata) + MEM_freeN(ndata); + + psys->flag &= ~PSYS_DRAWING; + + if(psys->lattice){ + end_latt_deform(); + psys->lattice=0; + } + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + wmMultMatrix(CTX_wm_window(C), ob->obmat); // bring back local matrix for dtx +} + +static void draw_particle_edit(const bContext *C, Scene *scene, View3D *v3d, Object *ob, ParticleSystem *psys, int dt) +{ + ParticleEdit *edit = psys->edit; + ParticleData *pa; + ParticleCacheKey **path; + ParticleEditKey *key; + ParticleEditSettings *pset = NULL; // XXX PE_settings(); + int i, k, totpart = psys->totpart, totchild=0, timed = pset->draw_timed; + char nosel[4], sel[4]; + float sel_col[3]; + float nosel_col[3]; + char val[32]; + + /* create path and child path cache if it doesn't exist already */ + if(psys->pathcache==0){ +// XXX PE_hide_keys_time(psys,CFRA); + psys_cache_paths(ob,psys,CFRA,0); + } + if(psys->pathcache==0) + return; + + if(pset->flag & PE_SHOW_CHILD && psys->part->draw_as == PART_DRAW_PATH) { + if(psys->childcache==0) + psys_cache_child_paths(ob, psys, CFRA, 0); + } + else if(!(pset->flag & PE_SHOW_CHILD) && psys->childcache) + free_child_path_cache(psys); + + /* opengl setup */ + if((v3d->flag & V3D_ZBUF_SELECT)==0) + glDisable(GL_DEPTH_TEST); + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + + /* 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; + + if(psys->childcache) + totchild = psys->totchildcache; + + /* draw paths */ + if(timed) + glEnable(GL_BLEND); + + glEnableClientState(GL_VERTEX_ARRAY); + + if(dt > OB_WIRE) { + /* solid shaded with lighting */ + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + glEnable(GL_COLOR_MATERIAL); + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + } + else { + /* flat wire color */ + glDisableClientState(GL_NORMAL_ARRAY); + glDisable(GL_LIGHTING); + UI_ThemeColor(TH_WIRE); + } + + /* only draw child paths with lighting */ + if(dt > OB_WIRE) + glEnable(GL_LIGHTING); + + if(psys->part->draw_as == PART_DRAW_PATH) { + for(i=0, path=psys->childcache; i<totchild; i++,path++){ + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co); + if(dt > OB_WIRE) { + glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel); + glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col); + } + + glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1); + } + } + + if(dt > OB_WIRE) + glDisable(GL_LIGHTING); + + if(pset->brushtype == PE_BRUSH_WEIGHT) { + glLineWidth(2.0f); + glEnableClientState(GL_COLOR_ARRAY); + glDisable(GL_LIGHTING); + } + + /* draw parents last without lighting */ + for(i=0, pa=psys->particles, path = psys->pathcache; i<totpart; i++, pa++, path++){ + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co); + if(dt > OB_WIRE) + glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel); + if(dt > OB_WIRE || pset->brushtype == PE_BRUSH_WEIGHT) + glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col); + + glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1); + } + + /* draw edit vertices */ + if(scene->selectmode!=SCE_SELECT_PATH){ + glDisableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glDisable(GL_LIGHTING); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + if(scene->selectmode==SCE_SELECT_POINT){ + float *cd=0,*cdata=0; + cd=cdata=MEM_callocN(edit->totkeys*(timed?4:3)*sizeof(float), "particle edit color data"); + + for(i=0, pa=psys->particles; i<totpart; i++, pa++){ + for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++){ + if(key->flag&PEK_SELECT){ + VECCOPY(cd,sel_col); + } + else{ + VECCOPY(cd,nosel_col); + } + if(timed) + *(cd+3) = (key->flag&PEK_HIDE)?0.0f:1.0f; + cd += (timed?4:3); + } + } + cd=cdata; + for(i=0, pa=psys->particles; i<totpart; i++, pa++){ + if((pa->flag & PARS_HIDE)==0){ + glVertexPointer(3, GL_FLOAT, sizeof(ParticleEditKey), edit->keys[i]->world_co); + glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd); + glDrawArrays(GL_POINTS, 0, pa->totkey); + } + cd += (timed?4:3) * pa->totkey; + + if((pset->flag&PE_SHOW_TIME) && (pa->flag&PARS_HIDE)==0 && !(G.f & G_RENDER_SHADOW)){ + for(k=0, key=edit->keys[i]+k; k<pa->totkey; k++, key++){ + if(key->flag & PEK_HIDE) continue; + + glRasterPos3fv(key->world_co); + sprintf(val," %.1f",*key->time); + BMF_DrawString(G.font, val); + } + } + } + if(cdata) + MEM_freeN(cdata); + cd=cdata=0; + } + else if(scene->selectmode == SCE_SELECT_END){ + for(i=0, pa=psys->particles; i<totpart; i++, pa++){ + if((pa->flag & PARS_HIDE)==0){ + key = edit->keys[i] + pa->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->world_co); + glEnd(); + + if((pset->flag & PE_SHOW_TIME) && !(G.f & G_RENDER_SHADOW)){ + glRasterPos3fv(key->world_co); + sprintf(val," %.1f",*key->time); + BMF_DrawString(G.font, val); + } + } + } + } + } + + 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); + + wmMultMatrix(CTX_wm_window(C), ob->obmat); // bring back local matrix for dtx + glPointSize(1.0); +} + +unsigned int nurbcol[8]= { + 0, 0x9090, 0x409030, 0x603080, 0, 0x40fff0, 0x40c033, 0xA090F0 }; + +static void tekenhandlesN(Nurb *nu, short sel) +{ + BezTriple *bezt; + float *fp; + unsigned int *col; + int a; + + if(nu->hide || (G.f & G_HIDDENHANDLES)) return; + + glBegin(GL_LINES); + + if( (nu->type & 7)==1) { + 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[bezt->h1]); + glVertex3fv(fp); + glVertex3fv(fp+3); + + cpack(col[bezt->h2]); + glVertex3fv(fp+3); + glVertex3fv(fp+6); + } + else if( (bezt->f1 & SELECT)==sel) { + fp= bezt->vec[0]; + + cpack(col[bezt->h1]); + glVertex3fv(fp); + glVertex3fv(fp+3); + } + else if( (bezt->f3 & SELECT)==sel) { + fp= bezt->vec[1]; + + cpack(col[bezt->h2]); + glVertex3fv(fp); + glVertex3fv(fp+3); + } + } + bezt++; + } + } + glEnd(); +} + +static void tekenvertsN(Nurb *nu, short sel) +{ + 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 & 7)==1) { + + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt->hide==0) { + if (G.f & G_HIDDENHANDLES) { + 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 & 7) { + case CU_POLY: + cpack(nurbcol[3]); + bp= nu->bp; + for(b=0; b<nu->pntsv; b++) { + if(nu->flagu & 1) glBegin(GL_LINE_LOOP); + else glBegin(GL_LINE_STRIP); + + for(a=0; a<nu->pntsu; a++, bp++) { + glVertex3fv(bp->vec); + } + + glEnd(); + } + break; + case CU_NURBS: + + bp= nu->bp; + for(b=0; b<nu->pntsv; 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; b<nu->pntsu; 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, Base *base, Nurb *nurb, int dt) +{ + Object *ob= base->object; + Curve *cu = ob->data; + Nurb *nu; + BevList *bl; + +// XXX retopo_matrix_update(v3d); + + /* DispList */ + UI_ThemeColor(TH_WIRE); + drawDispList(scene, v3d, base, dt); + + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + + /* first non-selected handles */ + for(nu=nurb; nu; nu=nu->next) { + if((nu->type & 7)==CU_BEZIER) { + tekenhandlesN(nu, 0); + } + } + draw_editnurb(ob, nurb, 0); + draw_editnurb(ob, nurb, 1); + /* selected handles */ + for(nu=nurb; nu; nu=nu->next) { + if((nu->type & 7)==1) tekenhandlesN(nu, 1); + tekenvertsN(nu, 0); + } + + 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 && scene->editbutsize > 0.0015) { + 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 * scene->editbutsize; + float ox,oy,oz; // Offset perpendicular to the curve + float dx,dy,dz; // Delta along the curve + + ox = fac*bevp->mat[0][0]; + oy = fac*bevp->mat[0][1]; + oz = fac*bevp->mat[0][2]; + + dx = fac*bevp->mat[2][0]; + dy = fac*bevp->mat[2][1]; + dz = fac*bevp->mat[2][2]; + + glBegin(GL_LINE_STRIP); + glVertex3f(bevp->x - ox - dx, bevp->y - oy - dy, bevp->z - oz - dz); + glVertex3f(bevp->x, bevp->y, bevp->z); + glVertex3f(bevp->x + ox - dx, bevp->y + oy - dy, bevp->z + oz - dz); + glEnd(); + + bevp += skip+1; + nr -= skip; + } + } + } + + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + + for(nu=nurb; nu; nu=nu->next) { + tekenvertsN(nu, 1); + } + + if(v3d->zbuf) glEnable(GL_DEPTH_TEST); +} + +/* draw a sphere for use as an empty drawtype */ +static void draw_empty_sphere (float size) +{ + float cent=0; + GLUquadricObj *qobj = gluNewQuadric(); + gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); + + glPushMatrix(); + glTranslatef(cent, cent, cent); + glScalef(size, size, size); + gluSphere(qobj, 1.0, 8, 5); + + glPopMatrix(); + + gluDeleteQuadric(qobj); +} + +/* 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) +{ + 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; a<icu->totvert; 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(); +} + + +static void tekentextcurs(void) +{ + cpack(0); + + set_inverted_drawing(1); + glBegin(GL_QUADS); + glVertex2fv(G.textcurs[0]); + glVertex2fv(G.textcurs[1]); + glVertex2fv(G.textcurs[2]); + glVertex2fv(G.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; a<tot; a++) { + if (a+start>31) + 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; a<tot; a++) { + if (a+start>31) + 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(const bContext *C, Scene *scene, View3D *v3d, 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(ob==G.obedit) { + UI_ThemeColor(TH_WIRE); + if((G.f & G_PICKSEL)==0 ) drawDispList(scene, v3d, base, dt); + ml= editelems.first; + } + else { + if((base->flag & OB_FROMDUPLI)==0) + drawDispList(scene, v3d, base, dt); + ml= mb->elems.first; + } + + if(ml==NULL) return 1; + + /* in case solid draw, reset wire colors */ + if(ob!=G.obedit && (ob->flag & SELECT)) { + if(ob==OBACT) UI_ThemeColor(TH_ACTIVE); + else UI_ThemeColor(TH_SELECT); + } + else UI_ThemeColor(TH_WIRE); + + wmGetMatrix(CTX_wm_window(C), tmat); + Mat4Invert(imat, tmat); + Normalize(imat[0]); + Normalize(imat[1]); + + while(ml) { + + /* draw radius */ + if(ob==G.obedit) { + 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(ob==G.obedit) { + 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(const bContext *C, 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; + + if(ob!=G.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(CTX_wm_window(C), 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(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(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(View3D *v3d, 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(v3d, 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->flag & OB_POSEMODE)) + draw_armature(base, OB_WIRE, 0); + } + + glLineWidth(1.0); + glDepthMask(1); +} + +static void drawWireExtra(Scene *scene, View3D *v3d, Object *ob) +{ + if(ob!=G.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(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(v3d, 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(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); + } + } +} + +//<rcruiz> +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(); + glRasterPos3fv(v); + if (axis==0) + BMF_DrawString(G.font, "px"); + else if (axis==1) + BMF_DrawString(G.font, "py"); + else + BMF_DrawString(G.font, "pz"); + } + glLineWidth (1.0f); + setlinestyle(0); +} + +/* flag can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET */ +void draw_object(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) +{ + static int warning_recursive= 0; + Object *ob; + Curve *cu; + float cfraont; + float vec1[3], vec2[3]; + unsigned int col=0; + int sel, drawtype, colindex= 0, ipoflag; + 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!=G.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(!(G.f & G_PARTICLEEDIT)) { + /* xray and transp are set when it is drawing the 2nd/3rd pass */ + if(!v3d->xray && !v3d->transp && (ob->dtx & OB_DRAWXRAY)) { + add_view3d_after(v3d, base, V3D_XRAY, flag); + return; + } + } + } + + /* draw keys? */ + if(base==(scene->basact) || (base->flag & (SELECT+BA_WAS_SEL))) { + if(flag==0 && warning_recursive==0 && ob!=G.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(ob, (scene->r.cfra)); + draw_object(C, 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(ob, (scene->r.cfra)); + draw_object(C, 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(ob); + v3d->drawtype= drawtype; + + BLI_freelistN(&elems); + + warning_recursive= 0; + } + } + } + + /* patch? children objects with a timeoffs change the parents. How to solve! */ + /* if( ((int)ob->ctime) != F_(scene->r.cfra)) where_is_object(ob); */ + + wmMultMatrix(CTX_wm_window(C), ob->obmat); + + /* which wire color */ + if((flag & DRAW_CONSTCOLOR) == 0) { + project_short(ar, v3d, 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 && (G.f & (G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT))) { + if(ob->type==OB_MESH) { + + if(ob==G.obedit); + else { + if(dt<OB_SOLID) + zbufoff= 1; + + dt= OB_SHADED; + glEnable(GL_DEPTH_TEST); + } + } + else { + if(dt<OB_SOLID) { + dt= OB_SOLID; + glEnable(GL_DEPTH_TEST); + zbufoff= 1; + } + } + } + + /* draw-extra supported for boundbox drawmode too */ + if(dt>=OB_BOUNDBOX ) { + + dtx= ob->dtx; + if(G.obedit==ob) { + // the only 2 extra drawtypes alowed in editmode + dtx= dtx & (OB_DRAWWIRE|OB_TEXSPACE); + } + + if(G.f & G_DRAW_EXT) { + if(ob->type==OB_EMPTY || ob->type==OB_CAMERA || ob->type==OB_LAMP) dt= OB_WIRE; + } + } + + /* draw outline for selected solid objects, mesh does itself */ + if((v3d->flag & V3D_SELECT_OUTLINE) && ob->type!=OB_MESH) { + if(dt>OB_WIRE && dt<OB_TEXTURE && ob!=G.obedit && (flag && DRAW_SCENESET)==0) { + if (!(ob->dtx&OB_DRAWWIRE) && (ob->flag&SELECT) && !(flag&DRAW_PICKING)) { + drawSolidSelect(v3d, base); + } + } + } + + switch( ob->type) { + case OB_MESH: + if (!(base->flag&OB_RADIO)) { + empty_object= draw_mesh_object(scene, v3d, base, dt, flag); + if(flag!=DRAW_CONSTCOLOR) dtx &= ~OB_DRAWWIRE; // mesh draws wire itself + } + + break; + case OB_FONT: + cu= ob->data; + if (cu->disp.first==NULL) makeDispListCurveTypes(ob, 0); + if(ob==G.obedit) { + tekentextcurs(); + + if (cu->flag & CU_FAST) { + cpack(0xFFFFFF); + set_inverted_drawing(1); + drawDispList(scene, v3d, base, OB_WIRE); + set_inverted_drawing(0); + } else { + drawDispList(scene, v3d, 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; i<cu->totbox; 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 (getselection(&selstart, &selend) && selboxes) { + float selboxw; + + cpack(0xffffff); + set_inverted_drawing(1); + for (i=0; i<(selend-selstart+1); i++) { + SelBox *sb = &(selboxes[i]); + + if (i<(selend-selstart)) { + if (selboxes[i+1].y == sb->y) + selboxw= 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(ob); + else if(boundbox_clip(v3d, ob->obmat, cu->bb)) + empty_object= drawDispList(scene, v3d, base, dt); + + break; + case OB_CURVE: + case OB_SURF: + cu= ob->data; + /* still needed for curves hidden in other layers. depgraph doesnt handle that yet */ + if (cu->disp.first==NULL) makeDispListCurveTypes(ob, 0); + + if(ob==G.obedit) { + drawnurb(scene, v3d, base, editNurb.first, dt); + } + else if(dt==OB_BOUNDBOX) + draw_bounding_volume(ob); + else if(boundbox_clip(v3d, ob->obmat, cu->bb)) { + empty_object= drawDispList(scene, v3d, base, dt); + + if(cu->path) + curve_draw_speed(scene, ob); + } + break; + case OB_MBALL: + if(ob==G.obedit) + drawmball(C, scene, v3d, base, dt); + else if(dt==OB_BOUNDBOX) + draw_bounding_volume(ob); + else + empty_object= drawmball(C, scene, v3d, base, dt); + break; + case OB_EMPTY: + drawaxes(ob->empty_drawsize, flag, ob->empty_drawtype); + break; + case OB_LAMP: + drawlamp(C, scene, v3d, ob); + if(dtx || (base->flag & SELECT)) wmMultMatrix(CTX_wm_window(C), ob->obmat); + break; + case OB_CAMERA: + drawcamera(C, scene, v3d, ob, flag); + break; + case OB_LATTICE: + drawlattice(v3d, ob); + break; + case OB_ARMATURE: + if(dt>OB_WIRE) GPU_enable_material(0, NULL); // we use default material + empty_object= draw_armature(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(C, scene, ob); + + /* code for new particle system */ + if( (warning_recursive==0) && + (ob->particlesystem.first) && + (flag & DRAW_PICKING)==0 && + (ob!=G.obedit) + ) { + ParticleSystem *psys; + if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */ + glDepthMask(GL_FALSE); + + for(psys=ob->particlesystem.first; psys; psys=psys->next) + draw_new_particle_system(C, v3d, base, psys, dt); + + if(G.f & G_PARTICLEEDIT && ob==OBACT) { + psys= NULL; // XXX PE_get_current(ob); + if(psys && !G.obedit && psys_in_edit_mode(psys)) + draw_particle_edit(C, scene, v3d, ob, psys, dt); + } + glDepthMask(GL_TRUE); + if(col) cpack(col); + } + + { + 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(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) { + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + glRasterPos3f(0.0, 0.0, 0.0); + + BMF_DrawString(G.font, " "); + BMF_DrawString(G.font, ob->id.name+2); + if(v3d->zbuf) glEnable(GL_DEPTH_TEST); + } + } + /*if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/ + if((dtx & OB_DRAWWIRE) && dt>=OB_SOLID) drawWireExtra(scene, v3d, ob); + } + + if(dt<OB_SHADED) { + if((ob->gameflag & 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(CTX_wm_window(C), tmat); + Mat4Invert(imat, tmat); + + setlinestyle(2); + drawcircball(GL_LINE_LOOP, vec, ob->inertia, imat); + setlinestyle(0); + } + } + + wmLoadMatrix(CTX_wm_window(C), v3d->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 || (G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))==0) { + 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, 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!=G.obedit) draw_hooks(ob); + + /* help lines and so */ + if(ob!=G.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); + make_axis_color(col, col2, 'z'); + glColor3ubv((GLubyte *)col2); + + cob= constraints_make_evalob(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(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(); +} + +void draw_object_ext(const bContext *C, ARegion *ar, View3D *v3d, Scene *scene, Base *base) +{ + + if(v3d==NULL || base==NULL) return; + + if(v3d->drawtype > OB_WIRE) { + v3d->zbuf= 1; + glEnable(GL_DEPTH_TEST); + } + + G.f |= G_DRAW_EXT; + + glDrawBuffer(GL_FRONT); +// XXX persp(PERSP_VIEW); + + if(v3d->flag & V3D_CLIPPING) + view3d_set_clipping(v3d); + + draw_object(C, scene, ar, v3d, base, 0); + + if(v3d->flag & V3D_CLIPPING) + view3d_clr_clipping(); + + G.f &= ~G_DRAW_EXT; + + bglFlush(); /* reveil frontbuffer drawing */ + glDrawBuffer(GL_BACK); + + if(v3d->zbuf) { + v3d->zbuf= 0; + glDisable(GL_DEPTH_TEST); + } +// XXX ar->win_swap= WIN_FRONT_OK; +} + +/* ***************** 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 int 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); + + return offset + G.totvert; +} + +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 int bbs_mesh_wire(DerivedMesh *dm, int offset) +{ + dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(intptr_t) offset); + + return offset + G.totedge; +} + +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 int bbs_mesh_solid_EM(Scene *scene, View3D *v3d, 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, G.obedit->dt) ) { + glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE)); + + bglBegin(GL_POINTS); + dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, NULL); + bglEnd(); + } + + return 1+G.totface; + } else { + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0); + return 1; + } +} + +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(Object *ob) +{ + DerivedMesh *dm = mesh_get_derived_final(ob, get_viewedit_datamask()); + 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(const bContext *C, Scene *scene, View3D *v3d, Object *ob) +{ + + wmMultMatrix(CTX_wm_window(C), ob->obmat); + + glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + + switch( ob->type) { + case OB_MESH: + if(ob==G.obedit) { + DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + + EM_init_index_arrays(1, 1, 1); + + em_solidoffs= bbs_mesh_solid_EM(scene, v3d, dm, scene->selectmode & SCE_SELECT_FACE); + + bglPolygonOffset(1.0); + + // we draw edges always, for loop (select) tools + em_wireoffs= bbs_mesh_wire(dm, em_solidoffs); + + // we draw verts if vert select mode or if in transform (for snap). + if(scene->selectmode & SCE_SELECT_VERTEX || G.moving & G_TRANSFORM_EDIT) + em_vertoffs= bbs_mesh_verts(dm, em_wireoffs); + else em_vertoffs= em_wireoffs; + + bglPolygonOffset(0.0); + + dm->release(dm); + + EM_free_index_arrays(); + } + else bbs_mesh_solid(ob); + + break; + case OB_CURVE: + case OB_SURF: + break; + } + + wmLoadMatrix(CTX_wm_window(C), v3d->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, Object *ob, int dt, int outline) +{ + DerivedMesh *dm=NULL, *edm=NULL; + int glsl; + + if(G.obedit && ob->data==G.obedit->data) + edm= editmesh_get_derived_base(); + else + dm = mesh_get_derived_final(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_set_object_materials(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_disable_material(); + } + 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, Object *ob, int dt, int outline) +{ + if (ob == NULL) + return; + + switch (ob->type) { + case OB_MESH: + draw_object_mesh_instance(scene, v3d, ob, dt, outline); + break; + case OB_EMPTY: + drawaxes(ob->empty_drawsize, 0, ob->empty_drawtype); + break; + } +} |