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
30 #include "MEM_guardedalloc.h"
32 #include "DNA_camera_types.h"
33 #include "DNA_curve_types.h"
34 #include "DNA_constraint_types.h" /* for drawing constraint */
35 #include "DNA_lamp_types.h"
36 #include "DNA_lattice_types.h"
37 #include "DNA_material_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_meta_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_smoke_types.h"
42 #include "DNA_world_types.h"
43 #include "DNA_object_types.h"
45 #include "BLI_blenlib.h"
48 #include "BKE_anim.h" /* for the where_on_path function */
49 #include "BKE_armature.h"
50 #include "BKE_camera.h"
51 #include "BKE_constraint.h" /* for the get_constraint_target function */
52 #include "BKE_curve.h"
53 #include "BKE_DerivedMesh.h"
54 #include "BKE_deform.h"
55 #include "BKE_displist.h"
57 #include "BKE_global.h"
58 #include "BKE_image.h"
60 #include "BKE_lattice.h"
62 #include "BKE_material.h"
63 #include "BKE_mball.h"
64 #include "BKE_modifier.h"
65 #include "BKE_object.h"
66 #include "BKE_paint.h"
67 #include "BKE_particle.h"
68 #include "BKE_pointcache.h"
69 #include "BKE_scene.h"
71 #include "BKE_tracking.h"
73 #include "BKE_tessmesh.h"
75 #include "IMB_imbuf.h"
76 #include "IMB_imbuf_types.h"
79 #include "BIF_glutil.h"
82 #include "GPU_extensions.h"
85 #include "ED_particle.h"
86 #include "ED_screen.h"
87 #include "ED_sculpt.h"
90 #include "UI_resources.h"
95 #include "view3d_intern.h" /* bad level include */
97 typedef enum eWireDrawMode {
100 OBDRAW_WIRE_ON_DEPTH = 2
103 typedef struct drawDMVerts_userData {
104 BMEditMesh *em; /* BMESH BRANCH ONLY */
109 /* cached theme values */
110 unsigned char th_editmesh_active[4];
111 unsigned char th_vertex_select[4];
112 unsigned char th_vertex[4];
113 unsigned char th_skin_root[4];
114 float th_vertex_size;
116 /* for skin node drawing */
119 } drawDMVerts_userData;
121 typedef struct drawDMEdgesSel_userData {
122 BMEditMesh *em; /* BMESH BRANCH ONLY */
124 unsigned char *baseCol, *selCol, *actCol;
126 } drawDMEdgesSel_userData;
128 typedef struct drawDMFacesSel_userData {
129 unsigned char *cols[4];
131 DerivedMesh *dm; /* BMESH BRANCH ONLY */
132 BMEditMesh *em; /* BMESH BRANCH ONLY */
135 int *orig_index_mf_to_mpoly;
136 int *orig_index_mp_to_orig;
137 } drawDMFacesSel_userData;
139 typedef struct drawDMNormal_userData {
145 } drawDMNormal_userData;
147 typedef struct bbsObmodeMeshVerts_userData {
150 } bbsObmodeMeshVerts_userData;
152 static void draw_bounding_volume(Scene *scene, Object *ob, char type);
154 static void drawcube_size(float size);
155 static void drawcircle_size(float size);
156 static void draw_empty_sphere(float size);
157 static void draw_empty_cone(float size);
159 static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
161 float col_wire[3], col_bg[3], col[3];
163 rgb_uchar_to_float(col_wire, ob_wire_col);
165 UI_GetThemeColor3fv(theme_id, col_bg);
166 interp_v3_v3v3(col, col_bg, col_wire, fac);
170 /* this condition has been made more complex since editmode can draw textures */
171 static int check_object_draw_texture(Scene *scene, View3D *v3d, int drawtype)
173 /* texture and material draw modes */
174 if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID)
178 if (v3d->drawtype == OB_SOLID && (v3d->flag2 & V3D_SOLID_TEX) && !BKE_scene_use_new_shading_nodes(scene))
184 static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
186 if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
189 if (G.f & G_BACKBUFSEL)
192 if ((vd->flag & V3D_ZBUF_SELECT) == 0)
195 /* if its drawing textures with zbuf sel, then don't draw dots */
196 if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
199 if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
205 /* ************************ */
207 /* check for glsl drawing */
209 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const short dt)
211 if (!GPU_glsl_support())
215 if (!check_object_draw_texture(scene, v3d, dt))
217 if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
219 if (BKE_scene_use_new_shading_nodes(scene))
222 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
225 static int check_alpha_pass(Base *base)
227 if (base->flag & OB_FROMDUPLI)
233 if (base->object->mode & OB_MODE_ALL_PAINT)
236 return (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 Optimized Drawing Speed ------------------ */
261 /* 32 values of sin function (still same result!) */
262 #define CIRCLE_RESOL 32
264 static const float sinval[CIRCLE_RESOL] = {
299 /* 32 values of cos function (still same result!) */
300 static const float cosval[CIRCLE_RESOL] = {
335 static void draw_xyz_wire(const float c[3], float size, int axis)
337 float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
338 float dim = size * 0.1f;
339 float dx[3], dy[3], dz[3];
341 dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
342 dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
343 dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
349 /* bottom left to top right */
350 sub_v3_v3v3(v1, c, dx);
352 add_v3_v3v3(v2, c, dx);
358 /* top left to bottom right */
371 /* bottom left to top right */
372 mul_v3_fl(dx, 0.75f);
373 sub_v3_v3v3(v1, c, dx);
375 add_v3_v3v3(v2, c, dx);
381 /* top left to center */
392 glBegin(GL_LINE_STRIP);
394 /* start at top left */
395 sub_v3_v3v3(v1, c, dx);
396 add_v3_v3v3(v1, c, dz);
421 void drawaxes(float size, char drawtype)
424 float v1[3] = {0.0, 0.0, 0.0};
425 float v2[3] = {0.0, 0.0, 0.0};
426 float v3[3] = {0.0, 0.0, 0.0};
431 for (axis = 0; axis < 3; axis++) {
439 /* reset v1 & v2 to zero */
440 v1[axis] = v2[axis] = 0.0f;
445 case OB_SINGLE_ARROW:
448 /* in positive z direction only */
455 glBegin(GL_TRIANGLES);
457 v2[0] = size * 0.035f; v2[1] = size * 0.035f;
458 v3[0] = size * -0.035f; v3[1] = size * 0.035f;
459 v2[2] = v3[2] = size * 0.75f;
461 for (axis = 0; axis < 4; axis++) {
484 drawcircle_size(size);
487 case OB_EMPTY_SPHERE:
488 draw_empty_sphere(size);
492 draw_empty_cone(size);
498 for (axis = 0; axis < 3; axis++) {
499 const int arrow_axis = (axis == 0) ? 1 : 0;
507 v1[axis] = size * 0.85f;
508 v1[arrow_axis] = -size * 0.08f;
512 v1[arrow_axis] = size * 0.08f;
518 v2[axis] += size * 0.125f;
520 draw_xyz_wire(v2, size, axis);
523 /* reset v1 & v2 to zero */
524 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
532 /* Function to draw an Image on a empty Object */
533 static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
535 Image *ima = (Image *)ob->data;
536 ImBuf *ibuf = ima ? BKE_image_acquire_ibuf(ima, NULL, NULL) : NULL;
538 float scale, ofs_x, ofs_y, sca_x, sca_y;
541 if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
542 IMB_rect_from_float(ibuf);
545 /* Get the buffer dimensions so we can fallback to fake ones */
546 if (ibuf && ibuf->rect) {
555 /* Get the image aspect even if the buffer is invalid */
557 if (ima->aspx > ima->aspy) {
559 sca_y = ima->aspy / ima->aspx;
561 else if (ima->aspx < ima->aspy) {
562 sca_x = ima->aspx / ima->aspy;
575 /* Calculate the scale center based on objects origin */
576 ofs_x = ob->ima_ofs[0] * ima_x;
577 ofs_y = ob->ima_ofs[1] * ima_y;
579 glMatrixMode(GL_MODELVIEW);
582 /* Make sure we are drawing at the origin */
583 glTranslatef(0.0f, 0.0f, 0.0f);
585 /* Calculate Image scale */
586 scale = (ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y));
588 /* Set the object scale */
589 glScalef(scale * sca_x, scale * sca_y, 1.0f);
591 if (ibuf && ibuf->rect) {
592 /* Setup GL params */
594 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
596 /* Use the object color and alpha */
599 /* Draw the Image on the screen */
600 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
601 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
606 if ((dflag & DRAW_CONSTCOLOR) == 0) {
607 glColor3ubv(ob_wire_col);
609 /* Calculate the outline vertex positions */
610 glBegin(GL_LINE_LOOP);
611 glVertex2f(ofs_x, ofs_y);
612 glVertex2f(ofs_x + ima_x, ofs_y);
613 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
614 glVertex2f(ofs_x, ofs_y + ima_y);
618 /* Reset GL settings */
619 glMatrixMode(GL_MODELVIEW);
622 BKE_image_release_ibuf(ima, ibuf, NULL);
625 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[][4])
628 float *viter = (float *)verts;
631 mul_v3_v3fl(vx, tmat[0], rad);
632 mul_v3_v3fl(vy, tmat[1], rad);
634 for (a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
635 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
636 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
637 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
641 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
643 float verts[CIRCLE_RESOL][3];
645 circball_array_fill(verts, cent, rad, tmat);
647 glEnableClientState(GL_VERTEX_ARRAY);
648 glVertexPointer(3, GL_FLOAT, 0, verts);
649 glDrawArrays(mode, 0, CIRCLE_RESOL);
650 glDisableClientState(GL_VERTEX_ARRAY);
653 /* circle for object centers, special_color is for library or ob users */
654 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
656 const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
657 float verts[CIRCLE_RESOL][3];
659 /* using gldepthfunc guarantees that it does write z values,
660 * but not checks for it, so centers remain visible independent order of drawing */
661 if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
665 if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
667 else glColor4ub(0x55, 0xCC, 0xCC, 155);
670 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
671 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
672 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
675 circball_array_fill(verts, co, size, rv3d->viewinv);
677 /* enable vertex array */
678 glEnableClientState(GL_VERTEX_ARRAY);
679 glVertexPointer(3, GL_FLOAT, 0, verts);
681 /* 1. draw filled, blended polygon */
682 glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
684 /* 2. draw outline */
685 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
686 glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
689 glDisableClientState(GL_VERTEX_ARRAY);
693 if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
696 /* *********** text drawing for object/particles/armature ************* */
697 static ListBase CachedText[3];
698 static int CachedTextLevel = 0;
700 typedef struct ViewCachedString {
701 struct ViewCachedString *next, *prev;
711 /* str is allocated past the end */
714 void view3d_cached_text_draw_begin(void)
716 ListBase *strings = &CachedText[CachedTextLevel];
717 strings->first = strings->last = NULL;
721 void view3d_cached_text_draw_add(const float co[3],
723 short xoffs, short flag,
724 const unsigned char col[4])
726 int alloc_len = strlen(str) + 1;
727 ListBase *strings = &CachedText[CachedTextLevel - 1];
728 /* TODO, replace with more efficient malloc, perhaps memarena per draw? */
729 ViewCachedString *vos = MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
731 BLI_addtail(strings, vos);
732 copy_v3_v3(vos->vec, co);
733 copy_v4_v4_char((char *)vos->col.ub, (const char *)col);
736 vos->str_len = alloc_len - 1;
738 /* allocate past the end */
739 memcpy(++vos, str, alloc_len);
742 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
744 RegionView3D *rv3d = ar->regiondata;
745 ListBase *strings = &CachedText[CachedTextLevel - 1];
746 ViewCachedString *vos;
749 /* project first and test */
750 for (vos = strings->first; vos; vos = vos->next) {
751 if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
752 mul_m4_v3(mat, vos->vec);
754 if (ED_view3d_project_short_ex(ar,
755 (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
756 (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
758 V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK)
763 vos->sco[0] = IS_CLIPPED;
768 int col_pack_prev = 0;
771 bglMats mats; /* ZBuffer depth vars */
778 if (rv3d->rflag & RV3D_CLIPPING) {
779 ED_view3d_clipping_disable();
782 glMatrixMode(GL_PROJECTION);
784 glMatrixMode(GL_MODELVIEW);
786 ED_region_pixelspace(ar);
789 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
795 for (vos = strings->first; vos; vos = vos->next) {
796 /* too slow, reading opengl info while drawing is very bad,
797 * better to see if we can use the zbuffer while in pixel space - campbell */
799 if (v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
800 gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
801 glReadPixels(ar->winrct.xmin + vos->mval[0] + vos->xoffs, ar->winrct.ymin + vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
807 if (vos->sco[0] != IS_CLIPPED) {
808 const char *str = (char *)(vos + 1);
810 if (col_pack_prev != vos->col.pack) {
811 glColor3ubv(vos->col.ub);
812 col_pack_prev = vos->col.pack;
815 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
816 BLF_draw_default_ascii :
818 )( (float)vos->sco[0] + vos->xoffs,
820 (depth_write) ? 0.0f : 2.0f,
827 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
833 glMatrixMode(GL_PROJECTION);
835 glMatrixMode(GL_MODELVIEW);
838 if (rv3d->rflag & RV3D_CLIPPING) {
839 ED_view3d_clipping_enable();
844 BLI_freelistN(strings);
849 /* ******************** primitive drawing ******************* */
851 static void drawcube(void)
854 glBegin(GL_LINE_STRIP);
855 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
856 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
857 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
860 glBegin(GL_LINE_STRIP);
861 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
864 glBegin(GL_LINE_STRIP);
865 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
868 glBegin(GL_LINE_STRIP);
869 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
873 /* draws a cube on given the scaling of the cube, assuming that
874 * all required matrices have been set (used for drawing empties)
876 static void drawcube_size(float size)
878 glBegin(GL_LINE_STRIP);
879 glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size);
880 glVertex3f(-size, size, size); glVertex3f(-size, size, -size);
882 glVertex3f(-size, -size, -size); glVertex3f(size, -size, -size);
883 glVertex3f(size, -size, size); glVertex3f(size, size, size);
885 glVertex3f(size, size, -size); glVertex3f(size, -size, -size);
888 glBegin(GL_LINE_STRIP);
889 glVertex3f(-size, -size, size); glVertex3f(size, -size, size);
892 glBegin(GL_LINE_STRIP);
893 glVertex3f(-size, size, size); glVertex3f(size, size, size);
896 glBegin(GL_LINE_STRIP);
897 glVertex3f(-size, size, -size); glVertex3f(size, size, -size);
901 /* this is an unused (old) cube-drawing function based on a given size */
903 static void drawcube_size(const float size[3])
907 glScalef(size[0], size[1], size[2]);
910 glBegin(GL_LINE_STRIP);
911 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
912 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
913 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
916 glBegin(GL_LINE_STRIP);
917 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
920 glBegin(GL_LINE_STRIP);
921 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
924 glBegin(GL_LINE_STRIP);
925 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
932 static void drawshadbuflimits(Lamp *la, float mat[][4])
934 float sta[3], end[3], lavec[3];
936 negate_v3_v3(lavec, mat[2]);
939 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
940 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
942 glBegin(GL_LINE_STRIP);
957 static void spotvolume(float lvec[3], float vvec[3], const float inp)
959 /* camera is at 0,0,0 */
960 float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
963 normalize_v3(vvec); /* is this the correct vector ? */
965 cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec en lvec */
966 cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parrallel with lvec */
968 /* vectors are exactly aligned, use the X axis, this is arbitrary */
969 if (normalize_v3(plane) == 0.0f)
972 /* now we've got two equations: one of a cone and one of a plane, but we have
973 * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
975 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
976 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
978 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
985 angle = saacos(plane[2]) / 2.0f;
987 si = sqrtf(1 - co * co);
994 quat_to_mat3(mat1, q);
996 /* rotate lamp vector now over acos(inp) degrees */
997 copy_v3_v3(vvec, lvec);
1001 si = sqrtf(1.0f - inp * inp);
1007 mul_m3_m3m3(mat3, mat2, mat1);
1011 mul_m3_m3m3(mat4, mat2, mat1);
1014 mul_m3_m3m3(mat2, mat1, mat3);
1015 mul_m3_v3(mat2, lvec);
1016 mul_m3_m3m3(mat2, mat1, mat4);
1017 mul_m3_v3(mat2, vvec);
1022 static void draw_spot_cone(Lamp *la, float x, float z)
1026 glBegin(GL_TRIANGLE_FAN);
1027 glVertex3f(0.0f, 0.0f, -x);
1029 if (la->mode & LA_SQUARE) {
1030 glVertex3f(z, z, 0);
1031 glVertex3f(-z, z, 0);
1032 glVertex3f(-z, -z, 0);
1033 glVertex3f(z, -z, 0);
1034 glVertex3f(z, z, 0);
1040 for (a = 0; a < 33; a++) {
1041 angle = a * M_PI * 2 / (33 - 1);
1042 glVertex3f(z * cosf(angle), z * sinf(angle), 0);
1049 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1051 glEnable(GL_CULL_FACE);
1055 /* draw backside darkening */
1056 glCullFace(GL_FRONT);
1058 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1059 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1061 draw_spot_cone(la, x, z);
1063 /* draw front side lighting */
1064 glCullFace(GL_BACK);
1066 glBlendFunc(GL_ONE, GL_ONE);
1067 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1069 draw_spot_cone(la, x, z);
1072 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1073 glDisable(GL_BLEND);
1075 glDisable(GL_CULL_FACE);
1076 glCullFace(GL_BACK);
1079 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
1080 const short dt, const short dflag, const unsigned char ob_wire_col[4])
1082 Object *ob = base->object;
1083 const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1084 Lamp *la = ob->data;
1085 float vec[3], lvec[3], vvec[3], circrad, x, y, z;
1089 unsigned char curcol[4];
1090 unsigned char col[4];
1091 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1092 /* the moment of view3d_draw_transp() call */
1093 const short is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1094 const short drawcone = ((dt > OB_WIRE) &&
1095 !(G.f & G_PICKSEL) &&
1096 (la->type == LA_SPOT) &&
1097 (la->mode & LA_SHOW_CONE) &&
1098 !(base->flag & OB_FROMDUPLI) &&
1101 if (drawcone && !v3d->transp) {
1102 /* in this case we need to draw delayed */
1103 ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
1107 /* we first draw only the screen aligned & fixed scale stuff */
1109 glLoadMatrixf(rv3d->viewmat);
1111 /* lets calculate the scale: */
1112 lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
1114 /* and view aligned matrix: */
1115 copy_m4_m4(imat, rv3d->viewinv);
1116 normalize_v3(imat[0]);
1117 normalize_v3(imat[1]);
1120 copy_v3_v3(vec, ob->obmat[3]);
1122 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1123 /* for AA effects */
1124 curcol[0] = ob_wire_col[0];
1125 curcol[1] = ob_wire_col[1];
1126 curcol[2] = ob_wire_col[2];
1128 glColor4ubv(curcol);
1131 if (lampsize > 0.0f) {
1133 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1134 if (ob->id.us > 1) {
1135 if (ob == OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1136 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1142 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1143 glDisable(GL_BLEND);
1144 drawcircball(GL_POLYGON, vec, lampsize, imat);
1147 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1149 glColor4ubv(curcol);
1153 circrad = 3.0f * lampsize;
1156 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1158 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1159 if (la->type != LA_HEMI) {
1160 if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1161 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
1170 /* draw the pretty sun rays */
1171 if (la->type == LA_SUN) {
1172 float v1[3], v2[3], mat[3][3];
1175 /* setup a 45 degree rotation matrix */
1176 vec_rot_to_mat3(mat, imat[2], (float)M_PI / 4.0f);
1179 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1180 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1183 glTranslatef(vec[0], vec[1], vec[2]);
1188 for (axis = 0; axis < 8; axis++) {
1196 glTranslatef(-vec[0], -vec[1], -vec[2]);
1200 if (la->type == LA_LOCAL) {
1201 if (la->mode & LA_SPHERE) {
1202 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1206 glPopMatrix(); /* back in object space */
1210 /* skip drawing extra info */
1212 else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
1213 lvec[0] = lvec[1] = 0.0;
1215 x = rv3d->persmat[0][2];
1216 y = rv3d->persmat[1][2];
1217 z = rv3d->persmat[2][2];
1218 vvec[0] = x * ob->obmat[0][0] + y * ob->obmat[0][1] + z * ob->obmat[0][2];
1219 vvec[1] = x * ob->obmat[1][0] + y * ob->obmat[1][1] + z * ob->obmat[1][2];
1220 vvec[2] = x * ob->obmat[2][0] + y * ob->obmat[2][1] + z * ob->obmat[2][2];
1222 y = cosf(la->spotsize * (float)(M_PI / 360.0));
1223 spotvolume(lvec, vvec, y);
1228 /* draw the angled sides of the cone */
1229 glBegin(GL_LINE_STRIP);
1235 z = x * sqrtf(1.0f - y * y);
1238 /* draw the circle/square at the end of the cone */
1239 glTranslatef(0.0, 0.0, x);
1240 if (la->mode & LA_SQUARE) {
1242 float z_abs = fabs(z);
1244 tvec[0] = tvec[1] = z_abs;
1247 glBegin(GL_LINE_LOOP);
1249 tvec[1] = -z_abs; /* neg */
1251 tvec[0] = -z_abs; /* neg */
1253 tvec[1] = z_abs; /* pos */
1258 circ(0.0, 0.0, fabsf(z));
1261 /* draw the circle/square representing spotbl */
1262 if (la->type == LA_SPOT) {
1263 float spotblcirc = fabs(z) * (1 - pow(la->spotblend, 2));
1264 /* hide line if it is zero size or overlaps with outer border,
1265 * previously it adjusted to always to show it but that seems
1266 * confusing because it doesn't show the actual blend size */
1267 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1268 circ(0.0, 0.0, spotblcirc);
1272 draw_transp_spot_volume(la, x, z);
1274 /* draw clip start, useful for wide cones where its not obvious where the start is */
1275 glTranslatef(0.0, 0.0, -x); /* reverse translation above */
1276 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1279 float clipsta_fac = la->clipsta / -x;
1281 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1282 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1284 glBegin(GL_LINE_STRIP);
1285 glVertex3fv(lvec_clip);
1286 glVertex3fv(vvec_clip);
1290 else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1292 /* draw the line from the circle along the dist */
1293 glBegin(GL_LINE_STRIP);
1300 if (la->type == LA_HEMI) {
1301 /* draw the hemisphere curves */
1302 short axis, steps, dir;
1303 float outdist, zdist, mul;
1305 outdist = 0.14; mul = 1.4; dir = 1;
1308 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1309 for (axis = 0; axis < 4; axis++) {
1310 float v[3] = {0.0, 0.0, 0.0};
1313 glBegin(GL_LINE_STRIP);
1315 for (steps = 0; steps < 6; steps++) {
1316 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1317 /* make the arcs start at the edge of the energy circle */
1318 if (steps == 0) v[0] = dir * circrad;
1319 else v[0] = v[0] + dir * (steps * outdist);
1321 else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1322 /* make the arcs start at the edge of the energy circle */
1323 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1326 v[2] = v[2] - steps * zdist;
1330 zdist = zdist * mul;
1334 /* flip the direction */
1339 else if (la->type == LA_AREA) {
1341 if (la->area_shape == LA_AREA_SQUARE)
1342 fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
1343 else if (la->area_shape == LA_AREA_RECT)
1344 fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
1346 glBegin(GL_LINE_STRIP);
1347 glVertex3f(0.0, 0.0, -circrad);
1348 glVertex3f(0.0, 0.0, -la->dist);
1352 /* and back to viewspace */
1353 glLoadMatrixf(rv3d->viewmat);
1354 copy_v3_v3(vec, ob->obmat[3]);
1358 if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == FALSE)) {
1359 drawshadbuflimits(la, ob->obmat);
1362 UI_GetThemeColor4ubv(TH_LAMP, col);
1367 if (vec[2] > 0) vec[2] -= circrad;
1368 else vec[2] += circrad;
1370 glBegin(GL_LINE_STRIP);
1382 glDisable(GL_BLEND);
1384 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1385 /* restore for drawing extra stuff */
1386 glColor3ubv(ob_wire_col);
1390 static void draw_limit_line(float sta, float end, unsigned int col)
1393 glVertex3f(0.0, 0.0, -sta);
1394 glVertex3f(0.0, 0.0, -end);
1400 glVertex3f(0.0, 0.0, -sta);
1401 glVertex3f(0.0, 0.0, -end);
1407 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1408 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1409 static void draw_focus_cross(float dist, float size)
1412 glVertex3f(-size, 0.f, -dist);
1413 glVertex3f(size, 0.f, -dist);
1414 glVertex3f(0.f, -size, -dist);
1415 glVertex3f(0.f, size, -dist);
1419 #ifdef VIEW3D_CAMERA_BORDER_HACK
1420 unsigned char view3d_camera_border_hack_col[3];
1421 short view3d_camera_border_hack_test = FALSE;
1424 /* ****************** draw clip data *************** */
1426 static void draw_bundle_sphere(void)
1428 static GLuint displist = 0;
1430 if (displist == 0) {
1431 GLUquadricObj *qobj;
1433 displist = glGenLists(1);
1434 glNewList(displist, GL_COMPILE);
1436 qobj = gluNewQuadric();
1437 gluQuadricDrawStyle(qobj, GLU_FILL);
1438 glShadeModel(GL_SMOOTH);
1439 gluSphere(qobj, 0.05, 8, 8);
1440 glShadeModel(GL_FLAT);
1441 gluDeleteQuadric(qobj);
1446 glCallList(displist);
1449 static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
1450 MovieClip *clip, MovieTrackingObject *tracking_object,
1451 const short dflag, const unsigned char ob_wire_col[4],
1452 int *global_track_index, int draw_selected)
1454 MovieTracking *tracking = &clip->tracking;
1455 MovieTrackingTrack *track;
1456 float mat[4][4], imat[4][4];
1457 unsigned char col_unsel[4], col_sel[4];
1458 int tracknr = *global_track_index;
1459 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
1461 UI_GetThemeColor4ubv(TH_TEXT, col_unsel);
1462 UI_GetThemeColor4ubv(TH_SELECT, col_sel);
1464 BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
1468 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1469 /* current ogl matrix is translated in camera space, bundles should
1470 * be rendered in world space, so camera matrix should be "removed"
1471 * from current ogl matrix */
1472 invert_m4_m4(imat, base->object->obmat);
1474 glMultMatrixf(imat);
1480 BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, scene->r.cfra, obmat);
1482 invert_m4_m4(imat, obmat);
1483 glMultMatrixf(imat);
1486 for (track = tracksbase->first; track; track = track->next) {
1487 int selected = TRACK_SELECTED(track);
1489 if (draw_selected && !selected)
1492 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1495 if (dflag & DRAW_PICKING)
1496 glLoadName(base->selcol + (tracknr << 16));
1499 glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
1500 glScalef(v3d->bundle_size / 0.05f, v3d->bundle_size / 0.05f, v3d->bundle_size / 0.05f);
1502 if (v3d->drawtype == OB_WIRE) {
1503 glDisable(GL_LIGHTING);
1505 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1506 if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
1507 glColor3ubv(ob_wire_col);
1510 glColor3fv(track->color);
1514 drawaxes(0.05f, v3d->bundle_drawtype);
1516 glEnable(GL_LIGHTING);
1518 else if (v3d->drawtype > OB_WIRE) {
1519 if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1520 /* selection outline */
1522 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1523 glColor3ubv(ob_wire_col);
1527 glDisable(GL_LIGHTING);
1528 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1530 draw_bundle_sphere();
1532 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1533 glEnable(GL_LIGHTING);
1537 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1538 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1539 else UI_ThemeColor(TH_BUNDLE_SOLID);
1542 draw_bundle_sphere();
1545 glDisable(GL_LIGHTING);
1547 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1549 glColor3ubv(ob_wire_col);
1552 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1553 else UI_ThemeColor(TH_WIRE);
1557 drawaxes(0.05f, v3d->bundle_drawtype);
1559 glEnable(GL_LIGHTING);
1565 if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1568 mul_v3_m4v3(pos, mat, track->bundle_pos);
1569 view3d_cached_text_draw_add(pos, track->name, 10, V3D_CACHE_TEXT_GLOBALSPACE, selected ? col_sel : col_unsel);
1575 if ((dflag & DRAW_PICKING) == 0) {
1576 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1577 MovieTrackingReconstruction *reconstruction;
1578 reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
1580 if (reconstruction->camnr) {
1581 MovieReconstructedCamera *camera = reconstruction->cameras;
1584 glDisable(GL_LIGHTING);
1585 UI_ThemeColor(TH_CAMERA_PATH);
1588 glBegin(GL_LINE_STRIP);
1589 for (a = 0; a < reconstruction->camnr; a++, camera++) {
1590 glVertex3fv(camera->mat[3]);
1595 glEnable(GL_LIGHTING);
1602 *global_track_index = tracknr;
1605 static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip,
1606 const short dflag, const unsigned char ob_wire_col[4],
1609 MovieTracking *tracking = &clip->tracking;
1610 MovieTrackingObject *tracking_object;
1611 int global_track_index = 1;
1613 if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1616 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1619 glEnable(GL_LIGHTING);
1620 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1621 glEnable(GL_COLOR_MATERIAL);
1622 glShadeModel(GL_SMOOTH);
1624 tracking_object = tracking->objects.first;
1625 while (tracking_object) {
1626 draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
1627 dflag, ob_wire_col, &global_track_index, draw_selected);
1629 tracking_object = tracking_object->next;
1633 glShadeModel(GL_FLAT);
1634 glDisable(GL_COLOR_MATERIAL);
1635 glDisable(GL_LIGHTING);
1637 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1638 glColor3ubv(ob_wire_col);
1641 if (dflag & DRAW_PICKING)
1642 glLoadName(base->selcol);
1645 /* flag similar to draw_object() */
1646 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
1647 const short dflag, const unsigned char ob_wire_col[4])
1649 /* a standing up pyramid with (0,0,0) as top */
1651 Object *ob = base->object;
1653 float vec[4][3], asp[2], shift[2], scale[3];
1656 const short is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
1657 MovieClip *clip = BKE_object_movieclip_get(scene, base->object, 0);
1659 /* draw data for movie clip set as active for scene */
1661 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, FALSE);
1662 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, TRUE);
1665 #ifdef VIEW3D_CAMERA_BORDER_HACK
1666 if (is_view && !(G.f & G_PICKSEL)) {
1667 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1668 view3d_camera_border_hack_col[0] = ob_wire_col[0];
1669 view3d_camera_border_hack_col[1] = ob_wire_col[1];
1670 view3d_camera_border_hack_col[2] = ob_wire_col[2];
1674 glGetFloatv(GL_CURRENT_COLOR, col);
1675 rgb_float_to_uchar(view3d_camera_border_hack_col, col);
1677 view3d_camera_border_hack_test = TRUE;
1684 scale[0] = 1.0f / len_v3(ob->obmat[0]);
1685 scale[1] = 1.0f / len_v3(ob->obmat[1]);
1686 scale[2] = 1.0f / len_v3(ob->obmat[2]);
1688 BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
1689 asp, shift, &drawsize, vec);
1691 glDisable(GL_LIGHTING);
1692 glDisable(GL_CULL_FACE);
1695 glBegin(GL_LINE_LOOP);
1696 glVertex3fv(vec[0]);
1697 glVertex3fv(vec[1]);
1698 glVertex3fv(vec[2]);
1699 glVertex3fv(vec[3]);
1707 /* center point to camera frame */
1708 glBegin(GL_LINE_STRIP);
1709 glVertex3fv(vec[1]);
1711 glVertex3fv(vec[0]);
1712 glVertex3fv(vec[3]);
1714 glVertex3fv(vec[2]);
1719 tvec[2] = vec[1][2]; /* copy the depth */
1722 /* draw an outline arrow for inactive cameras and filled
1723 * for active cameras. We actually draw both outline+filled
1724 * for active cameras so the wire can be seen side-on */
1725 for (i = 0; i < 2; i++) {
1726 if (i == 0) glBegin(GL_LINE_LOOP);
1727 else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1730 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
1731 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
1732 glVertex3fv(tvec); /* left */
1734 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
1735 glVertex3fv(tvec); /* right */
1738 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
1739 glVertex3fv(tvec); /* top */
1745 if (cam->flag & (CAM_SHOWLIMITS + CAM_SHOWMIST)) {
1749 /* draw in normalized object matrix space */
1750 copy_m4_m4(nobmat, ob->obmat);
1751 normalize_m4(nobmat);
1754 glLoadMatrixf(rv3d->viewmat);
1755 glMultMatrixf(nobmat);
1757 if (cam->flag & CAM_SHOWLIMITS) {
1758 draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
1759 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
1760 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
1763 wrld = scene->world;
1764 if (cam->flag & CAM_SHOWMIST)
1765 if (wrld) draw_limit_line(wrld->miststa, wrld->miststa + wrld->mistdist, 0xFFFFFF);
1772 /* flag similar to draw_object() */
1773 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
1774 Object *UNUSED(ob), int UNUSED(flag))
1776 //Speaker *spk = ob->data;
1783 for (j = 0; j < 3; j++) {
1784 vec[2] = 0.25f * j - 0.125f;
1786 glBegin(GL_LINE_LOOP);
1787 for (i = 0; i < 16; i++) {
1788 vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1789 vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1795 for (j = 0; j < 4; j++) {
1796 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1797 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1798 glBegin(GL_LINE_STRIP);
1799 for (i = 0; i < 3; i++) {
1805 vec[2] = 0.25f * i - 0.125f;
1811 glDisable(GL_BLEND);
1814 static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
1816 BPoint *bp = lt->def;
1817 float *co = dl ? dl->verts : NULL;
1820 UI_ThemeColor(sel ? TH_VERTEX_SELECT : TH_VERTEX);
1821 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1822 bglBegin(GL_POINTS);
1824 for (w = 0; w < lt->pntsw; w++) {
1825 int wxt = (w == 0 || w == lt->pntsw - 1);
1826 for (v = 0; v < lt->pntsv; v++) {
1827 int vxt = (v == 0 || v == lt->pntsv - 1);
1828 for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
1829 int uxt = (u == 0 || u == lt->pntsu - 1);
1830 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1831 if (bp->hide == 0) {
1832 if ((bp->f1 & SELECT) == sel) {
1833 bglVertex3fv(dl ? co : bp->vec);
1845 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
1847 int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
1851 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, use_wcol - 1);
1853 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
1859 glVertex3fv(&dl->verts[index * 3]);
1862 glVertex3fv(lt->def[index].vec);
1866 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1867 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1869 Lattice *lt = ob->data;
1872 int use_wcol = FALSE, is_edit = (lt->editlatt != NULL);
1874 /* now we default make displist, this will modifiers work for non animated case */
1875 if (ob->disp.first == NULL)
1876 BKE_lattice_modifiers_calc(scene, ob);
1877 dl = BKE_displist_find(&ob->disp, DL_VERTS);
1880 lt = lt->editlatt->latt;
1884 if (ob->defbase.first && lt->dvert) {
1885 use_wcol = ob->actdef;
1886 glShadeModel(GL_SMOOTH);
1891 for (w = 0; w < lt->pntsw; w++) {
1892 int wxt = (w == 0 || w == lt->pntsw - 1);
1893 for (v = 0; v < lt->pntsv; v++) {
1894 int vxt = (v == 0 || v == lt->pntsv - 1);
1895 for (u = 0; u < lt->pntsu; u++) {
1896 int uxt = (u == 0 || u == lt->pntsu - 1);
1898 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
1899 drawlattice__point(lt, dl, u, v, w - 1, use_wcol);
1900 drawlattice__point(lt, dl, u, v, w, use_wcol);
1902 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1903 drawlattice__point(lt, dl, u, v - 1, w, use_wcol);
1904 drawlattice__point(lt, dl, u, v, w, use_wcol);
1906 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1907 drawlattice__point(lt, dl, u - 1, v, w, use_wcol);
1908 drawlattice__point(lt, dl, u, v, w, use_wcol);
1915 /* restoration for weight colors */
1917 glShadeModel(GL_FLAT);
1920 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
1922 lattice_draw_verts(lt, dl, 0);
1923 lattice_draw_verts(lt, dl, 1);
1925 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1929 /* ***************** ******************** */
1932 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
1933 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
1935 MVert *mv = &((MVert *)userData)[index];
1937 if (!(mv->flag & ME_HIDE)) {
1938 const char sel = mv->flag & SELECT;
1940 /* TODO define selected color */
1942 glColor3f(1.0f, 1.0f, 0.0f);
1945 glColor3f(0.0f, 0.0f, 0.0f);
1952 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
1955 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, me->mvert);
1959 /* ************** DRAW MESH ****************** */
1961 /* First section is all the "simple" draw routines,
1962 * ones that just pass some sort of primitive to GL,
1963 * with perhaps various options to control lighting,
1966 * These routines should not have user interface related
1970 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
1974 copy_m3_m4(obmat, ob->obmat);
1976 data->uniform_scale = is_uniform_scaled_m3(obmat);
1978 if (!data->uniform_scale) {
1979 /* inverted matrix */
1980 invert_m3_m3(data->imat, obmat);
1982 /* transposed inverted matrix */
1983 copy_m3_m3(data->tmat, data->imat);
1984 transpose_m3(data->tmat);
1988 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
1990 drawDMNormal_userData *data = userData;
1991 BMFace *efa = EDBM_face_at_index(data->em, index);
1994 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
1995 if (!data->uniform_scale) {
1996 mul_v3_m3v3(n, data->tmat, (float *) no);
1998 mul_m3_v3(data->imat, n);
2005 glVertex3f(cent[0] + n[0] * data->normalsize,
2006 cent[1] + n[1] * data->normalsize,
2007 cent[2] + n[2] * data->normalsize);
2011 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2013 drawDMNormal_userData data;
2016 data.normalsize = scene->toolsettings->normalsize;
2018 calcDrawDMNormalScale(ob, &data);
2021 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data);
2025 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2027 BMFace *efa = EDBM_face_at_index(((void **)userData)[0], index);
2028 int sel = *(((int **)userData)[1]);
2030 if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT) == sel) {
2034 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel)
2036 void *ptrs[2] = {em, &sel};
2038 bglBegin(GL_POINTS);
2039 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs);
2043 static void draw_dm_vert_normals__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
2045 drawDMNormal_userData *data = userData;
2046 BMVert *eve = EDBM_vert_at_index(data->em, index);
2048 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2052 copy_v3_v3(no, no_f);
2055 no[0] = no_s[0] / 32767.0f;
2056 no[1] = no_s[1] / 32767.0f;
2057 no[2] = no_s[2] / 32767.0f;
2060 if (!data->uniform_scale) {
2061 mul_v3_m3v3(n, data->tmat, (float *) no);
2063 mul_m3_v3(data->imat, n);
2070 glVertex3f(co[0] + n[0] * data->normalsize,
2071 co[1] + n[1] * data->normalsize,
2072 co[2] + n[2] * data->normalsize);
2076 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2078 drawDMNormal_userData data;
2081 data.normalsize = scene->toolsettings->normalsize;
2083 calcDrawDMNormalScale(ob, &data);
2086 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data);
2090 /* Draw verts with color set based on selection */
2091 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2092 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2094 drawDMVerts_userData *data = userData;
2095 BMVert *eve = EDBM_vert_at_index(data->em, index);
2097 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2098 /* skin nodes: draw a red circle around the root
2100 if (data->has_vskin) {
2101 const MVertSkin *vs = CustomData_bmesh_get(&data->em->bm->vdata,
2104 if (vs->flag & MVERT_SKIN_ROOT) {
2105 float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2108 glColor4ubv(data->th_skin_root);
2109 drawcircball(GL_LINES, co, radius, data->imat);
2111 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2112 bglBegin(GL_POINTS);
2116 /* draw active larger - need to stop/start point drawing for this :/ */
2117 if (eve == data->eve_act) {
2118 glColor4ubv(data->th_editmesh_active);
2122 glPointSize(data->th_vertex_size);
2123 bglBegin(GL_POINTS);
2127 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2128 glPointSize(data->th_vertex_size);
2129 bglBegin(GL_POINTS);
2137 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act,
2140 drawDMVerts_userData data;
2142 data.eve_act = eve_act;
2145 /* Cache theme values */
2146 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2147 UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2148 UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2149 UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2150 data.th_vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2152 /* For skin root drawing */
2153 data.has_vskin = CustomData_has_layer(&em->bm->vdata, CD_MVERT_SKIN);
2154 /* view-aligned matrix */
2155 mult_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2156 invert_m4(data.imat);
2158 bglBegin(GL_POINTS);
2159 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
2163 /* Draw edges with color set based on selection */
2164 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2167 //unsigned char **cols = userData, *col;
2168 drawDMEdgesSel_userData *data = userData;
2171 eed = EDBM_edge_at_index(data->em, index);
2173 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2174 if (eed == data->eed_act) {
2175 glColor4ubv(data->actCol);
2178 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2182 col = data->baseCol;
2184 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2186 return DM_DRAW_OPTION_SKIP;
2190 return DM_DRAW_OPTION_NORMAL;
2193 return DM_DRAW_OPTION_SKIP;
2196 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2197 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2199 drawDMEdgesSel_userData data;
2201 data.baseCol = baseCol;
2202 data.selCol = selCol;
2203 data.actCol = actCol;
2205 data.eed_act = eed_act;
2206 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2210 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2212 if (BM_elem_flag_test(EDBM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2213 return DM_DRAW_OPTION_SKIP;
2215 return DM_DRAW_OPTION_NORMAL;
2218 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2220 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
2223 /* Draw edges with color interpolated based on selection */
2224 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2226 if (BM_elem_flag_test(EDBM_edge_at_index(((void **)userData)[0], index), BM_ELEM_HIDDEN))
2227 return DM_DRAW_OPTION_SKIP;
2229 return DM_DRAW_OPTION_NORMAL;
2231 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2233 BMEdge *eed = EDBM_edge_at_index(((void **)userData)[0], index);
2234 unsigned char **cols = userData;
2235 unsigned char *col0 = cols[(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1];
2236 unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1];
2238 glColor4ub(col0[0] + (col1[0] - col0[0]) * t,
2239 col0[1] + (col1[1] - col0[1]) * t,
2240 col0[2] + (col1[2] - col0[2]) * t,
2241 col0[3] + (col1[3] - col0[3]) * t);
2244 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2246 void *cols[3] = {em, baseCol, selCol};
2248 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2251 /* Draw only seam edges */
2252 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2254 BMEdge *eed = EDBM_edge_at_index(userData, index);
2256 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
2257 return DM_DRAW_OPTION_NORMAL;
2259 return DM_DRAW_OPTION_SKIP;
2262 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2264 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
2267 /* Draw only sharp edges */
2268 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2270 BMEdge *eed = EDBM_edge_at_index(userData, index);
2272 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
2273 return DM_DRAW_OPTION_NORMAL;
2275 return DM_DRAW_OPTION_SKIP;
2278 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2280 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
2283 /* Draw only Freestyle feature edges */
2284 static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
2286 BMEdge *eed = EDBM_edge_at_index(userData, index);
2288 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_FREESTYLE))
2289 return DM_DRAW_OPTION_NORMAL;
2291 return DM_DRAW_OPTION_SKIP;
2294 static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
2296 dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em);
2299 /* Draw faces with color set based on selection
2300 * return 2 for the active face so it renders with stipple enabled */
2301 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
2303 drawDMFacesSel_userData *data = userData;
2304 BMFace *efa = EDBM_face_at_index(data->em, index);
2308 return DM_DRAW_OPTION_SKIP;
2310 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2311 if (efa == data->efa_act) {
2312 glColor4ubv(data->cols[3]);
2313 return DM_DRAW_OPTION_STIPPLE;
2316 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : BM_elem_flag_test(efa, BM_ELEM_FREESTYLE) ? 2 : 0];
2318 return DM_DRAW_OPTION_SKIP;
2320 return DM_DRAW_OPTION_NORMAL;
2323 return DM_DRAW_OPTION_SKIP;
2326 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2329 drawDMFacesSel_userData *data = userData;
2333 unsigned char *col, *next_col;
2335 if (!data->orig_index_mf_to_mpoly)
2338 efa = EDBM_face_at_index(data->em, DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, index));
2339 next_efa = EDBM_face_at_index(data->em, DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, next_index));
2341 if (efa == next_efa)
2344 if (efa == data->efa_act || next_efa == data->efa_act)
2347 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : BM_elem_flag_test(efa, BM_ELEM_FREESTYLE) ? 2 : 0];
2348 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : BM_elem_flag_test(next_efa, BM_ELEM_FREESTYLE) ? 2 : 0];
2350 if (col[3] == 0 || next_col[3] == 0)
2353 return col == next_col;
2356 /* also draws the active face */
2357 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2358 unsigned char *selCol, unsigned char *markCol, unsigned char *actCol, BMFace *efa_act)
2360 drawDMFacesSel_userData data;
2362 data.cols[0] = baseCol;
2364 data.cols[1] = selCol;
2365 data.cols[2] = markCol;
2366 data.cols[3] = actCol;
2367 data.efa_act = efa_act;
2369 data.orig_index_mf_to_mpoly = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
2370 data.orig_index_mp_to_orig = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
2371 if ((data.orig_index_mf_to_mpoly && data.orig_index_mp_to_orig) == FALSE) {
2372 data.orig_index_mf_to_mpoly = data.orig_index_mp_to_orig = NULL;
2375 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
2378 static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
2380 BMEditMesh *em = userData;
2381 BMEdge *eed = EDBM_edge_at_index(userData, index);
2382 float *crease = eed ? (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE) : NULL;
2385 return DM_DRAW_OPTION_SKIP;
2387 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *crease != 0.0f) {
2388 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, *crease);
2389 return DM_DRAW_OPTION_NORMAL;
2392 return DM_DRAW_OPTION_SKIP;
2395 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
2398 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em);
2402 static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
2404 BMEditMesh *em = userData;
2405 BMEdge *eed = EDBM_edge_at_index(userData, index);
2406 float *bweight = (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
2409 return DM_DRAW_OPTION_SKIP;
2411 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *bweight != 0.0f) {
2412 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, *bweight);
2413 return DM_DRAW_OPTION_NORMAL;
2416 return DM_DRAW_OPTION_SKIP;
2419 static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
2420 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2422 BMEditMesh *em = userData;
2423 BMVert *eve = EDBM_vert_at_index(userData, index);
2424 float *bweight = (float *)CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_BWEIGHT);
2429 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && *bweight != 0.0f) {
2430 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, *bweight);
2434 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2436 ToolSettings *ts = scene->toolsettings;
2438 if (ts->selectmode & SCE_SELECT_VERTEX) {
2439 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2440 bglBegin(GL_POINTS);
2441 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em);
2446 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em);
2451 /* Second section of routines: Combine first sets to form fancy
2452 * drawing routines (for example rendering twice to get overlays).
2454 * Also includes routines that are basic drawing but are too
2455 * specialized to be split out (like drawing creases or measurements).
2458 /* EditMesh drawing routines*/
2460 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
2461 BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act,
2464 ToolSettings *ts = scene->toolsettings;
2467 if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */
2469 for (sel = 0; sel < 2; sel++) {
2470 unsigned char col[4], fcol[4];
2473 UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
2474 UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE, fcol);
2476 for (pass = 0; pass < 2; pass++) {
2477 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2478 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2481 if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
2482 glDisable(GL_DEPTH_TEST);
2490 size = (size > 2.1f ? size / 2.0f : size);
2491 fsize = (fsize > 2.1f ? fsize / 2.0f : fsize);
2492 col[3] = fcol[3] = 100;
2495 col[3] = fcol[3] = 255;
2498 if (ts->selectmode & SCE_SELECT_VERTEX) {
2501 draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
2504 if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2507 draw_dm_face_centers(em, cageDM, sel);
2511 glDisable(GL_BLEND);
2512 glEnable(GL_DEPTH_TEST);
2517 if (v3d->zbuf) glDepthMask(1);
2521 static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
2522 Mesh *me, DerivedMesh *cageDM, short sel_only,
2525 ToolSettings *ts = scene->toolsettings;
2527 unsigned char wireCol[4], selCol[4], actCol[4];
2529 /* since this function does transparent... */
2530 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2531 UI_GetThemeColor4ubv(TH_WIRE, wireCol);
2532 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2534 /* when sel only is used, don't render wire, only selected, this is used for
2535 * textured draw mode when the 'edges' option is disabled */
2539 for (pass = 0; pass < 2; pass++) {
2540 /* show wires in transparent when no zbuf clipping for select */
2542 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) {
2544 glDisable(GL_DEPTH_TEST);
2546 if (!sel_only) wireCol[3] = 85;
2554 if (!sel_only) wireCol[3] = 255;
2557 if (ts->selectmode == SCE_SELECT_FACE) {
2558 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2560 else if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) {
2561 if (cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2562 glShadeModel(GL_SMOOTH);
2563 draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
2564 glShadeModel(GL_FLAT);
2567 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2572 glColor4ubv(wireCol);
2573 draw_dm_edges(em, cageDM);
2578 glDisable(GL_BLEND);
2579 glEnable(GL_DEPTH_TEST);
2584 static void draw_em_measure_stats(View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit)
2586 const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
2587 Mesh *me = ob->data;
2588 float v1[3], v2[3], v3[3], vmid[3], fvec[3];
2589 char numstr[32]; /* Stores the measurement display text here */
2590 const char *conv_float; /* Use a float conversion matching the grid size */
2591 unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */
2592 float area; /* area of the face */
2593 float grid = unit->system ? unit->scale_length : v3d->grid;
2594 const int do_split = unit->flag & USER_UNIT_OPT_SPLIT;
2595 const int do_global = v3d->flag & V3D_GLOBAL_STATS;
2596 const int do_moving = G.moving;
2601 /* make the precision of the display value proportionate to the gridsize */
2603 if (grid < 0.01f) conv_float = "%.6g";
2604 else if (grid < 0.1f) conv_float = "%.5g";
2605 else if (grid < 1.0f) conv_float = "%.4g";
2606 else if (grid < 10.0f) conv_float = "%.3g";
2607 else conv_float = "%.2g";
2609 if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2612 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2614 eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
2615 for (; eed; eed = BM_iter_step(&iter)) {
2616 /* draw selected edges, or edges next to selected verts while draging */
2617 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
2618 (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
2619 BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
2622 copy_v3_v3(v1, eed->v1->co);
2623 copy_v3_v3(v2, eed->v2->co);
2625 mid_v3_v3v3(vmid, v1, v2);
2628 mul_mat3_m4_v3(ob->obmat, v1);
2629 mul_mat3_m4_v3(ob->obmat, v2);
2633 bUnit_AsString(numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
2634 unit->system, B_UNIT_LENGTH, do_split, FALSE);
2637 sprintf(numstr, conv_float, len_v3v3(v1, v2));
2640 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col);
2645 if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2646 /* would be nice to use BM_face_calc_area, but that is for 2d faces
2647 * so instead add up tessellation triangle areas */
2651 #define DRAW_EM_MEASURE_STATS_FACEAREA() \
2652 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \
2653 mul_v3_fl(vmid, 1.0f / (float)n); \
2655 bUnit_AsString(numstr, sizeof(numstr), \
2656 (double)(area * unit->scale_length), \
2657 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); \
2659 BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
2660 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col); \
2663 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2669 for (i = 0; i < em->tottri; i++) {
2670 BMLoop **l = em->looptris[i];
2671 if (f && l[0]->f != f) {
2672 DRAW_EM_MEASURE_STATS_FACEAREA();
2679 copy_v3_v3(v1, l[0]->v->co);
2680 copy_v3_v3(v2, l[1]->v->co);
2681 copy_v3_v3(v3, l[2]->v->co);
2682 add_v3_v3(vmid, v1);
2683 add_v3_v3(vmid, v2);
2684 add_v3_v3(vmid, v3);
2687 mul_mat3_m4_v3(ob->obmat, v1);
2688 mul_mat3_m4_v3(ob->obmat, v2);
2689 mul_mat3_m4_v3(ob->obmat, v3);
2691 area += area_tri_v3(v1, v2, v3);
2695 DRAW_EM_MEASURE_STATS_FACEAREA();
2697 #undef DRAW_EM_MEASURE_STATS_FACEAREA
2700 if (me->drawflag & ME_DRAWEXTRA_FACEANG) {
2702 int is_rad = unit->system_rotation == USER_UNIT_ROT_RADIANS;
2704 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2707 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2708 const int is_face_sel = BM_elem_flag_test(efa, BM_ELEM_SELECT);
2710 if (is_face_sel || do_moving) {
2713 int is_first = TRUE;
2715 BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
2716 if (is_face_sel || (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT))) {
2719 /* lazy init center calc */
2721 BM_face_calc_center_bounds(efa, vmid);
2722 /* Avoid triple matrix multiply every vertex for 'global' */
2724 copy_v3_v3(v1, loop->prev->v->co);
2725 copy_v3_v3(v2, loop->v->co);
2726 mul_mat3_m4_v3(ob->obmat, v1);
2727 mul_mat3_m4_v3(ob->obmat, v2);
2733 copy_v3_v3(v3, loop->next->v->co);
2735 mul_mat3_m4_v3(ob->obmat, v3);
2737 angle = angle_v3v3v3(v1, v2, v3);
2742 angle = angle_v3v3v3(loop->prev->v->co, loop->v->co, loop->next->v->co);
2745 BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
2746 interp_v3_v3v3(fvec, vmid, loop->v->co, 0.8f);
2747 view3d_cached_text_draw_add(fvec, numstr, 0, txt_flag, col);
2755 static void draw_em_indices(BMEditMesh *em)
2757 const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
2764 unsigned char col[4];
2769 /* For now, reuse appropriate theme colors from stats text colors */
2771 if (em->selectmode & SCE_SELECT_VERTEX) {
2772 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2773 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
2774 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
2775 sprintf(numstr, "%d", i);
2776 view3d_cached_text_draw_add(v->co, numstr, 0, txt_flag, col);
2782 if (em->selectmode & SCE_SELECT_EDGE) {
2784 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2785 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2786 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
2787 sprintf(numstr, "%d", i);
2788 mid_v3_v3v3(pos, e->v1->co, e->v2->co);
2789 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
2795 if (em->selectmode & SCE_SELECT_FACE) {
2797 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2798 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
2799 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
2800 BM_face_calc_center_mean(f, pos);
2801 sprintf(numstr, "%d", i);
2802 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
2809 static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
2811 BMFace *efa = EDBM_face_at_index(userData, index);
2813 if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2814 GPU_enable_material(efa->mat_nr + 1, NULL);
2815 return DM_DRAW_OPTION_NORMAL;
2818 return DM_DRAW_OPTION_SKIP;
2821 static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
2823 BMFace *efa = EDBM_face_at_index(userData, index);
2825 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2826 return DM_DRAW_OPTION_SKIP;
2828 return DM_DRAW_OPTION_NORMAL;
2831 static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
2832 Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const short dt)
2835 Mesh *me = ob->data;
2836 BMFace *efa_act = BM_active_face_get(em->bm, FALSE, FALSE); /* annoying but active faces is stored differently */
2837 BMEdge *eed_act = NULL;
2838 BMVert *eve_act = NULL;
2840 if (em->bm->selected.last) {
2841 BMEditSelection *ese = em->bm->selected.last;
2842 /* face is handeled above */
2844 if (ese->type == BM_FACE) {
2845 efa_act = (BMFace *)ese->data;
2849 if (ese->htype == BM_EDGE) {
2850 eed_act = (BMEdge *)ese->ele;
2852 else if (ese->htype == BM_VERT) {
2853 eve_act = (BMVert *)ese->ele;
2857 EDBM_index_arrays_init(em, 1, 1, 1);
2860 if (check_object_draw_texture(scene, v3d, dt)) {
2861 if (draw_glsl_material(scene, ob, v3d, dt)) {
2862 glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
2864 finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
2865 draw_em_fancy__setGLSLFaceOpts, em);
2866 GPU_disable_material();
2868 glFrontFace(GL_CCW);
2871 draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
2875 /* 3 floats for position,
2876 * 3 for normal and times two because the faces may actually be quads instead of triangles */
2877 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (me->flag & ME_TWOSIDED) ? GL_TRUE : GL_FALSE);
2879 glEnable(GL_LIGHTING);
2880 glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
2881 finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, 0);
2883 glFrontFace(GL_CCW);
2884 glDisable(GL_LIGHTING);
2885 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
2888 /* Setup for drawing wire over, disable zbuffer
2889 * write to show selected edge wires better */
2890 UI_ThemeColor(TH_WIRE);
2892 bglPolygonOffset(rv3d->dist, 1.0);
2896 if (cageDM != finalDM) {
2897 UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
2898 finalDM->drawEdges(finalDM, 1, 0);
2902 if (me->drawflag & ME_DRAWFACES) { /* transp faces */
2903 unsigned char col1[4], col2[4], col3[4], col4[4];
2905 UI_GetThemeColor4ubv(TH_FACE, col1);
2906 UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
2907 UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col3);
2908 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col4);
2911 glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
2913 /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
2914 if (check_object_draw_texture(scene, v3d, dt))
2917 if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE))
2920 draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
2922 glDisable(GL_BLEND);
2923 glDepthMask(1); /* restore write in zbuffer */
2926 /* even if draw faces is off it would be nice to draw the stipple face
2927 * Make all other faces zero alpha except for the active
2929 unsigned char col1[4], col2[4], col3[4], col4[4];
2930 col1[3] = col2[3] = col3[3] = 0; /* don't draw */
2931 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col4);
2934 glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
2936 draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
2938 glDisable(GL_BLEND);
2939 glDepthMask(1); /* restore write in zbuffer */
2943 /* here starts all fancy draw-extra over */
2944 if ((me->drawflag & ME_DRAWEDGES) == 0 && check_object_draw_texture(scene, v3d, dt)) {
2945 /* we are drawing textures and 'ME_DRAWEDGES' is disabled, don't draw any edges */
2947 /* only draw selected edges otherwise there is no way of telling if a face is selected */
2948 draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
2952 if (me->drawflag & ME_DRAWSEAMS) {
2953 UI_ThemeColor(TH_EDGE_SEAM);
2956 draw_dm_edges_seams(em, cageDM);
2958 glColor3ub(0, 0, 0);
2962 if (me->drawflag & ME_DRAWSHARP) {
2963 UI_ThemeColor(TH_EDGE_SHARP);
2966 draw_dm_edges_sharp(em, cageDM);
2968 glColor3ub(0, 0, 0);
2972 if(me->drawflag & ME_DRAW_FREESTYLE_EDGE) {
2973 UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
2976 draw_dm_edges_freestyle(em, cageDM);
2982 if (me->drawflag & ME_DRAWCREASES && CustomData_has_layer(&em->bm->edata, CD_CREASE)) {
2983 draw_dm_creases(em, cageDM);
2985 if (me->drawflag & ME_DRAWBWEIGHTS) {
2986 draw_dm_bweights(em, scene, cageDM);
2989 draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
2993 draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d);
2995 if (me->drawflag & ME_DRAWNORMALS) {
2996 UI_ThemeColor(TH_NORMAL);
2997 draw_dm_face_normals(em, scene, ob, cageDM);
2999 if (me->drawflag & ME_DRAW_VNORMALS) {
3000 UI_ThemeColor(TH_VNORMAL);
3001 draw_dm_vert_normals(em, scene, ob, cageDM);
3004 if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_FACEAREA | ME_DRAWEXTRA_FACEANG)) &&
3005 !(v3d->flag2 & V3D_RENDER_OVERRIDE))
3007 draw_em_measure_stats(v3d, ob, em, &scene->unit);
3010 if ((G.debug & G_DEBUG) && (me->drawflag & ME_DRAWEXTRA_INDICES) &&
3011 !(v3d->flag2 & V3D_RENDER_OVERRIDE))
3013 draw_em_indices(em);
3019 bglPolygonOffset(rv3d->dist, 0.0);
3020 GPU_disable_material();
3023 EDBM_index_arrays_free(em);
3026 /* Mesh drawing routines */
3028 static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
3030 if ((v3d->transp == FALSE) && /* not when we draw the transparent pass */
3031 (ob->mode & OB_MODE_ALL_PAINT) == FALSE) /* not when painting (its distracting) - campbell */
3033 glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
3036 /* if transparent, we cannot draw the edges for solid select... edges have no material info.
3037 * drawFacesSolid() doesn't draw the transparent faces */
3038 if (ob->dtx & OB_DRAWTRANSP) {
3039 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
3040 dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
3041 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3042 GPU_disable_material();
3045 dm->drawEdges(dm, 0, 1);
3053 static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
3054 const short dt, const unsigned char ob_wire_col[4], const short dflag)
3056 Object *ob = base->object;
3057 Mesh *me = ob->data;
3058 Material *ma = give_current_material(ob, 1);
3059 const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO));
3060 eWireDrawMode draw_wire = OBDRAW_WIRE_OFF;
3061 int /* totvert,*/ totedge, totface;
3062 DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
3063 const short is_obact = (ob == OBACT);
3064 int draw_flags = (is_obact && paint_facesel_test(ob)) ? DRAW_FACE_SELECT : 0;