4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * Contributor(s): Blender Foundation, full recode and added functions
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/space_view3d/drawobject.c
36 #include "MEM_guardedalloc.h"
38 #include "DNA_camera_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_constraint_types.h" // for drawing constraint
41 #include "DNA_lamp_types.h"
42 #include "DNA_lattice_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_meta_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_smoke_types.h"
48 #include "DNA_speaker_types.h"
49 #include "DNA_world_types.h"
50 #include "DNA_armature_types.h"
52 #include "BLI_utildefines.h"
53 #include "BLI_blenlib.h"
55 #include "BLI_editVert.h"
56 #include "BLI_edgehash.h"
58 #include "BLI_utildefines.h"
60 #include "BKE_anim.h" //for the where_on_path function
61 #include "BKE_constraint.h" // for the get_constraint_target function
62 #include "BKE_curve.h"
63 #include "BKE_DerivedMesh.h"
64 #include "BKE_deform.h"
65 #include "BKE_displist.h"
67 #include "BKE_global.h"
68 #include "BKE_image.h"
70 #include "BKE_lattice.h"
72 #include "BKE_material.h"
73 #include "BKE_mball.h"
74 #include "BKE_modifier.h"
75 #include "BKE_object.h"
76 #include "BKE_paint.h"
77 #include "BKE_particle.h"
78 #include "BKE_pointcache.h"
81 #include "BKE_tessmesh.h"
83 #include "smoke_API.h"
85 #include "IMB_imbuf.h"
86 #include "IMB_imbuf_types.h"
89 #include "BIF_glutil.h"
92 #include "GPU_extensions.h"
95 #include "ED_particle.h"
96 #include "ED_screen.h"
97 #include "ED_sculpt.h"
99 #include "ED_curve.h" /* for curve_editnurbs */
101 #include "UI_resources.h"
104 #include "wm_subwindow.h"
107 #include "view3d_intern.h" // own include
110 /* this condition has been made more complex since editmode can draw textures */
111 #define CHECK_OB_DRAWTEXTURE(vd, dt) \
112 ((vd->drawtype==OB_TEXTURE && dt>OB_SOLID) || \
113 (vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX))
115 static void draw_bounding_volume(Scene *scene, Object *ob);
117 static void drawcube_size(float size);
118 static void drawcircle_size(float size);
119 static void draw_empty_sphere(float size);
120 static void draw_empty_cone(float size);
122 static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
124 if((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
127 if(G.f & G_BACKBUFSEL)
130 if((vd->flag & V3D_ZBUF_SELECT) == 0)
133 /* if its drawing textures with zbuf sel, then dont draw dots */
134 if(dt==OB_TEXTURE && vd->drawtype==OB_TEXTURE)
137 if(vd->drawtype>=OB_SOLID && vd->flag2 & V3D_SOLID_TEX)
143 /* ************* only use while object drawing **************
144 * or after running ED_view3d_init_mats_rv3d
146 static void view3d_project_short_clip(ARegion *ar, const float vec[3], short *adr, int local)
148 RegionView3D *rv3d= ar->regiondata;
149 float fx, fy, vec4[4];
153 /* clipplanes in eye space */
154 if(rv3d->rflag & RV3D_CLIPPING) {
155 if(ED_view3d_test_clipping(rv3d, vec, local))
159 copy_v3_v3(vec4, vec);
162 mul_m4_v4(rv3d->persmatob, vec4);
164 /* clipplanes in window space */
165 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
166 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
168 if( fx>0 && fx<ar->winx) {
170 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
172 if(fy > 0.0f && fy < (float)ar->winy) {
173 adr[0]= (short)floorf(fx);
174 adr[1]= (short)floorf(fy);
180 /* only use while object drawing */
181 static void view3d_project_short_noclip(ARegion *ar, const float vec[3], short *adr)
183 RegionView3D *rv3d= ar->regiondata;
184 float fx, fy, vec4[4];
188 copy_v3_v3(vec4, vec);
191 mul_m4_v4(rv3d->persmatob, vec4);
193 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
194 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
196 if( fx>-32700 && fx<32700) {
198 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
200 if(fy > -32700.0f && fy < 32700.0f) {
201 adr[0]= (short)floorf(fx);
202 adr[1]= (short)floorf(fy);
208 /* ************************ */
210 /* check for glsl drawing */
212 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
214 if(!GPU_glsl_support())
218 if(!CHECK_OB_DRAWTEXTURE(v3d, dt))
220 if(ob==OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
223 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
226 static int check_material_alpha(Base *base, Mesh *me, int glsl)
228 if(base->flag & OB_FROMDUPLI)
237 return (glsl || (base->object->dtx & OB_DRAWTRANSP));
241 static unsigned int colortab[24]=
242 {0x0, 0xFF88FF, 0xFFBBFF,
243 0x403000, 0xFFFF88, 0xFFFFBB,
244 0x104040, 0x66CCCC, 0x77CCCC,
245 0x104010, 0x55BB55, 0x66FF66,
250 static float cube[8][3] = {
261 /* ----------------- OpenGL Circle Drawing - Tables for Optimised Drawing Speed ------------------ */
262 /* 32 values of sin function (still same result!) */
263 #define CIRCLE_RESOL 32
265 static const float sinval[CIRCLE_RESOL] = {
300 /* 32 values of cos function (still same result!) */
301 static const float cosval[CIRCLE_RESOL] = {
336 static void draw_xyz_wire(const float c[3], float size, int axis)
338 float v1[3]= {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
339 float dim = size * 0.1f;
340 float dx[3], dy[3], dz[3];
342 dx[0]=dim; dx[1]=0.f; dx[2]=0.f;
343 dy[0]=0.f; dy[1]=dim; dy[2]=0.f;
344 dz[0]=0.f; dz[1]=0.f; dz[2]=dim;
350 /* bottom left to top right */
351 sub_v3_v3v3(v1, c, dx);
353 add_v3_v3v3(v2, c, dx);
359 /* top left to bottom right */
372 /* bottom left to top right */
373 mul_v3_fl(dx, 0.75f);
374 sub_v3_v3v3(v1, c, dx);
376 add_v3_v3v3(v2, c, dx);
382 /* top left to center */
393 glBegin(GL_LINE_STRIP);
395 /* start at top left */
396 sub_v3_v3v3(v1, c, dx);
397 add_v3_v3v3(v1, c, dz);
422 void drawaxes(float size, char drawtype)
425 float v1[3]= {0.0, 0.0, 0.0};
426 float v2[3]= {0.0, 0.0, 0.0};
427 float v3[3]= {0.0, 0.0, 0.0};
432 for (axis=0; axis<3; axis++) {
440 /* reset v1 & v2 to zero */
441 v1[axis]= v2[axis]= 0.0f;
446 case OB_SINGLE_ARROW:
449 /* in positive z direction only */
456 glBegin(GL_TRIANGLES);
458 v2[0]= size * 0.035f; v2[1] = size * 0.035f;
459 v3[0]= size * -0.035f; v3[1] = size * 0.035f;
460 v2[2]= v3[2]= size * 0.75f;
462 for (axis=0; axis<4; axis++) {
484 drawcircle_size(size);
487 case OB_EMPTY_SPHERE:
488 draw_empty_sphere(size);
492 draw_empty_cone(size);
497 for (axis=0; axis<3; axis++) {
498 const int arrow_axis= (axis==0) ? 1:0;
506 v1[axis]= size*0.85f;
507 v1[arrow_axis]= -size*0.08f;
511 v1[arrow_axis]= size*0.08f;
517 v2[axis]+= size*0.125f;
519 draw_xyz_wire(v2, size, axis);
522 /* reset v1 & v2 to zero */
523 v1[arrow_axis]= v1[axis]= v2[axis]= 0.0f;
530 /* Function to draw an Image on a empty Object */
531 static void draw_empty_image(Object *ob)
533 Image *ima = (Image*)ob->data;
534 ImBuf *ibuf = ima ? BKE_image_get_ibuf(ima, NULL) : NULL;
536 float scale, ofs_x, ofs_y, sca_x, sca_y;
539 if(ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
540 IMB_rect_from_float(ibuf);
543 /* Get the buffer dimensions so we can fallback to fake ones */
544 if(ibuf && ibuf->rect) {
553 /* Get the image aspect even if the buffer is invalid */
555 if(ima->aspx > ima->aspy) {
557 sca_y= ima->aspy / ima->aspx;
559 else if(ima->aspx < ima->aspy) {
560 sca_x= ima->aspx / ima->aspy;
573 /* Calculate the scale center based on objects origin */
574 ofs_x= ob->ima_ofs[0] * ima_x;
575 ofs_y= ob->ima_ofs[1] * ima_y;
577 glMatrixMode(GL_MODELVIEW);
580 /* Make sure we are drawing at the origin */
581 glTranslatef(0.0f, 0.0f, 0.0f);
583 /* Calculate Image scale */
584 scale= (ob->empty_drawsize / (float)MAX2(ima_x * sca_x, ima_y * sca_y));
586 /* Set the object scale */
587 glScalef(scale * sca_x, scale * sca_y, 1.0f);
589 if(ibuf && ibuf->rect) {
590 /* Setup GL params */
592 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
594 /* Use the object color and alpha */
597 /* Draw the Image on the screen */
598 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
599 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
604 UI_ThemeColor((ob->flag & SELECT) ? TH_SELECT : TH_WIRE);
606 /* Calculate the outline vertex positions */
607 glBegin(GL_LINE_LOOP);
608 glVertex2f(ofs_x, ofs_y);
609 glVertex2f(ofs_x + ima_x, ofs_y);
610 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
611 glVertex2f(ofs_x, ofs_y + ima_y);
614 /* Reset GL settings */
615 glMatrixMode(GL_MODELVIEW);
619 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[][4])
622 float *viter= (float *)verts;
625 mul_v3_v3fl(vx, tmat[0], rad);
626 mul_v3_v3fl(vy, tmat[1], rad);
628 for (a=0; a < CIRCLE_RESOL; a++, viter += 3) {
629 viter[0]= cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
630 viter[1]= cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
631 viter[2]= cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
635 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
637 float verts[CIRCLE_RESOL][3];
639 circball_array_fill(verts, cent, rad, tmat);
641 glEnableClientState(GL_VERTEX_ARRAY);
642 glVertexPointer(3, GL_FLOAT, 0, verts);
643 glDrawArrays(mode, 0, CIRCLE_RESOL);
644 glDisableClientState(GL_VERTEX_ARRAY);
647 /* circle for object centers, special_color is for library or ob users */
648 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
650 const float size= ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
651 float verts[CIRCLE_RESOL][3];
653 /* using gldepthfunc guarantees that it does write z values, but not checks for it, so centers remain visible independt order of drawing */
654 if(v3d->zbuf) glDepthFunc(GL_ALWAYS);
658 if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
660 else glColor4ub(0x55, 0xCC, 0xCC, 155);
663 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
664 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
665 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
668 circball_array_fill(verts, co, size, rv3d->viewinv);
670 /* enable vertex array */
671 glEnableClientState(GL_VERTEX_ARRAY);
672 glVertexPointer(3, GL_FLOAT, 0, verts);
674 /* 1. draw filled, blended polygon */
675 glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
677 /* 2. draw outline */
678 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
679 glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
682 glDisableClientState(GL_VERTEX_ARRAY);
686 if(v3d->zbuf) glDepthFunc(GL_LEQUAL);
689 /* *********** text drawing for object/particles/armature ************* */
690 static ListBase CachedText[3];
691 static int CachedTextLevel= 0;
693 typedef struct ViewCachedString {
694 struct ViewCachedString *next, *prev;
704 /* str is allocated past the end */
707 void view3d_cached_text_draw_begin(void)
709 ListBase *strings= &CachedText[CachedTextLevel];
710 strings->first= strings->last= NULL;
714 void view3d_cached_text_draw_add(const float co[3], const char *str, short xoffs, short flag, const unsigned char col[4])
716 int alloc_len= strlen(str) + 1;
717 ListBase *strings= &CachedText[CachedTextLevel-1];
718 ViewCachedString *vos= MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
720 BLI_addtail(strings, vos);
721 copy_v3_v3(vos->vec, co);
722 vos->col.pack= *((int *)col);
725 vos->str_len= alloc_len-1;
727 /* allocate past the end */
728 memcpy(++vos, str, alloc_len);
731 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
733 RegionView3D *rv3d= ar->regiondata;
734 ListBase *strings= &CachedText[CachedTextLevel-1];
735 ViewCachedString *vos;
738 /* project first and test */
739 for(vos= strings->first; vos; vos= vos->next) {
740 if(mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
741 mul_m4_v3(mat, vos->vec);
742 view3d_project_short_clip(ar, vos->vec, vos->sco, 0);
743 if(vos->sco[0]!=IS_CLIPPED)
748 int col_pack_prev= 0;
751 bglMats mats; /* ZBuffer depth vars */
758 if(rv3d->rflag & RV3D_CLIPPING)
760 glDisable(GL_CLIP_PLANE0+a);
762 glMatrixMode(GL_PROJECTION);
764 glMatrixMode(GL_MODELVIEW);
766 ED_region_pixelspace(ar);
769 if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
773 for(vos= strings->first; vos; vos= vos->next) {
774 #if 0 // too slow, reading opengl info while drawing is very bad, better to see if we cn use the zbuffer while in pixel space - campbell
775 if(v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
776 gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
777 glReadPixels(ar->winrct.xmin+vos->mval[0]+vos->xoffs, ar->winrct.ymin+vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
783 if(vos->sco[0]!=IS_CLIPPED) {
784 const char *str= (char *)(vos+1);
786 if(col_pack_prev != vos->col.pack) {
787 glColor3ubv(vos->col.ub);
788 col_pack_prev= vos->col.pack;
790 if(vos->flag & V3D_CACHE_TEXT_ASCII) {
791 BLF_draw_default_ascii((float)vos->sco[0]+vos->xoffs, (float)vos->sco[1], (depth_write)? 0.0f: 2.0f, str, vos->str_len);
794 BLF_draw_default((float)vos->sco[0]+vos->xoffs, (float)vos->sco[1], (depth_write)? 0.0f: 2.0f, str, vos->str_len);
800 if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
804 glMatrixMode(GL_PROJECTION);
806 glMatrixMode(GL_MODELVIEW);
809 if(rv3d->rflag & RV3D_CLIPPING)
811 glEnable(GL_CLIP_PLANE0+a);
815 BLI_freelistN(strings);
820 /* ******************** primitive drawing ******************* */
822 static void drawcube(void)
825 glBegin(GL_LINE_STRIP);
826 glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
827 glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
828 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
831 glBegin(GL_LINE_STRIP);
832 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
835 glBegin(GL_LINE_STRIP);
836 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
839 glBegin(GL_LINE_STRIP);
840 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
844 /* draws a cube on given the scaling of the cube, assuming that
845 * all required matrices have been set (used for drawing empties)
847 static void drawcube_size(float size)
849 glBegin(GL_LINE_STRIP);
850 glVertex3f(-size,-size,-size); glVertex3f(-size,-size,size);glVertex3f(-size,size,size); glVertex3f(-size,size,-size);
851 glVertex3f(-size,-size,-size); glVertex3f(size,-size,-size);glVertex3f(size,-size,size); glVertex3f(size,size,size);
852 glVertex3f(size,size,-size); glVertex3f(size,-size,-size);
855 glBegin(GL_LINE_STRIP);
856 glVertex3f(-size,-size,size); glVertex3f(size,-size,size);
859 glBegin(GL_LINE_STRIP);
860 glVertex3f(-size,size,size); glVertex3f(size,size,size);
863 glBegin(GL_LINE_STRIP);
864 glVertex3f(-size,size,-size); glVertex3f(size,size,-size);
868 /* this is an unused (old) cube-drawing function based on a given size */
870 static void drawcube_size(const float size[3])
874 glScalef(size[0], size[1], size[2]);
877 glBegin(GL_LINE_STRIP);
878 glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
879 glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
880 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
883 glBegin(GL_LINE_STRIP);
884 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
887 glBegin(GL_LINE_STRIP);
888 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
891 glBegin(GL_LINE_STRIP);
892 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
899 static void drawshadbuflimits(Lamp *la, float mat[][4])
901 float sta[3], end[3], lavec[3];
903 negate_v3_v3(lavec, mat[2]);
906 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
907 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
909 glBegin(GL_LINE_STRIP);
924 static void spotvolume(float lvec[3], float vvec[3], const float inp)
926 /* camera is at 0,0,0 */
927 float temp[3],plane[3],mat1[3][3],mat2[3][3],mat3[3][3],mat4[3][3],q[4],co,si,angle;
930 normalize_v3(vvec); /* is this the correct vector ? */
932 cross_v3_v3v3(temp,vvec,lvec); /* equation for a plane through vvec en lvec */
933 cross_v3_v3v3(plane,lvec,temp); /* a plane perpendicular to this, parrallel with lvec */
935 /* vectors are exactly aligned, use the X axis, this is arbitrary */
936 if(normalize_v3(plane) == 0.0f)
939 /* now we've got two equations: one of a cone and one of a plane, but we have
940 three unknowns. We remove one unkown by rotating the plane to z=0 (the plane normal) */
942 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
943 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
945 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
952 angle = saacos(plane[2])/2.0f;
961 quat_to_mat3(mat1,q);
963 /* rotate lamp vector now over acos(inp) degrees */
964 copy_v3_v3(vvec, lvec);
968 si = sqrtf(1.0f-inp*inp);
974 mul_m3_m3m3(mat3,mat2,mat1);
978 mul_m3_m3m3(mat4,mat2,mat1);
981 mul_m3_m3m3(mat2,mat1,mat3);
982 mul_m3_v3(mat2,lvec);
983 mul_m3_m3m3(mat2,mat1,mat4);
984 mul_m3_v3(mat2,vvec);
989 static void draw_spot_cone(Lamp *la, float x, float z)
993 glBegin(GL_TRIANGLE_FAN);
994 glVertex3f(0.0f, 0.0f, -x);
996 if(la->mode & LA_SQUARE) {
998 glVertex3f(-z, z, 0);
999 glVertex3f(-z, -z, 0);
1000 glVertex3f(z, -z, 0);
1001 glVertex3f(z, z, 0);
1007 for(a=0; a<33; a++) {
1008 angle= a*M_PI*2/(33-1);
1009 glVertex3f(z*cosf(angle), z*sinf(angle), 0);
1016 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1018 glEnable(GL_CULL_FACE);
1022 /* draw backside darkening */
1023 glCullFace(GL_FRONT);
1025 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1026 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1028 draw_spot_cone(la, x, z);
1030 /* draw front side lighting */
1031 glCullFace(GL_BACK);
1033 glBlendFunc(GL_ONE, GL_ONE);
1034 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1036 draw_spot_cone(la, x, z);
1039 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1040 glDisable(GL_BLEND);
1042 glDisable(GL_CULL_FACE);
1043 glCullFace(GL_BACK);
1046 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
1048 Object *ob= base->object;
1049 const float pixsize= ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1051 float vec[3], lvec[3], vvec[3], circrad, x,y,z;
1053 float imat[4][4], curcol[4];
1054 unsigned char col[4];
1055 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1056 /* the moment of view3d_draw_transp() call */
1057 const short is_view= (rv3d->persp==RV3D_CAMOB && v3d->camera == base->object);
1058 const short drawcone= (dt>OB_WIRE && !(G.f & G_PICKSEL) && (la->type == LA_SPOT) && (la->mode & LA_SHOW_CONE) && !(base->flag & OB_FROMDUPLI) && !is_view);
1060 if(drawcone && !v3d->transp) {
1061 /* in this case we need to draw delayed */
1062 add_view3d_after(&v3d->afterdraw_transp, base, flag);
1066 /* we first draw only the screen aligned & fixed scale stuff */
1068 glLoadMatrixf(rv3d->viewmat);
1070 /* lets calculate the scale: */
1071 lampsize= pixsize*((float)U.obcenter_dia*0.5f);
1073 /* and view aligned matrix: */
1074 copy_m4_m4(imat, rv3d->viewinv);
1075 normalize_v3(imat[0]);
1076 normalize_v3(imat[1]);
1079 copy_v3_v3(vec, ob->obmat[3]);
1081 /* for AA effects */
1082 glGetFloatv(GL_CURRENT_COLOR, curcol);
1086 if(lampsize > 0.0f) {
1089 if (ob==OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1090 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1095 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1096 glDisable(GL_BLEND);
1097 drawcircball(GL_POLYGON, vec, lampsize, imat);
1104 circrad = 3.0f*lampsize;
1107 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1109 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1110 if(la->type!=LA_HEMI) {
1111 if( (la->mode & LA_SHAD_RAY) ||
1112 ((la->mode & LA_SHAD_BUF) && (la->type==LA_SPOT))
1114 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f*pixsize, imat);
1123 /* draw the pretty sun rays */
1124 if(la->type==LA_SUN) {
1125 float v1[3], v2[3], mat[3][3];
1128 /* setup a 45 degree rotation matrix */
1129 vec_rot_to_mat3(mat, imat[2], (float)M_PI/4.0f);
1132 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1133 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1136 glTranslatef(vec[0], vec[1], vec[2]);
1141 for (axis=0; axis<8; axis++) {
1149 glTranslatef(-vec[0], -vec[1], -vec[2]);
1153 if (la->type==LA_LOCAL) {
1154 if(la->mode & LA_SPHERE) {
1155 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1157 /* yafray: for photonlight also draw lightcone as for spot */
1160 glPopMatrix(); /* back in object space */
1164 /* skip drawing extra info */
1166 else if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) {
1167 lvec[0]=lvec[1]= 0.0;
1169 x = rv3d->persmat[0][2];
1170 y = rv3d->persmat[1][2];
1171 z = rv3d->persmat[2][2];
1172 vvec[0]= x*ob->obmat[0][0] + y*ob->obmat[0][1] + z*ob->obmat[0][2];
1173 vvec[1]= x*ob->obmat[1][0] + y*ob->obmat[1][1] + z*ob->obmat[1][2];
1174 vvec[2]= x*ob->obmat[2][0] + y*ob->obmat[2][1] + z*ob->obmat[2][2];
1176 y = cosf(la->spotsize*(float)(M_PI/360.0));
1177 spotvolume(lvec, vvec, y);
1182 /* draw the angled sides of the cone */
1183 glBegin(GL_LINE_STRIP);
1189 z = x*sqrtf(1.0f - y*y);
1192 /* draw the circle/square at the end of the cone */
1193 glTranslatef(0.0, 0.0 , x);
1194 if(la->mode & LA_SQUARE) {
1196 float z_abs= fabs(z);
1198 tvec[0]= tvec[1]= z_abs;
1201 glBegin(GL_LINE_LOOP);
1203 tvec[1]= -z_abs; /* neg */
1205 tvec[0]= -z_abs; /* neg */
1207 tvec[1]= z_abs; /* pos */
1211 else circ(0.0, 0.0, fabsf(z));
1213 /* draw the circle/square representing spotbl */
1214 if(la->type==LA_SPOT) {
1215 float spotblcirc = fabs(z)*(1 - pow(la->spotblend, 2));
1216 /* hide line if it is zero size or overlaps with outer border,
1217 previously it adjusted to always to show it but that seems
1218 confusing because it doesn't show the actual blend size */
1219 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1220 circ(0.0, 0.0, spotblcirc);
1224 draw_transp_spot_volume(la, x, z);
1226 /* draw clip start, useful for wide cones where its not obvious where the start is */
1227 glTranslatef(0.0, 0.0 , -x); /* reverse translation above */
1228 if(la->type==LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1231 float clipsta_fac= la->clipsta / -x;
1233 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1234 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1236 glBegin(GL_LINE_STRIP);
1237 glVertex3fv(lvec_clip);
1238 glVertex3fv(vvec_clip);
1242 else if ELEM(la->type, LA_HEMI, LA_SUN) {
1244 /* draw the line from the circle along the dist */
1245 glBegin(GL_LINE_STRIP);
1252 if(la->type==LA_HEMI) {
1253 /* draw the hemisphere curves */
1254 short axis, steps, dir;
1255 float outdist, zdist, mul;
1257 outdist = 0.14; mul = 1.4; dir = 1;
1260 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1261 for (axis=0; axis<4; axis++) {
1262 float v[3]= {0.0, 0.0, 0.0};
1265 glBegin(GL_LINE_STRIP);
1267 for (steps=0; steps<6; steps++) {
1268 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1269 /* make the arcs start at the edge of the energy circle */
1270 if (steps == 0) v[0] = dir*circrad;
1271 else v[0] = v[0] + dir*(steps*outdist);
1272 } else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1273 /* make the arcs start at the edge of the energy circle */
1274 if (steps == 0) v[1] = dir*circrad;
1275 else v[1] = v[1] + dir*(steps*outdist);
1278 v[2] = v[2] - steps*zdist;
1282 zdist = zdist * mul;
1286 /* flip the direction */
1290 } else if(la->type==LA_AREA) {
1292 if(la->area_shape==LA_AREA_SQUARE)
1293 fdrawbox(-la->area_size*0.5f, -la->area_size*0.5f, la->area_size*0.5f, la->area_size*0.5f);
1294 else if(la->area_shape==LA_AREA_RECT)
1295 fdrawbox(-la->area_size*0.5f, -la->area_sizey*0.5f, la->area_size*0.5f, la->area_sizey*0.5f);
1297 glBegin(GL_LINE_STRIP);
1298 glVertex3f(0.0,0.0,-circrad);
1299 glVertex3f(0.0,0.0,-la->dist);
1303 /* and back to viewspace */
1304 glLoadMatrixf(rv3d->viewmat);
1305 copy_v3_v3(vec, ob->obmat[3]);
1309 if((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == FALSE)) {
1310 drawshadbuflimits(la, ob->obmat);
1313 UI_GetThemeColor4ubv(TH_LAMP, col);
1318 if (vec[2]>0) vec[2] -= circrad;
1319 else vec[2] += circrad;
1321 glBegin(GL_LINE_STRIP);
1333 glDisable(GL_BLEND);
1335 /* restore for drawing extra stuff */
1340 static void draw_limit_line(float sta, float end, unsigned int col)
1343 glVertex3f(0.0, 0.0, -sta);
1344 glVertex3f(0.0, 0.0, -end);
1350 glVertex3f(0.0, 0.0, -sta);
1351 glVertex3f(0.0, 0.0, -end);
1357 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1358 /* qdn: now also enabled for Blender to set focus point for defocus composit node */
1359 static void draw_focus_cross(float dist, float size)
1362 glVertex3f(-size, 0.f, -dist);
1363 glVertex3f(size, 0.f, -dist);
1364 glVertex3f(0.f, -size, -dist);
1365 glVertex3f(0.f, size, -dist);
1369 #ifdef VIEW3D_CAMERA_BORDER_HACK
1370 float view3d_camera_border_hack_col[4];
1371 short view3d_camera_border_hack_test= FALSE;
1374 /* flag similar to draw_object() */
1375 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int flag)
1377 /* a standing up pyramid with (0,0,0) as top */
1379 float vec[8][4], facx, facy, depth, aspx, aspy, caspx, caspy, shx, shy;
1382 const short is_view= (rv3d->persp==RV3D_CAMOB && ob==v3d->camera);
1384 const float scax= 1.0f / len_v3(ob->obmat[0]);
1385 const float scay= 1.0f / len_v3(ob->obmat[1]);
1386 const float scaz= 1.0f / len_v3(ob->obmat[2]);
1388 #ifdef VIEW3D_CAMERA_BORDER_HACK
1389 if(is_view && !(G.f & G_PICKSEL)) {
1390 glGetFloatv(GL_CURRENT_COLOR, view3d_camera_border_hack_col);
1391 view3d_camera_border_hack_test= TRUE;
1397 aspx= (float) scene->r.xsch*scene->r.xasp;
1398 aspy= (float) scene->r.ysch*scene->r.yasp;
1409 glDisable(GL_LIGHTING);
1410 glDisable(GL_CULL_FACE);
1412 if(cam->type==CAM_ORTHO) {
1413 facx= 0.5f * cam->ortho_scale * caspx * scax;
1414 facy= 0.5f * cam->ortho_scale * caspy * scay;
1415 shx= cam->shiftx * cam->ortho_scale * scax;
1416 shy= cam->shifty * cam->ortho_scale * scay;
1417 depth= is_view ? -((cam->clipsta * scaz) + 0.1f) : - cam->drawsize * cam->ortho_scale * scaz;
1419 drawsize= 0.5f * cam->ortho_scale;
1422 /* that way it's always visible - clipsta+0.1 */
1424 drawsize= cam->drawsize / ((scax + scay + scaz) / 3.0f);
1427 /* fixed depth, variable size (avoids exceeding clipping range) */
1428 depth = -(cam->clipsta + 0.1f);
1429 fac = depth / (cam->lens/-16.0f * scaz);
1432 /* fixed size, variable depth (stays a reasonable size in the 3D view) */
1433 depth= drawsize * cam->lens/-16.0f * scaz;
1437 facx= fac * caspx * scax;
1438 facy= fac * caspy * scay;
1439 shx= cam->shiftx*fac*2 * scax;
1440 shy= cam->shifty*fac*2 * scay;
1443 vec[0][0]= 0.0; vec[0][1]= 0.0; vec[0][2]= 0.0;
1444 vec[1][0]= shx + facx; vec[1][1]= shy + facy; vec[1][2]= depth;
1445 vec[2][0]= shx + facx; vec[2][1]= shy - facy; vec[2][2]= depth;
1446 vec[3][0]= shx - facx; vec[3][1]= shy - facy; vec[3][2]= depth;
1447 vec[4][0]= shx - facx; vec[4][1]= shy + facy; vec[4][2]= depth;
1450 glBegin(GL_LINE_LOOP);
1451 glVertex3fv(vec[1]);
1452 glVertex3fv(vec[2]);
1453 glVertex3fv(vec[3]);
1454 glVertex3fv(vec[4]);
1460 /* center point to camera frame */
1461 glBegin(GL_LINE_STRIP);
1462 glVertex3fv(vec[2]);
1463 glVertex3fv(vec[0]);
1464 glVertex3fv(vec[1]);
1465 glVertex3fv(vec[4]);
1466 glVertex3fv(vec[0]);
1467 glVertex3fv(vec[3]);
1475 /* draw an outline arrow for inactive cameras and filled
1476 * for active cameras. We actually draw both outline+filled
1477 * for active cameras so the wire can be seen side-on */
1479 if (i==0) glBegin(GL_LINE_LOOP);
1480 else if (i==1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1483 vec[0][0]= shx + ((-0.7f * drawsize) * scax);
1484 vec[0][1]= shy + ((drawsize * (caspy + 0.1f)) * scay);
1485 glVertex3fv(vec[0]); /* left */
1487 vec[0][0]= shx + ((0.7f * drawsize) * scax);
1488 glVertex3fv(vec[0]); /* right */
1491 vec[0][1]= shy + ((1.1f * drawsize * (caspy + 0.7f)) * scay);
1492 glVertex3fv(vec[0]); /* top */
1498 if(cam->flag & (CAM_SHOWLIMITS+CAM_SHOWMIST)) {
1502 /* draw in normalized object matrix space */
1503 copy_m4_m4(nobmat, ob->obmat);
1504 normalize_m4(nobmat);
1507 glLoadMatrixf(rv3d->viewmat);
1508 glMultMatrixf(nobmat);
1510 if(cam->flag & CAM_SHOWLIMITS) {
1511 draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
1512 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composit node */
1513 draw_focus_cross(dof_camera(ob), cam->drawsize);
1517 if(cam->flag & CAM_SHOWMIST)
1518 if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF);
1525 /* flag similar to draw_object() */
1526 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d), Object *UNUSED(ob), int UNUSED(flag))
1528 //Speaker *spk = ob->data;
1535 for(j = 0; j < 3; j++) {
1536 vec[2] = 0.25f * j -0.125f;
1538 glBegin(GL_LINE_LOOP);
1539 for(i = 0; i < 16; i++) {
1540 vec[0] = cosf(M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1541 vec[1] = sinf(M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1547 for(j = 0; j < 4; j++) {
1548 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1549 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1550 glBegin(GL_LINE_STRIP);
1551 for(i = 0; i < 3; i++) {
1557 vec[2] = 0.25f * i -0.125f;
1563 glDisable(GL_BLEND);
1566 static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
1568 BPoint *bp = lt->def;
1569 float *co = dl?dl->verts:NULL;
1572 UI_ThemeColor(sel?TH_VERTEX_SELECT:TH_VERTEX);
1573 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1574 bglBegin(GL_POINTS);
1576 for(w=0; w<lt->pntsw; w++) {
1577 int wxt = (w==0 || w==lt->pntsw-1);
1578 for(v=0; v<lt->pntsv; v++) {
1579 int vxt = (v==0 || v==lt->pntsv-1);
1580 for(u=0; u<lt->pntsu; u++, bp++, co+=3) {
1581 int uxt = (u==0 || u==lt->pntsu-1);
1582 if(!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1584 if((bp->f1 & SELECT)==sel) {
1585 bglVertex3fv(dl?co:bp->vec);
1597 void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPoint *bp, int x, int y), void *userData)
1599 Object *obedit= vc->obedit;
1600 Lattice *lt= obedit->data;
1601 BPoint *bp = lt->editlatt->latt->def;
1602 DispList *dl = find_displist(&obedit->disp, DL_VERTS);
1603 float *co = dl?dl->verts:NULL;
1604 int i, N = lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
1605 short s[2] = {IS_CLIPPED, 0};
1607 ED_view3d_local_clipping(vc->rv3d, obedit->obmat); /* for local clipping lookups */
1609 for (i=0; i<N; i++, bp++, co+=3) {
1611 view3d_project_short_clip(vc->ar, dl?co:bp->vec, s, 1);
1612 if (s[0] != IS_CLIPPED)
1613 func(userData, bp, s[0], s[1]);
1618 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
1620 int index = ((w*lt->pntsv + v)*lt->pntsu) + u;
1624 MDeformWeight *mdw= defvert_find_index (lt->dvert+index, use_wcol-1);
1626 weight_to_rgb(mdw?mdw->weight:0.0f, col, col+1, col+2);
1632 glVertex3fv(&dl->verts[index*3]);
1634 glVertex3fv(lt->def[index].vec);
1638 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1639 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1641 Lattice *lt= ob->data;
1644 int use_wcol= 0, is_edit= (lt->editlatt != NULL);
1646 /* now we default make displist, this will modifiers work for non animated case */
1647 if(ob->disp.first==NULL)
1648 lattice_calc_modifiers(scene, ob);
1649 dl= find_displist(&ob->disp, DL_VERTS);
1652 lt= lt->editlatt->latt;
1656 if(ob->defbase.first && lt->dvert) {
1657 use_wcol= ob->actdef;
1658 glShadeModel(GL_SMOOTH);
1663 for(w=0; w<lt->pntsw; w++) {
1664 int wxt = (w==0 || w==lt->pntsw-1);
1665 for(v=0; v<lt->pntsv; v++) {
1666 int vxt = (v==0 || v==lt->pntsv-1);
1667 for(u=0; u<lt->pntsu; u++) {
1668 int uxt = (u==0 || u==lt->pntsu-1);
1670 if(w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
1671 drawlattice__point(lt, dl, u, v, w-1, use_wcol);
1672 drawlattice__point(lt, dl, u, v, w, use_wcol);
1674 if(v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1675 drawlattice__point(lt, dl, u, v-1, w, use_wcol);
1676 drawlattice__point(lt, dl, u, v, w, use_wcol);
1678 if(u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1679 drawlattice__point(lt, dl, u-1, v, w, use_wcol);
1680 drawlattice__point(lt, dl, u, v, w, use_wcol);
1687 /* restoration for weight colors */
1689 glShadeModel(GL_FLAT);
1692 if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
1694 lattice_draw_verts(lt, dl, 0);
1695 lattice_draw_verts(lt, dl, 1);
1697 if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
1701 /* ***************** ******************** */
1703 /* Note! - foreach funcs should be called while drawing or directly after
1704 * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
1705 * but would not give correct results with dupli's for eg. which dont
1706 * use the object matrix in the useual way */
1707 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1709 struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
1710 BMVert *eve = EDBM_get_vert_for_index(data->vc.em, index);
1712 if (!BM_TestHFlag(eve, BM_HIDDEN)) {
1713 short s[2]= {IS_CLIPPED, 0};
1715 if (data->clipVerts) {
1716 view3d_project_short_clip(data->vc.ar, co, s, 1);
1719 mul_v3_m4v3(co2, data->vc.obedit->obmat, co);
1720 project_short_noclip(data->vc.ar, co2, s);
1723 if (s[0]!=IS_CLIPPED)
1724 data->func(data->userData, eve, s[0], s[1], index);
1728 void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BMVert *eve, int x, int y, int index), void *userData, int clipVerts)
1730 struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
1731 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1735 data.userData = userData;
1736 data.clipVerts = clipVerts;
1738 EDBM_init_index_arrays(vc->em, 1, 0, 0);
1740 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1742 dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
1743 EDBM_free_index_arrays(vc->em);
1748 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
1750 struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
1751 BMEdge *eed = EDBM_get_edge_for_index(data->vc.em, index);
1753 if (!BM_TestHFlag(eed, BM_HIDDEN)) {
1756 if (data->clipVerts==1) {
1757 view3d_project_short_clip(data->vc.ar, v0co, s[0], 1);
1758 view3d_project_short_clip(data->vc.ar, v1co, s[1], 1);
1760 float v1_co[3], v2_co[3];
1762 mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co);
1763 mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co);
1765 project_short_noclip(data->vc.ar, v1_co, s[0]);
1766 project_short_noclip(data->vc.ar, v2_co, s[1]);
1768 if (data->clipVerts==2) {
1769 if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<data->vc.ar->winx && s[0][1]<data->vc.ar->winy))
1770 if (!(s[1][0]>=0 && s[1][1]>= 0 && s[1][0]<data->vc.ar->winx && s[1][1]<data->vc.ar->winy))
1775 data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index);
1779 void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
1781 struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
1782 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1786 data.userData = userData;
1787 data.clipVerts = clipVerts;
1789 EDBM_init_index_arrays(vc->em, 0, 1, 0);
1791 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1793 dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
1794 EDBM_free_index_arrays(vc->em);
1799 static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
1801 struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } *data = userData;
1802 BMFace *efa = EDBM_get_face_for_index(data->vc.em, index);
1804 if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) {
1808 mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent);
1809 project_short(data->vc.ar, cent2, s);
1811 if (s[0] != IS_CLIPPED) {
1812 data->func(data->userData, efa, s[0], s[1], index);
1817 void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, BMFace *efa, int x, int y, int index), void *userData)
1819 struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } data;
1820 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1824 data.userData = userData;
1826 EDBM_init_index_arrays(vc->em, 0, 0, 1);
1828 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1830 dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
1831 EDBM_free_index_arrays(vc->em);
1836 void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y), void *userData)
1838 Curve *cu= vc->obedit->data;
1839 short s[2] = {IS_CLIPPED, 0};
1842 ListBase *nurbs= curve_editnurbs(cu);
1844 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1846 for (nu= nurbs->first; nu; nu=nu->next) {
1847 if(nu->type == CU_BEZIER) {
1848 for (i=0; i<nu->pntsu; i++) {
1849 BezTriple *bezt = &nu->bezt[i];
1853 if(cu->drawflag & CU_HIDE_HANDLES) {
1854 view3d_project_short_clip(vc->ar, bezt->vec[1], s, 1);
1855 if (s[0] != IS_CLIPPED)
1856 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
1858 view3d_project_short_clip(vc->ar, bezt->vec[0], s, 1);
1859 if (s[0] != IS_CLIPPED)
1860 func(userData, nu, NULL, bezt, 0, s[0], s[1]);
1861 view3d_project_short_clip(vc->ar, bezt->vec[1], s, 1);
1862 if (s[0] != IS_CLIPPED)
1863 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
1864 view3d_project_short_clip(vc->ar, bezt->vec[2], s, 1);
1865 if (s[0] != IS_CLIPPED)
1866 func(userData, nu, NULL, bezt, 2, s[0], s[1]);
1872 for (i=0; i<nu->pntsu*nu->pntsv; i++) {
1873 BPoint *bp = &nu->bp[i];
1876 view3d_project_short_clip(vc->ar, bp->vec, s, 1);
1877 if (s[0] != IS_CLIPPED)
1878 func(userData, nu, bp, NULL, -1, s[0], s[1]);
1885 /* ************** DRAW MESH ****************** */
1887 /* First section is all the "simple" draw routines,
1888 * ones that just pass some sort of primitive to GL,
1889 * with perhaps various options to control lighting,
1892 * These routines should not have user interface related
1896 static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
1898 Scene *scene= ((void **)userData)[0];
1899 BMEditMesh *em = ((void **)userData)[1];
1900 BMFace *efa = EDBM_get_face_for_index(em, index);
1901 ToolSettings *ts= scene->toolsettings;
1903 if (!BM_TestHFlag(efa, BM_HIDDEN)) {
1905 glVertex3f( cent[0] + no[0]*ts->normalsize,
1906 cent[1] + no[1]*ts->normalsize,
1907 cent[2] + no[2]*ts->normalsize);
1910 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
1912 void *ptrs[2] = {scene, em};
1915 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, ptrs);
1919 static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
1921 BMFace *efa = EDBM_get_face_for_index(((void **)userData)[0], index);
1922 int sel = *(((int **)userData)[1]);
1924 if (efa && !BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)==sel) {
1928 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel)
1930 void *ptrs[2] = {em, &sel};
1932 bglBegin(GL_POINTS);
1933 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs);
1937 static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
1939 Scene *scene= ((void **)userData)[0];
1940 ToolSettings *ts= scene->toolsettings;
1941 BMEditMesh *em = ((void **)userData)[1];
1942 BMVert *eve = EDBM_get_vert_for_index(em, index);
1944 if (!BM_TestHFlag(eve, BM_HIDDEN)) {
1948 glVertex3f( co[0] + no_f[0]*ts->normalsize,
1949 co[1] + no_f[1]*ts->normalsize,
1950 co[2] + no_f[2]*ts->normalsize);
1952 glVertex3f( co[0] + no_s[0]*ts->normalsize/32767.0f,
1953 co[1] + no_s[1]*ts->normalsize/32767.0f,
1954 co[2] + no_s[2]*ts->normalsize/32767.0f);
1958 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
1960 void *ptrs[2] = {scene, em};
1963 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, ptrs);
1967 /* Draw verts with color set based on selection */
1968 static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1970 struct { BMEditMesh *em; int sel; BMVert *eve_act; } *data = userData;
1971 BMVert *eve = EDBM_get_vert_for_index(data->em, index);
1973 if (!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)==data->sel) {
1974 /* draw active larger - need to stop/start point drawing for this :/ */
1975 if (eve==data->eve_act) {
1976 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
1977 UI_ThemeColor4(TH_EDITMESH_ACTIVE);
1982 bglBegin(GL_POINTS);
1986 UI_ThemeColor4(data->sel?TH_VERTEX_SELECT:TH_VERTEX);
1988 bglBegin(GL_POINTS);
1995 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act)
1997 struct { BMEditMesh *em; int sel; BMVert *eve_act; } data;
1999 data.eve_act = eve_act;
2002 bglBegin(GL_POINTS);
2003 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
2006 bglBegin(GL_POINTS);
2007 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
2011 /* Draw edges with color set based on selection */
2012 static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2015 //unsigned char **cols = userData, *col;
2016 struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } * data = userData;
2019 eed = EDBM_get_edge_for_index(data->em, index);
2021 if (!BM_TestHFlag(eed, BM_HIDDEN)) {
2022 if (eed==data->eed_act) {
2023 glColor4ubv(data->actCol);
2025 if (BM_TestHFlag(eed, BM_SELECT)) {
2028 col = data->baseCol;
2030 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2031 if (col[3]==0) return 0;
2040 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2041 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2043 struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } data;
2045 data.baseCol = baseCol;
2046 data.selCol = selCol;
2047 data.actCol = actCol;
2049 data.eed_act = eed_act;
2050 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2054 static int draw_dm_edges__setDrawOptions(void *userData, int index)
2056 return !BM_TestHFlag(EDBM_get_edge_for_index(userData, index), BM_HIDDEN);
2058 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2060 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
2063 /* Draw edges with color interpolated based on selection */
2064 static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2066 return !BM_TestHFlag(EDBM_get_edge_for_index(((void**)userData)[0], index), BM_HIDDEN);
2068 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2070 BMEdge *eed = EDBM_get_edge_for_index(((void**)userData)[0], index);
2071 unsigned char **cols = userData;
2072 unsigned char *col0 = cols[(BM_TestHFlag(eed->v1, BM_SELECT))?2:1];
2073 unsigned char *col1 = cols[(BM_TestHFlag(eed->v2, BM_SELECT))?2:1];
2075 glColor4ub( col0[0] + (col1[0]-col0[0])*t,
2076 col0[1] + (col1[1]-col0[1])*t,
2077 col0[2] + (col1[2]-col0[2])*t,
2078 col0[3] + (col1[3]-col0[3])*t);
2081 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2083 void *cols[3] = {em, baseCol, selCol};
2085 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2088 /* Draw only seam edges */
2089 static int draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2091 BMEdge *eed = EDBM_get_edge_for_index(userData, index);
2093 return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SEAM);
2096 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2098 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
2101 /* Draw only sharp edges */
2102 static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2104 BMEdge *eed = EDBM_get_edge_for_index(userData, index);
2106 return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SHARP);
2108 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2110 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
2114 /* Draw faces with color set based on selection
2115 * return 2 for the active face so it renders with stipple enabled */
2116 static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r))
2118 struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} *data = userData;
2119 BMFace *efa = EDBM_get_face_for_index(data->em, index);
2125 if (!BM_TestHFlag(efa, BM_HIDDEN)) {
2126 if (efa == data->efa_act) {
2127 glColor4ubv(data->cols[2]);
2129 return 2; /* stipple */
2131 col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0];
2132 if (col[3]==0) return 0;
2142 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2144 struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} * data = userData;
2145 BMFace *efa = EDBM_get_face_for_index(data->em, index);
2146 BMFace *next_efa = EDBM_get_face_for_index(data->em, next_index);
2147 unsigned char *col, *next_col;
2152 if(efa == data->efa_act || next_efa == data->efa_act)
2155 col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0];
2156 next_col = data->cols[BM_TestHFlag(next_efa, BM_SELECT)?1:0];
2158 if(col[3]==0 || next_col[3]==0)
2161 return col == next_col;
2164 /* also draws the active face */
2165 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2166 unsigned char *selCol, unsigned char *actCol, BMFace *efa_act, Mesh *me)
2168 struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} data;
2170 data.cols[0] = baseCol;
2172 data.cols[1] = selCol;
2173 data.cols[2] = actCol;
2174 data.efa_act = efa_act;
2177 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions);
2180 static int draw_dm_creases__setDrawOptions(void *userData, int index)
2182 BMEditMesh *em = userData;
2183 BMEdge *eed = EDBM_get_edge_for_index(userData, index);
2184 float *crease = eed ? bm_get_cd_float(&em->bm->edata, eed->head.data, CD_CREASE) : NULL;
2189 if (!BM_TestHFlag(eed, BM_HIDDEN) && *crease!=0.0f) {
2190 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, *crease);
2196 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
2199 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em);
2203 static int draw_dm_bweights__setDrawOptions(void *userData, int index)
2205 BMEditMesh *em = userData;
2206 BMEdge *eed = EDBM_get_edge_for_index(userData, index);
2207 float *bweight = bm_get_cd_float(&em->bm->edata, eed->head.data, CD_BWEIGHT);
2212 if (!BM_TestHFlag(eed, BM_HIDDEN) && *bweight!=0.0f) {
2213 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, *bweight);
2219 static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
2221 BMEditMesh *em = userData;
2222 BMVert *eve = EDBM_get_vert_for_index(userData, index);
2223 float *bweight = bm_get_cd_float(&em->bm->vdata, eve->head.data, CD_BWEIGHT);
2228 if (!BM_TestHFlag(eve, BM_HIDDEN) && *bweight!=0.0f) {
2229 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, *bweight);
2233 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2235 ToolSettings *ts= scene->toolsettings;
2237 if (ts->selectmode & SCE_SELECT_VERTEX) {
2238 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2239 bglBegin(GL_POINTS);
2240 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em);
2245 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em);
2250 /* Second section of routines: Combine first sets to form fancy
2251 * drawing routines (for example rendering twice to get overlays).
2253 * Also includes routines that are basic drawing but are too
2254 * specialized to be split out (like drawing creases or measurements).
2257 /* EditMesh drawing routines*/
2259 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
2260 BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act)
2262 ToolSettings *ts= scene->toolsettings;
2265 if(v3d->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select
2267 for (sel=0; sel<2; sel++) {
2268 unsigned char col[4], fcol[4];
2271 UI_GetThemeColor3ubv(sel?TH_VERTEX_SELECT:TH_VERTEX, col);
2272 UI_GetThemeColor3ubv(sel?TH_FACE_DOT:TH_WIRE, fcol);
2274 for (pass=0; pass<2; pass++) {
2275 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2276 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2279 if(v3d->zbuf && !(v3d->flag&V3D_ZBUF_SELECT)) {
2280 glDisable(GL_DEPTH_TEST);
2287 size = (size > 2.1f ? size/2.0f:size);
2288 fsize = (fsize > 2.1f ? fsize/2.0f:fsize);
2289 col[3] = fcol[3] = 100;
2291 col[3] = fcol[3] = 255;
2294 if(ts->selectmode & SCE_SELECT_VERTEX) {
2297 draw_dm_verts(em, cageDM, sel, eve_act);
2300 if(check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2303 draw_dm_face_centers(em, cageDM, sel);
2307 glDisable(GL_BLEND);
2308 glEnable(GL_DEPTH_TEST);
2313 if(v3d->zbuf) glDepthMask(1);
2317 static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
2318 Mesh *me, DerivedMesh *cageDM, short sel_only,
2321 ToolSettings *ts= scene->toolsettings;
2323 unsigned char wireCol[4], selCol[4], actCol[4];
2325 /* since this function does transparant... */
2326 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2327 UI_GetThemeColor4ubv(TH_WIRE, wireCol);
2328 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2330 /* when sel only is used, dont render wire, only selected, this is used for
2331 * textured draw mode when the 'edges' option is disabled */
2335 for (pass=0; pass<2; pass++) {
2336 /* show wires in transparant when no zbuf clipping for select */
2338 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0) {
2340 glDisable(GL_DEPTH_TEST);
2342 if (!sel_only) wireCol[3] = 85;
2348 if (!sel_only) wireCol[3] = 255;
2351 if(ts->selectmode == SCE_SELECT_FACE) {
2352 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2354 else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
2355 if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2356 glShadeModel(GL_SMOOTH);
2357 draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
2358 glShadeModel(GL_FLAT);
2360 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2365 glColor4ubv(wireCol);
2366 draw_dm_edges(em, cageDM);
2371 glDisable(GL_BLEND);
2372 glEnable(GL_DEPTH_TEST);
2377 static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d,
2378 Object *ob, BMEditMesh *em, UnitSettings *unit)
2381 float v1[3], v2[3], v3[3], vmid[3], fvec[3];
2382 char val[32]; /* Stores the measurement display text here */
2383 const char *conv_float; /* Use a float conversion matching the grid size */
2384 unsigned char col[4]= {0, 0, 0, 255}; /* color of the text to draw */
2385 float area; /* area of the face */
2386 float grid= unit->system ? unit->scale_length : v3d->grid;
2387 const int do_split= unit->flag & USER_UNIT_OPT_SPLIT;
2388 const int do_global= v3d->flag & V3D_GLOBAL_STATS;
2389 const int do_moving= G.moving;
2394 /* make the precision of the pronted value proportionate to the gridsize */
2396 if (grid < 0.01f) conv_float= "%.6g";
2397 else if (grid < 0.1f) conv_float= "%.5g";
2398 else if (grid < 1.0f) conv_float= "%.4g";
2399 else if (grid < 10.0f) conv_float= "%.3g";
2400 else conv_float= "%.2g";
2402 if(v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0)
2403 glDisable(GL_DEPTH_TEST);
2405 if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0f);
2407 if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2410 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2412 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
2413 for(; eed; eed=BMIter_Step(&iter)) {
2414 /* draw selected edges, or edges next to selected verts while draging */
2415 if(BM_TestHFlag(eed, BM_SELECT) ||
2416 (do_moving && (BM_TestHFlag(eed->v1, BM_SELECT) || BM_TestHFlag(eed->v2, BM_SELECT) ))) {
2418 copy_v3_v3(v1, eed->v1->co);
2419 copy_v3_v3(v2, eed->v2->co);
2421 interp_v3_v3v3(vmid, v1, v2, 0.5f);
2424 mul_mat3_m4_v3(ob->obmat, v1);
2425 mul_mat3_m4_v3(ob->obmat, v2);
2428 bUnit_AsString(val, sizeof(val), len_v3v3(v1, v2)*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE);
2430 sprintf(val, conv_float, len_v3v3(v1, v2));
2432 view3d_cached_text_draw_add(vmid, val, 0, V3D_CACHE_TEXT_ASCII, col);
2437 if(me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2438 /* would be nice to use BM_face_area, but that is for 2d faces
2439 so instead add up tessalation triangle areas */
2443 #define DRAW_EM_MEASURE_STATS_FACEAREA(void)\
2444 if (BM_TestHFlag(f, BM_SELECT)) {\
2445 mul_v3_fl(vmid, 1.0/n);\
2447 bUnit_AsString(val, sizeof(val), area*unit->scale_length,\
2448 3, unit->system, B_UNIT_LENGTH, do_split, FALSE);\
2450 sprintf(val, conv_float, area);\
2451 view3d_cached_text_draw_add(vmid, val, 0, V3D_CACHE_TEXT_ASCII, col);\
2454 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2460 for(i = 0; i < em->tottri; i++) {
2461 BMLoop **l = em->looptris[i];
2462 if(f && l[0]->f != f) {
2463 DRAW_EM_MEASURE_STATS_FACEAREA();
2470 copy_v3_v3(v1, l[0]->v->co);
2471 copy_v3_v3(v2, l[1]->v->co);
2472 copy_v3_v3(v3, l[2]->v->co);
2474 mul_mat3_m4_v3(ob->obmat, v1);
2475 mul_mat3_m4_v3(ob->obmat, v2);
2476 mul_mat3_m4_v3(ob->obmat, v3);
2478 area += area_tri_v3(v1, v2, v3);
2479 add_v3_v3(vmid, v1);
2480 add_v3_v3(vmid, v2);
2481 add_v3_v3(vmid, v3);
2486 DRAW_EM_MEASURE_STATS_FACEAREA();
2488 #undef DRAW_EM_MEASURE_STATS_FACEAREA
2491 if(me->drawflag & ME_DRAWEXTRA_FACEANG) {
2494 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2497 for(efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
2498 efa; efa=BMIter_Step(&iter)) {
2502 BM_Compute_Face_Center(em->bm, efa, vmid);
2504 for(loop = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
2505 loop; loop = BMIter_Step(&liter)) {
2507 float v1[3], v2[3], v3[3];
2509 copy_v3_v3(v1, loop->prev->v->co);
2510 copy_v3_v3(v2, loop->v->co);
2511 copy_v3_v3(v3, loop->next->v->co);
2514 mul_mat3_m4_v3(ob->obmat, v1);
2515 mul_mat3_m4_v3(ob->obmat, v2);
2516 mul_mat3_m4_v3(ob->obmat, v3);
2519 if(BM_TestHFlag(efa, BM_SELECT) ||
2520 (do_moving && BM_TestHFlag(loop->v, BM_SELECT))){
2521 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
2522 interp_v3_v3v3(fvec, vmid, v2, 0.8f);
2523 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2529 /* useful for debugging index vs shape key index */
2536 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2538 if(CustomData_has_layer(&em->bm->vdata, CD_SHAPE_KEYINDEX)) {
2540 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2541 keyi = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
2542 if(keyi && *keyi != ORIGINDEX_NONE) {
2543 sprintf(val, "%d:%d", j, *keyi);
2546 sprintf(val, "%d", j);
2548 view3d_cached_text_draw_add(eve->co, val, 0, V3D_CACHE_TEXT_ASCII, col);
2553 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2554 sprintf(val, "%d", j);
2555 view3d_cached_text_draw_add(eve->co, val, 0, V3D_CACHE_TEXT_ASCII, col);
2563 glEnable(GL_DEPTH_TEST);
2564 bglPolygonOffset(rv3d->dist, 0.0f);
2568 static int draw_em_fancy__setFaceOpts(void *userData, int index, int *UNUSED(drawSmooth_r))
2570 BMFace *efa = EDBM_get_face_for_index(userData, index);
2572 if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) {
2573 GPU_enable_material(efa->mat_nr+1, NULL);
2580 static int draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
2582 BMFace *efa = EDBM_get_face_for_index(userData, index);
2584 return !BM_TestHFlag(efa, BM_HIDDEN);
2587 static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob,
2588 BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
2591 Mesh *me = ob->data;
2592 BMFace *efa_act = BM_get_actFace(em->bm, 0); /* annoying but active faces is stored differently */
2593 BMEdge *eed_act = NULL;
2594 BMVert *eve_act = NULL;
2596 if (em->bm->selected.last) {
2597 BMEditSelection *ese = em->bm->selected.last;
2598 /* face is handeled above */
2599 /*if (ese->type == BM_FACE ) {
2600 efa_act = (BMFace *)ese->data;
2601 } else */ if ( ese->type == BM_EDGE ) {
2602 eed_act = (BMEdge *)ese->data;
2603 } else if ( ese->type == BM_VERT ) {
2604 eve_act = (BMVert *)ese->data;
2608 EDBM_init_index_arrays(em, 1, 1, 1);
2611 if(CHECK_OB_DRAWTEXTURE(v3d, dt)) {
2612 if(draw_glsl_material(scene, ob, v3d, dt)) {
2613 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2615 finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
2616 draw_em_fancy__setGLSLFaceOpts, em);
2617 GPU_disable_material();
2619 glFrontFace(GL_CCW);
2622 draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
2626 /* 3 floats for position, 3 for normal and times two because the faces may actually be quads instead of triangles */
2627 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED);
2629 glEnable(GL_LIGHTING);
2630 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2631 finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, me->edit_btmesh, 0, GPU_enable_material, NULL);
2633 glFrontFace(GL_CCW);
2634 glDisable(GL_LIGHTING);
2637 // Setup for drawing wire over, disable zbuffer
2638 // write to show selected edge wires better
2639 UI_ThemeColor(TH_WIRE);
2641 bglPolygonOffset(rv3d->dist, 1.0);
2645 if (cageDM!=finalDM) {
2646 UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
2647 finalDM->drawEdges(finalDM, 1, 0);
2651 if(me->drawflag & ME_DRAWFACES) { /* transp faces */
2652 unsigned char col1[4], col2[4], col3[4];
2654 UI_GetThemeColor4ubv(TH_FACE, col1);
2655 UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
2656 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
2659 glDepthMask(0); // disable write in zbuffer, needed for nice transp
2661 /* dont draw unselected faces, only selected, this is MUCH nicer when texturing */
2662 if CHECK_OB_DRAWTEXTURE(v3d, dt)
2665 draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me);
2667 glDisable(GL_BLEND);
2668 glDepthMask(1); // restore write in zbuffer
2669 } else if (efa_act) {
2670 /* even if draw faces is off it would be nice to draw the stipple face
2671 * Make all other faces zero alpha except for the active
2673 unsigned char col1[4], col2[4], col3[4];
2674 col1[3] = col2[3] = 0; /* dont draw */
2675 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
2678 glDepthMask(0); // disable write in zbuffer, needed for nice transp
2680 draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me);
2682 glDisable(GL_BLEND);
2683 glDepthMask(1); // restore write in zbuffer
2687 /* here starts all fancy draw-extra over */
2688 if((me->drawflag & ME_DRAWEDGES)==0 && CHECK_OB_DRAWTEXTURE(v3d, dt)) {
2689 /* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */
2691 /* only draw selected edges otherwise there is no way of telling if a face is selected */
2692 draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
2695 if(me->drawflag & ME_DRAWSEAMS) {
2696 UI_ThemeColor(TH_EDGE_SEAM);
2699 draw_dm_edges_seams(em, cageDM);
2705 if(me->drawflag & ME_DRAWSHARP) {
2706 UI_ThemeColor(TH_EDGE_SHARP);
2709 draw_dm_edges_sharp(em, cageDM);
2715 if(me->drawflag & ME_DRAWCREASES && CustomData_has_layer(&em->bm->edata, CD_CREASE)) {
2716 draw_dm_creases(em, cageDM);
2718 if(me->drawflag & ME_DRAWBWEIGHTS) {
2719 draw_dm_bweights(em, scene, cageDM);
2722 draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
2725 // XXX retopo_matrix_update(v3d);
2727 draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act);
2729 if(me->drawflag & ME_DRAWNORMALS) {
2730 UI_ThemeColor(TH_NORMAL);
2731 draw_dm_face_normals(em, scene, cageDM);
2733 if(me->drawflag & ME_DRAW_VNORMALS) {
2734 UI_ThemeColor(TH_VNORMAL);
2735 draw_dm_vert_normals(em, scene, cageDM);
2738 if(me->drawflag & (ME_DRAWEXTRA_EDGELEN|ME_DRAWEXTRA_FACEAREA|ME_DRAWEXTRA_FACEANG) && !((v3d->flag2 & V3D_RENDER_OVERRIDE)))
2739 draw_em_measure_stats(v3d, rv3d, ob, em, &scene->unit);
2744 bglPolygonOffset(rv3d->dist, 0.0);
2745 GPU_disable_material();
2748 EDBM_free_index_arrays(em);
2751 /* Mesh drawing routines */
2753 static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
2756 if(v3d->transp==0) { // not when we draw the transparent pass
2757 glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
2760 /* if transparent, we cannot draw the edges for solid select... edges have no material info.
2761 drawFacesSolid() doesn't draw the transparent faces */
2762 if(ob->dtx & OB_DRAWTRANSP) {
2763 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2764 dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
2765 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2766 GPU_disable_material();
2769 dm->drawEdges(dm, 0, 1);
2777 static int wpaint__setSolidDrawOptions(void *UNUSED(userData), int UNUSED(index), int *drawSmooth_r)
2783 static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
2785 Object *ob= base->object;
2786 Mesh *me = ob->data;
2787 Material *ma= give_current_material(ob, 1);
2788 const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO));
2789 const short is_paint_sel= (ob==OBACT && paint_facesel_test(ob));
2791 int /* totvert,*/ totedge, totface;
2792 DerivedMesh *dm= mesh_get_derived_final(scene, ob, scene->customdata_mask);
2797 if (ob->dtx&OB_DRAWWIRE) {
2798 draw_wire = 2; /* draw wire after solid using zoffset and depth buffer adjusment */
2801 /* totvert = dm->getNumVerts(dm); */ /*UNUSED*/
2802 totedge = dm->getNumEdges(dm);
2803 totface = dm->getNumTessFaces(dm);
2805 /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
2807 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2809 // Unwanted combination.
2810 if (is_paint_sel) draw_wire = 0;
2812 if(dt==OB_BOUNDBOX) {
2813 if((v3d->flag2 & V3D_RENDER_OVERRIDE && v3d->drawtype >= OB_WIRE)==0)
2814 draw_bounding_volume(scene, ob);
2816 else if(hasHaloMat || (totface==0 && totedge==0)) {
2821 else if(dt==OB_WIRE || totface==0) {
2822 draw_wire = 1; /* draw wire only, no depth buffer stuff */
2824 else if( (is_paint_sel || (ob==OBACT && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
2825 CHECK_OB_DRAWTEXTURE(v3d, dt))
2827 if ((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !(G.f&G_PICKSEL || is_paint_sel) && !draw_wire) {
2828 draw_mesh_object_outline(v3d, ob, dm);
2831 if(draw_glsl_material(scene, ob, v3d, dt)) {
2832 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2834 dm->drawFacesGLSL(dm, GPU_enable_material);
2835 // if(get_ob_property(ob, "Text"))
2836 // XXX draw_mesh_text(ob, 1);
2837 GPU_disable_material();
2839 glFrontFace(GL_CCW);
2842 draw_mesh_textured(scene, v3d, rv3d, ob, dm, is_paint_sel);
2846 if(base->flag & SELECT)
2847 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2849 UI_ThemeColor(TH_WIRE);
2851 if((v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
2852 dm->drawLooseEdges(dm);
2855 else if(dt==OB_SOLID) {
2856 if(ob==OBACT && ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
2857 /* weight paint in solid mode, special case. focus on making the weights clear
2858 * rather than the shading, this is also forced in wire view */
2859 GPU_enable_material(0, NULL);
2860 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material, NULL);
2862 bglPolygonOffset(rv3d->dist, 1.0);
2863 glDepthMask(0); // disable write in zbuffer, selected edge wires show better
2866 glColor4ub(255, 255, 255, 96);
2867 glEnable(GL_LINE_STIPPLE);
2868 glLineStipple(1, 0xAAAA);
2870 dm->drawEdges(dm, 1, 1);
2872 bglPolygonOffset(rv3d->dist, 0.0);
2874 glDisable(GL_LINE_STIPPLE);
2876 GPU_disable_material();
2878 /* since we already draw wire as wp guide, dont draw over the top */
2884 if((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !draw_wire && !ob->sculpt)
2885 draw_mesh_object_outline(v3d, ob, dm);
2887 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
2889 glEnable(GL_LIGHTING);
2890 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2892 if(ob->sculpt && (p=paint_get_active(scene))) {
2894 float (*fpl)[4] = NULL;
2895 int fast= (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
2897 if(ob->sculpt->partial_redraw) {
2898 if(ar->do_draw & RGN_DRAW_PARTIAL) {
2899 sculpt_get_redraw_planes(planes, ar, rv3d, ob);
2901 ob->sculpt->partial_redraw = 0;
2905 dm->drawFacesSolid(dm, fpl, fast, GPU_enable_material);
2908 dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
2910 GPU_disable_material();
2912 glFrontFace(GL_CCW);
2913 glDisable(GL_LIGHTING);
2915 if(base->flag & SELECT) {
2916 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2918 UI_ThemeColor(TH_WIRE);
2920 if(!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
2921 dm->drawLooseEdges(dm);
2924 else if(dt==OB_SHADED) {
2926 if(ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
2927 /* enforce default material settings */
2928 GPU_enable_material(0, NULL);
2930 /* but set default spec */
2931 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
2932 glEnable(GL_COLOR_MATERIAL); /* according manpages needed */
2933 glColor3ub(120, 120, 120);
2934 glDisable(GL_COLOR_MATERIAL);
2936 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
2937 glEnable(GL_LIGHTING);
2938 glEnable(GL_COLOR_MATERIAL);
2940 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material, NULL);
2941 glDisable(GL_COLOR_MATERIAL);
2942 glDisable(GL_LIGHTING);
2944 GPU_disable_material();
2946 else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) {
2948 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1, GPU_enable_material, NULL);
2950 glColor3f(1.0f, 1.0f, 1.0f);
2951 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0, GPU_enable_material, NULL);
2957 /* set default draw color back for wire or for draw-extra later on */
2959 if(base->flag & SELECT) {
2960 if(ob==OBACT && ob->flag & OB_FROMGROUP)
2961 UI_ThemeColor(TH_GROUP_ACTIVE);
2962 else if(ob->flag & OB_FROMGROUP)
2963 UI_ThemeColorShade(TH_GROUP_ACTIVE, -16);
2964 else if(flag!=DRAW_CONSTCOLOR)
2965 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2967 glColor3ub(80,80,80);
2969 if (ob->flag & OB_FROMGROUP)
2970 UI_ThemeColor(TH_GROUP);
2972 if(ob->dtx & OB_DRAWWIRE && flag==DRAW_CONSTCOLOR)
2973 glColor3ub(80,80,80);
2975 UI_ThemeColor(TH_WIRE);
2981 /* When using wireframe object traw in particle edit mode
2982 * the mesh gets in the way of seeing the particles, fade the wire color
2983 * with the background. */
2984 if(ob==OBACT && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
2985 float col_wire[4], col_bg[4], col[3];
2987 UI_GetThemeColor3fv(TH_BACK, col_bg);
2988 glGetFloatv(GL_CURRENT_COLOR, col_wire);
2989 interp_v3_v3v3(col, col_bg, col_wire, 0.15);
2993 /* If drawing wire and drawtype is not OB_WIRE then we are
2994 * overlaying the wires.
2996 * UPDATE bug #10290 - With this wire-only objects can draw
2997 * behind other objects depending on their order in the scene. 2x if 0's below. undo'ing zr's commit: r4059
2999 * if draw wire is 1 then just drawing wire, no need for depth buffer stuff,
3000 * otherwise this wire is to overlay solid mode faces so do some depth buffer tricks.
3002 if (dt!=OB_WIRE && draw_wire==2) {
3003 bglPolygonOffset(rv3d->dist, 1.0);
3004 glDepthMask(0); // disable write in zbuffer, selected edge wires show better
3007 if((v3d->flag2 & V3D_RENDER_OVERRIDE && v3d->drawtype >= OB_SOLID)==0)
3008 dm->drawEdges(dm, (dt==OB_WIRE || totface==0), me->drawflag & ME_ALLEDGES);
3010 if (dt!=OB_WIRE && draw_wire==2) {
3012 bglPolygonOffset(rv3d->dist, 0.0);
3019 /* returns 1 if nothing was drawn, for detecting to draw an object center */
3020 static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
3022 Object *ob= base->object;
3023 Object *obedit= scene->obedit;
3025 BMEditMesh *em= me->edit_btmesh;
3026 int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha, i;
3028 /* If we are drawing shadows and any of the materials don't cast a shadow,
3029 * then don't draw the object */
3030 if (v3d->flag2 & V3D_RENDER_SHADOW) {
3031 for(i=0; i<ob->totcol; ++i) {
3032 Material *ma= give_current_material(ob, i);
3033 if (ma && !(ma->mode & MA_SHADBUF)) {
3039 if(obedit && ob!=obedit && ob->data==obedit->data) {
3040 if(ob_get_key(ob) || ob_get_key(obedit));
3041 else if(ob->modifiers.first || obedit->modifiers.first);