2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation, full recode and added functions
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/space_view3d/drawobject.c
34 #include "MEM_guardedalloc.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_curve_types.h"
38 #include "DNA_constraint_types.h" // for drawing constraint
39 #include "DNA_dynamicpaint_types.h"
40 #include "DNA_lamp_types.h"
41 #include "DNA_lattice_types.h"
42 #include "DNA_material_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_meta_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_smoke_types.h"
47 #include "DNA_speaker_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_camera.h"
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"
78 #include "BKE_scene.h"
80 #include "BKE_movieclip.h"
81 #include "BKE_tracking.h"
83 #include "smoke_API.h"
85 #include "IMB_imbuf.h"
86 #include "IMB_imbuf_types.h"
89 #include "BIF_glutil.h"
92 #include "GPU_extensions.h"
95 #include "ED_particle.h"
96 #include "ED_screen.h"
97 #include "ED_sculpt.h"
99 #include "ED_curve.h" /* for curve_editnurbs */
101 #include "UI_resources.h"
104 #include "wm_subwindow.h"
107 #include "view3d_intern.h" // own include
110 /* this condition has been made more complex since editmode can draw textures */
111 #define CHECK_OB_DRAWTEXTURE(vd, dt) \
112 ((ELEM(vd->drawtype, OB_TEXTURE, OB_MATERIAL) && dt>OB_SOLID) || \
113 (vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX))
115 typedef enum eWireDrawMode {
118 OBDRAW_WIRE_ON_DEPTH= 2
121 static void draw_bounding_volume(Scene *scene, Object *ob, char type);
123 static void drawcube_size(float size);
124 static void drawcircle_size(float size);
125 static void draw_empty_sphere(float size);
126 static void draw_empty_cone(float size);
128 static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
130 if((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
133 if(G.f & G_BACKBUFSEL)
136 if((vd->flag & V3D_ZBUF_SELECT) == 0)
139 /* if its drawing textures with zbuf sel, then dont draw dots */
140 if(dt==OB_TEXTURE && vd->drawtype==OB_TEXTURE)
143 if(vd->drawtype>=OB_SOLID && vd->flag2 & V3D_SOLID_TEX)
149 /* ************* only use while object drawing **************
150 * or after running ED_view3d_init_mats_rv3d
152 static void view3d_project_short_clip(ARegion *ar, const float vec[3], short adr[2], int local)
154 RegionView3D *rv3d= ar->regiondata;
155 float fx, fy, vec4[4];
159 /* clipplanes in eye space */
160 if(rv3d->rflag & RV3D_CLIPPING) {
161 if(ED_view3d_test_clipping(rv3d, vec, local))
165 copy_v3_v3(vec4, vec);
168 mul_m4_v4(rv3d->persmatob, vec4);
170 /* clipplanes in window space */
171 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
172 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
174 if( fx>0 && fx<ar->winx) {
176 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
178 if(fy > 0.0f && fy < (float)ar->winy) {
179 adr[0]= (short)floorf(fx);
180 adr[1]= (short)floorf(fy);
186 /* only use while object drawing */
187 static void view3d_project_short_noclip(ARegion *ar, const float vec[3], short adr[2])
189 RegionView3D *rv3d= ar->regiondata;
190 float fx, fy, vec4[4];
194 copy_v3_v3(vec4, vec);
197 mul_m4_v4(rv3d->persmatob, vec4);
199 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
200 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
202 if( fx>-32700 && fx<32700) {
204 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
206 if(fy > -32700.0f && fy < 32700.0f) {
207 adr[0]= (short)floorf(fx);
208 adr[1]= (short)floorf(fy);
214 /* same as view3d_project_short_clip but use persmat instead of persmatob for projection */
215 static void view3d_project_short_clip_persmat(ARegion *ar, float *vec, short adr[2], int local)
217 RegionView3D *rv3d= ar->regiondata;
218 float fx, fy, vec4[4];
222 /* clipplanes in eye space */
223 if(rv3d->rflag & RV3D_CLIPPING) {
224 if(ED_view3d_test_clipping(rv3d, vec, local))
228 copy_v3_v3(vec4, vec);
231 mul_m4_v4(rv3d->persmat, vec4);
233 /* clipplanes in window space */
234 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* is the NEAR clipping cutoff for picking */
235 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
237 if( fx>0 && fx<ar->winx) {
239 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
241 if(fy > 0.0f && fy < (float)ar->winy) {
242 adr[0]= (short)floorf(fx);
243 adr[1]= (short)floorf(fy);
248 /* ************************ */
250 /* check for glsl drawing */
252 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
254 if(!GPU_glsl_support())
258 if(!CHECK_OB_DRAWTEXTURE(v3d, dt))
260 if(ob==OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
262 if(scene_use_new_shading_nodes(scene))
265 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
268 static int check_alpha_pass(Base *base)
270 if(base->flag & OB_FROMDUPLI)
276 return (base->object->dtx & OB_DRAWTRANSP);
280 static unsigned int colortab[24]=
281 {0x0, 0xFF88FF, 0xFFBBFF,
282 0x403000, 0xFFFF88, 0xFFFFBB,
283 0x104040, 0x66CCCC, 0x77CCCC,
284 0x104010, 0x55BB55, 0x66FF66,
289 static float cube[8][3] = {
300 /* ----------------- OpenGL Circle Drawing - Tables for Optimised Drawing Speed ------------------ */
301 /* 32 values of sin function (still same result!) */
302 #define CIRCLE_RESOL 32
304 static const float sinval[CIRCLE_RESOL] = {
339 /* 32 values of cos function (still same result!) */
340 static const float cosval[CIRCLE_RESOL] = {
375 static void draw_xyz_wire(const float c[3], float size, int axis)
377 float v1[3]= {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
378 float dim = size * 0.1f;
379 float dx[3], dy[3], dz[3];
381 dx[0]=dim; dx[1]=0.f; dx[2]=0.f;
382 dy[0]=0.f; dy[1]=dim; dy[2]=0.f;
383 dz[0]=0.f; dz[1]=0.f; dz[2]=dim;
389 /* bottom left to top right */
390 sub_v3_v3v3(v1, c, dx);
392 add_v3_v3v3(v2, c, dx);
398 /* top left to bottom right */
411 /* bottom left to top right */
412 mul_v3_fl(dx, 0.75f);
413 sub_v3_v3v3(v1, c, dx);
415 add_v3_v3v3(v2, c, dx);
421 /* top left to center */
432 glBegin(GL_LINE_STRIP);
434 /* start at top left */
435 sub_v3_v3v3(v1, c, dx);
436 add_v3_v3v3(v1, c, dz);
461 void drawaxes(float size, char drawtype)
464 float v1[3]= {0.0, 0.0, 0.0};
465 float v2[3]= {0.0, 0.0, 0.0};
466 float v3[3]= {0.0, 0.0, 0.0};
471 for (axis=0; axis<3; axis++) {
479 /* reset v1 & v2 to zero */
480 v1[axis]= v2[axis]= 0.0f;
485 case OB_SINGLE_ARROW:
488 /* in positive z direction only */
495 glBegin(GL_TRIANGLES);
497 v2[0]= size * 0.035f; v2[1] = size * 0.035f;
498 v3[0]= size * -0.035f; v3[1] = size * 0.035f;
499 v2[2]= v3[2]= size * 0.75f;
501 for (axis=0; axis<4; axis++) {
523 drawcircle_size(size);
526 case OB_EMPTY_SPHERE:
527 draw_empty_sphere(size);
531 draw_empty_cone(size);
536 for (axis=0; axis<3; axis++) {
537 const int arrow_axis= (axis==0) ? 1:0;
545 v1[axis]= size*0.85f;
546 v1[arrow_axis]= -size*0.08f;
550 v1[arrow_axis]= size*0.08f;
556 v2[axis]+= size*0.125f;
558 draw_xyz_wire(v2, size, axis);
561 /* reset v1 & v2 to zero */
562 v1[arrow_axis]= v1[axis]= v2[axis]= 0.0f;
569 /* Function to draw an Image on a empty Object */
570 static void draw_empty_image(Object *ob)
572 Image *ima = (Image*)ob->data;
573 ImBuf *ibuf = ima ? BKE_image_get_ibuf(ima, NULL) : NULL;
575 float scale, ofs_x, ofs_y, sca_x, sca_y;
578 if(ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
579 IMB_rect_from_float(ibuf);
582 /* Get the buffer dimensions so we can fallback to fake ones */
583 if(ibuf && ibuf->rect) {
592 /* Get the image aspect even if the buffer is invalid */
594 if(ima->aspx > ima->aspy) {
596 sca_y= ima->aspy / ima->aspx;
598 else if(ima->aspx < ima->aspy) {
599 sca_x= ima->aspx / ima->aspy;
612 /* Calculate the scale center based on objects origin */
613 ofs_x= ob->ima_ofs[0] * ima_x;
614 ofs_y= ob->ima_ofs[1] * ima_y;
616 glMatrixMode(GL_MODELVIEW);
619 /* Make sure we are drawing at the origin */
620 glTranslatef(0.0f, 0.0f, 0.0f);
622 /* Calculate Image scale */
623 scale= (ob->empty_drawsize / (float)MAX2(ima_x * sca_x, ima_y * sca_y));
625 /* Set the object scale */
626 glScalef(scale * sca_x, scale * sca_y, 1.0f);
628 if(ibuf && ibuf->rect) {
629 /* Setup GL params */
631 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
633 /* Use the object color and alpha */
636 /* Draw the Image on the screen */
637 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
638 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
643 UI_ThemeColor((ob->flag & SELECT) ? TH_SELECT : TH_WIRE);
645 /* Calculate the outline vertex positions */
646 glBegin(GL_LINE_LOOP);
647 glVertex2f(ofs_x, ofs_y);
648 glVertex2f(ofs_x + ima_x, ofs_y);
649 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
650 glVertex2f(ofs_x, ofs_y + ima_y);
653 /* Reset GL settings */
654 glMatrixMode(GL_MODELVIEW);
658 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[][4])
661 float *viter= (float *)verts;
664 mul_v3_v3fl(vx, tmat[0], rad);
665 mul_v3_v3fl(vy, tmat[1], rad);
667 for (a=0; a < CIRCLE_RESOL; a++, viter += 3) {
668 viter[0]= cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
669 viter[1]= cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
670 viter[2]= cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
674 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
676 float verts[CIRCLE_RESOL][3];
678 circball_array_fill(verts, cent, rad, tmat);
680 glEnableClientState(GL_VERTEX_ARRAY);
681 glVertexPointer(3, GL_FLOAT, 0, verts);
682 glDrawArrays(mode, 0, CIRCLE_RESOL);
683 glDisableClientState(GL_VERTEX_ARRAY);
686 /* circle for object centers, special_color is for library or ob users */
687 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
689 const float size= ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
690 float verts[CIRCLE_RESOL][3];
692 /* using gldepthfunc guarantees that it does write z values,
693 * but not checks for it, so centers remain visible independt order of drawing */
694 if(v3d->zbuf) glDepthFunc(GL_ALWAYS);
698 if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
700 else glColor4ub(0x55, 0xCC, 0xCC, 155);
703 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
704 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
705 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
708 circball_array_fill(verts, co, size, rv3d->viewinv);
710 /* enable vertex array */
711 glEnableClientState(GL_VERTEX_ARRAY);
712 glVertexPointer(3, GL_FLOAT, 0, verts);
714 /* 1. draw filled, blended polygon */
715 glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
717 /* 2. draw outline */
718 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
719 glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
722 glDisableClientState(GL_VERTEX_ARRAY);
726 if(v3d->zbuf) glDepthFunc(GL_LEQUAL);
729 /* *********** text drawing for object/particles/armature ************* */
730 static ListBase CachedText[3];
731 static int CachedTextLevel= 0;
733 typedef struct ViewCachedString {
734 struct ViewCachedString *next, *prev;
744 /* str is allocated past the end */
747 void view3d_cached_text_draw_begin(void)
749 ListBase *strings= &CachedText[CachedTextLevel];
750 strings->first= strings->last= NULL;
754 void view3d_cached_text_draw_add(const float co[3],
756 short xoffs, short flag,
757 const unsigned char col[4])
759 int alloc_len= strlen(str) + 1;
760 ListBase *strings= &CachedText[CachedTextLevel-1];
761 /* TODO, replace with more efficient malloc, perhaps memarena per draw? */
762 ViewCachedString *vos= MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
764 BLI_addtail(strings, vos);
765 copy_v3_v3(vos->vec, co);
766 vos->col.pack= *((int *)col);
769 vos->str_len= alloc_len-1;
771 /* allocate past the end */
772 memcpy(++vos, str, alloc_len);
775 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
777 RegionView3D *rv3d= ar->regiondata;
778 ListBase *strings= &CachedText[CachedTextLevel-1];
779 ViewCachedString *vos;
782 /* project first and test */
783 for(vos= strings->first; vos; vos= vos->next) {
784 if(mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
785 mul_m4_v3(mat, vos->vec);
787 if(vos->flag&V3D_CACHE_TEXT_GLOBALSPACE)
788 view3d_project_short_clip_persmat(ar, vos->vec, vos->sco, 0);
790 view3d_project_short_clip(ar, vos->vec, vos->sco, 0);
792 if(vos->sco[0]!=IS_CLIPPED)
797 int col_pack_prev= 0;
800 bglMats mats; /* ZBuffer depth vars */
807 if(rv3d->rflag & RV3D_CLIPPING)
809 glDisable(GL_CLIP_PLANE0+a);
811 glMatrixMode(GL_PROJECTION);
813 glMatrixMode(GL_MODELVIEW);
815 ED_region_pixelspace(ar);
818 if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
822 for(vos= strings->first; vos; vos= vos->next) {
823 /* too slow, reading opengl info while drawing is very bad,
824 * better to see if we can use the zbuffer while in pixel space - campbell */
826 if(v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
827 gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
828 glReadPixels(ar->winrct.xmin+vos->mval[0]+vos->xoffs, ar->winrct.ymin+vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
834 if(vos->sco[0]!=IS_CLIPPED) {
835 const char *str= (char *)(vos+1);
837 if(col_pack_prev != vos->col.pack) {
838 glColor3ubv(vos->col.ub);
839 col_pack_prev= vos->col.pack;
841 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
842 BLF_draw_default_ascii :
844 ) ( (float)vos->sco[0] + vos->xoffs,
846 (depth_write) ? 0.0f: 2.0f,
853 if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
857 glMatrixMode(GL_PROJECTION);
859 glMatrixMode(GL_MODELVIEW);
862 if(rv3d->rflag & RV3D_CLIPPING)
864 glEnable(GL_CLIP_PLANE0+a);
868 BLI_freelistN(strings);
873 /* ******************** primitive drawing ******************* */
875 static void drawcube(void)
878 glBegin(GL_LINE_STRIP);
879 glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
880 glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
881 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
884 glBegin(GL_LINE_STRIP);
885 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
888 glBegin(GL_LINE_STRIP);
889 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
892 glBegin(GL_LINE_STRIP);
893 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
897 /* draws a cube on given the scaling of the cube, assuming that
898 * all required matrices have been set (used for drawing empties)
900 static void drawcube_size(float size)
902 glBegin(GL_LINE_STRIP);
903 glVertex3f(-size,-size,-size); glVertex3f(-size,-size,size);
904 glVertex3f(-size,size,size); glVertex3f(-size,size,-size);
906 glVertex3f(-size,-size,-size); glVertex3f(size,-size,-size);
907 glVertex3f(size,-size,size); glVertex3f(size,size,size);
909 glVertex3f(size,size,-size); glVertex3f(size,-size,-size);
912 glBegin(GL_LINE_STRIP);
913 glVertex3f(-size,-size,size); glVertex3f(size,-size,size);
916 glBegin(GL_LINE_STRIP);
917 glVertex3f(-size,size,size); glVertex3f(size,size,size);
920 glBegin(GL_LINE_STRIP);
921 glVertex3f(-size,size,-size); glVertex3f(size,size,-size);
925 /* this is an unused (old) cube-drawing function based on a given size */
927 static void drawcube_size(const float size[3])
931 glScalef(size[0], size[1], size[2]);
934 glBegin(GL_LINE_STRIP);
935 glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
936 glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
937 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
940 glBegin(GL_LINE_STRIP);
941 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
944 glBegin(GL_LINE_STRIP);
945 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
948 glBegin(GL_LINE_STRIP);
949 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
956 static void drawshadbuflimits(Lamp *la, float mat[][4])
958 float sta[3], end[3], lavec[3];
960 negate_v3_v3(lavec, mat[2]);
963 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
964 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
966 glBegin(GL_LINE_STRIP);
981 static void spotvolume(float lvec[3], float vvec[3], const float inp)
983 /* camera is at 0,0,0 */
984 float temp[3],plane[3],mat1[3][3],mat2[3][3],mat3[3][3],mat4[3][3],q[4],co,si,angle;
987 normalize_v3(vvec); /* is this the correct vector ? */
989 cross_v3_v3v3(temp,vvec,lvec); /* equation for a plane through vvec en lvec */
990 cross_v3_v3v3(plane,lvec,temp); /* a plane perpendicular to this, parrallel with lvec */
992 /* vectors are exactly aligned, use the X axis, this is arbitrary */
993 if(normalize_v3(plane) == 0.0f)
996 /* now we've got two equations: one of a cone and one of a plane, but we have
997 three unknowns. We remove one unkown by rotating the plane to z=0 (the plane normal) */
999 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
1000 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
1002 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
1007 normalize_v3(&q[1]);
1009 angle = saacos(plane[2])/2.0f;
1011 si = sqrtf(1-co*co);
1018 quat_to_mat3(mat1,q);
1020 /* rotate lamp vector now over acos(inp) degrees */
1021 copy_v3_v3(vvec, lvec);
1025 si = sqrtf(1.0f-inp*inp);
1031 mul_m3_m3m3(mat3,mat2,mat1);
1035 mul_m3_m3m3(mat4,mat2,mat1);
1038 mul_m3_m3m3(mat2,mat1,mat3);
1039 mul_m3_v3(mat2,lvec);
1040 mul_m3_m3m3(mat2,mat1,mat4);
1041 mul_m3_v3(mat2,vvec);
1046 static void draw_spot_cone(Lamp *la, float x, float z)
1050 glBegin(GL_TRIANGLE_FAN);
1051 glVertex3f(0.0f, 0.0f, -x);
1053 if(la->mode & LA_SQUARE) {
1054 glVertex3f(z, z, 0);
1055 glVertex3f(-z, z, 0);
1056 glVertex3f(-z, -z, 0);
1057 glVertex3f(z, -z, 0);
1058 glVertex3f(z, z, 0);
1064 for(a=0; a<33; a++) {
1065 angle= a*M_PI*2/(33-1);
1066 glVertex3f(z*cosf(angle), z*sinf(angle), 0);
1073 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1075 glEnable(GL_CULL_FACE);
1079 /* draw backside darkening */
1080 glCullFace(GL_FRONT);
1082 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1083 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1085 draw_spot_cone(la, x, z);
1087 /* draw front side lighting */
1088 glCullFace(GL_BACK);
1090 glBlendFunc(GL_ONE, GL_ONE);
1091 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1093 draw_spot_cone(la, x, z);
1096 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1097 glDisable(GL_BLEND);
1099 glDisable(GL_CULL_FACE);
1100 glCullFace(GL_BACK);
1103 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
1105 Object *ob= base->object;
1106 const float pixsize= ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1108 float vec[3], lvec[3], vvec[3], circrad, x,y,z;
1110 float imat[4][4], curcol[4];
1111 unsigned char col[4];
1112 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1113 /* the moment of view3d_draw_transp() call */
1114 const short is_view= (rv3d->persp==RV3D_CAMOB && v3d->camera == base->object);
1115 const short drawcone= ((dt > OB_WIRE) &&
1116 !(G.f & G_PICKSEL) &&
1117 (la->type == LA_SPOT) &&
1118 (la->mode & LA_SHOW_CONE) &&
1119 !(base->flag & OB_FROMDUPLI) &&
1122 if(drawcone && !v3d->transp) {
1123 /* in this case we need to draw delayed */
1124 add_view3d_after(&v3d->afterdraw_transp, base, flag);
1128 /* we first draw only the screen aligned & fixed scale stuff */
1130 glLoadMatrixf(rv3d->viewmat);
1132 /* lets calculate the scale: */
1133 lampsize= pixsize*((float)U.obcenter_dia*0.5f);
1135 /* and view aligned matrix: */
1136 copy_m4_m4(imat, rv3d->viewinv);
1137 normalize_v3(imat[0]);
1138 normalize_v3(imat[1]);
1141 copy_v3_v3(vec, ob->obmat[3]);
1143 /* for AA effects */
1144 glGetFloatv(GL_CURRENT_COLOR, curcol);
1148 if(lampsize > 0.0f) {
1151 if (ob==OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1152 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1157 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1158 glDisable(GL_BLEND);
1159 drawcircball(GL_POLYGON, vec, lampsize, imat);
1166 circrad = 3.0f*lampsize;
1169 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1171 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1172 if(la->type!=LA_HEMI) {
1173 if( (la->mode & LA_SHAD_RAY) ||
1174 ((la->mode & LA_SHAD_BUF) && (la->type==LA_SPOT))
1176 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f*pixsize, imat);
1185 /* draw the pretty sun rays */
1186 if(la->type==LA_SUN) {
1187 float v1[3], v2[3], mat[3][3];
1190 /* setup a 45 degree rotation matrix */
1191 vec_rot_to_mat3(mat, imat[2], (float)M_PI/4.0f);
1194 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1195 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1198 glTranslatef(vec[0], vec[1], vec[2]);
1203 for (axis=0; axis<8; axis++) {
1211 glTranslatef(-vec[0], -vec[1], -vec[2]);
1215 if (la->type==LA_LOCAL) {
1216 if(la->mode & LA_SPHERE) {
1217 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1219 /* yafray: for photonlight also draw lightcone as for spot */
1222 glPopMatrix(); /* back in object space */
1226 /* skip drawing extra info */
1228 else if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) {
1229 lvec[0]=lvec[1]= 0.0;
1231 x = rv3d->persmat[0][2];
1232 y = rv3d->persmat[1][2];
1233 z = rv3d->persmat[2][2];
1234 vvec[0]= x*ob->obmat[0][0] + y*ob->obmat[0][1] + z*ob->obmat[0][2];
1235 vvec[1]= x*ob->obmat[1][0] + y*ob->obmat[1][1] + z*ob->obmat[1][2];
1236 vvec[2]= x*ob->obmat[2][0] + y*ob->obmat[2][1] + z*ob->obmat[2][2];
1238 y = cosf(la->spotsize*(float)(M_PI/360.0));
1239 spotvolume(lvec, vvec, y);
1244 /* draw the angled sides of the cone */
1245 glBegin(GL_LINE_STRIP);
1251 z = x*sqrtf(1.0f - y*y);
1254 /* draw the circle/square at the end of the cone */
1255 glTranslatef(0.0, 0.0 , x);
1256 if(la->mode & LA_SQUARE) {
1258 float z_abs= fabs(z);
1260 tvec[0]= tvec[1]= z_abs;
1263 glBegin(GL_LINE_LOOP);
1265 tvec[1]= -z_abs; /* neg */
1267 tvec[0]= -z_abs; /* neg */
1269 tvec[1]= z_abs; /* pos */
1273 else circ(0.0, 0.0, fabsf(z));
1275 /* draw the circle/square representing spotbl */
1276 if(la->type==LA_SPOT) {
1277 float spotblcirc = fabs(z)*(1 - pow(la->spotblend, 2));
1278 /* hide line if it is zero size or overlaps with outer border,
1279 previously it adjusted to always to show it but that seems
1280 confusing because it doesn't show the actual blend size */
1281 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1282 circ(0.0, 0.0, spotblcirc);
1286 draw_transp_spot_volume(la, x, z);
1288 /* draw clip start, useful for wide cones where its not obvious where the start is */
1289 glTranslatef(0.0, 0.0 , -x); /* reverse translation above */
1290 if(la->type==LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1293 float clipsta_fac= la->clipsta / -x;
1295 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1296 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1298 glBegin(GL_LINE_STRIP);
1299 glVertex3fv(lvec_clip);
1300 glVertex3fv(vvec_clip);
1304 else if ELEM(la->type, LA_HEMI, LA_SUN) {
1306 /* draw the line from the circle along the dist */
1307 glBegin(GL_LINE_STRIP);
1314 if(la->type==LA_HEMI) {
1315 /* draw the hemisphere curves */
1316 short axis, steps, dir;
1317 float outdist, zdist, mul;
1319 outdist = 0.14; mul = 1.4; dir = 1;
1322 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1323 for (axis=0; axis<4; axis++) {
1324 float v[3]= {0.0, 0.0, 0.0};
1327 glBegin(GL_LINE_STRIP);
1329 for (steps=0; steps<6; steps++) {
1330 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1331 /* make the arcs start at the edge of the energy circle */
1332 if (steps == 0) v[0] = dir*circrad;
1333 else v[0] = v[0] + dir*(steps*outdist);
1334 } else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1335 /* make the arcs start at the edge of the energy circle */
1336 if (steps == 0) v[1] = dir*circrad;
1337 else v[1] = v[1] + dir*(steps*outdist);
1340 v[2] = v[2] - steps*zdist;
1344 zdist = zdist * mul;
1348 /* flip the direction */
1352 } else if(la->type==LA_AREA) {
1354 if(la->area_shape==LA_AREA_SQUARE)
1355 fdrawbox(-la->area_size*0.5f, -la->area_size*0.5f, la->area_size*0.5f, la->area_size*0.5f);
1356 else if(la->area_shape==LA_AREA_RECT)
1357 fdrawbox(-la->area_size*0.5f, -la->area_sizey*0.5f, la->area_size*0.5f, la->area_sizey*0.5f);
1359 glBegin(GL_LINE_STRIP);
1360 glVertex3f(0.0,0.0,-circrad);
1361 glVertex3f(0.0,0.0,-la->dist);
1365 /* and back to viewspace */
1366 glLoadMatrixf(rv3d->viewmat);
1367 copy_v3_v3(vec, ob->obmat[3]);
1371 if((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == FALSE)) {
1372 drawshadbuflimits(la, ob->obmat);
1375 UI_GetThemeColor4ubv(TH_LAMP, col);
1380 if (vec[2]>0) vec[2] -= circrad;
1381 else vec[2] += circrad;
1383 glBegin(GL_LINE_STRIP);
1395 glDisable(GL_BLEND);
1397 /* restore for drawing extra stuff */
1402 static void draw_limit_line(float sta, float end, unsigned int col)
1405 glVertex3f(0.0, 0.0, -sta);
1406 glVertex3f(0.0, 0.0, -end);
1412 glVertex3f(0.0, 0.0, -sta);
1413 glVertex3f(0.0, 0.0, -end);
1419 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1420 /* qdn: now also enabled for Blender to set focus point for defocus composit node */
1421 static void draw_focus_cross(float dist, float size)
1424 glVertex3f(-size, 0.f, -dist);
1425 glVertex3f(size, 0.f, -dist);
1426 glVertex3f(0.f, -size, -dist);
1427 glVertex3f(0.f, size, -dist);
1431 #ifdef VIEW3D_CAMERA_BORDER_HACK
1432 float view3d_camera_border_hack_col[4];
1433 short view3d_camera_border_hack_test= FALSE;
1436 /* ****************** draw clip data *************** */
1438 static void draw_bundle_sphere(void)
1440 static GLuint displist= 0;
1442 if (displist == 0) {
1443 GLUquadricObj *qobj;
1445 displist= glGenLists(1);
1446 glNewList(displist, GL_COMPILE);
1448 qobj= gluNewQuadric();
1449 gluQuadricDrawStyle(qobj, GLU_FILL);
1450 glShadeModel(GL_SMOOTH);
1451 gluSphere(qobj, 0.05, 8, 8);
1452 glShadeModel(GL_FLAT);
1453 gluDeleteQuadric(qobj);
1458 glCallList(displist);
1461 static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip, int flag)
1463 MovieTracking *tracking= &clip->tracking;
1464 MovieTrackingTrack *track;
1465 float mat[4][4], imat[4][4], curcol[4];
1466 unsigned char col[4], scol[4];
1469 if((v3d->flag2&V3D_SHOW_RECONSTRUCTION)==0)
1472 if(v3d->flag2&V3D_RENDER_OVERRIDE)
1475 glGetFloatv(GL_CURRENT_COLOR, curcol);
1477 UI_GetThemeColor4ubv(TH_TEXT, col);
1478 UI_GetThemeColor4ubv(TH_SELECT, scol);
1480 BKE_get_tracking_mat(scene, base->object, mat);
1482 glEnable(GL_LIGHTING);
1483 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1484 glEnable(GL_COLOR_MATERIAL);
1485 glShadeModel(GL_SMOOTH);
1487 /* current ogl matrix is translated in camera space, bundles should
1488 be rendered in world space, so camera matrix should be "removed"
1489 from current ogl matrix */
1490 invert_m4_m4(imat, base->object->obmat);
1493 glMultMatrixf(imat);
1496 for ( track= tracking->tracks.first; track; track= track->next) {
1497 int selected= track->flag&SELECT || track->pat_flag&SELECT || track->search_flag&SELECT;
1498 if((track->flag&TRACK_HAS_BUNDLE)==0)
1501 if(flag&DRAW_PICKING)
1502 glLoadName(base->selcol + (bundlenr<<16));
1505 glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
1506 glScalef(v3d->bundle_size/0.05f, v3d->bundle_size/0.05f, v3d->bundle_size/0.05f);
1508 if(v3d->drawtype==OB_WIRE) {
1509 glDisable(GL_LIGHTING);
1513 if(base==BASACT) UI_ThemeColor(TH_ACTIVE);
1514 else UI_ThemeColor(TH_SELECT);
1516 if(track->flag&TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1517 else UI_ThemeColor(TH_WIRE);
1520 drawaxes(0.05f, v3d->bundle_drawtype);
1523 glEnable(GL_LIGHTING);
1524 } else if(v3d->drawtype>OB_WIRE) {
1525 if(v3d->bundle_drawtype==OB_EMPTY_SPHERE) {
1526 /* selection outline */
1528 if(base==BASACT) UI_ThemeColor(TH_ACTIVE);
1529 else UI_ThemeColor(TH_SELECT);
1533 glDisable(GL_LIGHTING);
1534 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1536 draw_bundle_sphere();
1538 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1539 glEnable(GL_LIGHTING);
1544 if(track->flag&TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1545 else UI_ThemeColor(TH_BUNDLE_SOLID);
1547 draw_bundle_sphere();
1549 glDisable(GL_LIGHTING);
1553 if(base==BASACT) UI_ThemeColor(TH_ACTIVE);
1554 else UI_ThemeColor(TH_SELECT);
1556 if(track->flag&TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1557 else UI_ThemeColor(TH_WIRE);
1560 drawaxes(0.05f, v3d->bundle_drawtype);
1563 glEnable(GL_LIGHTING);
1569 if((flag & DRAW_PICKING)==0 && (v3d->flag2&V3D_SHOW_BUNDLENAME)) {
1571 unsigned char tcol[4];
1573 if(selected) memcpy(tcol, scol, sizeof(tcol));
1574 else memcpy(tcol, col, sizeof(tcol));
1576 mul_v3_m4v3(pos, mat, track->bundle_pos);
1577 view3d_cached_text_draw_add(pos, track->name, 10, V3D_CACHE_TEXT_GLOBALSPACE, tcol);
1583 if((flag & DRAW_PICKING)==0) {
1584 if(v3d->flag2&V3D_SHOW_CAMERAPATH && clip->tracking.reconstruction.camnr) {
1586 MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
1587 MovieReconstructedCamera *camera= tracking->reconstruction.cameras;
1589 glDisable(GL_LIGHTING);
1590 UI_ThemeColor(TH_CAMERA_PATH);
1593 glBegin(GL_LINE_STRIP);
1594 for(a= 0; a<reconstruction->camnr; a++, camera++) {
1595 glVertex3fv(camera->mat[3]);
1600 glEnable(GL_LIGHTING);
1607 glShadeModel(GL_FLAT);
1608 glDisable(GL_COLOR_MATERIAL);
1609 glDisable(GL_LIGHTING);
1613 if(flag&DRAW_PICKING)
1614 glLoadName(base->selcol);
1617 /* flag similar to draw_object() */
1618 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int flag)
1620 /* a standing up pyramid with (0,0,0) as top */
1622 Object *ob= base->object;
1624 float vec[4][3], asp[2], shift[2], scale[3];
1627 const short is_view= (rv3d->persp==RV3D_CAMOB && ob==v3d->camera);
1628 MovieClip *clip= object_get_movieclip(scene, base->object, 0);
1630 /* draw data for movie clip set as active for scene */
1632 draw_viewport_reconstruction(scene, base, v3d, clip, flag);
1634 #ifdef VIEW3D_CAMERA_BORDER_HACK
1635 if(is_view && !(G.f & G_PICKSEL)) {
1636 glGetFloatv(GL_CURRENT_COLOR, view3d_camera_border_hack_col);
1637 view3d_camera_border_hack_test= TRUE;
1644 scale[0]= 1.0f / len_v3(ob->obmat[0]);
1645 scale[1]= 1.0f / len_v3(ob->obmat[1]);
1646 scale[2]= 1.0f / len_v3(ob->obmat[2]);
1648 camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
1649 asp, shift, &drawsize, vec);
1651 glDisable(GL_LIGHTING);
1652 glDisable(GL_CULL_FACE);
1655 glBegin(GL_LINE_LOOP);
1656 glVertex3fv(vec[0]);
1657 glVertex3fv(vec[1]);
1658 glVertex3fv(vec[2]);
1659 glVertex3fv(vec[3]);
1667 /* center point to camera frame */
1668 glBegin(GL_LINE_STRIP);
1669 glVertex3fv(vec[1]);
1671 glVertex3fv(vec[0]);
1672 glVertex3fv(vec[3]);
1674 glVertex3fv(vec[2]);
1679 tvec[2]= vec[1][2]; /* copy the depth */
1682 /* draw an outline arrow for inactive cameras and filled
1683 * for active cameras. We actually draw both outline+filled
1684 * for active cameras so the wire can be seen side-on */
1686 if (i==0) glBegin(GL_LINE_LOOP);
1687 else if (i==1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1690 tvec[0]= shift[0] + ((-0.7f * drawsize) * scale[0]);
1691 tvec[1]= shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
1692 glVertex3fv(tvec); /* left */
1694 tvec[0]= shift[0] + ((0.7f * drawsize) * scale[0]);
1695 glVertex3fv(tvec); /* right */
1698 tvec[1]= shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
1699 glVertex3fv(tvec); /* top */
1705 if(cam->flag & (CAM_SHOWLIMITS+CAM_SHOWMIST)) {
1709 /* draw in normalized object matrix space */
1710 copy_m4_m4(nobmat, ob->obmat);
1711 normalize_m4(nobmat);
1714 glLoadMatrixf(rv3d->viewmat);
1715 glMultMatrixf(nobmat);
1717 if(cam->flag & CAM_SHOWLIMITS) {
1718 draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
1719 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composit node */
1720 draw_focus_cross(object_camera_dof_distance(ob), cam->drawsize);
1724 if(cam->flag & CAM_SHOWMIST)
1725 if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF);
1732 /* flag similar to draw_object() */
1733 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
1734 Object *UNUSED(ob), int UNUSED(flag))
1736 //Speaker *spk = ob->data;
1743 for(j = 0; j < 3; j++) {
1744 vec[2] = 0.25f * j -0.125f;
1746 glBegin(GL_LINE_LOOP);
1747 for(i = 0; i < 16; i++) {
1748 vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1749 vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1755 for(j = 0; j < 4; j++) {
1756 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1757 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1758 glBegin(GL_LINE_STRIP);
1759 for(i = 0; i < 3; i++) {
1765 vec[2] = 0.25f * i -0.125f;
1771 glDisable(GL_BLEND);
1774 static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
1776 BPoint *bp = lt->def;
1777 float *co = dl?dl->verts:NULL;
1780 UI_ThemeColor(sel?TH_VERTEX_SELECT:TH_VERTEX);
1781 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1782 bglBegin(GL_POINTS);
1784 for(w=0; w<lt->pntsw; w++) {
1785 int wxt = (w==0 || w==lt->pntsw-1);
1786 for(v=0; v<lt->pntsv; v++) {
1787 int vxt = (v==0 || v==lt->pntsv-1);
1788 for(u=0; u<lt->pntsu; u++, bp++, co+=3) {
1789 int uxt = (u==0 || u==lt->pntsu-1);
1790 if(!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1792 if((bp->f1 & SELECT)==sel) {
1793 bglVertex3fv(dl?co:bp->vec);
1805 void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPoint *bp, int x, int y), void *userData)
1807 Object *obedit= vc->obedit;
1808 Lattice *lt= obedit->data;
1809 BPoint *bp = lt->editlatt->latt->def;
1810 DispList *dl = find_displist(&obedit->disp, DL_VERTS);
1811 float *co = dl?dl->verts:NULL;
1812 int i, N = lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
1813 short s[2] = {IS_CLIPPED, 0};
1815 ED_view3d_local_clipping(vc->rv3d, obedit->obmat); /* for local clipping lookups */
1817 for (i=0; i<N; i++, bp++, co+=3) {
1819 view3d_project_short_clip(vc->ar, dl?co:bp->vec, s, 1);
1820 if (s[0] != IS_CLIPPED)
1821 func(userData, bp, s[0], s[1]);
1826 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
1828 int index = ((w*lt->pntsv + v)*lt->pntsu) + u;
1832 MDeformWeight *mdw= defvert_find_index (lt->dvert+index, use_wcol-1);
1834 weight_to_rgb(col, mdw?mdw->weight:0.0f);
1840 glVertex3fv(&dl->verts[index*3]);
1842 glVertex3fv(lt->def[index].vec);
1846 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1847 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1849 Lattice *lt= ob->data;
1852 int use_wcol= 0, is_edit= (lt->editlatt != NULL);
1854 /* now we default make displist, this will modifiers work for non animated case */
1855 if(ob->disp.first==NULL)
1856 lattice_calc_modifiers(scene, ob);
1857 dl= find_displist(&ob->disp, DL_VERTS);
1860 lt= lt->editlatt->latt;
1864 if(ob->defbase.first && lt->dvert) {
1865 use_wcol= ob->actdef;
1866 glShadeModel(GL_SMOOTH);
1871 for(w=0; w<lt->pntsw; w++) {
1872 int wxt = (w==0 || w==lt->pntsw-1);
1873 for(v=0; v<lt->pntsv; v++) {
1874 int vxt = (v==0 || v==lt->pntsv-1);
1875 for(u=0; u<lt->pntsu; u++) {
1876 int uxt = (u==0 || u==lt->pntsu-1);
1878 if(w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
1879 drawlattice__point(lt, dl, u, v, w-1, use_wcol);
1880 drawlattice__point(lt, dl, u, v, w, use_wcol);
1882 if(v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1883 drawlattice__point(lt, dl, u, v-1, w, use_wcol);
1884 drawlattice__point(lt, dl, u, v, w, use_wcol);
1886 if(u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1887 drawlattice__point(lt, dl, u-1, v, w, use_wcol);
1888 drawlattice__point(lt, dl, u, v, w, use_wcol);
1895 /* restoration for weight colors */
1897 glShadeModel(GL_FLAT);
1900 if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
1902 lattice_draw_verts(lt, dl, 0);
1903 lattice_draw_verts(lt, dl, 1);
1905 if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
1909 /* ***************** ******************** */
1911 /* Note! - foreach funcs should be called while drawing or directly after
1912 * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
1913 * but would not give correct results with dupli's for eg. which dont
1914 * use the object matrix in the useual way */
1915 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1917 struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index);
1918 void *userData; ViewContext vc; eV3DClipTest clipVerts; } *data = userData;
1920 EditVert *eve = EM_get_vert_for_index(index);
1923 short s[2]= {IS_CLIPPED, 0};
1925 if (data->clipVerts != V3D_CLIP_TEST_OFF) {
1926 view3d_project_short_clip(data->vc.ar, co, s, 1);
1928 view3d_project_short_noclip(data->vc.ar, co, s);
1931 if (s[0]!=IS_CLIPPED)
1932 data->func(data->userData, eve, s[0], s[1], index);
1936 void mesh_foreachScreenVert(
1938 void (*func)(void *userData, EditVert *eve, int x, int y, int index),
1939 void *userData, eV3DClipTest clipVerts)
1941 struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index);
1942 void *userData; ViewContext vc; eV3DClipTest clipVerts; } data;
1944 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
1948 data.userData = userData;
1949 data.clipVerts = clipVerts;
1951 if(clipVerts != V3D_CLIP_TEST_OFF)
1952 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
1954 EM_init_index_arrays(vc->em, 1, 0, 0);
1955 dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
1956 EM_free_index_arrays();
1962 static void drawSelectedVertices__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
1964 MVert *mv = &((MVert *)userData)[index];
1966 if(!(mv->flag & ME_HIDE)) {
1967 const char sel= mv->flag & SELECT;
1969 // TODO define selected color
1971 glColor3f(1.0f, 1.0f, 0.0f);
1974 glColor3f(0.0f, 0.0f, 0.0f);
1981 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
1984 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, me->mvert);
1987 static int is_co_in_region(ARegion *ar, const short co[2])
1989 return ( (co[0] != IS_CLIPPED) && /* may be the only initialized value, check first */
1991 (co[0] < ar->winx) &&
1993 (co[1] < ar->winy));
1995 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
1997 struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index);
1998 void *userData; ViewContext vc; eV3DClipTest clipVerts; } *data = userData;
1999 EditEdge *eed = EM_get_edge_for_index(index);
2003 if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) {
2004 view3d_project_short_clip(data->vc.ar, v0co, s[0], 1);
2005 view3d_project_short_clip(data->vc.ar, v1co, s[1], 1);
2008 view3d_project_short_noclip(data->vc.ar, v0co, s[0]);
2009 view3d_project_short_noclip(data->vc.ar, v1co, s[1]);
2011 if (data->clipVerts == V3D_CLIP_TEST_REGION) {
2012 if ( !is_co_in_region(data->vc.ar, s[0]) &&
2013 !is_co_in_region(data->vc.ar, s[1]))
2020 data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index);
2024 void mesh_foreachScreenEdge(
2026 void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index),
2027 void *userData, eV3DClipTest clipVerts)
2029 struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index);
2030 void *userData; ViewContext vc; eV3DClipTest clipVerts; } data;
2031 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2035 data.userData = userData;
2036 data.clipVerts = clipVerts;
2038 if(clipVerts != V3D_CLIP_TEST_OFF)
2039 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2041 EM_init_index_arrays(vc->em, 0, 1, 0);
2042 dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
2043 EM_free_index_arrays();
2048 static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
2050 struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData;
2051 EditFace *efa = EM_get_face_for_index(index);
2054 if (efa && efa->h==0 && efa->fgonf!=EM_FGON) {
2055 view3d_project_short_clip(data->vc.ar, cent, s, 1);
2057 if (s[0] != IS_CLIPPED) {
2058 data->func(data->userData, efa, s[0], s[1], index);
2063 void mesh_foreachScreenFace(
2065 void (*func)(void *userData, EditFace *efa, int x, int y, int index),
2068 struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data;
2069 DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2073 data.userData = userData;
2076 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2078 EM_init_index_arrays(vc->em, 0, 0, 1);
2079 dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
2080 EM_free_index_arrays();
2085 void nurbs_foreachScreenVert(
2087 void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y),
2090 Curve *cu= vc->obedit->data;
2091 short s[2] = {IS_CLIPPED, 0};
2094 ListBase *nurbs= curve_editnurbs(cu);
2096 ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2098 for (nu= nurbs->first; nu; nu=nu->next) {
2099 if(nu->type == CU_BEZIER) {
2100 for (i=0; i<nu->pntsu; i++) {
2101 BezTriple *bezt = &nu->bezt[i];
2105 if(cu->drawflag & CU_HIDE_HANDLES) {
2106 view3d_project_short_clip(vc->ar, bezt->vec[1], s, 1);
2107 if (s[0] != IS_CLIPPED)
2108 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
2110 view3d_project_short_clip(vc->ar, bezt->vec[0], s, 1);
2111 if (s[0] != IS_CLIPPED)
2112 func(userData, nu, NULL, bezt, 0, s[0], s[1]);
2113 view3d_project_short_clip(vc->ar, bezt->vec[1], s, 1);
2114 if (s[0] != IS_CLIPPED)
2115 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
2116 view3d_project_short_clip(vc->ar, bezt->vec[2], s, 1);
2117 if (s[0] != IS_CLIPPED)
2118 func(userData, nu, NULL, bezt, 2, s[0], s[1]);
2124 for (i=0; i<nu->pntsu*nu->pntsv; i++) {
2125 BPoint *bp = &nu->bp[i];
2128 view3d_project_short_clip(vc->ar, bp->vec, s, 1);
2129 if (s[0] != IS_CLIPPED)
2130 func(userData, nu, bp, NULL, -1, s[0], s[1]);
2137 /* ************** DRAW MESH ****************** */
2139 /* First section is all the "simple" draw routines,
2140 * ones that just pass some sort of primitive to GL,
2141 * with perhaps various options to control lighting,
2144 * These routines should not have user interface related
2148 static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
2150 ToolSettings *ts= ((Scene *)userData)->toolsettings;
2151 EditFace *efa = EM_get_face_for_index(index);
2153 if (efa->h==0 && efa->fgonf!=EM_FGON) {
2155 glVertex3f( cent[0] + no[0]*ts->normalsize,
2156 cent[1] + no[1]*ts->normalsize,
2157 cent[2] + no[2]*ts->normalsize);
2160 static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm)
2163 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene);
2167 static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
2169 EditFace *efa = EM_get_face_for_index(index);
2170 int sel = *((int*) userData);
2172 if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) {
2176 static void draw_dm_face_centers(DerivedMesh *dm, int sel)
2178 bglBegin(GL_POINTS);
2179 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel);
2183 static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
2185 Scene *scene= (Scene *)userData;
2186 ToolSettings *ts= scene->toolsettings;
2187 EditVert *eve = EM_get_vert_for_index(index);
2193 glVertex3f( co[0] + no_f[0]*ts->normalsize,
2194 co[1] + no_f[1]*ts->normalsize,
2195 co[2] + no_f[2]*ts->normalsize);
2197 glVertex3f( co[0] + no_s[0]*ts->normalsize/32767.0f,
2198 co[1] + no_s[1]*ts->normalsize/32767.0f,
2199 co[2] + no_s[2]*ts->normalsize/32767.0f);
2203 static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm)
2206 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene);
2210 /* Draw verts with color set based on selection */
2211 static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
2213 struct { int sel; EditVert *eve_act; } * data = userData;
2214 EditVert *eve = EM_get_vert_for_index(index);
2216 if (eve->h==0 && (eve->f&SELECT)==data->sel) {
2217 /* draw active larger - need to stop/start point drawing for this :/ */
2218 if (eve==data->eve_act) {
2219 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2220 UI_ThemeColor4(TH_EDITMESH_ACTIVE);
2225 bglBegin(GL_POINTS);
2229 UI_ThemeColor4(data->sel?TH_VERTEX_SELECT:TH_VERTEX);
2231 bglBegin(GL_POINTS);
2238 static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
2240 struct { int sel; EditVert *eve_act; } data;
2242 data.eve_act = eve_act;
2244 bglBegin(GL_POINTS);
2245 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
2249 /* Draw edges with color set based on selection */
2250 static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2252 EditEdge *eed = EM_get_edge_for_index(index);
2253 //unsigned char **cols = userData, *col;
2254 struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData;
2258 if (eed==data->eed_act) {
2259 glColor4ubv(data->actCol);
2261 if (eed->f&SELECT) {
2264 col = data->baseCol;
2266 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2267 if (col[3]==0) return 0;
2276 static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act)
2278 struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data;
2280 data.baseCol = baseCol;
2281 data.selCol = selCol;
2282 data.actCol = actCol;
2283 data.eed_act = eed_act;
2284 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2288 static int draw_dm_edges__setDrawOptions(void *UNUSED(userData), int index)
2290 return EM_get_edge_for_index(index)->h==0;
2292 static void draw_dm_edges(DerivedMesh *dm)
2294 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL);
2297 /* Draw edges with color interpolated based on selection */
2298 static int draw_dm_edges_sel_interp__setDrawOptions(void *UNUSED(userData), int index)
2300 return EM_get_edge_for_index(index)->h==0;
2302 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2304 EditEdge *eed = EM_get_edge_for_index(index);
2305 unsigned char **cols = userData;
2306 unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0];
2307 unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0];
2309 glColor4ub( col0[0] + (col1[0]-col0[0])*t,
2310 col0[1] + (col1[1]-col0[1])*t,
2311 col0[2] + (col1[2]-col0[2])*t,
2312 col0[3] + (col1[3]-col0[3])*t);
2315 static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2317 unsigned char *cols[2];
2320 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2323 /* Draw only seam edges */
2324 static int draw_dm_edges_seams__setDrawOptions(void *UNUSED(userData), int index)
2326 EditEdge *eed = EM_get_edge_for_index(index);
2328 return (eed->h==0 && eed->seam);
2330 static void draw_dm_edges_seams(DerivedMesh *dm)
2332 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL);
2335 /* Draw only sharp edges */
2336 static int draw_dm_edges_sharp__setDrawOptions(void *UNUSED(userData), int index)
2338 EditEdge *eed = EM_get_edge_for_index(index);
2340 return (eed->h==0 && eed->sharp);
2342 static void draw_dm_edges_sharp(DerivedMesh *dm)
2344 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL);
2348 /* Draw faces with color set based on selection
2349 * return 2 for the active face so it renders with stipple enabled */
2350 static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r))
2352 struct { unsigned char *cols[3]; EditFace *efa_act; int *orig_index; } * data = userData;
2353 EditFace *efa = EM_get_face_for_index(index);
2357 if (efa == data->efa_act) {
2358 glColor4ubv(data->cols[2]);
2359 return 2; /* stipple */
2361 col = data->cols[(efa->f&SELECT)?1:0];
2362 if (col[3]==0) return 0;
2370 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2372 struct { unsigned char *cols[3]; EditFace *efa_act; int *orig_index; } *data = userData;
2375 unsigned char *col, *next_col;
2377 if(!data->orig_index)
2380 efa= EM_get_face_for_index(data->orig_index[index]);
2381 next_efa= EM_get_face_for_index(data->orig_index[next_index]);
2386 if(efa == data->efa_act || next_efa == data->efa_act)
2389 col = data->cols[(efa->f&SELECT)?1:0];
2390 next_col = data->cols[(next_efa->f&SELECT)?1:0];
2392 if(col[3]==0 || next_col[3]==0)
2395 return col == next_col;
2398 /* also draws the active face */
2399 static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act)
2401 struct { unsigned char *cols[3]; EditFace *efa_act; int *orig_index; } data;
2402 data.cols[0] = baseCol;
2403 data.cols[1] = selCol;
2404 data.cols[2] = actCol;
2405 data.efa_act = efa_act;
2406 data.orig_index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
2408 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
2411 static int draw_dm_creases__setDrawOptions(void *UNUSED(userData), int index)
2413 EditEdge *eed = EM_get_edge_for_index(index);
2415 if (eed->h==0 && eed->crease != 0.0f) {
2416 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, eed->crease);
2422 static void draw_dm_creases(DerivedMesh *dm)
2425 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL);
2429 static int draw_dm_bweights__setDrawOptions(void *UNUSED(userData), int index)
2431 EditEdge *eed = EM_get_edge_for_index(index);
2433 if (eed->h==0 && eed->bweight != 0.0f) {
2434 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight);
2440 static void draw_dm_bweights__mapFunc(void *UNUSED(userData), int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
2442 EditVert *eve = EM_get_vert_for_index(index);
2444 if (eve->h==0 && eve->bweight != 0.0f) {
2445 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight);
2449 static void draw_dm_bweights(Scene *scene, DerivedMesh *dm)
2451 ToolSettings *ts= scene->toolsettings;
2453 if (ts->selectmode & SCE_SELECT_VERTEX) {
2454 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2455 bglBegin(GL_POINTS);
2456 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL);
2461 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL);
2466 /* Second section of routines: Combine first sets to form fancy
2467 * drawing routines (for example rendering twice to get overlays).
2469 * Also includes routines that are basic drawing but are too
2470 * specialized to be split out (like drawing creases or measurements).
2473 /* EditMesh drawing routines*/
2475 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
2476 DerivedMesh *cageDM, EditVert *eve_act)
2478 ToolSettings *ts= scene->toolsettings;
2481 if(v3d->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select
2483 for (sel=0; sel<2; sel++) {
2484 unsigned char col[4], fcol[4];
2487 UI_GetThemeColor3ubv(sel?TH_VERTEX_SELECT:TH_VERTEX, col);
2488 UI_GetThemeColor3ubv(sel?TH_FACE_DOT:TH_WIRE, fcol);
2490 for (pass=0; pass<2; pass++) {
2491 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2492 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2495 if(v3d->zbuf && !(v3d->flag&V3D_ZBUF_SELECT)) {
2496 glDisable(GL_DEPTH_TEST);
2503 size = (size > 2.1f ? size/2.0f:size);
2504 fsize = (fsize > 2.1f ? fsize/2.0f:fsize);
2505 col[3] = fcol[3] = 100;
2507 col[3] = fcol[3] = 255;
2510 if(ts->selectmode & SCE_SELECT_VERTEX) {
2513 draw_dm_verts(cageDM, sel, eve_act);
2516 if(check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2519 draw_dm_face_centers(cageDM, sel);
2523 glDisable(GL_BLEND);
2524 glEnable(GL_DEPTH_TEST);
2529 if(v3d->zbuf) glDepthMask(1);
2533 static void draw_em_fancy_edges(Scene *scene, View3D *v3d,
2534 Mesh *me, DerivedMesh *cageDM, short sel_only,
2537 ToolSettings *ts= scene->toolsettings;
2539 unsigned char wireCol[4], selCol[4], actCol[4];
2541 /* since this function does transparant... */
2542 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2543 UI_GetThemeColor4ubv(TH_WIRE, wireCol);
2544 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2546 /* when sel only is used, dont render wire, only selected, this is used for
2547 * textured draw mode when the 'edges' option is disabled */
2551 for (pass=0; pass<2; pass++) {
2552 /* show wires in transparant when no zbuf clipping for select */
2554 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0) {
2556 glDisable(GL_DEPTH_TEST);
2558 if (!sel_only) wireCol[3] = 85;
2564 if (!sel_only) wireCol[3] = 255;
2567 if(ts->selectmode == SCE_SELECT_FACE) {
2568 draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
2570 else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
2571 if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2572 glShadeModel(GL_SMOOTH);
2573 draw_dm_edges_sel_interp(cageDM, wireCol, selCol);
2574 glShadeModel(GL_FLAT);
2576 draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
2581 glColor4ubv(wireCol);
2582 draw_dm_edges(cageDM);
2587 glDisable(GL_BLEND);
2588 glEnable(GL_DEPTH_TEST);
2593 static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d,
2594 Object *ob, EditMesh *em, UnitSettings *unit)
2599 float v1[3], v2[3], v3[3], v4[3], vmid[3];
2601 char val[32]; /* Stores the measurement display text here */
2602 const char *conv_float; /* Use a float conversion matching the grid size */
2603 unsigned char col[4]= {0, 0, 0, 255}; /* color of the text to draw */
2604 float area; /* area of the face */
2605 float grid= unit->system ? unit->scale_length : v3d->grid;
2606 const int do_split= unit->flag & USER_UNIT_OPT_SPLIT;
2607 const int do_global= v3d->flag & V3D_GLOBAL_STATS;
2608 const int do_moving= G.moving;
2610 /* make the precision of the pronted value proportionate to the gridsize */
2612 if (grid < 0.01f) conv_float= "%.6g";
2613 else if (grid < 0.1f) conv_float= "%.5g";
2614 else if (grid < 1.0f) conv_float= "%.4g";
2615 else if (grid < 10.0f) conv_float= "%.3g";
2616 else conv_float= "%.2g";
2618 if(v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0)
2619 glDisable(GL_DEPTH_TEST);
2621 if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0f);
2623 if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2624 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2626 for(eed= em->edges.first; eed; eed= eed->next) {
2627 /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */
2628 if((eed->h != EM_FGON) && ((eed->f & SELECT) || (do_moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) {
2629 copy_v3_v3(v1, eed->v1->co);
2630 copy_v3_v3(v2, eed->v2->co);
2632 mid_v3_v3v3(vmid, v1, v2);
2635 mul_mat3_m4_v3(ob->obmat, v1);
2636 mul_mat3_m4_v3(ob->obmat, v2);
2639 bUnit_AsString(val, sizeof(val), len_v3v3(v1, v2)*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE);
2641 sprintf(val, conv_float, len_v3v3(v1, v2));
2643 view3d_cached_text_draw_add(vmid, val, 0, V3D_CACHE_TEXT_ASCII, col);
2648 if(me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2649 // XXX extern int faceselectedOR(EditFace *efa, int flag); // editmesh.h shouldn't be in this file... ok for now?
2650 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2652 for(efa= em->faces.first; efa; efa= efa->next) {
2653 if((efa->f & SELECT)) { // XXX || (do_moving && faceselectedOR(efa, SELECT)) ) {
2654 copy_v3_v3(v1, efa->v1->co);
2655 copy_v3_v3(v2, efa->v2->co);
2656 copy_v3_v3(v3, efa->v3->co);
2658 copy_v3_v3(v4, efa->v4->co);
2661 mul_mat3_m4_v3(ob->obmat, v1);
2662 mul_mat3_m4_v3(ob->obmat, v2);
2663 mul_mat3_m4_v3(ob->obmat, v3);
2664 if (efa->v4) mul_mat3_m4_v3(ob->obmat, v4);
2668 area= area_quad_v3(v1, v2, v3, v4);
2670 area = area_tri_v3(v1, v2, v3);
2673 bUnit_AsString(val, sizeof(val), area*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); // XXX should be B_UNIT_AREA
2675 sprintf(val, conv_float, area);
2677 view3d_cached_text_draw_add(efa->cent, val, 0, V3D_CACHE_TEXT_ASCII, col);
2682 if(me->drawflag & ME_DRAWEXTRA_FACEANG) {
2683 EditEdge *e1, *e2, *e3, *e4;
2684 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2685 for(efa= em->faces.first; efa; efa= efa->next) {
2686 copy_v3_v3(v1, efa->v1->co);
2687 copy_v3_v3(v2, efa->v2->co);
2688 copy_v3_v3(v3, efa->v3->co);
2690 copy_v3_v3(v4, efa->v4->co);
2696 mul_mat3_m4_v3(ob->obmat, v1);
2697 mul_mat3_m4_v3(ob->obmat, v2);
2698 mul_mat3_m4_v3(ob->obmat, v3);
2699 mul_mat3_m4_v3(ob->obmat, v4); /* intentionally executed even for tri's */
2705 if(efa->e4) e4= efa->e4; else e4= e3;
2707 /* Calculate the angles */
2709 if( (e4->f & e1->f & SELECT) || (do_moving && (efa->v1->f & SELECT)) ) {
2711 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v4, v1, v2)));
2712 interp_v3_v3v3(fvec, efa->cent, efa->v1->co, 0.8f);
2713 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2715 if( (e1->f & e2->f & SELECT) || (do_moving && (efa->v2->f & SELECT)) ) {
2717 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
2718 interp_v3_v3v3(fvec, efa->cent, efa->v2->co, 0.8f);
2719 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2721 if( (e2->f & e3->f & SELECT) || (do_moving && (efa->v3->f & SELECT)) ) {
2724 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v4)));
2726 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v1)));
2727 interp_v3_v3v3(fvec, efa->cent, efa->v3->co, 0.8f);
2728 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2732 if( (e3->f & e4->f & SELECT) || (do_moving && (efa->v4->f & SELECT)) ) {
2733 sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v3, v4, v1)));
2734 interp_v3_v3v3(fvec, efa->cent, efa->v4->co, 0.8f);
2735 view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
2741 /* useful for debugging index vs shape key index */
2746 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2747 for(eve= em->verts.first, j= 0; eve; eve= eve->next, j++) {
2748 sprintf(val, "%d:%d", j, eve->keyindex);
2749 view3d_cached_text_draw_add(eve->co, val, 0, V3D_CACHE_TEXT_ASCII, col);
2755 glEnable(GL_DEPTH_TEST);
2756 bglPolygonOffset(rv3d->dist, 0.0f);
2760 static int draw_em_fancy__setFaceOpts(void *UNUSED(userData), int index, int *UNUSED(drawSmooth_r))
2762 EditFace *efa = EM_get_face_for_index(index);
2765 GPU_enable_material(efa->mat_nr+1, NULL);
2772 static int draw_em_fancy__setGLSLFaceOpts(void *UNUSED(userData), int index)
2774 EditFace *efa = EM_get_face_for_index(index);
2779 static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
2780 Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
2782 Mesh *me = ob->data;
2783 EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */
2784 EditEdge *eed_act = NULL;
2785 EditVert *eve_act = NULL;
2787 if (em->selected.last) {
2788 EditSelection *ese = em->selected.last;
2789 /* face is handeled above */
2790 /*if (ese->type == EDITFACE ) {
2791 efa_act = (EditFace *)ese->data;
2792 } else */ if ( ese->type == EDITEDGE ) {
2793 eed_act = (EditEdge *)ese->data;
2794 } else if ( ese->type == EDITVERT ) {
2795 eve_act = (EditVert *)ese->data;
2799 EM_init_index_arrays(em, 1, 1, 1);
2802 if(CHECK_OB_DRAWTEXTURE(v3d, dt)) {
2803 if(draw_glsl_material(scene, ob, v3d, dt)) {
2804 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2806 finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
2807 draw_em_fancy__setGLSLFaceOpts, em);
2808 GPU_disable_material();
2810 glFrontFace(GL_CCW);
2813 draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
2817 /* 3 floats for position,
2818 * 3 for normal and times two because the faces may actually be quads instead of triangles */
2819 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED);
2821 glEnable(GL_LIGHTING);
2822 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
2823 finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, NULL, 0);
2825 glFrontFace(GL_CCW);
2826 glDisable(GL_LIGHTING);
2829 // Setup for drawing wire over, disable zbuffer
2830 // write to show selected edge wires better
2831 UI_ThemeColor(TH_WIRE);
2833 bglPolygonOffset(rv3d->dist, 1.0);
2837 if (cageDM!=finalDM) {
2838 UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
2839 finalDM->drawEdges(finalDM, 1, 0);
2843 if(me->drawflag & ME_DRAWFACES) { /* transp faces */
2844 unsigned char col1[4], col2[4], col3[4];
2846 UI_GetThemeColor4ubv(TH_FACE, col1);
2847 UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
2848 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
2851 glDepthMask(0); // disable write in zbuffer, needed for nice transp
2853 /* dont draw unselected faces, only selected, this is MUCH nicer when texturing */
2854 if CHECK_OB_DRAWTEXTURE(v3d, dt)
2857 draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
2859 glDisable(GL_BLEND);
2860 glDepthMask(1); // restore write in zbuffer
2861 } else if (efa_act) {
2862 /* even if draw faces is off it would be nice to draw the stipple face
2863 * Make all other faces zero alpha except for the active
2865 unsigned char col1[4], col2[4], col3[4];
2866 col1[3] = col2[3] = 0; /* dont draw */
2867 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
2870 glDepthMask(0); // disable write in zbuffer, needed for nice transp
2872 draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
2874 glDisable(GL_BLEND);
2875 glDepthMask(1); // restore write in zbuffer
2879 /* here starts all fancy draw-extra over */
2880 if((me->drawflag & ME_DRAWEDGES)==0 && CHECK_OB_DRAWTEXTURE(v3d, dt)) {
2881 /* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */
2883 /* only draw selected edges otherwise there is no way of telling if a face is selected */
2884 draw_em_fancy_edges(scene, v3d, me, cageDM, 1, eed_act);
2887 if(me->drawflag & ME_DRAWSEAMS) {
2888 UI_ThemeColor(TH_EDGE_SEAM);
2891 draw_dm_edges_seams(cageDM);
2897 if(me->drawflag & ME_DRAWSHARP) {
2898 UI_ThemeColor(TH_EDGE_SHARP);
2901 draw_dm_edges_sharp(cageDM);
2907 if(me->drawflag & ME_DRAWCREASES) {
2908 draw_dm_creases(cageDM);
2910 if(me->drawflag & ME_DRAWBWEIGHTS) {
2911 draw_dm_bweights(scene, cageDM);
2914 draw_em_fancy_edges(scene, v3d, me, cageDM, 0, eed_act);
2917 // XXX retopo_matrix_update(v3d);
2919 draw_em_fancy_verts(scene, v3d, ob, cageDM, eve_act);
2921 if(me->drawflag & ME_DRAWNORMALS) {
2922 UI_ThemeColor(TH_NORMAL);
2923 draw_dm_face_normals(scene, cageDM);
2925 if(me->drawflag & ME_DRAW_VNORMALS) {
2926 UI_ThemeColor(TH_VNORMAL);
2927 draw_dm_vert_normals(scene, cageDM);
2930 if ( (me->drawflag & (ME_DRAWEXTRA_EDGELEN|ME_DRAWEXTRA_FACEAREA|ME_DRAWEXTRA_FACEANG)) &&
2931 !(v3d->flag2 & V3D_RENDER_OVERRIDE))
2933 draw_em_measure_stats(v3d, rv3d, ob, em, &scene->unit);
2939 bglPolygonOffset(rv3d->dist, 0.0);
2940 GPU_disable_material();
2943 EM_free_index_arrays();
2946 /* Mesh drawing routines */
2948 static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
2951 if(v3d->transp==0) { // not when we draw the transparent pass
2952 glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
2955 /* if transparent, we cannot draw the edges for solid select... edges have no material info.
2956 drawFacesSolid() doesn't draw the transparent faces */
2957 if(ob->dtx & OB_DRAWTRANSP) {
2958 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2959 dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
2960 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2961 GPU_disable_material();
2964 dm->drawEdges(dm, 0, 1);
2972 static int wpaint__setSolidDrawOptions(void *UNUSED(userData), int UNUSED(index), int *drawSmooth_r)
2978 static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
2980 Object *ob= base->object;
2981 Mesh *me = ob->data;
2982 Material *ma= give_current_material(ob, 1);
2983 const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO));
2984 eWireDrawMode draw_wire= OBDRAW_WIRE_OFF;
2985 int /* totvert,*/ totedge, totface;
2986 DerivedMesh *dm= mesh_get_derived_final(scene, ob, scene->customdata_mask);
2987 ModifierData *md = NULL;
2988 const short is_obact= (ob == OBACT);
2989 int draw_flags = (is_obact && paint_facesel_test(ob)) ? DRAW_FACE_SELECT : 0;
2994 /* check to draw dynamic paint colors */
2995 if ((md = modifiers_findByType(ob, eModifierType_DynamicPaint)))
2997 /* check if target has an active dpaint modifier */
2998 if(md && (md->mode & eModifierMode_Realtime))
3000 DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
3001 /* if canvas is ready to preview vertex colors */
3002 if (pmd->canvas && pmd->canvas->flags & MOD_DPAINT_PREVIEW_READY &&
3003 DM_get_face_data_layer(dm, CD_WEIGHT_MCOL)) {
3004 draw_flags |= DRAW_DYNAMIC_PAINT_PREVIEW;
3009 /* Unwanted combination */
3010 if (draw_flags & DRAW_FACE_SELECT) {
3011 draw_wire= OBDRAW_WIRE_OFF;
3013 else if (ob->dtx & OB_DRAWWIRE) {
3014 draw_wire= OBDRAW_WIRE_ON_DEPTH; /* draw wire after solid using zoffset and depth buffer adjusment */
3017 /* totvert = dm->getNumVerts(dm); */ /*UNUSED*/
3018 totedge = dm->getNumEdges(dm);
3019 totface = dm->getNumFaces(dm);
3021 /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
3022 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
3024 if(dt==OB_BOUNDBOX) {
3025 if((v3d->flag2 & V3D_RENDER_OVERRIDE && v3d->drawtype >= OB_WIRE)==0)
3026 draw_bounding_volume(scene, ob, ob->boundtype);
3028 else if(hasHaloMat || (totface==0 && totedge==0)) {
3033 else if(dt==OB_WIRE || totface==0) {
3034 draw_wire= OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
3036 else if ( (draw_flags & DRAW_FACE_SELECT || (is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
3037 CHECK_OB_DRAWTEXTURE(v3d, dt))
3039 if ( (v3d->flag & V3D_SELECT_OUTLINE) &&
3040 ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) &&
3041 (base->flag & SELECT) &&
3042 !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
3043 (draw_wire == OBDRAW_WIRE_OFF))
3045 draw_mesh_object_outline(v3d, ob, dm);
3048 if(draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_DYNAMIC_PAINT_PREVIEW)) {
3049 glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
3051 dm->drawFacesGLSL(dm, GPU_enable_material);
3052 // if(get_ob_property(ob, "Text"))
3053 // XXX draw_mesh_text(ob, 1);
3054 GPU_disable_material();
3056 glFrontFace(GL_CCW);