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_world_types.h"
49 #include "DNA_armature_types.h"
51 #include "BLI_blenlib.h"
53 #include "BLI_editVert.h"
54 #include "BLI_edgehash.h"
56 #include "BLI_utildefines.h"
58 #include "BKE_anim.h" //for the where_on_path function
59 #include "BKE_constraint.h" // for the get_constraint_target function
60 #include "BKE_DerivedMesh.h"
61 #include "BKE_deform.h"
62 #include "BKE_displist.h"
64 #include "BKE_global.h"
65 #include "BKE_image.h"
67 #include "BKE_lattice.h"
69 #include "BKE_material.h"
70 #include "BKE_mball.h"
71 #include "BKE_modifier.h"
72 #include "BKE_object.h"
73 #include "BKE_paint.h"
74 #include "BKE_particle.h"
75 #include "BKE_pointcache.h"
78 #include "smoke_API.h"
80 #include "IMB_imbuf.h"
81 #include "IMB_imbuf_types.h"
84 #include "BIF_glutil.h"
87 #include "GPU_extensions.h"
90 #include "ED_particle.h"
91 #include "ED_screen.h"
92 #include "ED_sculpt.h"
94 #include "ED_curve.h" /* for ED_curve_editnurbs */
96 #include "UI_resources.h"
99 #include "wm_subwindow.h"
102 #include "view3d_intern.h" // own include
105 /* this condition has been made more complex since editmode can draw textures */
106 #define CHECK_OB_DRAWTEXTURE(vd, dt) \
107 ((vd->drawtype==OB_TEXTURE && dt>OB_SOLID) || \
108 (vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX))
110 static void draw_bounding_volume(Scene *scene, Object *ob);
112 static void drawcube_size(float size);
113 static void drawcircle_size(float size);
114 static void draw_empty_sphere(float size);
115 static void draw_empty_cone(float size);
117 static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
119 if((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
122 if(G.f & G_BACKBUFSEL)
125 if((vd->flag & V3D_ZBUF_SELECT) == 0)
128 /* if its drawing textures with zbuf sel, then dont draw dots */
129 if(dt==OB_TEXTURE && vd->drawtype==OB_TEXTURE)
132 if(vd->drawtype>=OB_SOLID && vd->flag2 & V3D_SOLID_TEX)
138 /* ************* only use while object drawing **************
139 * or after running ED_view3d_init_mats_rv3d
141 static void view3d_project_short_clip(ARegion *ar, float *vec, short *adr, int local)
143 RegionView3D *rv3d= ar->regiondata;
144 float fx, fy, vec4[4];
148 /* clipplanes in eye space */
149 if(rv3d->rflag & RV3D_CLIPPING) {
150 if(ED_view3d_test_clipping(rv3d, vec, local))
154 copy_v3_v3(vec4, vec);
157 mul_m4_v4(rv3d->persmatob, vec4);
159 /* clipplanes in window space */
160 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
161 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
163 if( fx>0 && fx<ar->winx) {
165 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
167 if(fy > 0.0f && fy < (float)ar->winy) {
168 adr[0]= (short)floorf(fx);
169 adr[1]= (short)floorf(fy);
175 /* only use while object drawing */
176 static void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr)
178 RegionView3D *rv3d= ar->regiondata;
179 float fx, fy, vec4[4];
183 copy_v3_v3(vec4, vec);
186 mul_m4_v4(rv3d->persmatob, vec4);
188 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
189 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
191 if( fx>-32700 && fx<32700) {
193 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
195 if(fy > -32700.0f && fy < 32700.0f) {
196 adr[0]= (short)floorf(fx);
197 adr[1]= (short)floorf(fy);
203 /* ************************ */
205 /* check for glsl drawing */
207 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
209 if(!GPU_glsl_support())
213 if(!CHECK_OB_DRAWTEXTURE(v3d, dt))
215 if(ob==OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
218 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
221 static int check_material_alpha(Base *base, Mesh *me, int glsl)
223 if(base->flag & OB_FROMDUPLI)
232 return (glsl || (base->object->dtx & OB_DRAWTRANSP));
236 static unsigned int colortab[24]=
237 {0x0, 0xFF88FF, 0xFFBBFF,
238 0x403000, 0xFFFF88, 0xFFFFBB,
239 0x104040, 0x66CCCC, 0x77CCCC,
240 0x104010, 0x55BB55, 0x66FF66,
245 static float cube[8][3] = {
256 /* ----------------- OpenGL Circle Drawing - Tables for Optimised Drawing Speed ------------------ */
257 /* 32 values of sin function (still same result!) */
258 static float sinval[32] = {
293 /* 32 values of cos function (still same result!) */
294 static float cosval[32] ={
329 static void draw_xyz_wire(const float c[3], float size, int axis)
331 float v1[3]= {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
332 float dim = size * 0.1f;
333 float dx[3], dy[3], dz[3];
335 dx[0]=dim; dx[1]=0.f; dx[2]=0.f;
336 dy[0]=0.f; dy[1]=dim; dy[2]=0.f;
337 dz[0]=0.f; dz[1]=0.f; dz[2]=dim;
343 /* bottom left to top right */
344 sub_v3_v3v3(v1, c, dx);
346 add_v3_v3v3(v2, c, dx);
352 /* top left to bottom right */
365 /* bottom left to top right */
366 mul_v3_fl(dx, 0.75f);
367 sub_v3_v3v3(v1, c, dx);
369 add_v3_v3v3(v2, c, dx);
375 /* top left to center */
386 glBegin(GL_LINE_STRIP);
388 /* start at top left */
389 sub_v3_v3v3(v1, c, dx);
390 add_v3_v3v3(v1, c, dz);
415 void drawaxes(float size, char drawtype)
418 float v1[3]= {0.0, 0.0, 0.0};
419 float v2[3]= {0.0, 0.0, 0.0};
420 float v3[3]= {0.0, 0.0, 0.0};
425 for (axis=0; axis<3; axis++) {
433 /* reset v1 & v2 to zero */
434 v1[axis]= v2[axis]= 0.0f;
439 case OB_SINGLE_ARROW:
442 /* in positive z direction only */
449 glBegin(GL_TRIANGLES);
451 v2[0]= size * 0.035f; v2[1] = size * 0.035f;
452 v3[0]= size * -0.035f; v3[1] = size * 0.035f;
453 v2[2]= v3[2]= size * 0.75f;
455 for (axis=0; axis<4; axis++) {
477 drawcircle_size(size);
480 case OB_EMPTY_SPHERE:
481 draw_empty_sphere(size);
485 draw_empty_cone(size);
490 for (axis=0; axis<3; axis++) {
491 const int arrow_axis= (axis==0) ? 1:0;
499 v1[axis]= size*0.85f;
500 v1[arrow_axis]= -size*0.08f;
504 v1[arrow_axis]= size*0.08f;
510 v2[axis]+= size*0.125f;
512 draw_xyz_wire(v2, size, axis);
515 /* reset v1 & v2 to zero */
516 v1[arrow_axis]= v1[axis]= v2[axis]= 0.0f;
523 /* Function to draw an Image on a empty Object */
524 static void draw_empty_image(Object *ob)
526 Image *ima = (Image*)ob->data;
527 ImBuf *ibuf = ima ? BKE_image_get_ibuf(ima, NULL) : NULL;
529 float scale, ofs_x, ofs_y, sca_x, sca_y;
532 if(ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
533 IMB_rect_from_float(ibuf);
536 /* Get the buffer dimensions so we can fallback to fake ones */
537 if(ibuf && ibuf->rect) {
546 /* Get the image aspect even if the buffer is invalid */
548 if(ima->aspx > ima->aspy) {
550 sca_y= ima->aspy / ima->aspx;
552 else if(ima->aspx < ima->aspy) {
553 sca_x= ima->aspx / ima->aspy;
566 /* Calculate the scale center based on objects origin */
567 ofs_x= ob->ima_ofs[0] * ima_x;
568 ofs_y= ob->ima_ofs[1] * ima_y;
570 glMatrixMode(GL_MODELVIEW);
573 /* Make sure we are drawing at the origin */
574 glTranslatef(0.0f, 0.0f, 0.0f);
576 /* Calculate Image scale */
577 scale= (ob->empty_drawsize / (float)MAX2(ima_x * sca_x, ima_y * sca_y));
579 /* Set the object scale */
580 glScalef(scale * sca_x, scale * sca_y, 1.0f);
582 if(ibuf && ibuf->rect) {
583 /* Setup GL params */
585 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
587 /* Use the object color and alpha */
590 /* Draw the Image on the screen */
591 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
592 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
597 UI_ThemeColor((ob->flag & SELECT) ? TH_SELECT : TH_WIRE);
599 /* Calculate the outline vertex positions */
600 glBegin(GL_LINE_LOOP);
601 glVertex2f(ofs_x, ofs_y);
602 glVertex2f(ofs_x + ima_x, ofs_y);
603 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
604 glVertex2f(ofs_x, ofs_y + ima_y);
607 /* Reset GL settings */
608 glMatrixMode(GL_MODELVIEW);
612 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
614 float vec[3], vx[3], vy[3];
617 mul_v3_v3fl(vx, tmat[0], rad);
618 mul_v3_v3fl(vy, tmat[1], rad);
621 for(a=0; a<tot; a++) {
622 vec[0]= cent[0] + *(sinval+a) * vx[0] + *(cosval+a) * vy[0];
623 vec[1]= cent[1] + *(sinval+a) * vx[1] + *(cosval+a) * vy[1];
624 vec[2]= cent[2] + *(sinval+a) * vx[2] + *(cosval+a) * vy[2];
630 /* circle for object centers, special_color is for library or ob users */
631 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
633 const float size= ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
635 /* using gldepthfunc guarantees that it does write z values, but not checks for it, so centers remain visible independt order of drawing */
636 if(v3d->zbuf) glDepthFunc(GL_ALWAYS);
640 if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
642 else glColor4ub(0x55, 0xCC, 0xCC, 155);
645 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
646 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
647 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
649 drawcircball(GL_POLYGON, co, size, rv3d->viewinv);
651 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
652 drawcircball(GL_LINE_LOOP, co, size, rv3d->viewinv);
655 if(v3d->zbuf) glDepthFunc(GL_LEQUAL);
658 /* *********** text drawing for object/particles/armature ************* */
659 static ListBase CachedText[3];
660 static int CachedTextLevel= 0;
662 typedef struct ViewCachedString {
663 struct ViewCachedString *next, *prev;
673 /* str is allocated past the end */
676 void view3d_cached_text_draw_begin(void)
678 ListBase *strings= &CachedText[CachedTextLevel];
679 strings->first= strings->last= NULL;
683 void view3d_cached_text_draw_add(const float co[3], const char *str, short xoffs, short flag, const unsigned char col[4])
685 int alloc_len= strlen(str) + 1;
686 ListBase *strings= &CachedText[CachedTextLevel-1];
687 ViewCachedString *vos= MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
689 BLI_addtail(strings, vos);
690 copy_v3_v3(vos->vec, co);
691 vos->col.pack= *((int *)col);
694 vos->str_len= alloc_len-1;
696 /* allocate past the end */
697 memcpy(++vos, str, alloc_len);
700 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
702 RegionView3D *rv3d= ar->regiondata;
703 ListBase *strings= &CachedText[CachedTextLevel-1];
704 ViewCachedString *vos;
707 /* project first and test */
708 for(vos= strings->first; vos; vos= vos->next) {
709 if(mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
710 mul_m4_v3(mat, vos->vec);
711 view3d_project_short_clip(ar, vos->vec, vos->sco, 0);
712 if(vos->sco[0]!=IS_CLIPPED)
717 int col_pack_prev= 0;
720 bglMats mats; /* ZBuffer depth vars */
727 if(rv3d->rflag & RV3D_CLIPPING)
729 glDisable(GL_CLIP_PLANE0+a);
731 glMatrixMode(GL_PROJECTION);
733 glMatrixMode(GL_MODELVIEW);
735 ED_region_pixelspace(ar);
738 if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
742 for(vos= strings->first; vos; vos= vos->next) {
743 #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
744 if(v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
745 gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
746 glReadPixels(ar->winrct.xmin+vos->mval[0]+vos->xoffs, ar->winrct.ymin+vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
752 if(vos->sco[0]!=IS_CLIPPED) {
753 const char *str= (char *)(vos+1);
755 if(col_pack_prev != vos->col.pack) {
756 glColor3ubv(vos->col.ub);
757 col_pack_prev= vos->col.pack;
759 if(vos->flag & V3D_CACHE_TEXT_ASCII) {
760 BLF_draw_default_ascii((float)vos->sco[0]+vos->xoffs, (float)vos->sco[1], (depth_write)? 0.0f: 2.0f, str, vos->str_len);
763 BLF_draw_default((float)vos->sco[0]+vos->xoffs, (float)vos->sco[1], (depth_write)? 0.0f: 2.0f, str, vos->str_len);
769 if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
773 glMatrixMode(GL_PROJECTION);
775 glMatrixMode(GL_MODELVIEW);
778 if(rv3d->rflag & RV3D_CLIPPING)
780 glEnable(GL_CLIP_PLANE0+a);
784 BLI_freelistN(strings);
789 /* ******************** primitive drawing ******************* */
791 static void drawcube(void)
794 glBegin(GL_LINE_STRIP);
795 glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
796 glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
797 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
800 glBegin(GL_LINE_STRIP);
801 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
804 glBegin(GL_LINE_STRIP);
805 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
808 glBegin(GL_LINE_STRIP);
809 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
813 /* draws a cube on given the scaling of the cube, assuming that
814 * all required matrices have been set (used for drawing empties)
816 static void drawcube_size(float size)
818 glBegin(GL_LINE_STRIP);
819 glVertex3f(-size,-size,-size); glVertex3f(-size,-size,size);glVertex3f(-size,size,size); glVertex3f(-size,size,-size);
820 glVertex3f(-size,-size,-size); glVertex3f(size,-size,-size);glVertex3f(size,-size,size); glVertex3f(size,size,size);
821 glVertex3f(size,size,-size); glVertex3f(size,-size,-size);
824 glBegin(GL_LINE_STRIP);
825 glVertex3f(-size,-size,size); glVertex3f(size,-size,size);
828 glBegin(GL_LINE_STRIP);
829 glVertex3f(-size,size,size); glVertex3f(size,size,size);
832 glBegin(GL_LINE_STRIP);
833 glVertex3f(-size,size,-size); glVertex3f(size,size,-size);
837 /* this is an unused (old) cube-drawing function based on a given size */
839 static void drawcube_size(float *size)
843 glScalef(size[0], size[1], size[2]);
846 glBegin(GL_LINE_STRIP);
847 glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
848 glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
849 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
852 glBegin(GL_LINE_STRIP);
853 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
856 glBegin(GL_LINE_STRIP);
857 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
860 glBegin(GL_LINE_STRIP);
861 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
868 static void drawshadbuflimits(Lamp *la, float mat[][4])
870 float sta[3], end[3], lavec[3];
872 negate_v3_v3(lavec, mat[2]);
875 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
876 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
878 glBegin(GL_LINE_STRIP);
893 static void spotvolume(float *lvec, float *vvec, float inp)
895 /* camera is at 0,0,0 */
896 float temp[3],plane[3],mat1[3][3],mat2[3][3],mat3[3][3],mat4[3][3],q[4],co,si,angle;
899 normalize_v3(vvec); /* is this the correct vector ? */
901 cross_v3_v3v3(temp,vvec,lvec); /* equation for a plane through vvec en lvec */
902 cross_v3_v3v3(plane,lvec,temp); /* a plane perpendicular to this, parrallel with lvec */
904 /* vectors are exactly aligned, use the X axis, this is arbitrary */
905 if(normalize_v3(plane) == 0.0f)
908 /* now we've got two equations: one of a cone and one of a plane, but we have
909 three unknowns. We remove one unkown by rotating the plane to z=0 (the plane normal) */
911 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
912 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
914 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
921 angle = saacos(plane[2])/2.0f;
930 quat_to_mat3(mat1,q);
932 /* rotate lamp vector now over acos(inp) degrees */
933 copy_v3_v3(vvec, lvec);
937 si = sqrt(1-inp*inp);
943 mul_m3_m3m3(mat3,mat2,mat1);
947 mul_m3_m3m3(mat4,mat2,mat1);
950 mul_m3_m3m3(mat2,mat1,mat3);
951 mul_m3_v3(mat2,lvec);
952 mul_m3_m3m3(mat2,mat1,mat4);
953 mul_m3_v3(mat2,vvec);
958 static void draw_spot_cone(Lamp *la, float x, float z)
962 glBegin(GL_TRIANGLE_FAN);
963 glVertex3f(0.0f, 0.0f, -x);
965 if(la->mode & LA_SQUARE) {
967 glVertex3f(-z, z, 0);
968 glVertex3f(-z, -z, 0);
969 glVertex3f(z, -z, 0);
976 for(a=0; a<33; a++) {
977 angle= a*M_PI*2/(33-1);
978 glVertex3f(z*cosf(angle), z*sinf(angle), 0);
985 static void draw_transp_spot_volume(Lamp *la, float x, float z)
987 glEnable(GL_CULL_FACE);
991 /* draw backside darkening */
992 glCullFace(GL_FRONT);
994 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
995 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
997 draw_spot_cone(la, x, z);
999 /* draw front side lighting */
1000 glCullFace(GL_BACK);
1002 glBlendFunc(GL_ONE, GL_ONE);
1003 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1005 draw_spot_cone(la, x, z);
1008 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1009 glDisable(GL_BLEND);
1011 glDisable(GL_CULL_FACE);
1012 glCullFace(GL_BACK);
1015 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
1017 Object *ob= base->object;
1018 const float pixsize= ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1020 float vec[3], lvec[3], vvec[3], circrad, x,y,z;
1022 float imat[4][4], curcol[4];
1023 unsigned char col[4];
1024 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1025 /* the moment of view3d_draw_transp() call */
1026 const short is_view= (rv3d->persp==RV3D_CAMOB && v3d->camera == base->object);
1027 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);
1029 if(drawcone && !v3d->transp) {
1030 /* in this case we need to draw delayed */
1031 add_view3d_after(&v3d->afterdraw_transp, base, flag);
1035 /* we first draw only the screen aligned & fixed scale stuff */
1037 glLoadMatrixf(rv3d->viewmat);
1039 /* lets calculate the scale: */
1040 lampsize= pixsize*((float)U.obcenter_dia*0.5f);
1042 /* and view aligned matrix: */
1043 copy_m4_m4(imat, rv3d->viewinv);
1044 normalize_v3(imat[0]);
1045 normalize_v3(imat[1]);
1048 copy_v3_v3(vec, ob->obmat[3]);
1050 /* for AA effects */
1051 glGetFloatv(GL_CURRENT_COLOR, curcol);
1055 if(lampsize > 0.0f) {
1058 if (ob==OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1059 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1064 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1065 glDisable(GL_BLEND);
1066 drawcircball(GL_POLYGON, vec, lampsize, imat);
1073 circrad = 3.0f*lampsize;
1076 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1078 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1079 if(la->type!=LA_HEMI) {
1080 if( (la->mode & LA_SHAD_RAY) ||
1081 ((la->mode & LA_SHAD_BUF) && (la->type==LA_SPOT))
1083 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f*pixsize, imat);
1092 /* draw the pretty sun rays */
1093 if(la->type==LA_SUN) {
1094 float v1[3], v2[3], mat[3][3];
1097 /* setup a 45 degree rotation matrix */
1098 vec_rot_to_mat3(mat, imat[2], (float)M_PI/4.0f);
1101 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1102 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1105 glTranslatef(vec[0], vec[1], vec[2]);
1110 for (axis=0; axis<8; axis++) {
1118 glTranslatef(-vec[0], -vec[1], -vec[2]);
1122 if (la->type==LA_LOCAL) {
1123 if(la->mode & LA_SPHERE) {
1124 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1126 /* yafray: for photonlight also draw lightcone as for spot */
1129 glPopMatrix(); /* back in object space */
1133 /* skip drawing extra info */
1135 else if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) {
1136 lvec[0]=lvec[1]= 0.0;
1138 x = rv3d->persmat[0][2];
1139 y = rv3d->persmat[1][2];
1140 z = rv3d->persmat[2][2];
1141 vvec[0]= x*ob->obmat[0][0] + y*ob->obmat[0][1] + z*ob->obmat[0][2];
1142 vvec[1]= x*ob->obmat[1][0] + y*ob->obmat[1][1] + z*ob->obmat[1][2];
1143 vvec[2]= x*ob->obmat[2][0] + y*ob->obmat[2][1] + z*ob->obmat[2][2];
1145 y = cosf(la->spotsize*(float)(M_PI/360.0));
1146 spotvolume(lvec, vvec, y);
1151 /* draw the angled sides of the cone */
1152 glBegin(GL_LINE_STRIP);
1158 z = x*sqrtf(1.0f - y*y);
1161 /* draw the circle/square at the end of the cone */
1162 glTranslatef(0.0, 0.0 , x);
1163 if(la->mode & LA_SQUARE) {
1165 float z_abs= fabs(z);
1167 tvec[0]= tvec[1]= z_abs;
1170 glBegin(GL_LINE_LOOP);
1172 tvec[1]= -z_abs; /* neg */
1174 tvec[0]= -z_abs; /* neg */
1176 tvec[1]= z_abs; /* pos */
1180 else circ(0.0, 0.0, fabsf(z));
1182 /* draw the circle/square representing spotbl */
1183 if(la->type==LA_SPOT) {
1184 float spotblcirc = fabs(z)*(1 - pow(la->spotblend, 2));
1185 /* hide line if it is zero size or overlaps with outer border,
1186 previously it adjusted to always to show it but that seems
1187 confusing because it doesn't show the actual blend size */
1188 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1189 circ(0.0, 0.0, spotblcirc);
1193 draw_transp_spot_volume(la, x, z);
1195 /* draw clip start, useful for wide cones where its not obvious where the start is */
1196 glTranslatef(0.0, 0.0 , -x); /* reverse translation above */
1197 if(la->type==LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1200 float clipsta_fac= la->clipsta / -x;
1202 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1203 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1205 glBegin(GL_LINE_STRIP);
1206 glVertex3fv(lvec_clip);
1207 glVertex3fv(vvec_clip);
1211 else if ELEM(la->type, LA_HEMI, LA_SUN) {
1213 /* draw the line from the circle along the dist */
1214 glBegin(GL_LINE_STRIP);
1221 if(la->type==LA_HEMI) {
1222 /* draw the hemisphere curves */
1223 short axis, steps, dir;
1224 float outdist, zdist, mul;
1226 outdist = 0.14; mul = 1.4; dir = 1;
1229 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1230 for (axis=0; axis<4; axis++) {
1231 float v[3]= {0.0, 0.0, 0.0};
1234 glBegin(GL_LINE_STRIP);
1236 for (steps=0; steps<6; steps++) {
1237 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1238 /* make the arcs start at the edge of the energy circle */
1239 if (steps == 0) v[0] = dir*circrad;
1240 else v[0] = v[0] + dir*(steps*outdist);
1241 } else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1242 /* make the arcs start at the edge of the energy circle */
1243 if (steps == 0) v[1] = dir*circrad;
1244 else v[1] = v[1] + dir*(steps*outdist);
1247 v[2] = v[2] - steps*zdist;
1251 zdist = zdist * mul;
1255 /* flip the direction */
1259 } else if(la->type==LA_AREA) {
1261 if(la->area_shape==LA_AREA_SQUARE)
1262 fdrawbox(-la->area_size*0.5f, -la->area_size*0.5f, la->area_size*0.5f, la->area_size*0.5f);
1263 else if(la->area_shape==LA_AREA_RECT)
1264 fdrawbox(-la->area_size*0.5f, -la->area_sizey*0.5f, la->area_size*0.5f, la->area_sizey*0.5f);
1266 glBegin(GL_LINE_STRIP);
1267 glVertex3f(0.0,0.0,-circrad);
1268 glVertex3f(0.0,0.0,-la->dist);
1272 /* and back to viewspace */
1273 glLoadMatrixf(rv3d->viewmat);
1274 copy_v3_v3(vec, ob->obmat[3]);
1278 if((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == FALSE)) {
1279 drawshadbuflimits(la, ob->obmat);
1282 UI_GetThemeColor4ubv(TH_LAMP, col);
1287 if (vec[2]>0) vec[2] -= circrad;
1288 else vec[2] += circrad;
1290 glBegin(GL_LINE_STRIP);
1302 glDisable(GL_BLEND);
1304 /* restore for drawing extra stuff */
1309 static void draw_limit_line(float sta, float end, unsigned int col)
1312 glVertex3f(0.0, 0.0, -sta);
1313 glVertex3f(0.0, 0.0, -end);
1319 glVertex3f(0.0, 0.0, -sta);
1320 glVertex3f(0.0, 0.0, -end);
1326 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1327 /* qdn: now also enabled for Blender to set focus point for defocus composit node */
1328 static void draw_focus_cross(float dist, float size)
1331 glVertex3f(-size, 0.f, -dist);
1332 glVertex3f(size, 0.f, -dist);
1333 glVertex3f(0.f, -size, -dist);
1334 glVertex3f(0.f, size, -dist);
1338 #ifdef VIEW3D_CAMERA_BORDER_HACK
1339 float view3d_camera_border_hack_col[4];
1340 short view3d_camera_border_hack_test= FALSE;
1343 /* flag similar to draw_object() */
1344 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int flag)
1346 /* a standing up pyramid with (0,0,0) as top */
1348 float vec[8][4], facx, facy, depth, aspx, aspy, caspx, caspy, shx, shy;
1351 const short is_view= (rv3d->persp==RV3D_CAMOB && ob==v3d->camera);
1353 const float scax= 1.0f / len_v3(ob->obmat[0]);
1354 const float scay= 1.0f / len_v3(ob->obmat[1]);
1355 const float scaz= 1.0f / len_v3(ob->obmat[2]);
1357 #ifdef VIEW3D_CAMERA_BORDER_HACK
1358 if(is_view && !(G.f & G_PICKSEL)) {
1359 glGetFloatv(GL_CURRENT_COLOR, view3d_camera_border_hack_col);
1360 view3d_camera_border_hack_test= TRUE;
1366 aspx= (float) scene->r.xsch*scene->r.xasp;
1367 aspy= (float) scene->r.ysch*scene->r.yasp;
1378 glDisable(GL_LIGHTING);
1379 glDisable(GL_CULL_FACE);
1381 if(cam->type==CAM_ORTHO) {
1382 facx= 0.5f * cam->ortho_scale * caspx * scax;
1383 facy= 0.5f * cam->ortho_scale * caspy * scay;
1384 shx= cam->shiftx * cam->ortho_scale * scax;
1385 shy= cam->shifty * cam->ortho_scale * scay;
1386 depth= is_view ? -((cam->clipsta * scaz) + 0.1f) : - cam->drawsize * cam->ortho_scale * scaz;
1388 drawsize= 0.5f * cam->ortho_scale;
1391 /* that way it's always visible - clipsta+0.1 */
1393 drawsize= cam->drawsize / ((scax + scay + scaz) / 3.0f);
1396 /* fixed depth, variable size (avoids exceeding clipping range) */
1397 depth = -(cam->clipsta + 0.1f);
1398 fac = depth / (cam->lens/-16.0f * scaz);
1401 /* fixed size, variable depth (stays a reasonable size in the 3D view) */
1402 depth= drawsize * cam->lens/-16.0f * scaz;
1406 facx= fac * caspx * scax;
1407 facy= fac * caspy * scay;
1408 shx= cam->shiftx*fac*2 * scax;
1409 shy= cam->shifty*fac*2 * scay;
1412 vec[0][0]= 0.0; vec[0][1]= 0.0; vec[0][2]= 0.0;
1413 vec[1][0]= shx + facx; vec[1][1]= shy + facy; vec[1][2]= depth;
1414 vec[2][0]= shx + facx; vec[2][1]= shy - facy; vec[2][2]= depth;
1415 vec[3][0]= shx - facx; vec[3][1]= shy - facy; vec[3][2]= depth;
1416 vec[4][0]= shx - facx; vec[4][1]= shy + facy; vec[4][2]= depth;
1419 glBegin(GL_LINE_LOOP);
1420 glVertex3fv(vec[1]);
1421 glVertex3fv(vec[2]);
1422 glVertex3fv(vec[3]);
1423 glVertex3fv(vec[4]);
1429 /* center point to camera frame */
1430 glBegin(GL_LINE_STRIP);
1431 glVertex3fv(vec[2]);
1432 glVertex3fv(vec[0]);
1433 glVertex3fv(vec[1]);
1434 glVertex3fv(vec[4]);
1435 glVertex3fv(vec[0]);
1436 glVertex3fv(vec[3]);
1444 /* draw an outline arrow for inactive cameras and filled
1445 * for active cameras. We actually draw both outline+filled
1446 * for active cameras so the wire can be seen side-on */
1448 if (i==0) glBegin(GL_LINE_LOOP);
1449 else if (i==1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1452 vec[0][0]= shx + ((-0.7f * drawsize) * scax);
1453 vec[0][1]= shy + ((drawsize * (caspy + 0.1f)) * scay);
1454 glVertex3fv(vec[0]); /* left */
1456 vec[0][0]= shx + ((0.7f * drawsize) * scax);
1457 glVertex3fv(vec[0]); /* right */
1460 vec[0][1]= shy + ((1.1f * drawsize * (caspy + 0.7f)) * scay);
1461 glVertex3fv(vec[0]); /* top */
1467 if(cam->flag & (CAM_SHOWLIMITS+CAM_SHOWMIST)) {
1471 /* draw in normalized object matrix space */
1472 copy_m4_m4(nobmat, ob->obmat);
1473 normalize_m4(nobmat);
1476 glLoadMatrixf(rv3d->viewmat);
1477 glMultMatrixf(nobmat);
1479 if(cam->flag & CAM_SHOWLIMITS) {
1480 draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
1481 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composit node */
1482 draw_focus_cross(dof_camera(ob), cam->drawsize);
1486 if(cam->flag & CAM_SHOWMIST)
1487 if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF);
1494 static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
1496 BPoint *bp = lt->def;
1497 float *co = dl?dl->verts:NULL;
1500 UI_ThemeColor(sel?TH_VERTEX_SELECT:TH_VERTEX);
1501 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1502 bglBegin(GL_POINTS);
1504 for(w=0; w<lt->pntsw; w++) {
1505 int wxt = (w==0 || w==lt->pntsw-1);
1506 for(v=0; v<lt->pntsv; v++) {
1507 int vxt = (v==0 || v==lt->pntsv-1);
1508 for(u=0; u<lt->pntsu; u++, bp++, co+=3) {
1509 int uxt = (u==0 || u==lt->pntsu-1);
1510 if(!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1512 if((bp->f1 & SELECT)==sel) {
1513 bglVertex3fv(dl?co:bp->vec);
1525 void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPoint *bp, int x, int y), void *userData)
1527 Object *obedit= vc->obedit;
1528 Lattice *lt= obedit->data;
1529 BPoint *bp = lt->editlatt->latt->def;
1530 DispList *dl = find_displist(&obedit->disp, DL_VERTS);
1531 float *co = dl?dl->verts:NULL;
1532 int i, N = lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
1533 short s[2] = {IS_CLIPPED, 0};
1535 ED_view3d_local_clipping(vc->rv3d, obedit->obmat); /* for local clipping lookups */
1537 for (i=0; i<N; i++, bp++, co+=3) {
1539 view3d_project_short_clip(vc->ar, dl?co:bp->vec, s, 1);
1540 if (s[0] != IS_CLIPPED)
1541 func(userData, bp, s[0], s[1]);
1546 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
1548 int index = ((w*lt->pntsv + v)*lt->pntsu) + u;
1552 MDeformWeight *mdw= defvert_find_index (lt->dvert+index, use_wcol-1);
1554 weight_to_rgb(mdw?mdw->weight:0.0f, col, col+1, col+2);
1560 glVertex3fv(&dl->verts[index*3]);
1562 glVertex3fv(lt->def[index].vec);
1566 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1567 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1569 Lattice *lt= ob->data;
1572 int use_wcol= 0, is_edit= (lt->editlatt != NULL);
1574 /* now we default make displist, this will modifiers work for non animated case */
1575 if(ob->disp.first==NULL)
1576 lattice_calc_modifiers(scene, ob);
1577 dl= find_displist(&ob->disp, DL_VERTS);
1580 lt= lt->editlatt->latt;
1584 if(ob->defbase.first && lt->dvert) {
1585 use_wcol= ob->actdef;
1586 glShadeModel(GL_SMOOTH);
1591 for(w=0; w<lt->pntsw; w++) {
1592 int wxt = (w==0 || w==lt->pntsw-1);
1593 for(v=0; v<lt->pntsv; v++) {
1594 int vxt = (v==0 || v==lt->pntsv-1);
1595 for(u=0; u<lt->pntsu; u++) {
1596 int uxt = (u==0 || u==lt->pntsu-1);
1598 if(w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
1599 drawlattice__point(lt, dl, u, v, w-1, use_wcol);
1600 drawlattice__point(lt, dl, u, v, w, use_wcol);
1602 if(v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1603 drawlattice__point(lt, dl, u, v-1, w, use_wcol);
1604 drawlattice__point(lt, dl, u, v, w, use_wcol);
1606 if(u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1607 drawlattice__point(lt, dl, u-1, v, w, use_wcol);
1608 drawlattice__point(lt, dl, u, v, w, use_wcol);
1615 /* restoration for weight colors */
1617 glShadeModel(GL_FLAT);
1620 if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
1622 lattice_draw_verts(lt, dl, 0);
1623 lattice_draw_verts(lt, dl, 1);
1625 if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
1629 /* ***************** ******************** */
1631 /* Note! - foreach funcs should be called while drawing or directly after
1632 * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
1633 * but would not give correct results with dupli's for eg. which dont
1634 * use the object matrix in the useual way */
1635 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1637 struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
1638 EditVert *eve = EM_get_vert_for_index(index);
1641 short s[2]= {IS_CLIPPED, 0};
1643 if (data->clipVerts) {
1644 view3d_project_short_clip(data->vc.ar, co, s, 1);
1646 view3d_project_short_noclip(data->vc.ar, co, s);
1649 if (s[0]!=IS_CLIPPED)
1650 data->func(data->userData, eve, s[0], s[1], index);
1654 void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts)
1656 struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data;
1657 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1661 data.userData = userData;
1662 data.clipVerts = clipVerts;
1665 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1667 EM_init_index_arrays(vc->em, 1, 0, 0);
1668 dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
1669 EM_free_index_arrays();
1674 static void mesh_obmode_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1676 struct { void (*func)(void *userData, MVert *mv, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
1677 Mesh *me = data->vc.obact->data;
1678 MVert *mv = me->mvert+index;
1679 //MVert *dmv = CDDM_get_verts(data->vc.obact->derivedFinal)+index;
1680 //MVert *mv = CDDM_get_verts(data->vc.obact->derivedFinal)+index;
1681 if ((mv->flag & ME_HIDE)==0) {
1682 short s[2]= {IS_CLIPPED, 0};
1684 if (data->clipVerts) {
1685 view3d_project_short_clip(data->vc.ar, co, s, 1);
1687 view3d_project_short_noclip(data->vc.ar, co, s);
1690 if (s[0]!=IS_CLIPPED)
1691 data->func(data->userData, mv, s[0], s[1], index);
1695 void mesh_obmode_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, MVert *mv, int x, int y, int index), void *userData, int clipVerts)
1697 struct { void (*func)(void *userData, MVert *mv, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data;
1698 DerivedMesh *dm = mesh_get_derived_final(vc->scene, vc->obact, CD_MASK_BAREMESH);
1702 data.userData = userData;
1703 data.clipVerts = clipVerts;
1706 ED_view3d_local_clipping(vc->rv3d, vc->obact->obmat); /* for local clipping lookups */
1708 dm->foreachMappedVert(dm, mesh_obmode_foreachScreenVert__mapFunc, &data);
1712 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
1714 struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
1715 EditEdge *eed = EM_get_edge_for_index(index);
1719 if (data->clipVerts==1) {
1720 view3d_project_short_clip(data->vc.ar, v0co, s[0], 1);
1721 view3d_project_short_clip(data->vc.ar, v1co, s[1], 1);
1723 view3d_project_short_noclip(data->vc.ar, v0co, s[0]);
1724 view3d_project_short_noclip(data->vc.ar, v1co, s[1]);
1726 if (data->clipVerts==2) {
1727 if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<data->vc.ar->winx && s[0][1]<data->vc.ar->winy))
1728 if (!(s[1][0]>=0 && s[1][1]>= 0 && s[1][0]<data->vc.ar->winx && s[1][1]<data->vc.ar->winy))
1733 data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index);
1737 void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
1739 struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } data;
1740 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1744 data.userData = userData;
1745 data.clipVerts = clipVerts;
1748 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1750 EM_init_index_arrays(vc->em, 0, 1, 0);
1751 dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
1752 EM_free_index_arrays();
1757 static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
1759 struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData;
1760 EditFace *efa = EM_get_face_for_index(index);
1763 if (efa && efa->h==0 && efa->fgonf!=EM_FGON) {
1764 view3d_project_short_clip(data->vc.ar, cent, s, 1);
1766 data->func(data->userData, efa, s[0], s[1], index);
1770 void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData)
1772 struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data;
1773 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1777 data.userData = userData;
1780 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1782 EM_init_index_arrays(vc->em, 0, 0, 1);
1783 dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
1784 EM_free_index_arrays();
1789 void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y), void *userData)
1791 Curve *cu= vc->obedit->data;
1792 short s[2] = {IS_CLIPPED, 0};
1795 ListBase *nurbs= ED_curve_editnurbs(cu);
1797 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1799 for (nu= nurbs->first; nu; nu=nu->next) {
1800 if(nu->type == CU_BEZIER) {
1801 for (i=0; i<nu->pntsu; i++) {
1802 BezTriple *bezt = &nu->bezt[i];
1806 if(cu->drawflag & CU_HIDE_HANDLES) {
1807 view3d_project_short_clip(vc->ar, bezt->vec[1], s, 1);
1808 if (s[0] != IS_CLIPPED)
1809 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
1811 view3d_project_short_clip(vc->ar, bezt->vec[0], s, 1);
1812 if (s[0] != IS_CLIPPED)
1813 func(userData, nu, NULL, bezt, 0, s[0], s[1]);
1814 view3d_project_short_clip(vc->ar, bezt->vec[1], s, 1);
1815 if (s[0] != IS_CLIPPED)
1816 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
1817 view3d_project_short_clip(vc->ar, bezt->vec[2], s, 1);
1818 if (s[0] != IS_CLIPPED)
1819 func(userData, nu, NULL, bezt, 2, s[0], s[1]);
1825 for (i=0; i<nu->pntsu*nu->pntsv; i++) {
1826 BPoint *bp = &nu->bp[i];
1829 view3d_project_short_clip(vc->ar, bp->vec, s, 1);
1830 if (s[0] != IS_CLIPPED)
1831 func(userData, nu, bp, NULL, -1, s[0], s[1]);
1838 /* ************** DRAW MESH ****************** */
1840 /* First section is all the "simple" draw routines,
1841 * ones that just pass some sort of primitive to GL,
1842 * with perhaps various options to control lighting,
1845 * These routines should not have user interface related
1849 static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
1851 ToolSettings *ts= ((Scene *)userData)->toolsettings;
1852 EditFace *efa = EM_get_face_for_index(index);
1854 if (efa->h==0 && efa->fgonf!=EM_FGON) {
1856 glVertex3f( cent[0] + no[0]*ts->normalsize,
1857 cent[1] + no[1]*ts->normalsize,
1858 cent[2] + no[2]*ts->normalsize);
1861 static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm)
1864 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene);
1868 static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
1870 EditFace *efa = EM_get_face_for_index(index);
1871 int sel = *((int*) userData);
1873 if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) {
1877 static void draw_dm_face_centers(DerivedMesh *dm, int sel)
1879 bglBegin(GL_POINTS);
1880 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel);
1884 static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
1886 Scene *scene= (Scene *)userData;
1887 ToolSettings *ts= scene->toolsettings;
1888 EditVert *eve = EM_get_vert_for_index(index);
1894 glVertex3f( co[0] + no_f[0]*ts->normalsize,
1895 co[1] + no_f[1]*ts->normalsize,
1896 co[2] + no_f[2]*ts->normalsize);
1898 glVertex3f( co[0] + no_s[0]*ts->normalsize/32767.0f,
1899 co[1] + no_s[1]*ts->normalsize/32767.0f,
1900 co[2] + no_s[2]*ts->normalsize/32767.0f);
1904 static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm)
1907 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene);
1911 /* Draw verts with color set based on selection */
1912 static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1914 struct { int sel; EditVert *eve_act; } * data = userData;
1915 EditVert *eve = EM_get_vert_for_index(index);
1917 if (eve->h==0 && (eve->f&SELECT)==data->sel) {
1918 /* draw active larger - need to stop/start point drawing for this :/ */
1919 if (eve==data->eve_act) {
1920 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
1921 UI_ThemeColor4(TH_EDITMESH_ACTIVE);
1926 bglBegin(GL_POINTS);
1930 UI_ThemeColor4(data->sel?TH_VERTEX_SELECT:TH_VERTEX);
1932 bglBegin(GL_POINTS);
1939 static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
1941 struct { int sel; EditVert *eve_act; } data;
1943 data.eve_act = eve_act;
1945 bglBegin(GL_POINTS);
1946 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
1950 /* Draw edges with color set based on selection */
1951 static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
1953 EditEdge *eed = EM_get_edge_for_index(index);
1954 //unsigned char **cols = userData, *col;
1955 struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData;
1959 if (eed==data->eed_act) {
1960 glColor4ubv(data->actCol);
1962 if (eed->f&SELECT) {
1965 col = data->baseCol;
1967 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
1968 if (col[3]==0) return 0;
1977 static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act)
1979 struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data;
1981 data.baseCol = baseCol;
1982 data.selCol = selCol;
1983 data.actCol = actCol;
1984 data.eed_act = eed_act;
1985 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
1989 static int draw_dm_edges__setDrawOptions(void *UNUSED(userData), int index)
1991 return EM_get_edge_for_index(index)->h==0;
1993 static void draw_dm_edges(DerivedMesh *dm)
1995 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL);
1998 /* Draw edges with color interpolated based on selection */
1999 static int draw_dm_edges_sel_interp__setDrawOptions(void *UNUSED(userData), int index)
2001 return EM_get_edge_for_index(index)->h==0;
2003 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2005 EditEdge *eed = EM_get_edge_for_index(index);
2006 unsigned char **cols = userData;
2007 unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0];
2008 unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0];
2010 glColor4ub( col0[0] + (col1[0]-col0[0])*t,
2011 col0[1] + (col1[1]-col0[1])*t,
2012 col0[2] + (col1[2]-col0[2])*t,
2013 col0[3] + (col1[3]-col0[3])*t);
2016 static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2018 unsigned char *cols[2];
2021 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2024 /* Draw only seam edges */
2025 static int draw_dm_edges_seams__setDrawOptions(void *UNUSED(userData), int index)
2027 EditEdge *eed = EM_get_edge_for_index(index);
2029 return (eed->h==0 && eed->seam);
2031 static void draw_dm_edges_seams(DerivedMesh *dm)
2033 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL);
2036 /* Draw only sharp edges */
2037 static int draw_dm_edges_sharp__setDrawOptions(void *UNUSED(userData), int index)
2039 EditEdge *eed = EM_get_edge_for_index(index);
2041 return (eed->h==0 && eed->sharp);
2043 static void draw_dm_edges_sharp(DerivedMesh *dm)
2045 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL);
2049 /* Draw faces with color set based on selection
2050 * return 2 for the active face so it renders with stipple enabled */
2051 static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r))
2053 struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
2054 EditFace *efa = EM_get_face_for_index(index);
2058 if (efa == data->efa_act) {
2059 glColor4ubv(data->cols[2]);
2060 return 2; /* stipple */
2062 col = data->cols[(efa->f&SELECT)?1:0];
2063 if (col[3]==0) return 0;
2071 /* also draws the active face */
2072 static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act)
2074 struct { unsigned char *cols[3]; EditFace *efa_act; } data;
2075 data.cols[0] = baseCol;
2076 data.cols[1] = selCol;
2077 data.cols[2] = actCol;
2078 data.efa_act = efa_act;
2080 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material);
2083 static int draw_dm_creases__setDrawOptions(void *UNUSED(userData), int index)
2085 EditEdge *eed = EM_get_edge_for_index(index);
2087 if (eed->h==0 && eed->crease != 0.0f) {
2088 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, eed->crease);
2094 static void draw_dm_creases(DerivedMesh *dm)
2097 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL);
2101 static int draw_dm_bweights__setDrawOptions(void *UNUSED(userData), int index)
2103 EditEdge *eed = EM_get_edge_for_index(index);
2105 if (eed->h==0 && eed->bweight != 0.0f) {
2106 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight);
2112 static void draw_dm_bweights__mapFunc(void *UNUSED(userData), int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
2114 EditVert *eve = EM_get_vert_for_index(index);
2116 if (eve->h==0 && eve->bweight != 0.0f) {
2117 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight);
2121 static void draw_dm_bweights(Scene *scene, DerivedMesh *dm)
2123 ToolSettings *ts= scene->toolsettings;
2125 if (ts->selectmode & SCE_SELECT_VERTEX) {
2126 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2127 bglBegin(GL_POINTS);
2128 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL);
2133 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL);
2138 /* Second section of routines: Combine first sets to form fancy
2139 * drawing routines (for example rendering twice to get overlays).
2141 * Also includes routines that are basic drawing but are too
2142 * specialized to be split out (like drawing creases or measurements).
2145 /* EditMesh drawing routines*/
2147 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, DerivedMesh *cageDM, EditVert *eve_act)
2149 ToolSettings *ts= scene->toolsettings;
2152 if(v3d->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select
2154 for (sel=0; sel<2; sel++) {
2155 unsigned char col[4], fcol[4];
2158 UI_GetThemeColor3ubv(sel?TH_VERTEX_SELECT:TH_VERTEX, col);
2159 UI_GetThemeColor3ubv(sel?TH_FACE_DOT:TH_WIRE, fcol);
2161 for (pass=0; pass<2; pass++) {
2162 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2163 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2166 if(v3d->zbuf && !(v3d->flag&V3D_ZBUF_SELECT)) {
2167 glDisable(GL_DEPTH_TEST);
2174 size = (size > 2.1f ? size/2.0f:size);
2175 fsize = (fsize > 2.1f ? fsize/2.0f:fsize);
2176 col[3] = fcol[3] = 100;
2178 col[3] = fcol[3] = 255;
2181 if(ts->selectmode & SCE_SELECT_VERTEX) {
2184 draw_dm_verts(cageDM, sel, eve_act);
2187 if(check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2190 draw_dm_face_centers(cageDM, sel);
2194 glDisable(GL_BLEND);
2195 glEnable(GL_DEPTH_TEST);
2200 if(v3d->zbuf) glDepthMask(1);
2204 static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act)
2206 ToolSettings *ts= scene->toolsettings;
2208 unsigned char wireCol[4], selCol[4], actCol[4];
2210 /* since this function does transparant... */
2211 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2212 UI_GetThemeColor4ubv(TH_WIRE, wireCol);
2213 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2215 /* when sel only is used, dont render wire, only selected, this is used for
2216 * textured draw mode when the 'edges' option is disabled */
2220 for (pass=0; pass<2; pass++) {
2221 /* show wires in transparant when no zbuf clipping for select */
2223 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0) {
2225 glDisable(GL_DEPTH_TEST);
2227 if (!sel_only) wireCol[3] = 85;
2233 if (!sel_only) wireCol[3] = 255;
2236 if(ts->selectmode == SCE_SELECT_FACE) {
2237 draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
2239 else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
2240 if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2241 glShadeModel(GL_SMOOTH);
2242 draw_dm_edges_sel_interp(cageDM, wireCol, selCol);
2243 glShadeModel(GL_FLAT);
2245 draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
2250 glColor4ubv(wireCol);
2251 draw_dm_edges(cageDM);
2256 glDisable(GL_BLEND);
2257 glEnable(GL_DEPTH_TEST);
2262 static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, UnitSettings *unit)
2267 float v1[3], v2[3], v3[3], v4[3], vmid[3];
2269 char val[32]; /* Stores the measurement display text here */
2270 const char *conv_float; /* Use a float conversion matching the grid size */
2271 unsigned char col[4]= {0, 0, 0, 255}; /* color of the text to draw */
2272 float area; /* area of the face */
2273 float grid= unit->system ? unit->scale_length : v3d->grid;
2274 const int do_split= unit->flag & USER_UNIT_OPT_SPLIT;
2275 const int do_global= v3d->flag & V3D_GLOBAL_STATS;
2276 const int do_moving= G.moving;
2278 /* make the precision of the pronted value proportionate to the gridsize */
2280 if (grid < 0.01f) conv_float= "%.6g";
2281 else if (grid < 0.1f) conv_float= "%.5g";
2282 else if (grid < 1.0f) conv_float= "%.4g";
2283 else if (grid < 10.0f) conv_float= "%.3g";
2284 else conv_float= "%.2g";
2286 if(v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0)
2287 glDisable(GL_DEPTH_TEST);
2289 if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0f);
2291 if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2292 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2294 for(eed= em->edges.first; eed; eed= eed->next) {
2295 /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */
2296 if((eed->h != EM_FGON) && ((eed->f & SELECT) || (do_moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) {
2297 copy_v3_v3(v1, eed->v1->co);
2298 copy_v3_v3(v2, eed->v2->co);
2300 interp_v3_v3v3(vmid, v1, v2, 0.5f);
2303 mul_mat3_m4_v3(ob->obmat, v1);
2304 mul_mat3_m4_v3(ob->obmat, v2);
2307 bUnit_AsString(val, sizeof(val), len_v3v3(v1, v2)*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE);
2309 sprintf(val, conv_float, len_v3v3(v1, v2));
2311 view3d_cached_text_draw_add(vmid, val, 0, V3D_CACHE_TEXT_ASCII, col);
2316 if(me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2317 // XXX extern int faceselectedOR(EditFace *efa, int flag); // editmesh.h shouldn't be in this file... ok for now?
2318 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2320 for(efa= em->faces.first; efa; efa= efa->next) {
2321 if((efa->f & SELECT)) { // XXX || (do_moving && faceselectedOR(efa, SELECT)) ) {
2322 copy_v3_v3(v1, efa->v1->co);
2323 copy_v3_v3(v2, efa->v2->co);
2324 copy_v3_v3(v3, efa->v3->co);
2326 copy_v3_v3(v4, efa->v4->co);
2329 mul_mat3_m4_v3(ob->obmat, v1);
2330 mul_mat3_m4_v3(ob->obmat, v2);
2331 mul_mat3_m4_v3(ob->obmat, v3);
2332 if (efa->v4) mul_mat3_m4_v3(ob->obmat, v4);
2336 area= area_quad_v3(v1, v2, v3, v4);
2338 area = area_tri_v3(v1, v2, v3);
2341 bUnit_AsString(val, sizeof(val), area*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); // XXX should be B_UNIT_AREA
2343 sprintf(val, conv_float, area);
2345 view3d_cached_text_draw_add(efa->cent, val, 0, V3D_CACHE_TEXT_ASCII, col);
2350 if(me->drawflag & ME_DRAWEXTRA_FACEANG) {
2351 EditEdge *e1, *e2, *e3, *e4;
2352 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2353 for(efa= em->faces.first; efa; efa= efa->next) {
2354 copy_v3_v3(v1, efa->v1->co);
2355 copy_v3_v3(v2, efa->v2->co);
2356 copy_v3_v3(v3, efa->v3->co);
2358 copy_v3_v3(v4, efa->v4->co);
2364 mul_mat3_m4_v3(ob->obmat, v1);
2365 mul_mat3_m4_v3(ob->obmat, v2);
2366 mul_mat3_m4_v3(ob->obmat, v3);
2367 mul_mat3_m4_v3(ob->obmat, v4); /* intentionally executed even for tri's */
2373 if(efa->e4) e4= efa->e4; else e4= e3;
2375 /* Calculate the angles */
2377 if( (e4->f & e1->f & SELECT) || (do_moving && (efa->v1->f & SELECT)) ) {
2379 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v4, v1, v2)));
2380 interp_v3_v3v3(fvec, efa->cent, efa->v1->co, 0.8f);
2381 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2383 if( (e1->f & e2->f & SELECT) || (do_moving && (efa->v2->f & SELECT)) ) {
2385 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
2386 interp_v3_v3v3(fvec, efa->cent, efa->v2->co, 0.8f);
2387 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2389 if( (e2->f & e3->f & SELECT) || (do_moving && (efa->v3->f & SELECT)) ) {
2392 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v4)));
2394 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v1)));
2395 interp_v3_v3v3(fvec, efa->cent, efa->v3->co, 0.8f);
2396 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2400 if( (e3->f & e4->f & SELECT) || (do_moving && (efa->v4->f & SELECT)) ) {
2401 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v3, v4, v1)));
2402 interp_v3_v3v3(fvec, efa->cent, efa->v4->co, 0.8f);
2403 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2409 /* useful for debugging index vs shape key index */
2414 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2415 for(eve= em->verts.first, j= 0; eve; eve= eve->next, j++) {
2416 sprintf(val, "%d:%d", j, eve->keyindex);
2417 view3d_cached_text_draw_add(eve->co, val, 0, V3D_CACHE_TEXT_ASCII, col);
2423 glEnable(GL_DEPTH_TEST);
2424 bglPolygonOffset(rv3d->dist, 0.0f);
2428 static int draw_em_fancy__setFaceOpts(void *UNUSED(userData), int index, int *UNUSED(drawSmooth_r))
2430 EditFace *efa = EM_get_face_for_index(index);
2433 GPU_enable_material(efa->mat_nr+1, NULL);
2440 static int draw_em_fancy__setGLSLFaceOpts(void *UNUSED(userData), int index)
2442 EditFace *efa = EM_get_face_for_index(index);
2447 static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
2449 Mesh *me = ob->data;
2450 EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */
2451 EditEdge *eed_act = NULL;
2452 EditVert *eve_act = NULL;
2454 if (em->selected.last) {
2455 EditSelection *ese = em->selected.last;
2456 /* face is handeled above */
2457 /*if (ese->type == EDITFACE ) {
2458 efa_act = (EditFace *)ese->data;
2459 } else */ if ( ese->type == EDITEDGE ) {
2460 eed_act = (EditEdge *)ese->data;
2461 } else if ( ese->type == EDITVERT ) {
2462 eve_act = (EditVert *)ese->data;
2466 EM_init_index_arrays(em, 1, 1, 1);
2469 if(CHECK_OB_DRAWTEXTURE(v3d, dt)) {
2470 if(draw_glsl_material(scene, ob, v3d, dt)) {
2471 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2473 finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
2474 draw_em_fancy__setGLSLFaceOpts, NULL);
2475 GPU_disable_material();
2477 glFrontFace(GL_CCW);
2480 draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
2484 /* 3 floats for position, 3 for normal and times two because the faces may actually be quads instead of triangles */
2485 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED);
2487 glEnable(GL_LIGHTING);
2488 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2490 finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, NULL, 0, GPU_enable_material);
2492 glFrontFace(GL_CCW);
2493 glDisable(GL_LIGHTING);
2496 // Setup for drawing wire over, disable zbuffer
2497 // write to show selected edge wires better
2498 UI_ThemeColor(TH_WIRE);
2500 bglPolygonOffset(rv3d->dist, 1.0);
2504 if (cageDM!=finalDM) {
2505 UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
2506 finalDM->drawEdges(finalDM, 1, 0);
2510 if(me->drawflag & ME_DRAWFACES) { /* transp faces */
2511 unsigned char col1[4], col2[4], col3[4];
2513 UI_GetThemeColor4ubv(TH_FACE, col1);
2514 UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
2515 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
2518 glDepthMask(0); // disable write in zbuffer, needed for nice transp
2520 /* dont draw unselected faces, only selected, this is MUCH nicer when texturing */
2521 if CHECK_OB_DRAWTEXTURE(v3d, dt)
2524 draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
2526 glDisable(GL_BLEND);
2527 glDepthMask(1); // restore write in zbuffer
2528 } else if (efa_act) {
2529 /* even if draw faces is off it would be nice to draw the stipple face
2530 * Make all other faces zero alpha except for the active
2532 unsigned char col1[4], col2[4], col3[4];
2533 col1[3] = col2[3] = 0; /* dont draw */
2534 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
2537 glDepthMask(0); // disable write in zbuffer, needed for nice transp
2539 draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
2541 glDisable(GL_BLEND);
2542 glDepthMask(1); // restore write in zbuffer
2546 /* here starts all fancy draw-extra over */
2547 if((me->drawflag & ME_DRAWEDGES)==0 && CHECK_OB_DRAWTEXTURE(v3d, dt)) {
2548 /* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */
2550 /* only draw selected edges otherwise there is no way of telling if a face is selected */
2551 draw_em_fancy_edges(scene, v3d, me, cageDM, 1, eed_act);
2554 if(me->drawflag & ME_DRAWSEAMS) {
2555 UI_ThemeColor(TH_EDGE_SEAM);
2558 draw_dm_edges_seams(cageDM);
2564 if(me->drawflag & ME_DRAWSHARP) {
2565 UI_ThemeColor(TH_EDGE_SHARP);
2568 draw_dm_edges_sharp(cageDM);
2574 if(me->drawflag & ME_DRAWCREASES) {
2575 draw_dm_creases(cageDM);
2577 if(me->drawflag & ME_DRAWBWEIGHTS) {
2578 draw_dm_bweights(scene, cageDM);
2581 draw_em_fancy_edges(scene, v3d, me, cageDM, 0, eed_act);
2584 // XXX retopo_matrix_update(v3d);
2586 draw_em_fancy_verts(scene, v3d, ob, cageDM, eve_act);
2588 if(me->drawflag & ME_DRAWNORMALS) {
2589 UI_ThemeColor(TH_NORMAL);
2590 draw_dm_face_normals(scene, cageDM);
2592 if(me->drawflag & ME_DRAW_VNORMALS) {
2593 UI_ThemeColor(TH_VNORMAL);
2594 draw_dm_vert_normals(scene, cageDM);
2597 if(me->drawflag & (ME_DRAWEXTRA_EDGELEN|ME_DRAWEXTRA_FACEAREA|ME_DRAWEXTRA_FACEANG) && !((v3d->flag2 & V3D_RENDER_OVERRIDE)))
2598 draw_em_measure_stats(v3d, rv3d, ob, em, &scene->unit);
2603 bglPolygonOffset(rv3d->dist, 0.0);
2604 GPU_disable_material();
2607 EM_free_index_arrays();
2610 /* Mesh drawing routines */
2612 static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
2615 if(v3d->transp==0) { // not when we draw the transparent pass
2616 glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
2619 /* if transparent, we cannot draw the edges for solid select... edges have no material info.
2620 drawFacesSolid() doesn't draw the transparent faces */
2621 if(ob->dtx & OB_DRAWTRANSP) {
2622 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2623 dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
2624 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2625 GPU_disable_material();
2628 dm->drawEdges(dm, 0, 1);
2636 static int wpaint__setSolidDrawOptions(void *UNUSED(userData), int UNUSED(index), int *drawSmooth_r)
2642 static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
2644 Object *ob= base->object;
2645 Mesh *me = ob->data;
2646 Material *ma= give_current_material(ob, 1);
2647 const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO));
2648 const short is_paint_sel= (ob==OBACT && paint_facesel_test(ob));
2650 int /* totvert,*/ totedge, totface;
2651 DerivedMesh *dm= mesh_get_derived_final(scene, ob, scene->customdata_mask);
2656 if (ob->dtx&OB_DRAWWIRE) {
2657 draw_wire = 2; /* draw wire after solid using zoffset and depth buffer adjusment */
2660 /* totvert = dm->getNumVerts(dm); */ /*UNUSED*/
2661 totedge = dm->getNumEdges(dm);
2662 totface = dm->getNumFaces(dm);
2664 /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
2666 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2668 // Unwanted combination.
2669 if (is_paint_sel) draw_wire = 0;
2671 if(dt==OB_BOUNDBOX) {
2672 if((v3d->flag2 & V3D_RENDER_OVERRIDE && v3d->drawtype >= OB_WIRE)==0)
2673 draw_bounding_volume(scene, ob);
2675 else if(hasHaloMat || (totface==0 && totedge==0)) {
2680 else if(dt==OB_WIRE || totface==0) {
2681 draw_wire = 1; /* draw wire only, no depth buffer stuff */
2683 else if( (is_paint_sel || (ob==OBACT && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
2684 CHECK_OB_DRAWTEXTURE(v3d, dt))
2686 if ((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !(G.f&G_PICKSEL || is_paint_sel) && !draw_wire) {
2687 draw_mesh_object_outline(v3d, ob, dm);
2690 if(draw_glsl_material(scene, ob, v3d, dt)) {
2691 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2693 dm->drawFacesGLSL(dm, GPU_enable_material);
2694 // if(get_ob_property(ob, "Text"))
2695 // XXX draw_mesh_text(ob, 1);
2696 GPU_disable_material();
2698 glFrontFace(GL_CCW);
2701 draw_mesh_textured(scene, v3d, rv3d, ob, dm, is_paint_sel);
2705 if(base->flag & SELECT)
2706 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2708 UI_ThemeColor(TH_WIRE);
2710 if((v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
2711 dm->drawLooseEdges(dm);
2714 else if(dt==OB_SOLID) {
2715 if(ob==OBACT && ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
2716 /* weight paint in solid mode, special case. focus on making the weights clear
2717 * rather than the shading, this is also forced in wire view */
2718 GPU_enable_material(0, NULL);
2719 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material);
2721 bglPolygonOffset(rv3d->dist, 1.0);
2722 glDepthMask(0); // disable write in zbuffer, selected edge wires show better
2725 glColor4ub(255, 255, 255, 96);
2726 glEnable(GL_LINE_STIPPLE);
2727 glLineStipple(1, 0xAAAA);
2729 dm->drawEdges(dm, 1, 1);
2731 bglPolygonOffset(rv3d->dist, 0.0);
2733 glDisable(GL_LINE_STIPPLE);
2735 GPU_disable_material();
2737 /* since we already draw wire as wp guide, dont draw over the top */
2743 if((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !draw_wire && !ob->sculpt)
2744 draw_mesh_object_outline(v3d, ob, dm);
2746 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
2748 glEnable(GL_LIGHTING);
2749 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2751 if(ob->sculpt && (p=paint_get_active(scene))) {
2753 float (*fpl)[4] = NULL;
2754 int fast= (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
2756 if(ob->sculpt->partial_redraw) {
2757 if(ar->do_draw & RGN_DRAW_PARTIAL) {
2758 sculpt_get_redraw_planes(planes, ar, rv3d, ob);
2760 ob->sculpt->partial_redraw = 0;
2764 dm->drawFacesSolid(dm, fpl, fast, GPU_enable_material);
2767 dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
2769 GPU_disable_material();
2771 glFrontFace(GL_CCW);
2772 glDisable(GL_LIGHTING);
2774 if(base->flag & SELECT) {
2775 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2777 UI_ThemeColor(TH_WIRE);
2779 if(!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
2780 dm->drawLooseEdges(dm);
2783 else if(dt==OB_SHADED) {
2785 if(ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
2786 /* enforce default material settings */
2787 GPU_enable_material(0, NULL);
2789 /* but set default spec */
2790 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
2791 glEnable(GL_COLOR_MATERIAL); /* according manpages needed */
2792 glColor3ub(120, 120, 120);
2793 glDisable(GL_COLOR_MATERIAL);
2795 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
2796 glEnable(GL_LIGHTING);
2797 glEnable(GL_COLOR_MATERIAL);
2799 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material);
2800 glDisable(GL_COLOR_MATERIAL);
2801 glDisable(GL_LIGHTING);
2803 GPU_disable_material();
2805 else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) {
2807 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1, GPU_enable_material);
2809 glColor3f(1.0f, 1.0f, 1.0f);
2810 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0, GPU_enable_material);
2815 /* set default draw color back for wire or for draw-extra later on */
2817 if(base->flag & SELECT) {
2818 if(ob==OBACT && ob->flag & OB_FROMGROUP)
2819 UI_ThemeColor(TH_GROUP_ACTIVE);
2820 else if(ob->flag & OB_FROMGROUP)
2821 UI_ThemeColorShade(TH_GROUP_ACTIVE, -16);
2822 else if(flag!=DRAW_CONSTCOLOR)
2823 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2825 glColor3ub(80,80,80);
2827 if (ob->flag & OB_FROMGROUP)
2828 UI_ThemeColor(TH_GROUP);
2830 if(ob->dtx & OB_DRAWWIRE && flag==DRAW_CONSTCOLOR)
2831 glColor3ub(80,80,80);
2833 UI_ThemeColor(TH_WIRE);
2839 /* When using wireframe object traw in particle edit mode
2840 * the mesh gets in the way of seeing the particles, fade the wire color
2841 * with the background. */
2842 if(ob==OBACT && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
2843 float col_wire[4], col_bg[4], col[3];
2845 UI_GetThemeColor3fv(TH_BACK, col_bg);
2846 glGetFloatv(GL_CURRENT_COLOR, col_wire);
2847 interp_v3_v3v3(col, col_bg, col_wire, 0.15);
2851 /* If drawing wire and drawtype is not OB_WIRE then we are
2852 * overlaying the wires.
2854 * UPDATE bug #10290 - With this wire-only objects can draw
2855 * behind other objects depending on their order in the scene. 2x if 0's below. undo'ing zr's commit: r4059
2857 * if draw wire is 1 then just drawing wire, no need for depth buffer stuff,
2858 * otherwise this wire is to overlay solid mode faces so do some depth buffer tricks.
2860 if (dt!=OB_WIRE && draw_wire==2) {
2861 bglPolygonOffset(rv3d->dist, 1.0);
2862 glDepthMask(0); // disable write in zbuffer, selected edge wires show better
2865 if((v3d->flag2 & V3D_RENDER_OVERRIDE && v3d->drawtype >= OB_SOLID)==0)
2866 dm->drawEdges(dm, (dt==OB_WIRE || totface==0), me->drawflag & ME_ALLEDGES);
2868 if (dt!=OB_WIRE && draw_wire==2) {
2870 bglPolygonOffset(rv3d->dist, 0.0);
2874 if(paint_vertsel_test(ob) && dm->drawSelectedVerts) {
2875 glColor3f(0.0f, 0.0f, 0.0f);
2876 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
2877 dm->drawSelectedVerts(dm);
2883 /* returns 1 if nothing was drawn, for detecting to draw an object center */
2884 static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
2886 Object *ob= base->object;
2887 Object *obedit= scene->obedit;
2889 EditMesh *em= me->edit_mesh;
2890 int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha;
2892 if(obedit && ob!=obedit && ob->data==obedit->data) {
2893 if(ob_get_key(ob) || ob_get_key(obedit));
2894 else if(ob->modifiers.first || obedit->modifiers.first);
2898 if(ob==obedit || drawlinked) {
2899 DerivedMesh *finalDM, *cageDM;
2902 finalDM = cageDM = editmesh_get_derived_base(ob, em);
2904 cageDM = editmesh_get_derived_cage_and_final(scene, ob, em, &finalDM,
2905 scene->customdata_mask);
2908 // no transp in editmode, the fancy draw over goes bad then
2909 glsl = draw_glsl_material(scene, ob, v3d, dt);
2910 GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
2913 draw_em_fancy(scene, v3d, rv3d, ob, em, cageDM, finalDM, dt);
2915 GPU_end_object_materials();
2917 if (obedit!=ob && finalDM)
2918 finalDM->release(finalDM);
2921 /* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */
2922 if(me->totface<=4 || ED_view3d_boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) {
2923 glsl = draw_glsl_material(scene, ob, v3d, dt);
2924 check_alpha = check_material_alpha(base, me, glsl);
2926 if(dt==OB_SOLID || glsl) {
2927 GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl,
2928 (check_alpha)? &do_alpha_pass: NULL);
2931 draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, flag);
2933 GPU_end_object_materials();
2935 if(me->totvert==0) retval= 1;
2939 /* GPU_begin_object_materials checked if this is needed */
2941 if(ob->dtx & OB_DRAWXRAY) {
2942 add_view3d_after(&v3d->afterdraw_xraytransp, base, flag);
2945 add_view3d_after(&v3d->afterdraw_transp, base, flag);
2948 else if(ob->dtx & OB_DRAWXRAY && ob->dtx & OB_DRAWTRANSP) {
2949 /* special case xray+transp when alpha is 1.0, without this the object vanishes */
2950 if(v3d->xray == 0 && v3d->transp == 0) {
2951 add_view3d_after(&v3d->afterdraw_xray, base, flag);
2958 /* ************** DRAW DISPLIST ****************** */
2960 static int draw_index_wire= 1;
2961 static int index3_nors_incr= 1;
2963 /* returns 1 when nothing was drawn */
2964 static int drawDispListwire(ListBase *dlbase)
2970 if(dlbase==NULL) return 1;
2972 glEnableClientState(GL_VERTEX_ARRAY);
2973 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2975 for(dl= dlbase->first; dl; dl= dl->next) {
2976 if(dl->parts==0 || dl->nr==0)
2984 glVertexPointer(3, GL_FLOAT, 0, data);
2986 for(parts=0; parts<dl->parts; parts++)
2987 glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr);
2992 glVertexPointer(3, GL_FLOAT, 0, data);
2994 for(parts=0; parts<dl->parts; parts++)
2995 glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr);
3000 glVertexPointer(3, GL_FLOAT, 0, data);
3002 for(parts=0; parts<dl->parts; parts++) {
3003 if(dl->flag & DL_CYCL_U)
3004 glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr);
3006 glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr);
3009 for(nr=0; nr<dl->nr; nr++) {
3012 data= ( dl->verts )+3*nr;
3015 if(dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP);
3016 else glBegin(GL_LINE_STRIP);
3024 /* (ton) this code crashes for me when resolv is 86 or higher... no clue */
3025 // glVertexPointer(3, GL_FLOAT, sizeof(float)*3*dl->nr, data + 3*nr);
3026 // if(dl->flag & DL_CYCL_V)
3027 // glDrawArrays(GL_LINE_LOOP, 0, dl->parts);
3029 // glDrawArrays(GL_LINE_STRIP, 0, dl->parts);
3034 if(draw_index_wire) {
3035 glVertexPointer(3, GL_FLOAT, 0, dl->verts);
3036 glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index);
3041 if(draw_index_wire) {
3042 glVertexPointer(3, GL_FLOAT, 0, dl->verts);
3043 glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index);
3049 glDisableClientState(GL_VERTEX_ARRAY);
3050 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3055 static void drawDispListsolid(ListBase *lb, Object *ob, int glsl)
3058 GPUVertexAttribs gattribs;
3059 float *data, curcol[4];
3062 if(lb==NULL) return;
3064 /* for drawing wire */
3065 glGetFloatv(GL_CURRENT_COLOR, curcol);
3067 glEnable(GL_LIGHTING);
3068 glEnableClientState(GL_VERTEX_ARRAY);
3070 if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
3071 else glFrontFace(GL_CCW);
3073 if(ob->type==OB_MBALL) { // mball always smooth shaded
3074 glShadeModel(GL_SMOOTH);
3084 if(ob->type==OB_SURF) {