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_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_edgehash.h"
57 #include "BLI_utildefines.h"
59 #include "BKE_anim.h" //for the where_on_path function
60 #include "BKE_constraint.h" // for the get_constraint_target function
61 #include "BKE_curve.h"
62 #include "BKE_DerivedMesh.h"
63 #include "BKE_deform.h"
64 #include "BKE_displist.h"
66 #include "BKE_global.h"
67 #include "BKE_image.h"
69 #include "BKE_lattice.h"
71 #include "BKE_material.h"
72 #include "BKE_mball.h"
73 #include "BKE_modifier.h"
74 #include "BKE_object.h"
75 #include "BKE_paint.h"
76 #include "BKE_particle.h"
77 #include "BKE_pointcache.h"
81 #include "smoke_API.h"
83 #include "IMB_imbuf.h"
84 #include "IMB_imbuf_types.h"
87 #include "BIF_glutil.h"
89 #include "GPU_buffers.h"// Jason
91 #include "GPU_extensions.h"
94 #include "ED_particle.h"
95 #include "ED_screen.h"
96 #include "ED_sculpt.h"
98 #include "ED_curve.h" /* for curve_editnurbs */
100 #include "UI_resources.h"
103 #include "wm_subwindow.h"
106 #include "view3d_intern.h" // own include
109 /* this condition has been made more complex since editmode can draw textures */
110 #define CHECK_OB_DRAWTEXTURE(vd, dt) \
111 ((vd->drawtype==OB_TEXTURE && dt>OB_SOLID) || \
112 (vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX))
114 static void draw_bounding_volume(Scene *scene, Object *ob);
116 static void drawcube_size(float size);
117 static void drawcircle_size(float size);
118 static void draw_empty_sphere(float size);
119 static void draw_empty_cone(float size);
121 static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
123 if((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
126 if(G.f & G_BACKBUFSEL)
129 if((vd->flag & V3D_ZBUF_SELECT) == 0)
132 /* if its drawing textures with zbuf sel, then dont draw dots */
133 if(dt==OB_TEXTURE && vd->drawtype==OB_TEXTURE)
136 if(vd->drawtype>=OB_SOLID && vd->flag2 & V3D_SOLID_TEX)
142 /* ************* only use while object drawing **************
143 * or after running ED_view3d_init_mats_rv3d
145 static void view3d_project_short_clip(ARegion *ar, const float vec[3], short *adr, int local)
147 RegionView3D *rv3d= ar->regiondata;
148 float fx, fy, vec4[4];
152 /* clipplanes in eye space */
153 if(rv3d->rflag & RV3D_CLIPPING) {
154 if(ED_view3d_test_clipping(rv3d, vec, local))
158 copy_v3_v3(vec4, vec);
161 mul_m4_v4(rv3d->persmatob, vec4);
163 /* clipplanes in window space */
164 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
165 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
167 if( fx>0 && fx<ar->winx) {
169 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
171 if(fy > 0.0f && fy < (float)ar->winy) {
172 adr[0]= (short)floorf(fx);
173 adr[1]= (short)floorf(fy);
179 /* only use while object drawing */
180 static void view3d_project_short_noclip(ARegion *ar, const float vec[3], short *adr)
182 RegionView3D *rv3d= ar->regiondata;
183 float fx, fy, vec4[4];
187 copy_v3_v3(vec4, vec);
190 mul_m4_v4(rv3d->persmatob, vec4);
192 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
193 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
195 if( fx>-32700 && fx<32700) {
197 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
199 if(fy > -32700.0f && fy < 32700.0f) {
200 adr[0]= (short)floorf(fx);
201 adr[1]= (short)floorf(fy);
207 /* ************************ */
209 /* check for glsl drawing */
211 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
213 if(!GPU_glsl_support())
217 if(!CHECK_OB_DRAWTEXTURE(v3d, dt))
219 if(ob==OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
222 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
225 static int check_material_alpha(Base *base, Mesh *me, int glsl)
227 if(base->flag & OB_FROMDUPLI)
236 return (glsl || (base->object->dtx & OB_DRAWTRANSP));
240 static unsigned int colortab[24]=
241 {0x0, 0xFF88FF, 0xFFBBFF,
242 0x403000, 0xFFFF88, 0xFFFFBB,
243 0x104040, 0x66CCCC, 0x77CCCC,
244 0x104010, 0x55BB55, 0x66FF66,
249 static float cube[8][3] = {
260 /* ----------------- OpenGL Circle Drawing - Tables for Optimised Drawing Speed ------------------ */
261 /* 32 values of sin function (still same result!) */
262 static float sinval[32] = {
297 /* 32 values of cos function (still same result!) */
298 static float cosval[32] ={
333 static void draw_xyz_wire(const float c[3], float size, int axis)
335 float v1[3]= {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
336 float dim = size * 0.1f;
337 float dx[3], dy[3], dz[3];
339 dx[0]=dim; dx[1]=0.f; dx[2]=0.f;
340 dy[0]=0.f; dy[1]=dim; dy[2]=0.f;
341 dz[0]=0.f; dz[1]=0.f; dz[2]=dim;
347 /* bottom left to top right */
348 sub_v3_v3v3(v1, c, dx);
350 add_v3_v3v3(v2, c, dx);
356 /* top left to bottom right */
369 /* bottom left to top right */
370 mul_v3_fl(dx, 0.75f);
371 sub_v3_v3v3(v1, c, dx);
373 add_v3_v3v3(v2, c, dx);
379 /* top left to center */
390 glBegin(GL_LINE_STRIP);
392 /* start at top left */
393 sub_v3_v3v3(v1, c, dx);
394 add_v3_v3v3(v1, c, dz);
419 void drawaxes(float size, char drawtype)
422 float v1[3]= {0.0, 0.0, 0.0};
423 float v2[3]= {0.0, 0.0, 0.0};
424 float v3[3]= {0.0, 0.0, 0.0};
429 for (axis=0; axis<3; axis++) {
437 /* reset v1 & v2 to zero */
438 v1[axis]= v2[axis]= 0.0f;
443 case OB_SINGLE_ARROW:
446 /* in positive z direction only */
453 glBegin(GL_TRIANGLES);
455 v2[0]= size * 0.035f; v2[1] = size * 0.035f;
456 v3[0]= size * -0.035f; v3[1] = size * 0.035f;
457 v2[2]= v3[2]= size * 0.75f;
459 for (axis=0; axis<4; axis++) {
481 drawcircle_size(size);
484 case OB_EMPTY_SPHERE:
485 draw_empty_sphere(size);
489 draw_empty_cone(size);
494 for (axis=0; axis<3; axis++) {
495 const int arrow_axis= (axis==0) ? 1:0;
503 v1[axis]= size*0.85f;
504 v1[arrow_axis]= -size*0.08f;
508 v1[arrow_axis]= size*0.08f;
514 v2[axis]+= size*0.125f;
516 draw_xyz_wire(v2, size, axis);
519 /* reset v1 & v2 to zero */
520 v1[arrow_axis]= v1[axis]= v2[axis]= 0.0f;
527 /* Function to draw an Image on a empty Object */
528 static void draw_empty_image(Object *ob)
530 Image *ima = (Image*)ob->data;
531 ImBuf *ibuf = ima ? BKE_image_get_ibuf(ima, NULL) : NULL;
533 float scale, ofs_x, ofs_y, sca_x, sca_y;
536 if(ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
537 IMB_rect_from_float(ibuf);
540 /* Get the buffer dimensions so we can fallback to fake ones */
541 if(ibuf && ibuf->rect) {
550 /* Get the image aspect even if the buffer is invalid */
552 if(ima->aspx > ima->aspy) {
554 sca_y= ima->aspy / ima->aspx;
556 else if(ima->aspx < ima->aspy) {
557 sca_x= ima->aspx / ima->aspy;
570 /* Calculate the scale center based on objects origin */
571 ofs_x= ob->ima_ofs[0] * ima_x;
572 ofs_y= ob->ima_ofs[1] * ima_y;
574 glMatrixMode(GL_MODELVIEW);
577 /* Make sure we are drawing at the origin */
578 glTranslatef(0.0f, 0.0f, 0.0f);
580 /* Calculate Image scale */
581 scale= (ob->empty_drawsize / (float)MAX2(ima_x * sca_x, ima_y * sca_y));
583 /* Set the object scale */
584 glScalef(scale * sca_x, scale * sca_y, 1.0f);
586 if(ibuf && ibuf->rect) {
587 /* Setup GL params */
589 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
591 /* Use the object color and alpha */
594 /* Draw the Image on the screen */
595 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
596 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
601 UI_ThemeColor((ob->flag & SELECT) ? TH_SELECT : TH_WIRE);
603 /* Calculate the outline vertex positions */
604 glBegin(GL_LINE_LOOP);
605 glVertex2f(ofs_x, ofs_y);
606 glVertex2f(ofs_x + ima_x, ofs_y);
607 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
608 glVertex2f(ofs_x, ofs_y + ima_y);
611 /* Reset GL settings */
612 glMatrixMode(GL_MODELVIEW);
616 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
618 float vec[3], vx[3], vy[3];
621 mul_v3_v3fl(vx, tmat[0], rad);
622 mul_v3_v3fl(vy, tmat[1], rad);
625 for(a=0; a<tot; a++) {
626 vec[0]= cent[0] + *(sinval+a) * vx[0] + *(cosval+a) * vy[0];
627 vec[1]= cent[1] + *(sinval+a) * vx[1] + *(cosval+a) * vy[1];
628 vec[2]= cent[2] + *(sinval+a) * vx[2] + *(cosval+a) * vy[2];
634 /* circle for object centers, special_color is for library or ob users */
635 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
637 const float size= ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
639 /* using gldepthfunc guarantees that it does write z values, but not checks for it, so centers remain visible independt order of drawing */
640 if(v3d->zbuf) glDepthFunc(GL_ALWAYS);
644 if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
646 else glColor4ub(0x55, 0xCC, 0xCC, 155);
649 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
650 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
651 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
653 drawcircball(GL_POLYGON, co, size, rv3d->viewinv);
655 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
656 drawcircball(GL_LINE_LOOP, co, size, rv3d->viewinv);
659 if(v3d->zbuf) glDepthFunc(GL_LEQUAL);
662 /* *********** text drawing for object/particles/armature ************* */
663 static ListBase CachedText[3];
664 static int CachedTextLevel= 0;
666 typedef struct ViewCachedString {
667 struct ViewCachedString *next, *prev;
677 /* str is allocated past the end */
680 void view3d_cached_text_draw_begin(void)
682 ListBase *strings= &CachedText[CachedTextLevel];
683 strings->first= strings->last= NULL;
687 void view3d_cached_text_draw_add(const float co[3], const char *str, short xoffs, short flag, const unsigned char col[4])
689 int alloc_len= strlen(str) + 1;
690 ListBase *strings= &CachedText[CachedTextLevel-1];
691 ViewCachedString *vos= MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
693 BLI_addtail(strings, vos);
694 copy_v3_v3(vos->vec, co);
695 vos->col.pack= *((int *)col);
698 vos->str_len= alloc_len-1;
700 /* allocate past the end */
701 memcpy(++vos, str, alloc_len);
704 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
706 RegionView3D *rv3d= ar->regiondata;
707 ListBase *strings= &CachedText[CachedTextLevel-1];
708 ViewCachedString *vos;
711 /* project first and test */
712 for(vos= strings->first; vos; vos= vos->next) {
713 if(mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
714 mul_m4_v3(mat, vos->vec);
715 view3d_project_short_clip(ar, vos->vec, vos->sco, 0);
716 if(vos->sco[0]!=IS_CLIPPED)
721 int col_pack_prev= 0;
724 bglMats mats; /* ZBuffer depth vars */
731 if(rv3d->rflag & RV3D_CLIPPING)
733 glDisable(GL_CLIP_PLANE0+a);
735 glMatrixMode(GL_PROJECTION);
737 glMatrixMode(GL_MODELVIEW);
739 ED_region_pixelspace(ar);
742 if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
746 for(vos= strings->first; vos; vos= vos->next) {
747 #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
748 if(v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
749 gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
750 glReadPixels(ar->winrct.xmin+vos->mval[0]+vos->xoffs, ar->winrct.ymin+vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
756 if(vos->sco[0]!=IS_CLIPPED) {
757 const char *str= (char *)(vos+1);
759 if(col_pack_prev != vos->col.pack) {
760 glColor3ubv(vos->col.ub);
761 col_pack_prev= vos->col.pack;
763 if(vos->flag & V3D_CACHE_TEXT_ASCII) {
764 BLF_draw_default_ascii((float)vos->sco[0]+vos->xoffs, (float)vos->sco[1], (depth_write)? 0.0f: 2.0f, str, vos->str_len);
767 BLF_draw_default((float)vos->sco[0]+vos->xoffs, (float)vos->sco[1], (depth_write)? 0.0f: 2.0f, str, vos->str_len);
773 if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
777 glMatrixMode(GL_PROJECTION);
779 glMatrixMode(GL_MODELVIEW);
782 if(rv3d->rflag & RV3D_CLIPPING)
784 glEnable(GL_CLIP_PLANE0+a);
788 BLI_freelistN(strings);
793 /* ******************** primitive drawing ******************* */
795 static void drawcube(void)
798 glBegin(GL_LINE_STRIP);
799 glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
800 glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
801 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
804 glBegin(GL_LINE_STRIP);
805 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
808 glBegin(GL_LINE_STRIP);
809 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
812 glBegin(GL_LINE_STRIP);
813 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
817 /* draws a cube on given the scaling of the cube, assuming that
818 * all required matrices have been set (used for drawing empties)
820 static void drawcube_size(float size)
822 glBegin(GL_LINE_STRIP);
823 glVertex3f(-size,-size,-size); glVertex3f(-size,-size,size);glVertex3f(-size,size,size); glVertex3f(-size,size,-size);
824 glVertex3f(-size,-size,-size); glVertex3f(size,-size,-size);glVertex3f(size,-size,size); glVertex3f(size,size,size);
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);
836 glBegin(GL_LINE_STRIP);
837 glVertex3f(-size,size,-size); glVertex3f(size,size,-size);
841 /* this is an unused (old) cube-drawing function based on a given size */
843 static void drawcube_size(const float size[3])
847 glScalef(size[0], size[1], size[2]);
850 glBegin(GL_LINE_STRIP);
851 glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
852 glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
853 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
856 glBegin(GL_LINE_STRIP);
857 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
860 glBegin(GL_LINE_STRIP);
861 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
864 glBegin(GL_LINE_STRIP);
865 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
872 static void drawshadbuflimits(Lamp *la, float mat[][4])
874 float sta[3], end[3], lavec[3];
876 negate_v3_v3(lavec, mat[2]);
879 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
880 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
882 glBegin(GL_LINE_STRIP);
897 static void spotvolume(float lvec[3], float vvec[3], const float inp)
899 /* camera is at 0,0,0 */
900 float temp[3],plane[3],mat1[3][3],mat2[3][3],mat3[3][3],mat4[3][3],q[4],co,si,angle;
903 normalize_v3(vvec); /* is this the correct vector ? */
905 cross_v3_v3v3(temp,vvec,lvec); /* equation for a plane through vvec en lvec */
906 cross_v3_v3v3(plane,lvec,temp); /* a plane perpendicular to this, parrallel with lvec */
908 /* vectors are exactly aligned, use the X axis, this is arbitrary */
909 if(normalize_v3(plane) == 0.0f)
912 /* now we've got two equations: one of a cone and one of a plane, but we have
913 three unknowns. We remove one unkown by rotating the plane to z=0 (the plane normal) */
915 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
916 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
918 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
925 angle = saacos(plane[2])/2.0f;
934 quat_to_mat3(mat1,q);
936 /* rotate lamp vector now over acos(inp) degrees */
937 copy_v3_v3(vvec, lvec);
941 si = sqrtf(1.0f-inp*inp);
947 mul_m3_m3m3(mat3,mat2,mat1);
951 mul_m3_m3m3(mat4,mat2,mat1);
954 mul_m3_m3m3(mat2,mat1,mat3);
955 mul_m3_v3(mat2,lvec);
956 mul_m3_m3m3(mat2,mat1,mat4);
957 mul_m3_v3(mat2,vvec);
962 static void draw_spot_cone(Lamp *la, float x, float z)
966 glBegin(GL_TRIANGLE_FAN);
967 glVertex3f(0.0f, 0.0f, -x);
969 if(la->mode & LA_SQUARE) {
971 glVertex3f(-z, z, 0);
972 glVertex3f(-z, -z, 0);
973 glVertex3f(z, -z, 0);
980 for(a=0; a<33; a++) {
981 angle= a*M_PI*2/(33-1);
982 glVertex3f(z*cosf(angle), z*sinf(angle), 0);
989 static void draw_transp_spot_volume(Lamp *la, float x, float z)
991 glEnable(GL_CULL_FACE);
995 /* draw backside darkening */
996 glCullFace(GL_FRONT);
998 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
999 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1001 draw_spot_cone(la, x, z);
1003 /* draw front side lighting */
1004 glCullFace(GL_BACK);
1006 glBlendFunc(GL_ONE, GL_ONE);
1007 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1009 draw_spot_cone(la, x, z);
1012 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1013 glDisable(GL_BLEND);
1015 glDisable(GL_CULL_FACE);
1016 glCullFace(GL_BACK);
1019 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
1021 Object *ob= base->object;
1022 const float pixsize= ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1024 float vec[3], lvec[3], vvec[3], circrad, x,y,z;
1026 float imat[4][4], curcol[4];
1027 unsigned char col[4];
1028 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1029 /* the moment of view3d_draw_transp() call */
1030 const short is_view= (rv3d->persp==RV3D_CAMOB && v3d->camera == base->object);
1031 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);
1033 if(drawcone && !v3d->transp) {
1034 /* in this case we need to draw delayed */
1035 add_view3d_after(&v3d->afterdraw_transp, base, flag);
1039 /* we first draw only the screen aligned & fixed scale stuff */
1041 glLoadMatrixf(rv3d->viewmat);
1043 /* lets calculate the scale: */
1044 lampsize= pixsize*((float)U.obcenter_dia*0.5f);
1046 /* and view aligned matrix: */
1047 copy_m4_m4(imat, rv3d->viewinv);
1048 normalize_v3(imat[0]);
1049 normalize_v3(imat[1]);
1052 copy_v3_v3(vec, ob->obmat[3]);
1054 /* for AA effects */
1055 glGetFloatv(GL_CURRENT_COLOR, curcol);
1059 if(lampsize > 0.0f) {
1062 if (ob==OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1063 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1068 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1069 glDisable(GL_BLEND);
1070 drawcircball(GL_POLYGON, vec, lampsize, imat);
1077 circrad = 3.0f*lampsize;
1080 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1082 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1083 if(la->type!=LA_HEMI) {
1084 if( (la->mode & LA_SHAD_RAY) ||
1085 ((la->mode & LA_SHAD_BUF) && (la->type==LA_SPOT))
1087 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f*pixsize, imat);
1096 /* draw the pretty sun rays */
1097 if(la->type==LA_SUN) {
1098 float v1[3], v2[3], mat[3][3];
1101 /* setup a 45 degree rotation matrix */
1102 vec_rot_to_mat3(mat, imat[2], (float)M_PI/4.0f);
1105 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1106 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1109 glTranslatef(vec[0], vec[1], vec[2]);
1114 for (axis=0; axis<8; axis++) {
1122 glTranslatef(-vec[0], -vec[1], -vec[2]);
1126 if (la->type==LA_LOCAL) {
1127 if(la->mode & LA_SPHERE) {
1128 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1130 /* yafray: for photonlight also draw lightcone as for spot */
1133 glPopMatrix(); /* back in object space */
1137 /* skip drawing extra info */
1139 else if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) {
1140 lvec[0]=lvec[1]= 0.0;
1142 x = rv3d->persmat[0][2];
1143 y = rv3d->persmat[1][2];
1144 z = rv3d->persmat[2][2];
1145 vvec[0]= x*ob->obmat[0][0] + y*ob->obmat[0][1] + z*ob->obmat[0][2];
1146 vvec[1]= x*ob->obmat[1][0] + y*ob->obmat[1][1] + z*ob->obmat[1][2];
1147 vvec[2]= x*ob->obmat[2][0] + y*ob->obmat[2][1] + z*ob->obmat[2][2];
1149 y = cosf(la->spotsize*(float)(M_PI/360.0));
1150 spotvolume(lvec, vvec, y);
1155 /* draw the angled sides of the cone */
1156 glBegin(GL_LINE_STRIP);
1162 z = x*sqrtf(1.0f - y*y);
1165 /* draw the circle/square at the end of the cone */
1166 glTranslatef(0.0, 0.0 , x);
1167 if(la->mode & LA_SQUARE) {
1169 float z_abs= fabs(z);
1171 tvec[0]= tvec[1]= z_abs;
1174 glBegin(GL_LINE_LOOP);
1176 tvec[1]= -z_abs; /* neg */
1178 tvec[0]= -z_abs; /* neg */
1180 tvec[1]= z_abs; /* pos */
1184 else circ(0.0, 0.0, fabsf(z));
1186 /* draw the circle/square representing spotbl */
1187 if(la->type==LA_SPOT) {
1188 float spotblcirc = fabs(z)*(1 - pow(la->spotblend, 2));
1189 /* hide line if it is zero size or overlaps with outer border,
1190 previously it adjusted to always to show it but that seems
1191 confusing because it doesn't show the actual blend size */
1192 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1193 circ(0.0, 0.0, spotblcirc);
1197 draw_transp_spot_volume(la, x, z);
1199 /* draw clip start, useful for wide cones where its not obvious where the start is */
1200 glTranslatef(0.0, 0.0 , -x); /* reverse translation above */
1201 if(la->type==LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1204 float clipsta_fac= la->clipsta / -x;
1206 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1207 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1209 glBegin(GL_LINE_STRIP);
1210 glVertex3fv(lvec_clip);
1211 glVertex3fv(vvec_clip);
1215 else if ELEM(la->type, LA_HEMI, LA_SUN) {
1217 /* draw the line from the circle along the dist */
1218 glBegin(GL_LINE_STRIP);
1225 if(la->type==LA_HEMI) {
1226 /* draw the hemisphere curves */
1227 short axis, steps, dir;
1228 float outdist, zdist, mul;
1230 outdist = 0.14; mul = 1.4; dir = 1;
1233 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1234 for (axis=0; axis<4; axis++) {
1235 float v[3]= {0.0, 0.0, 0.0};
1238 glBegin(GL_LINE_STRIP);
1240 for (steps=0; steps<6; steps++) {
1241 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1242 /* make the arcs start at the edge of the energy circle */
1243 if (steps == 0) v[0] = dir*circrad;
1244 else v[0] = v[0] + dir*(steps*outdist);
1245 } else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1246 /* make the arcs start at the edge of the energy circle */
1247 if (steps == 0) v[1] = dir*circrad;
1248 else v[1] = v[1] + dir*(steps*outdist);
1251 v[2] = v[2] - steps*zdist;
1255 zdist = zdist * mul;
1259 /* flip the direction */
1263 } else if(la->type==LA_AREA) {
1265 if(la->area_shape==LA_AREA_SQUARE)
1266 fdrawbox(-la->area_size*0.5f, -la->area_size*0.5f, la->area_size*0.5f, la->area_size*0.5f);
1267 else if(la->area_shape==LA_AREA_RECT)
1268 fdrawbox(-la->area_size*0.5f, -la->area_sizey*0.5f, la->area_size*0.5f, la->area_sizey*0.5f);
1270 glBegin(GL_LINE_STRIP);
1271 glVertex3f(0.0,0.0,-circrad);
1272 glVertex3f(0.0,0.0,-la->dist);
1276 /* and back to viewspace */
1277 glLoadMatrixf(rv3d->viewmat);
1278 copy_v3_v3(vec, ob->obmat[3]);
1282 if((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == FALSE)) {
1283 drawshadbuflimits(la, ob->obmat);
1286 UI_GetThemeColor4ubv(TH_LAMP, col);
1291 if (vec[2]>0) vec[2] -= circrad;
1292 else vec[2] += circrad;
1294 glBegin(GL_LINE_STRIP);
1306 glDisable(GL_BLEND);
1308 /* restore for drawing extra stuff */
1313 static void draw_limit_line(float sta, float end, unsigned int col)
1316 glVertex3f(0.0, 0.0, -sta);
1317 glVertex3f(0.0, 0.0, -end);
1323 glVertex3f(0.0, 0.0, -sta);
1324 glVertex3f(0.0, 0.0, -end);
1330 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1331 /* qdn: now also enabled for Blender to set focus point for defocus composit node */
1332 static void draw_focus_cross(float dist, float size)
1335 glVertex3f(-size, 0.f, -dist);
1336 glVertex3f(size, 0.f, -dist);
1337 glVertex3f(0.f, -size, -dist);
1338 glVertex3f(0.f, size, -dist);
1342 #ifdef VIEW3D_CAMERA_BORDER_HACK
1343 float view3d_camera_border_hack_col[4];
1344 short view3d_camera_border_hack_test= FALSE;
1347 /* flag similar to draw_object() */
1348 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int flag)
1350 /* a standing up pyramid with (0,0,0) as top */
1352 float vec[8][4], facx, facy, depth, aspx, aspy, caspx, caspy, shx, shy;
1355 const short is_view= (rv3d->persp==RV3D_CAMOB && ob==v3d->camera);
1357 const float scax= 1.0f / len_v3(ob->obmat[0]);
1358 const float scay= 1.0f / len_v3(ob->obmat[1]);
1359 const float scaz= 1.0f / len_v3(ob->obmat[2]);
1361 #ifdef VIEW3D_CAMERA_BORDER_HACK
1362 if(is_view && !(G.f & G_PICKSEL)) {
1363 glGetFloatv(GL_CURRENT_COLOR, view3d_camera_border_hack_col);
1364 view3d_camera_border_hack_test= TRUE;
1370 aspx= (float) scene->r.xsch*scene->r.xasp;
1371 aspy= (float) scene->r.ysch*scene->r.yasp;
1382 glDisable(GL_LIGHTING);
1383 glDisable(GL_CULL_FACE);
1385 if(cam->type==CAM_ORTHO) {
1386 facx= 0.5f * cam->ortho_scale * caspx * scax;
1387 facy= 0.5f * cam->ortho_scale * caspy * scay;
1388 shx= cam->shiftx * cam->ortho_scale * scax;
1389 shy= cam->shifty * cam->ortho_scale * scay;
1390 depth= is_view ? -((cam->clipsta * scaz) + 0.1f) : - cam->drawsize * cam->ortho_scale * scaz;
1392 drawsize= 0.5f * cam->ortho_scale;
1395 /* that way it's always visible - clipsta+0.1 */
1397 drawsize= cam->drawsize / ((scax + scay + scaz) / 3.0f);
1400 /* fixed depth, variable size (avoids exceeding clipping range) */
1401 depth = -(cam->clipsta + 0.1f);
1402 fac = depth / (cam->lens/-16.0f * scaz);
1405 /* fixed size, variable depth (stays a reasonable size in the 3D view) */
1406 depth= drawsize * cam->lens/-16.0f * scaz;
1410 facx= fac * caspx * scax;
1411 facy= fac * caspy * scay;
1412 shx= cam->shiftx*fac*2 * scax;
1413 shy= cam->shifty*fac*2 * scay;
1416 vec[0][0]= 0.0; vec[0][1]= 0.0; vec[0][2]= 0.0;
1417 vec[1][0]= shx + facx; vec[1][1]= shy + facy; vec[1][2]= depth;
1418 vec[2][0]= shx + facx; vec[2][1]= shy - facy; vec[2][2]= depth;
1419 vec[3][0]= shx - facx; vec[3][1]= shy - facy; vec[3][2]= depth;
1420 vec[4][0]= shx - facx; vec[4][1]= shy + facy; vec[4][2]= depth;
1423 glBegin(GL_LINE_LOOP);
1424 glVertex3fv(vec[1]);
1425 glVertex3fv(vec[2]);
1426 glVertex3fv(vec[3]);
1427 glVertex3fv(vec[4]);
1433 /* center point to camera frame */
1434 glBegin(GL_LINE_STRIP);
1435 glVertex3fv(vec[2]);
1436 glVertex3fv(vec[0]);
1437 glVertex3fv(vec[1]);
1438 glVertex3fv(vec[4]);
1439 glVertex3fv(vec[0]);
1440 glVertex3fv(vec[3]);
1448 /* draw an outline arrow for inactive cameras and filled
1449 * for active cameras. We actually draw both outline+filled
1450 * for active cameras so the wire can be seen side-on */
1452 if (i==0) glBegin(GL_LINE_LOOP);
1453 else if (i==1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1456 vec[0][0]= shx + ((-0.7f * drawsize) * scax);
1457 vec[0][1]= shy + ((drawsize * (caspy + 0.1f)) * scay);
1458 glVertex3fv(vec[0]); /* left */
1460 vec[0][0]= shx + ((0.7f * drawsize) * scax);
1461 glVertex3fv(vec[0]); /* right */
1464 vec[0][1]= shy + ((1.1f * drawsize * (caspy + 0.7f)) * scay);
1465 glVertex3fv(vec[0]); /* top */
1471 if(cam->flag & (CAM_SHOWLIMITS+CAM_SHOWMIST)) {
1475 /* draw in normalized object matrix space */
1476 copy_m4_m4(nobmat, ob->obmat);
1477 normalize_m4(nobmat);
1480 glLoadMatrixf(rv3d->viewmat);
1481 glMultMatrixf(nobmat);
1483 if(cam->flag & CAM_SHOWLIMITS) {
1484 draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
1485 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composit node */
1486 draw_focus_cross(dof_camera(ob), cam->drawsize);
1490 if(cam->flag & CAM_SHOWMIST)
1491 if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF);
1498 /* flag similar to draw_object() */
1499 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d), Object *UNUSED(ob), int UNUSED(flag))
1501 //Speaker *spk = ob->data;
1508 for(j = 0; j < 3; j++) {
1509 vec[2] = 0.25f * j -0.125f;
1511 glBegin(GL_LINE_LOOP);
1512 for(i = 0; i < 16; i++) {
1513 vec[0] = cosf(M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1514 vec[1] = sinf(M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1520 for(j = 0; j < 4; j++) {
1521 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1522 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1523 glBegin(GL_LINE_STRIP);
1524 for(i = 0; i < 3; i++) {
1530 vec[2] = 0.25f * i -0.125f;
1536 glDisable(GL_BLEND);
1539 static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
1541 BPoint *bp = lt->def;
1542 float *co = dl?dl->verts:NULL;
1545 UI_ThemeColor(sel?TH_VERTEX_SELECT:TH_VERTEX);
1546 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1547 bglBegin(GL_POINTS);
1549 for(w=0; w<lt->pntsw; w++) {
1550 int wxt = (w==0 || w==lt->pntsw-1);
1551 for(v=0; v<lt->pntsv; v++) {
1552 int vxt = (v==0 || v==lt->pntsv-1);
1553 for(u=0; u<lt->pntsu; u++, bp++, co+=3) {
1554 int uxt = (u==0 || u==lt->pntsu-1);
1555 if(!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1557 if((bp->f1 & SELECT)==sel) {
1558 bglVertex3fv(dl?co:bp->vec);
1570 void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPoint *bp, int x, int y), void *userData)
1572 Object *obedit= vc->obedit;
1573 Lattice *lt= obedit->data;
1574 BPoint *bp = lt->editlatt->latt->def;
1575 DispList *dl = find_displist(&obedit->disp, DL_VERTS);
1576 float *co = dl?dl->verts:NULL;
1577 int i, N = lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
1578 short s[2] = {IS_CLIPPED, 0};
1580 ED_view3d_local_clipping(vc->rv3d, obedit->obmat); /* for local clipping lookups */
1582 for (i=0; i<N; i++, bp++, co+=3) {
1584 view3d_project_short_clip(vc->ar, dl?co:bp->vec, s, 1);
1585 if (s[0] != IS_CLIPPED)
1586 func(userData, bp, s[0], s[1]);
1591 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
1593 int index = ((w*lt->pntsv + v)*lt->pntsu) + u;
1597 MDeformWeight *mdw= defvert_find_index (lt->dvert+index, use_wcol-1);
1599 weight_to_rgb(mdw?mdw->weight:0.0f, col, col+1, col+2);
1605 glVertex3fv(&dl->verts[index*3]);
1607 glVertex3fv(lt->def[index].vec);
1611 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1612 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1614 Lattice *lt= ob->data;
1617 int use_wcol= 0, is_edit= (lt->editlatt != NULL);
1619 /* now we default make displist, this will modifiers work for non animated case */
1620 if(ob->disp.first==NULL)
1621 lattice_calc_modifiers(scene, ob);
1622 dl= find_displist(&ob->disp, DL_VERTS);
1625 lt= lt->editlatt->latt;
1629 if(ob->defbase.first && lt->dvert) {
1630 use_wcol= ob->actdef;
1631 glShadeModel(GL_SMOOTH);
1636 for(w=0; w<lt->pntsw; w++) {
1637 int wxt = (w==0 || w==lt->pntsw-1);
1638 for(v=0; v<lt->pntsv; v++) {
1639 int vxt = (v==0 || v==lt->pntsv-1);
1640 for(u=0; u<lt->pntsu; u++) {
1641 int uxt = (u==0 || u==lt->pntsu-1);
1643 if(w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
1644 drawlattice__point(lt, dl, u, v, w-1, use_wcol);
1645 drawlattice__point(lt, dl, u, v, w, use_wcol);
1647 if(v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1648 drawlattice__point(lt, dl, u, v-1, w, use_wcol);
1649 drawlattice__point(lt, dl, u, v, w, use_wcol);
1651 if(u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1652 drawlattice__point(lt, dl, u-1, v, w, use_wcol);
1653 drawlattice__point(lt, dl, u, v, w, use_wcol);
1660 /* restoration for weight colors */
1662 glShadeModel(GL_FLAT);
1665 if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
1667 lattice_draw_verts(lt, dl, 0);
1668 lattice_draw_verts(lt, dl, 1);
1670 if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
1674 /* ***************** ******************** */
1676 /* Note! - foreach funcs should be called while drawing or directly after
1677 * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
1678 * but would not give correct results with dupli's for eg. which dont
1679 * use the object matrix in the useual way */
1680 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1682 struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
1683 EditVert *eve = EM_get_vert_for_index(index);
1686 short s[2]= {IS_CLIPPED, 0};
1688 if (data->clipVerts) {
1689 view3d_project_short_clip(data->vc.ar, co, s, 1);
1691 view3d_project_short_noclip(data->vc.ar, co, s);
1694 if (s[0]!=IS_CLIPPED)
1695 data->func(data->userData, eve, s[0], s[1], index);
1699 void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts)
1701 struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data;
1702 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1706 data.userData = userData;
1707 data.clipVerts = clipVerts;
1710 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1712 EM_init_index_arrays(vc->em, 1, 0, 0);
1713 dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
1714 EM_free_index_arrays();
1719 static void mesh_obmode_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1721 struct { void (*func)(void *userData, MVert *mv, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
1722 Mesh *me = data->vc.obact->data;
1723 MVert *mv = me->mvert+index;
1724 //MVert *dmv = CDDM_get_verts(data->vc.obact->derivedFinal)+index;
1725 //MVert *mv = CDDM_get_verts(data->vc.obact->derivedFinal)+index;
1726 if ((mv->flag & ME_HIDE)==0) {
1727 short s[2]= {IS_CLIPPED, 0};
1729 if (data->clipVerts) {
1730 view3d_project_short_clip(data->vc.ar, co, s, 1);
1732 view3d_project_short_noclip(data->vc.ar, co, s);
1735 if (s[0]!=IS_CLIPPED)
1736 data->func(data->userData, mv, s[0], s[1], index);
1740 void mesh_obmode_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, MVert *mv, int x, int y, int index), void *userData, int clipVerts)
1742 struct { void (*func)(void *userData, MVert *mv, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data;
1743 DerivedMesh *dm = mesh_get_derived_final(vc->scene, vc->obact, CD_MASK_BAREMESH);
1747 data.userData = userData;
1748 data.clipVerts = clipVerts;
1751 ED_view3d_local_clipping(vc->rv3d, vc->obact->obmat); /* for local clipping lookups */
1753 dm->foreachMappedVert(dm, mesh_obmode_foreachScreenVert__mapFunc, &data);
1758 /* Jason draw callback */
1759 static void drawSelectedVertices__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
1761 MVert *mv = userData;
1763 //printf("%d\n", index);
1764 if(!(mv->flag & ME_HIDE)) {
1765 const char sel= mv->flag & 1;
1767 // TODO define selected color
1769 glColor3f(1.0f, 1.0f, 0.0f);
1771 glColor3f(0.0f, 0.0f, 0.0f);
1778 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me) {
1780 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, me->mvert);
1783 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
1785 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;
1786 EditEdge *eed = EM_get_edge_for_index(index);
1790 if (data->clipVerts==1) {
1791 view3d_project_short_clip(data->vc.ar, v0co, s[0], 1);
1792 view3d_project_short_clip(data->vc.ar, v1co, s[1], 1);
1794 view3d_project_short_noclip(data->vc.ar, v0co, s[0]);
1795 view3d_project_short_noclip(data->vc.ar, v1co, s[1]);
1797 if (data->clipVerts==2) {
1798 if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<data->vc.ar->winx && s[0][1]<data->vc.ar->winy))
1799 if (!(s[1][0]>=0 && s[1][1]>= 0 && s[1][0]<data->vc.ar->winx && s[1][1]<data->vc.ar->winy))
1804 data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index);
1808 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)
1810 struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } data;
1811 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1815 data.userData = userData;
1816 data.clipVerts = clipVerts;
1819 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1821 EM_init_index_arrays(vc->em, 0, 1, 0);
1822 dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
1823 EM_free_index_arrays();
1828 static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
1830 struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData;
1831 EditFace *efa = EM_get_face_for_index(index);
1834 if (efa && efa->h==0 && efa->fgonf!=EM_FGON) {
1835 view3d_project_short_clip(data->vc.ar, cent, s, 1);
1837 data->func(data->userData, efa, s[0], s[1], index);
1841 void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData)
1843 struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data;
1844 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1848 data.userData = userData;
1851 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1853 EM_init_index_arrays(vc->em, 0, 0, 1);
1854 dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
1855 EM_free_index_arrays();
1860 void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y), void *userData)
1862 Curve *cu= vc->obedit->data;
1863 short s[2] = {IS_CLIPPED, 0};
1866 ListBase *nurbs= curve_editnurbs(cu);
1868 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1870 for (nu= nurbs->first; nu; nu=nu->next) {
1871 if(nu->type == CU_BEZIER) {
1872 for (i=0; i<nu->pntsu; i++) {
1873 BezTriple *bezt = &nu->bezt[i];
1877 if(cu->drawflag & CU_HIDE_HANDLES) {
1878 view3d_project_short_clip(vc->ar, bezt->vec[1], s, 1);
1879 if (s[0] != IS_CLIPPED)
1880 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
1882 view3d_project_short_clip(vc->ar, bezt->vec[0], s, 1);
1883 if (s[0] != IS_CLIPPED)
1884 func(userData, nu, NULL, bezt, 0, s[0], s[1]);
1885 view3d_project_short_clip(vc->ar, bezt->vec[1], s, 1);
1886 if (s[0] != IS_CLIPPED)
1887 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
1888 view3d_project_short_clip(vc->ar, bezt->vec[2], s, 1);
1889 if (s[0] != IS_CLIPPED)
1890 func(userData, nu, NULL, bezt, 2, s[0], s[1]);
1896 for (i=0; i<nu->pntsu*nu->pntsv; i++) {
1897 BPoint *bp = &nu->bp[i];
1900 view3d_project_short_clip(vc->ar, bp->vec, s, 1);
1901 if (s[0] != IS_CLIPPED)
1902 func(userData, nu, bp, NULL, -1, s[0], s[1]);
1909 /* ************** DRAW MESH ****************** */
1911 /* First section is all the "simple" draw routines,
1912 * ones that just pass some sort of primitive to GL,
1913 * with perhaps various options to control lighting,
1916 * These routines should not have user interface related
1920 static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
1922 ToolSettings *ts= ((Scene *)userData)->toolsettings;
1923 EditFace *efa = EM_get_face_for_index(index);
1925 if (efa->h==0 && efa->fgonf!=EM_FGON) {
1927 glVertex3f( cent[0] + no[0]*ts->normalsize,
1928 cent[1] + no[1]*ts->normalsize,
1929 cent[2] + no[2]*ts->normalsize);
1932 static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm)
1935 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene);
1939 static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
1941 EditFace *efa = EM_get_face_for_index(index);
1942 int sel = *((int*) userData);
1944 if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) {
1948 static void draw_dm_face_centers(DerivedMesh *dm, int sel)
1950 bglBegin(GL_POINTS);
1951 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel);
1955 static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
1957 Scene *scene= (Scene *)userData;
1958 ToolSettings *ts= scene->toolsettings;
1959 EditVert *eve = EM_get_vert_for_index(index);
1965 glVertex3f( co[0] + no_f[0]*ts->normalsize,
1966 co[1] + no_f[1]*ts->normalsize,
1967 co[2] + no_f[2]*ts->normalsize);
1969 glVertex3f( co[0] + no_s[0]*ts->normalsize/32767.0f,
1970 co[1] + no_s[1]*ts->normalsize/32767.0f,
1971 co[2] + no_s[2]*ts->normalsize/32767.0f);
1975 static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm)
1978 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene);
1982 /* Draw verts with color set based on selection */
1983 static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1985 struct { int sel; EditVert *eve_act; } * data = userData;
1986 EditVert *eve = EM_get_vert_for_index(index);
1988 if (eve->h==0 && (eve->f&SELECT)==data->sel) {
1989 /* draw active larger - need to stop/start point drawing for this :/ */
1990 if (eve==data->eve_act) {
1991 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
1992 UI_ThemeColor4(TH_EDITMESH_ACTIVE);
1997 bglBegin(GL_POINTS);
2001 UI_ThemeColor4(data->sel?TH_VERTEX_SELECT:TH_VERTEX);
2003 bglBegin(GL_POINTS);
2010 static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
2012 struct { int sel; EditVert *eve_act; } data;
2014 data.eve_act = eve_act;
2016 bglBegin(GL_POINTS);
2017 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
2021 /* Draw edges with color set based on selection */
2022 static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2024 EditEdge *eed = EM_get_edge_for_index(index);
2025 //unsigned char **cols = userData, *col;
2026 struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData;
2030 if (eed==data->eed_act) {
2031 glColor4ubv(data->actCol);
2033 if (eed->f&SELECT) {
2036 col = data->baseCol;
2038 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2039 if (col[3]==0) return 0;
2048 static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act)
2050 struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data;
2052 data.baseCol = baseCol;
2053 data.selCol = selCol;
2054 data.actCol = actCol;
2055 data.eed_act = eed_act;
2056 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2060 static int draw_dm_edges__setDrawOptions(void *UNUSED(userData), int index)
2062 return EM_get_edge_for_index(index)->h==0;
2064 static void draw_dm_edges(DerivedMesh *dm)
2066 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL);
2069 /* Draw edges with color interpolated based on selection */
2070 static int draw_dm_edges_sel_interp__setDrawOptions(void *UNUSED(userData), int index)
2072 return EM_get_edge_for_index(index)->h==0;
2074 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2076 EditEdge *eed = EM_get_edge_for_index(index);
2077 unsigned char **cols = userData;
2078 unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0];
2079 unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0];
2081 glColor4ub( col0[0] + (col1[0]-col0[0])*t,
2082 col0[1] + (col1[1]-col0[1])*t,
2083 col0[2] + (col1[2]-col0[2])*t,
2084 col0[3] + (col1[3]-col0[3])*t);
2087 static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2089 unsigned char *cols[2];
2092 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2095 /* Draw only seam edges */
2096 static int draw_dm_edges_seams__setDrawOptions(void *UNUSED(userData), int index)
2098 EditEdge *eed = EM_get_edge_for_index(index);
2100 return (eed->h==0 && eed->seam);
2102 static void draw_dm_edges_seams(DerivedMesh *dm)
2104 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL);
2107 /* Draw only sharp edges */
2108 static int draw_dm_edges_sharp__setDrawOptions(void *UNUSED(userData), int index)
2110 EditEdge *eed = EM_get_edge_for_index(index);
2112 return (eed->h==0 && eed->sharp);
2114 static void draw_dm_edges_sharp(DerivedMesh *dm)
2116 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL);
2120 /* Draw faces with color set based on selection
2121 * return 2 for the active face so it renders with stipple enabled */
2122 static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r))
2124 struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
2125 EditFace *efa = EM_get_face_for_index(index);
2129 if (efa == data->efa_act) {
2130 glColor4ubv(data->cols[2]);
2131 return 2; /* stipple */
2133 col = data->cols[(efa->f&SELECT)?1:0];
2134 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]; EditFace *efa_act; } * data = userData;
2145 EditFace *efa = EM_get_face_for_index(index);
2146 EditFace *next_efa = EM_get_face_for_index(next_index);
2147 unsigned char *col, *next_col;
2152 if(efa == data->efa_act || next_efa == data->efa_act)
2155 col = data->cols[(efa->f&SELECT)?1:0];
2156 next_col = data->cols[(next_efa->f&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(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act)
2167 struct { unsigned char *cols[3]; EditFace *efa_act; } data;
2168 data.cols[0] = baseCol;
2169 data.cols[1] = selCol;
2170 data.cols[2] = actCol;
2171 data.efa_act = efa_act;
2173 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions);
2176 static int draw_dm_creases__setDrawOptions(void *UNUSED(userData), int index)
2178 EditEdge *eed = EM_get_edge_for_index(index);
2180 if (eed->h==0 && eed->crease != 0.0f) {
2181 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, eed->crease);
2187 static void draw_dm_creases(DerivedMesh *dm)
2190 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL);
2194 static int draw_dm_bweights__setDrawOptions(void *UNUSED(userData), int index)
2196 EditEdge *eed = EM_get_edge_for_index(index);
2198 if (eed->h==0 && eed->bweight != 0.0f) {
2199 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight);
2205 static void draw_dm_bweights__mapFunc(void *UNUSED(userData), int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
2207 EditVert *eve = EM_get_vert_for_index(index);
2209 if (eve->h==0 && eve->bweight != 0.0f) {
2210 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight);
2214 static void draw_dm_bweights(Scene *scene, DerivedMesh *dm)
2216 ToolSettings *ts= scene->toolsettings;
2218 if (ts->selectmode & SCE_SELECT_VERTEX) {
2219 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2220 bglBegin(GL_POINTS);
2221 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL);
2226 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL);
2231 /* Second section of routines: Combine first sets to form fancy
2232 * drawing routines (for example rendering twice to get overlays).
2234 * Also includes routines that are basic drawing but are too
2235 * specialized to be split out (like drawing creases or measurements).
2238 /* EditMesh drawing routines*/
2240 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, DerivedMesh *cageDM, EditVert *eve_act)
2242 ToolSettings *ts= scene->toolsettings;
2245 if(v3d->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select
2247 for (sel=0; sel<2; sel++) {
2248 unsigned char col[4], fcol[4];
2251 UI_GetThemeColor3ubv(sel?TH_VERTEX_SELECT:TH_VERTEX, col);
2252 UI_GetThemeColor3ubv(sel?TH_FACE_DOT:TH_WIRE, fcol);
2254 for (pass=0; pass<2; pass++) {
2255 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2256 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2259 if(v3d->zbuf && !(v3d->flag&V3D_ZBUF_SELECT)) {
2260 glDisable(GL_DEPTH_TEST);
2267 size = (size > 2.1f ? size/2.0f:size);
2268 fsize = (fsize > 2.1f ? fsize/2.0f:fsize);
2269 col[3] = fcol[3] = 100;
2271 col[3] = fcol[3] = 255;
2274 if(ts->selectmode & SCE_SELECT_VERTEX) {
2277 draw_dm_verts(cageDM, sel, eve_act);
2280 if(check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2283 draw_dm_face_centers(cageDM, sel);
2287 glDisable(GL_BLEND);
2288 glEnable(GL_DEPTH_TEST);
2293 if(v3d->zbuf) glDepthMask(1);
2297 static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act)
2299 ToolSettings *ts= scene->toolsettings;
2301 unsigned char wireCol[4], selCol[4], actCol[4];
2303 /* since this function does transparant... */
2304 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2305 UI_GetThemeColor4ubv(TH_WIRE, wireCol);
2306 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2308 /* when sel only is used, dont render wire, only selected, this is used for
2309 * textured draw mode when the 'edges' option is disabled */
2313 for (pass=0; pass<2; pass++) {
2314 /* show wires in transparant when no zbuf clipping for select */
2316 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0) {
2318 glDisable(GL_DEPTH_TEST);
2320 if (!sel_only) wireCol[3] = 85;
2326 if (!sel_only) wireCol[3] = 255;
2329 if(ts->selectmode == SCE_SELECT_FACE) {
2330 draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
2332 else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
2333 if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2334 glShadeModel(GL_SMOOTH);
2335 draw_dm_edges_sel_interp(cageDM, wireCol, selCol);
2336 glShadeModel(GL_FLAT);
2338 draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
2343 glColor4ubv(wireCol);
2344 draw_dm_edges(cageDM);
2349 glDisable(GL_BLEND);
2350 glEnable(GL_DEPTH_TEST);
2355 static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, UnitSettings *unit)
2360 float v1[3], v2[3], v3[3], v4[3], vmid[3];
2362 char val[32]; /* Stores the measurement display text here */
2363 const char *conv_float; /* Use a float conversion matching the grid size */
2364 unsigned char col[4]= {0, 0, 0, 255}; /* color of the text to draw */
2365 float area; /* area of the face */
2366 float grid= unit->system ? unit->scale_length : v3d->grid;
2367 const int do_split= unit->flag & USER_UNIT_OPT_SPLIT;
2368 const int do_global= v3d->flag & V3D_GLOBAL_STATS;
2369 const int do_moving= G.moving;
2371 /* make the precision of the pronted value proportionate to the gridsize */
2373 if (grid < 0.01f) conv_float= "%.6g";
2374 else if (grid < 0.1f) conv_float= "%.5g";
2375 else if (grid < 1.0f) conv_float= "%.4g";
2376 else if (grid < 10.0f) conv_float= "%.3g";
2377 else conv_float= "%.2g";
2379 if(v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0)
2380 glDisable(GL_DEPTH_TEST);
2382 if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0f);
2384 if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2385 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2387 for(eed= em->edges.first; eed; eed= eed->next) {
2388 /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */
2389 if((eed->h != EM_FGON) && ((eed->f & SELECT) || (do_moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) {
2390 copy_v3_v3(v1, eed->v1->co);
2391 copy_v3_v3(v2, eed->v2->co);
2393 interp_v3_v3v3(vmid, v1, v2, 0.5f);
2396 mul_mat3_m4_v3(ob->obmat, v1);
2397 mul_mat3_m4_v3(ob->obmat, v2);
2400 bUnit_AsString(val, sizeof(val), len_v3v3(v1, v2)*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE);
2402 sprintf(val, conv_float, len_v3v3(v1, v2));
2404 view3d_cached_text_draw_add(vmid, val, 0, V3D_CACHE_TEXT_ASCII, col);
2409 if(me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2410 // XXX extern int faceselectedOR(EditFace *efa, int flag); // editmesh.h shouldn't be in this file... ok for now?
2411 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2413 for(efa= em->faces.first; efa; efa= efa->next) {
2414 if((efa->f & SELECT)) { // XXX || (do_moving && faceselectedOR(efa, SELECT)) ) {
2415 copy_v3_v3(v1, efa->v1->co);
2416 copy_v3_v3(v2, efa->v2->co);
2417 copy_v3_v3(v3, efa->v3->co);
2419 copy_v3_v3(v4, efa->v4->co);
2422 mul_mat3_m4_v3(ob->obmat, v1);
2423 mul_mat3_m4_v3(ob->obmat, v2);
2424 mul_mat3_m4_v3(ob->obmat, v3);
2425 if (efa->v4) mul_mat3_m4_v3(ob->obmat, v4);
2429 area= area_quad_v3(v1, v2, v3, v4);
2431 area = area_tri_v3(v1, v2, v3);
2434 bUnit_AsString(val, sizeof(val), area*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); // XXX should be B_UNIT_AREA
2436 sprintf(val, conv_float, area);
2438 view3d_cached_text_draw_add(efa->cent, val, 0, V3D_CACHE_TEXT_ASCII, col);
2443 if(me->drawflag & ME_DRAWEXTRA_FACEANG) {
2444 EditEdge *e1, *e2, *e3, *e4;
2445 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2446 for(efa= em->faces.first; efa; efa= efa->next) {
2447 copy_v3_v3(v1, efa->v1->co);
2448 copy_v3_v3(v2, efa->v2->co);
2449 copy_v3_v3(v3, efa->v3->co);
2451 copy_v3_v3(v4, efa->v4->co);
2457 mul_mat3_m4_v3(ob->obmat, v1);
2458 mul_mat3_m4_v3(ob->obmat, v2);
2459 mul_mat3_m4_v3(ob->obmat, v3);
2460 mul_mat3_m4_v3(ob->obmat, v4); /* intentionally executed even for tri's */
2466 if(efa->e4) e4= efa->e4; else e4= e3;
2468 /* Calculate the angles */
2470 if( (e4->f & e1->f & SELECT) || (do_moving && (efa->v1->f & SELECT)) ) {
2472 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v4, v1, v2)));
2473 interp_v3_v3v3(fvec, efa->cent, efa->v1->co, 0.8f);
2474 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2476 if( (e1->f & e2->f & SELECT) || (do_moving && (efa->v2->f & SELECT)) ) {
2478 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
2479 interp_v3_v3v3(fvec, efa->cent, efa->v2->co, 0.8f);
2480 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2482 if( (e2->f & e3->f & SELECT) || (do_moving && (efa->v3->f & SELECT)) ) {
2485 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v4)));
2487 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v1)));
2488 interp_v3_v3v3(fvec, efa->cent, efa->v3->co, 0.8f);
2489 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2493 if( (e3->f & e4->f & SELECT) || (do_moving && (efa->v4->f & SELECT)) ) {
2494 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v3, v4, v1)));
2495 interp_v3_v3v3(fvec, efa->cent, efa->v4->co, 0.8f);
2496 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2502 /* useful for debugging index vs shape key index */
2507 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2508 for(eve= em->verts.first, j= 0; eve; eve= eve->next, j++) {
2509 sprintf(val, "%d:%d", j, eve->keyindex);
2510 view3d_cached_text_draw_add(eve->co, val, 0, V3D_CACHE_TEXT_ASCII, col);
2516 glEnable(GL_DEPTH_TEST);
2517 bglPolygonOffset(rv3d->dist, 0.0f);
2521 static int draw_em_fancy__setFaceOpts(void *UNUSED(userData), int index, int *UNUSED(drawSmooth_r))
2523 EditFace *efa = EM_get_face_for_index(index);
2526 GPU_enable_material(efa->mat_nr+1, NULL);
2533 static int draw_em_fancy__setGLSLFaceOpts(void *UNUSED(userData), int index)
2535 EditFace *efa = EM_get_face_for_index(index);
2540 static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
2542 Mesh *me = ob->data;
2543 EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */
2544 EditEdge *eed_act = NULL;
2545 EditVert *eve_act = NULL;
2547 if (em->selected.last) {
2548 EditSelection *ese = em->selected.last;
2549 /* face is handeled above */
2550 /*if (ese->type == EDITFACE ) {
2551 efa_act = (EditFace *)ese->data;
2552 } else */ if ( ese->type == EDITEDGE ) {
2553 eed_act = (EditEdge *)ese->data;
2554 } else if ( ese->type == EDITVERT ) {
2555 eve_act = (EditVert *)ese->data;
2559 EM_init_index_arrays(em, 1, 1, 1);
2562 if(CHECK_OB_DRAWTEXTURE(v3d, dt)) {
2563 if(draw_glsl_material(scene, ob, v3d, dt)) {
2564 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2566 finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
2567 draw_em_fancy__setGLSLFaceOpts, NULL);
2568 GPU_disable_material();
2570 glFrontFace(GL_CCW);
2573 draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
2577 /* 3 floats for position, 3 for normal and times two because the faces may actually be quads instead of triangles */
2578 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED);
2580 glEnable(GL_LIGHTING);
2581 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2583 finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, NULL, 0, GPU_enable_material, NULL);
2585 glFrontFace(GL_CCW);
2586 glDisable(GL_LIGHTING);
2589 // Setup for drawing wire over, disable zbuffer
2590 // write to show selected edge wires better
2591 UI_ThemeColor(TH_WIRE);
2593 bglPolygonOffset(rv3d->dist, 1.0);
2597 if (cageDM!=finalDM) {
2598 UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
2599 finalDM->drawEdges(finalDM, 1, 0);
2603 if(me->drawflag & ME_DRAWFACES) { /* transp faces */
2604 unsigned char col1[4], col2[4], col3[4];
2606 UI_GetThemeColor4ubv(TH_FACE, col1);
2607 UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
2608 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
2611 glDepthMask(0); // disable write in zbuffer, needed for nice transp
2613 /* dont draw unselected faces, only selected, this is MUCH nicer when texturing */
2614 if CHECK_OB_DRAWTEXTURE(v3d, dt)
2617 draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
2619 glDisable(GL_BLEND);
2620 glDepthMask(1); // restore write in zbuffer
2621 } else if (efa_act) {
2622 /* even if draw faces is off it would be nice to draw the stipple face
2623 * Make all other faces zero alpha except for the active
2625 unsigned char col1[4], col2[4], col3[4];
2626 col1[3] = col2[3] = 0; /* dont draw */
2627 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
2630 glDepthMask(0); // disable write in zbuffer, needed for nice transp
2632 draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
2634 glDisable(GL_BLEND);
2635 glDepthMask(1); // restore write in zbuffer
2639 /* here starts all fancy draw-extra over */
2640 if((me->drawflag & ME_DRAWEDGES)==0 && CHECK_OB_DRAWTEXTURE(v3d, dt)) {
2641 /* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */
2643 /* only draw selected edges otherwise there is no way of telling if a face is selected */
2644 draw_em_fancy_edges(scene, v3d, me, cageDM, 1, eed_act);
2647 if(me->drawflag & ME_DRAWSEAMS) {
2648 UI_ThemeColor(TH_EDGE_SEAM);
2651 draw_dm_edges_seams(cageDM);
2657 if(me->drawflag & ME_DRAWSHARP) {
2658 UI_ThemeColor(TH_EDGE_SHARP);
2661 draw_dm_edges_sharp(cageDM);
2667 if(me->drawflag & ME_DRAWCREASES) {
2668 draw_dm_creases(cageDM);
2670 if(me->drawflag & ME_DRAWBWEIGHTS) {
2671 draw_dm_bweights(scene, cageDM);
2674 draw_em_fancy_edges(scene, v3d, me, cageDM, 0, eed_act);
2677 // XXX retopo_matrix_update(v3d);
2679 draw_em_fancy_verts(scene, v3d, ob, cageDM, eve_act);
2681 if(me->drawflag & ME_DRAWNORMALS) {
2682 UI_ThemeColor(TH_NORMAL);
2683 draw_dm_face_normals(scene, cageDM);
2685 if(me->drawflag & ME_DRAW_VNORMALS) {
2686 UI_ThemeColor(TH_VNORMAL);
2687 draw_dm_vert_normals(scene, cageDM);
2690 if(me->drawflag & (ME_DRAWEXTRA_EDGELEN|ME_DRAWEXTRA_FACEAREA|ME_DRAWEXTRA_FACEANG) && !((v3d->flag2 & V3D_RENDER_OVERRIDE)))
2691 draw_em_measure_stats(v3d, rv3d, ob, em, &scene->unit);
2696 bglPolygonOffset(rv3d->dist, 0.0);
2697 GPU_disable_material();
2700 EM_free_index_arrays();
2703 /* Mesh drawing routines */
2705 static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
2708 if(v3d->transp==0) { // not when we draw the transparent pass
2709 glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
2712 /* if transparent, we cannot draw the edges for solid select... edges have no material info.
2713 drawFacesSolid() doesn't draw the transparent faces */
2714 if(ob->dtx & OB_DRAWTRANSP) {
2715 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2716 dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
2717 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2718 GPU_disable_material();
2721 dm->drawEdges(dm, 0, 1);
2729 static int wpaint__setSolidDrawOptions(void *UNUSED(userData), int UNUSED(index), int *drawSmooth_r)
2735 static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
2737 Object *ob= base->object;
2738 Mesh *me = ob->data;
2739 Material *ma= give_current_material(ob, 1);
2740 const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO));
2741 const short is_paint_sel= (ob==OBACT && paint_facesel_test(ob));
2743 int /* totvert,*/ totedge, totface;
2744 DerivedMesh *dm= mesh_get_derived_final(scene, ob, scene->customdata_mask);
2749 if (ob->dtx&OB_DRAWWIRE) {
2750 draw_wire = 2; /* draw wire after solid using zoffset and depth buffer adjusment */
2753 /* totvert = dm->getNumVerts(dm); */ /*UNUSED*/
2754 totedge = dm->getNumEdges(dm);
2755 totface = dm->getNumFaces(dm);
2757 /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
2759 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2761 // Unwanted combination.
2762 if (is_paint_sel) draw_wire = 0;
2764 if(dt==OB_BOUNDBOX) {
2765 if((v3d->flag2 & V3D_RENDER_OVERRIDE && v3d->drawtype >= OB_WIRE)==0)
2766 draw_bounding_volume(scene, ob);
2768 else if(hasHaloMat || (totface==0 && totedge==0)) {
2773 else if(dt==OB_WIRE || totface==0) {
2774 draw_wire = 1; /* draw wire only, no depth buffer stuff */
2776 else if( (is_paint_sel || (ob==OBACT && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
2777 CHECK_OB_DRAWTEXTURE(v3d, dt))
2779 if ((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !(G.f&G_PICKSEL || is_paint_sel) && !draw_wire) {
2780 draw_mesh_object_outline(v3d, ob, dm);
2783 if(draw_glsl_material(scene, ob, v3d, dt)) {
2784 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2786 dm->drawFacesGLSL(dm, GPU_enable_material);
2787 // if(get_ob_property(ob, "Text"))
2788 // XXX draw_mesh_text(ob, 1);
2789 GPU_disable_material();
2791 glFrontFace(GL_CCW);
2794 draw_mesh_textured(scene, v3d, rv3d, ob, dm, is_paint_sel);
2798 if(base->flag & SELECT)
2799 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2801 UI_ThemeColor(TH_WIRE);
2803 if((v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
2804 dm->drawLooseEdges(dm);
2807 else if(dt==OB_SOLID) {
2808 if(ob==OBACT && ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
2809 /* weight paint in solid mode, special case. focus on making the weights clear
2810 * rather than the shading, this is also forced in wire view */
2811 GPU_enable_material(0, NULL);
2812 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material, NULL);
2814 bglPolygonOffset(rv3d->dist, 1.0);
2815 glDepthMask(0); // disable write in zbuffer, selected edge wires show better
2818 glColor4ub(255, 255, 255, 96);
2819 glEnable(GL_LINE_STIPPLE);
2820 glLineStipple(1, 0xAAAA);
2822 dm->drawEdges(dm, 1, 1);
2824 bglPolygonOffset(rv3d->dist, 0.0);
2826 glDisable(GL_LINE_STIPPLE);
2828 GPU_disable_material();
2830 /* since we already draw wire as wp guide, dont draw over the top */
2836 if((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !draw_wire && !ob->sculpt)
2837 draw_mesh_object_outline(v3d, ob, dm);
2839 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
2841 glEnable(GL_LIGHTING);
2842 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2844 if(ob->sculpt && (p=paint_get_active(scene))) {
2846 float (*fpl)[4] = NULL;
2847 int fast= (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
2849 if(ob->sculpt->partial_redraw) {
2850 if(ar->do_draw & RGN_DRAW_PARTIAL) {
2851 sculpt_get_redraw_planes(planes, ar, rv3d, ob);
2853 ob->sculpt->partial_redraw = 0;
2857 dm->drawFacesSolid(dm, fpl, fast, GPU_enable_material);
2860 dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
2862 GPU_disable_material();
2864 glFrontFace(GL_CCW);
2865 glDisable(GL_LIGHTING);
2867 if(base->flag & SELECT) {
2868 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2870 UI_ThemeColor(TH_WIRE);
2872 if(!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
2873 dm->drawLooseEdges(dm);
2876 else if(dt==OB_SHADED) {
2878 if(ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
2879 /* enforce default material settings */
2880 GPU_enable_material(0, NULL);
2882 /* but set default spec */
2883 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
2884 glEnable(GL_COLOR_MATERIAL); /* according manpages needed */
2885 glColor3ub(120, 120, 120);
2886 glDisable(GL_COLOR_MATERIAL);
2888 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
2889 glEnable(GL_LIGHTING);
2890 glEnable(GL_COLOR_MATERIAL);
2892 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material, NULL);
2893 glDisable(GL_COLOR_MATERIAL);
2894 glDisable(GL_LIGHTING);
2896 GPU_disable_material();
2898 else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) {
2900 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1, GPU_enable_material, NULL);
2902 glColor3f(1.0f, 1.0f, 1.0f);
2903 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0, GPU_enable_material, NULL);
2909 /* set default draw color back for wire or for draw-extra later on */
2911 if(base->flag & SELECT) {
2912 if(ob==OBACT && ob->flag & OB_FROMGROUP)
2913 UI_ThemeColor(TH_GROUP_ACTIVE);
2914 else if(ob->flag & OB_FROMGROUP)
2915 UI_ThemeColorShade(TH_GROUP_ACTIVE, -16);
2916 else if(flag!=DRAW_CONSTCOLOR)
2917 UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
2919 glColor3ub(80,80,80);
2921 if (ob->flag & OB_FROMGROUP)
2922 UI_ThemeColor(TH_GROUP);
2924 if(ob->dtx & OB_DRAWWIRE && flag==DRAW_CONSTCOLOR)
2925 glColor3ub(80,80,80);
2927 UI_ThemeColor(TH_WIRE);
2933 /* When using wireframe object traw in particle edit mode
2934 * the mesh gets in the way of seeing the particles, fade the wire color
2935 * with the background. */
2936 if(ob==OBACT && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
2937 float col_wire[4], col_bg[4], col[3];
2939 UI_GetThemeColor3fv(TH_BACK, col_bg);
2940 glGetFloatv(GL_CURRENT_COLOR, col_wire);
2941 interp_v3_v3v3(col, col_bg, col_wire, 0.15);
2945 /* If drawing wire and drawtype is not OB_WIRE then we are
2946 * overlaying the wires.
2948 * UPDATE bug #10290 - With this wire-only objects can draw
2949 * behind other objects depending on their order in the scene. 2x if 0's below. undo'ing zr's commit: r4059
2951 * if draw wire is 1 then just drawing wire, no need for depth buffer stuff,
2952 * otherwise this wire is to overlay solid mode faces so do some depth buffer tricks.
2954 if (dt!=OB_WIRE && draw_wire==2) {
2955 bglPolygonOffset(rv3d->dist, 1.0);
2956 glDepthMask(0); // disable write in zbuffer, selected edge wires show better
2959 if((v3d->flag2 & V3D_RENDER_OVERRIDE && v3d->drawtype >= OB_SOLID)==0)
2960 dm->drawEdges(dm, (dt==OB_WIRE || totface==0), me->drawflag & ME_ALLEDGES);
2962 if (dt!=OB_WIRE && draw_wire==2) {
2964 bglPolygonOffset(rv3d->dist, 0.0);
2968 if(paint_vertsel_test(ob)) {
2970 glColor3f(0.0f, 0.0f, 0.0f);
2971 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
2973 drawSelectedVertices(dm, ob->data);
2980 /* returns 1 if nothing was drawn, for detecting to draw an object center */
2981 static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
2983 Object *ob= base->object;
2984 Object *obedit= scene->obedit;
2986 EditMesh *em= me->edit_mesh;
2987 int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha, i;
2989 /* If we are drawing shadows and any of the materials don't cast a shadow,
2990 * then don't draw the object */
2991 if (v3d->flag2 & V3D_RENDER_SHADOW) {
2992 for(i=0; i<ob->totcol; ++i) {
2993 Material *ma= give_current_material(ob, i);
2994 if (ma && !(ma->mode & MA_SHADBUF)) {
3000 if(obedit && ob!=obedit && ob->data==obedit->data) {
3001 if(ob_get_key(ob) || ob_get_key(obedit));
3002 else if(ob->modifiers.first || obedit->modifiers.first);
3006 if(ob==obedit || drawlinked) {
3007 DerivedMesh *finalDM, *cageDM;
3010 finalDM = cageDM = editmesh_get_derived_base(ob, em);
3012 cageDM = editmesh_get_derived_cage_and_final(scene, ob, em, &finalDM,
3013 scene->customdata_mask);
3016 // no transp in editmode, the fancy draw over goes bad then
3017 glsl = draw_glsl_material(scene, ob, v3d, dt);
3018 GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
3021 draw_em_fancy(scene, v3d, rv3d, ob, em, cageDM, finalDM, dt);
3023 GPU_end_object_materials();
3025 if (obedit!=ob && finalDM)
3026 finalDM->release(finalDM);
3029 /* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */
3030 if(me->totface<=4 || ED_view3d_boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) {
3031 glsl = draw_glsl_material(scene, ob, v3d, dt);
3032 check_alpha = check_material_alpha(base, me, glsl);
3034 if(dt==OB_SOLID || glsl) {
3035 GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl,
3036 (check_alpha)? &do_alpha_pass: NULL);
3039 draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, flag);
3041 GPU_end_object_materials();
3043 if(me->totvert==0) retval= 1;
3047 /* GPU_begin_object_materials checked if this is needed */
3049 if(ob->dtx & OB_DRAWXRAY) {
3050 add_view3d_after(&v3d->afterdraw_xraytransp, base, flag);
3053 add_view3d_after(&v3d->afterdraw_transp, base, flag);
3056 else if(ob->dtx & OB_DRAWXRAY && ob->dtx & OB_DRAWTRANSP) {
3057 /* special case xray+transp when alpha is 1.0, without this the object vanishes */
3058 if(v3d->xray == 0 && v3d->transp == 0) {
3059 add_view3d_after(&v3d->afterdraw_xray, base, flag);
3066 /* ************** DRAW DISPLIST ****************** */
3068 static int draw_index_wire= 1;
3069 static int index3_nors_incr= 1;
3071 /* returns 1 when nothing was drawn */
3072 static int drawDispListwire(ListBase *dlbase)
3078 if(dlbase==NULL) return 1;
3080 glEnableClientState(GL_VERTEX_ARRAY);
3081 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
3083 for(dl= dlbase->first; dl; dl= dl->next) {
3084 if(dl->parts==0 || dl->nr==0)
3092 glVertexPointer(3, GL_FLOAT, 0, data);
3094 for(parts=0; parts<dl->parts; parts++)
3095 glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr);
3100 glVertexPointer(3, GL_FLOAT, 0, data);