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_rigidbody_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_smoke_types.h"
43 #include "DNA_world_types.h"
44 #include "DNA_object_types.h"
46 #include "BLI_blenlib.h"
49 #include "BKE_anim.h" /* for the where_on_path function */
50 #include "BKE_armature.h"
51 #include "BKE_camera.h"
52 #include "BKE_constraint.h" /* for the get_constraint_target function */
53 #include "BKE_curve.h"
54 #include "BKE_DerivedMesh.h"
55 #include "BKE_deform.h"
56 #include "BKE_displist.h"
58 #include "BKE_global.h"
59 #include "BKE_image.h"
61 #include "BKE_lattice.h"
63 #include "BKE_material.h"
64 #include "BKE_mball.h"
65 #include "BKE_modifier.h"
66 #include "BKE_object.h"
67 #include "BKE_paint.h"
68 #include "BKE_particle.h"
69 #include "BKE_pointcache.h"
70 #include "BKE_scene.h"
72 #include "BKE_tracking.h"
74 #include "BKE_editmesh.h"
76 #include "IMB_imbuf.h"
77 #include "IMB_imbuf_types.h"
80 #include "BIF_glutil.h"
83 #include "GPU_extensions.h"
86 #include "ED_particle.h"
87 #include "ED_screen.h"
88 #include "ED_sculpt.h"
91 #include "UI_resources.h"
92 #include "UI_interface_icons.h"
97 #include "view3d_intern.h" /* bad level include */
99 typedef enum eWireDrawMode {
102 OBDRAW_WIRE_ON_DEPTH = 2
105 typedef struct drawDMVerts_userData {
111 /* cached theme values */
112 unsigned char th_editmesh_active[4];
113 unsigned char th_vertex_select[4];
114 unsigned char th_vertex[4];
115 unsigned char th_skin_root[4];
116 float th_vertex_size;
118 /* for skin node drawing */
121 } drawDMVerts_userData;
123 typedef struct drawDMEdgesSel_userData {
126 unsigned char *baseCol, *selCol, *actCol;
128 } drawDMEdgesSel_userData;
130 typedef struct drawDMFacesSel_userData {
131 #ifdef WITH_FREESTYLE
132 unsigned char *cols[4];
134 unsigned char *cols[3];
141 int *orig_index_mf_to_mpoly;
142 int *orig_index_mp_to_orig;
143 } drawDMFacesSel_userData;
145 typedef struct drawDMNormal_userData {
151 } drawDMNormal_userData;
153 typedef struct bbsObmodeMeshVerts_userData {
156 } bbsObmodeMeshVerts_userData;
158 typedef struct drawDMLayer_userData {
161 } drawDMLayer_userData;
163 static void draw_bounding_volume(Scene *scene, Object *ob, char type);
165 static void drawcube_size(float size);
166 static void drawcircle_size(float size);
167 static void draw_empty_sphere(float size);
168 static void draw_empty_cone(float size);
170 static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
172 float col_wire[3], col_bg[3], col[3];
174 rgb_uchar_to_float(col_wire, ob_wire_col);
176 UI_GetThemeColor3fv(theme_id, col_bg);
177 interp_v3_v3v3(col, col_bg, col_wire, fac);
181 /* this condition has been made more complex since editmode can draw textures */
182 static bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
184 /* texture and material draw modes */
185 if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
190 if ((v3d->drawtype == OB_SOLID) &&
191 (v3d->flag2 & V3D_SOLID_TEX) &&
192 (BKE_scene_use_new_shading_nodes(scene) == false))
197 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) {
204 static bool check_object_draw_editweight(Mesh *me, DerivedMesh *finalDM)
206 if (me->drawflag & ME_DRAWEIGHT) {
207 /* editmesh handles its own weight drawing */
208 if (finalDM->type != DM_TYPE_EDITBMESH) {
216 static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
218 if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
221 if (G.f & G_BACKBUFSEL)
224 if ((vd->flag & V3D_ZBUF_SELECT) == 0)
227 /* if its drawing textures with zbuf sel, then don't draw dots */
228 if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
231 if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
237 /* ************************ */
239 /* check for glsl drawing */
241 bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
243 if (!GPU_glsl_support())
247 if (!check_object_draw_texture(scene, v3d, dt))
249 if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
252 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
255 if (BKE_scene_use_new_shading_nodes(scene))
258 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
261 static bool check_alpha_pass(Base *base)
263 if (base->flag & OB_FROMDUPLI)
269 if (base->object->mode & OB_MODE_ALL_PAINT)
272 return (base->object->dtx & OB_DRAWTRANSP);
276 static const unsigned int colortab[] = {
277 0x0, 0x403000, 0xFFFF88
280 /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
281 /* 32 values of sin function (still same result!) */
282 #define CIRCLE_RESOL 32
284 static const float sinval[CIRCLE_RESOL] = {
319 /* 32 values of cos function (still same result!) */
320 static const float cosval[CIRCLE_RESOL] = {
355 static void draw_xyz_wire(const float c[3], float size, int axis)
357 float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
358 float dim = size * 0.1f;
359 float dx[3], dy[3], dz[3];
361 dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
362 dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
363 dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
369 /* bottom left to top right */
370 sub_v3_v3v3(v1, c, dx);
372 add_v3_v3v3(v2, c, dx);
378 /* top left to bottom right */
391 /* bottom left to top right */
392 mul_v3_fl(dx, 0.75f);
393 sub_v3_v3v3(v1, c, dx);
395 add_v3_v3v3(v2, c, dx);
401 /* top left to center */
412 glBegin(GL_LINE_STRIP);
414 /* start at top left */
415 sub_v3_v3v3(v1, c, dx);
416 add_v3_v3v3(v1, c, dz);
441 void drawaxes(float size, char drawtype)
444 float v1[3] = {0.0, 0.0, 0.0};
445 float v2[3] = {0.0, 0.0, 0.0};
446 float v3[3] = {0.0, 0.0, 0.0};
451 for (axis = 0; axis < 3; axis++) {
459 /* reset v1 & v2 to zero */
460 v1[axis] = v2[axis] = 0.0f;
465 case OB_SINGLE_ARROW:
468 /* in positive z direction only */
475 glBegin(GL_TRIANGLES);
477 v2[0] = size * 0.035f; v2[1] = size * 0.035f;
478 v3[0] = size * -0.035f; v3[1] = size * 0.035f;
479 v2[2] = v3[2] = size * 0.75f;
481 for (axis = 0; axis < 4; axis++) {
504 drawcircle_size(size);
507 case OB_EMPTY_SPHERE:
508 draw_empty_sphere(size);
512 draw_empty_cone(size);
518 for (axis = 0; axis < 3; axis++) {
519 const int arrow_axis = (axis == 0) ? 1 : 0;
527 v1[axis] = size * 0.85f;
528 v1[arrow_axis] = -size * 0.08f;
532 v1[arrow_axis] = size * 0.08f;
538 v2[axis] += size * 0.125f;
540 draw_xyz_wire(v2, size, axis);
543 /* reset v1 & v2 to zero */
544 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
552 /* Function to draw an Image on a empty Object */
553 static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
555 Image *ima = (Image *)ob->data;
556 ImBuf *ibuf = ima ? BKE_image_acquire_ibuf(ima, NULL, NULL) : NULL;
558 float scale, ofs_x, ofs_y, sca_x, sca_y;
561 if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
562 IMB_rect_from_float(ibuf);
565 /* Get the buffer dimensions so we can fallback to fake ones */
566 if (ibuf && ibuf->rect) {
575 /* Get the image aspect even if the buffer is invalid */
577 if (ima->aspx > ima->aspy) {
579 sca_y = ima->aspy / ima->aspx;
581 else if (ima->aspx < ima->aspy) {
582 sca_x = ima->aspx / ima->aspy;
595 /* Calculate the scale center based on objects origin */
596 ofs_x = ob->ima_ofs[0] * ima_x;
597 ofs_y = ob->ima_ofs[1] * ima_y;
599 glMatrixMode(GL_MODELVIEW);
602 /* Make sure we are drawing at the origin */
603 glTranslatef(0.0f, 0.0f, 0.0f);
605 /* Calculate Image scale */
606 scale = (ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y));
608 /* Set the object scale */
609 glScalef(scale * sca_x, scale * sca_y, 1.0f);
611 if (ibuf && ibuf->rect) {
612 const bool use_clip = (U.glalphaclip != 1.0f);
613 /* Setup GL params */
615 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
618 glEnable(GL_ALPHA_TEST);
619 glAlphaFunc(GL_GREATER, U.glalphaclip);
622 /* Use the object color and alpha */
625 /* Draw the Image on the screen */
626 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
627 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
632 glDisable(GL_ALPHA_TEST);
633 glAlphaFunc(GL_GREATER, 0.0f);
637 if ((dflag & DRAW_CONSTCOLOR) == 0) {
638 glColor3ubv(ob_wire_col);
641 /* Calculate the outline vertex positions */
642 glBegin(GL_LINE_LOOP);
643 glVertex2f(ofs_x, ofs_y);
644 glVertex2f(ofs_x + ima_x, ofs_y);
645 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
646 glVertex2f(ofs_x, ofs_y + ima_y);
650 /* Reset GL settings */
651 glMatrixMode(GL_MODELVIEW);
654 BKE_image_release_ibuf(ima, ibuf, NULL);
657 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[4][4])
660 float *viter = (float *)verts;
663 mul_v3_v3fl(vx, tmat[0], rad);
664 mul_v3_v3fl(vy, tmat[1], rad);
666 for (a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
667 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
668 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
669 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
673 void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4])
675 float verts[CIRCLE_RESOL][3];
677 circball_array_fill(verts, cent, rad, tmat);
679 glEnableClientState(GL_VERTEX_ARRAY);
680 glVertexPointer(3, GL_FLOAT, 0, verts);
681 glDrawArrays(mode, 0, CIRCLE_RESOL);
682 glDisableClientState(GL_VERTEX_ARRAY);
685 /* circle for object centers, special_color is for library or ob users */
686 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
688 const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
689 float verts[CIRCLE_RESOL][3];
691 /* using gldepthfunc guarantees that it does write z values,
692 * but not checks for it, so centers remain visible independent order of drawing */
693 if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
697 if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
699 else glColor4ub(0x55, 0xCC, 0xCC, 155);
702 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
703 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
704 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
707 circball_array_fill(verts, co, size, rv3d->viewinv);
709 /* enable vertex array */
710 glEnableClientState(GL_VERTEX_ARRAY);
711 glVertexPointer(3, GL_FLOAT, 0, verts);
713 /* 1. draw filled, blended polygon */
714 glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
716 /* 2. draw outline */
717 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
718 glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
721 glDisableClientState(GL_VERTEX_ARRAY);
725 if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
728 /* *********** text drawing for object/particles/armature ************* */
729 static ListBase CachedText[3];
730 static int CachedTextLevel = 0;
732 typedef struct ViewCachedString {
733 struct ViewCachedString *next, *prev;
743 /* str is allocated past the end */
746 void view3d_cached_text_draw_begin(void)
748 ListBase *strings = &CachedText[CachedTextLevel];
749 strings->first = strings->last = NULL;
753 void view3d_cached_text_draw_add(const float co[3],
755 short xoffs, short flag,
756 const unsigned char col[4])
758 int alloc_len = strlen(str) + 1;
759 ListBase *strings = &CachedText[CachedTextLevel - 1];
760 /* TODO, replace with more efficient malloc, perhaps memarena per draw? */
761 ViewCachedString *vos = MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
763 BLI_addtail(strings, vos);
764 copy_v3_v3(vos->vec, co);
765 copy_v4_v4_char((char *)vos->col.ub, (const char *)col);
768 vos->str_len = alloc_len - 1;
770 /* allocate past the end */
771 memcpy(++vos, str, alloc_len);
774 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, float mat[4][4])
776 RegionView3D *rv3d = ar->regiondata;
777 ListBase *strings = &CachedText[CachedTextLevel - 1];
778 ViewCachedString *vos;
781 /* project first and test */
782 for (vos = strings->first; vos; vos = vos->next) {
783 if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
784 mul_m4_v3(mat, vos->vec);
786 if (ED_view3d_project_short_ex(ar,
787 (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
788 (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
790 V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
795 vos->sco[0] = IS_CLIPPED;
800 int col_pack_prev = 0;
803 bglMats mats; /* ZBuffer depth vars */
810 if (rv3d->rflag & RV3D_CLIPPING) {
811 ED_view3d_clipping_disable();
814 glMatrixMode(GL_PROJECTION);
816 glMatrixMode(GL_MODELVIEW);
818 ED_region_pixelspace(ar);
821 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
827 for (vos = strings->first; vos; vos = vos->next) {
828 if (vos->sco[0] != IS_CLIPPED) {
829 const char *str = (char *)(vos + 1);
831 if (col_pack_prev != vos->col.pack) {
832 glColor3ubv(vos->col.ub);
833 col_pack_prev = vos->col.pack;
836 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
837 BLF_draw_default_ascii :
839 )( (float)vos->sco[0] + vos->xoffs,
841 (depth_write) ? 0.0f : 2.0f,
848 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
854 glMatrixMode(GL_PROJECTION);
856 glMatrixMode(GL_MODELVIEW);
859 if (rv3d->rflag & RV3D_CLIPPING) {
860 ED_view3d_clipping_enable();
865 BLI_freelistN(strings);
870 /* ******************** primitive drawing ******************* */
872 /* draws a cube on given the scaling of the cube, assuming that
873 * all required matrices have been set (used for drawing empties)
875 static void drawcube_size(float size)
877 glBegin(GL_LINE_STRIP);
878 glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size);
879 glVertex3f(-size, size, size); glVertex3f(-size, size, -size);
881 glVertex3f(-size, -size, -size); glVertex3f(size, -size, -size);
882 glVertex3f(size, -size, size); glVertex3f(size, size, size);
884 glVertex3f(size, size, -size); glVertex3f(size, -size, -size);
887 glBegin(GL_LINE_STRIP);
888 glVertex3f(-size, -size, size); glVertex3f(size, -size, size);
891 glBegin(GL_LINE_STRIP);
892 glVertex3f(-size, size, size); glVertex3f(size, size, size);
895 glBegin(GL_LINE_STRIP);
896 glVertex3f(-size, size, -size); glVertex3f(size, size, -size);
900 /* this is an unused (old) cube-drawing function based on a given size */
902 static void drawcube_size(const float size[3])
906 glScalef(size[0], size[1], size[2]);
909 glBegin(GL_LINE_STRIP);
910 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
911 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
912 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
915 glBegin(GL_LINE_STRIP);
916 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
919 glBegin(GL_LINE_STRIP);
920 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
923 glBegin(GL_LINE_STRIP);
924 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
931 static void drawshadbuflimits(Lamp *la, float mat[4][4])
933 float sta[3], end[3], lavec[3];
935 negate_v3_v3(lavec, mat[2]);
938 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
939 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
941 glBegin(GL_LINE_STRIP);
956 static void spotvolume(float lvec[3], float vvec[3], const float inp)
958 /* camera is at 0,0,0 */
959 float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
962 normalize_v3(vvec); /* is this the correct vector ? */
964 cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec en lvec */
965 cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parrallel with lvec */
967 /* vectors are exactly aligned, use the X axis, this is arbitrary */
968 if (normalize_v3(plane) == 0.0f)
971 /* now we've got two equations: one of a cone and one of a plane, but we have
972 * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
974 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
975 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
977 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
984 angle = saacos(plane[2]) / 2.0f;
986 si = sqrtf(1 - co * co);
993 quat_to_mat3(mat1, q);
995 /* rotate lamp vector now over acos(inp) degrees */
996 copy_v3_v3(vvec, lvec);
1000 si = sqrtf(1.0f - inp * inp);
1006 mul_m3_m3m3(mat3, mat2, mat1);
1010 mul_m3_m3m3(mat4, mat2, mat1);
1013 mul_m3_m3m3(mat2, mat1, mat3);
1014 mul_m3_v3(mat2, lvec);
1015 mul_m3_m3m3(mat2, mat1, mat4);
1016 mul_m3_v3(mat2, vvec);
1021 static void draw_spot_cone(Lamp *la, float x, float z)
1025 glBegin(GL_TRIANGLE_FAN);
1026 glVertex3f(0.0f, 0.0f, -x);
1028 if (la->mode & LA_SQUARE) {
1029 glVertex3f(z, z, 0);
1030 glVertex3f(-z, z, 0);
1031 glVertex3f(-z, -z, 0);
1032 glVertex3f(z, -z, 0);
1033 glVertex3f(z, z, 0);
1039 for (a = 0; a < 33; a++) {
1040 angle = a * M_PI * 2 / (33 - 1);
1041 glVertex3f(z * cosf(angle), z * sinf(angle), 0);
1048 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1050 glEnable(GL_CULL_FACE);
1054 /* draw backside darkening */
1055 glCullFace(GL_FRONT);
1057 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1058 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1060 draw_spot_cone(la, x, z);
1062 /* draw front side lighting */
1063 glCullFace(GL_BACK);
1065 glBlendFunc(GL_ONE, GL_ONE);
1066 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1068 draw_spot_cone(la, x, z);
1071 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1072 glDisable(GL_BLEND);
1074 glDisable(GL_CULL_FACE);
1075 glCullFace(GL_BACK);
1078 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
1079 const char dt, const short dflag, const unsigned char ob_wire_col[4])
1081 Object *ob = base->object;
1082 const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1083 Lamp *la = ob->data;
1084 float vec[3], lvec[3], vvec[3], circrad, x, y, z;
1088 unsigned char curcol[4];
1089 unsigned char col[4];
1090 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1091 /* the moment of view3d_draw_transp() call */
1092 const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1093 const bool drawcone = ((dt > OB_WIRE) &&
1094 !(G.f & G_PICKSEL) &&
1095 (la->type == LA_SPOT) &&
1096 (la->mode & LA_SHOW_CONE) &&
1097 !(base->flag & OB_FROMDUPLI) &&
1100 if (drawcone && !v3d->transp) {
1101 /* in this case we need to draw delayed */
1102 ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
1106 /* we first draw only the screen aligned & fixed scale stuff */
1108 glLoadMatrixf(rv3d->viewmat);
1110 /* lets calculate the scale: */
1111 lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
1113 /* and view aligned matrix: */
1114 copy_m4_m4(imat, rv3d->viewinv);
1115 normalize_v3(imat[0]);
1116 normalize_v3(imat[1]);
1119 copy_v3_v3(vec, ob->obmat[3]);
1121 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1122 /* for AA effects */
1123 curcol[0] = ob_wire_col[0];
1124 curcol[1] = ob_wire_col[1];
1125 curcol[2] = ob_wire_col[2];
1127 glColor4ubv(curcol);
1130 if (lampsize > 0.0f) {
1132 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1133 if (ob->id.us > 1) {
1134 if (ob == OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1135 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1141 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1142 glDisable(GL_BLEND);
1143 drawcircball(GL_POLYGON, vec, lampsize, imat);
1146 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1148 glColor4ubv(curcol);
1152 circrad = 3.0f * lampsize;
1155 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1157 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1158 if (la->type != LA_HEMI) {
1159 if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1160 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
1169 /* draw the pretty sun rays */
1170 if (la->type == LA_SUN) {
1171 float v1[3], v2[3], mat[3][3];
1174 /* setup a 45 degree rotation matrix */
1175 axis_angle_normalized_to_mat3(mat, imat[2], (float)M_PI / 4.0f);
1178 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1179 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1182 glTranslatef(vec[0], vec[1], vec[2]);
1187 for (axis = 0; axis < 8; axis++) {
1195 glTranslatef(-vec[0], -vec[1], -vec[2]);
1199 if (la->type == LA_LOCAL) {
1200 if (la->mode & LA_SPHERE) {
1201 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1205 glPopMatrix(); /* back in object space */
1209 /* skip drawing extra info */
1211 else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
1212 lvec[0] = lvec[1] = 0.0;
1214 x = rv3d->persmat[0][2];
1215 y = rv3d->persmat[1][2];
1216 z = rv3d->persmat[2][2];
1217 vvec[0] = x * ob->obmat[0][0] + y * ob->obmat[0][1] + z * ob->obmat[0][2];
1218 vvec[1] = x * ob->obmat[1][0] + y * ob->obmat[1][1] + z * ob->obmat[1][2];
1219 vvec[2] = x * ob->obmat[2][0] + y * ob->obmat[2][1] + z * ob->obmat[2][2];
1221 y = cosf(la->spotsize * (float)(M_PI / 360.0));
1222 spotvolume(lvec, vvec, y);
1227 /* draw the angled sides of the cone */
1228 glBegin(GL_LINE_STRIP);
1234 z = x * sqrtf(1.0f - y * y);
1237 /* draw the circle/square at the end of the cone */
1238 glTranslatef(0.0, 0.0, x);
1239 if (la->mode & LA_SQUARE) {
1241 float z_abs = fabs(z);
1243 tvec[0] = tvec[1] = z_abs;
1246 glBegin(GL_LINE_LOOP);
1248 tvec[1] = -z_abs; /* neg */
1250 tvec[0] = -z_abs; /* neg */
1252 tvec[1] = z_abs; /* pos */
1257 circ(0.0, 0.0, fabsf(z));
1260 /* draw the circle/square representing spotbl */
1261 if (la->type == LA_SPOT) {
1262 float spotblcirc = fabs(z) * (1 - pow(la->spotblend, 2));
1263 /* hide line if it is zero size or overlaps with outer border,
1264 * previously it adjusted to always to show it but that seems
1265 * confusing because it doesn't show the actual blend size */
1266 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1267 circ(0.0, 0.0, spotblcirc);
1271 draw_transp_spot_volume(la, x, z);
1273 /* draw clip start, useful for wide cones where its not obvious where the start is */
1274 glTranslatef(0.0, 0.0, -x); /* reverse translation above */
1275 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1278 float clipsta_fac = la->clipsta / -x;
1280 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1281 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1283 glBegin(GL_LINE_STRIP);
1284 glVertex3fv(lvec_clip);
1285 glVertex3fv(vvec_clip);
1288 /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
1290 glBegin(GL_LINE_STRIP);
1291 glVertex3f(0.0, 0.0, -circrad);
1292 glVertex3f(0.0, 0.0, -la->dist);
1296 else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1298 /* draw the line from the circle along the dist */
1299 glBegin(GL_LINE_STRIP);
1306 if (la->type == LA_HEMI) {
1307 /* draw the hemisphere curves */
1308 short axis, steps, dir;
1309 float outdist, zdist, mul;
1311 outdist = 0.14; mul = 1.4; dir = 1;
1314 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1315 for (axis = 0; axis < 4; axis++) {
1316 float v[3] = {0.0, 0.0, 0.0};
1319 glBegin(GL_LINE_STRIP);
1321 for (steps = 0; steps < 6; steps++) {
1322 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1323 /* make the arcs start at the edge of the energy circle */
1324 if (steps == 0) v[0] = dir * circrad;
1325 else v[0] = v[0] + dir * (steps * outdist);
1327 else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1328 /* make the arcs start at the edge of the energy circle */
1329 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1332 v[2] = v[2] - steps * zdist;
1336 zdist = zdist * mul;
1340 /* flip the direction */
1345 else if (la->type == LA_AREA) {
1347 if (la->area_shape == LA_AREA_SQUARE)
1348 fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
1349 else if (la->area_shape == LA_AREA_RECT)
1350 fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
1352 glBegin(GL_LINE_STRIP);
1353 glVertex3f(0.0, 0.0, -circrad);
1354 glVertex3f(0.0, 0.0, -la->dist);
1358 /* and back to viewspace */
1359 glLoadMatrixf(rv3d->viewmat);
1360 copy_v3_v3(vec, ob->obmat[3]);
1364 if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) {
1365 drawshadbuflimits(la, ob->obmat);
1368 UI_GetThemeColor4ubv(TH_LAMP, col);
1373 if (vec[2] > 0) vec[2] -= circrad;
1374 else vec[2] += circrad;
1376 glBegin(GL_LINE_STRIP);
1388 glDisable(GL_BLEND);
1390 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1391 /* restore for drawing extra stuff */
1392 glColor3ubv(ob_wire_col);
1396 static void draw_limit_line(float sta, float end, const short dflag, unsigned int col)
1399 glVertex3f(0.0, 0.0, -sta);
1400 glVertex3f(0.0, 0.0, -end);
1403 if (!(dflag & DRAW_PICKING)) {
1407 glVertex3f(0.0, 0.0, -sta);
1408 glVertex3f(0.0, 0.0, -end);
1415 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1416 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1417 static void draw_focus_cross(float dist, float size)
1420 glVertex3f(-size, 0.f, -dist);
1421 glVertex3f(size, 0.f, -dist);
1422 glVertex3f(0.f, -size, -dist);
1423 glVertex3f(0.f, size, -dist);
1427 #ifdef VIEW3D_CAMERA_BORDER_HACK
1428 unsigned char view3d_camera_border_hack_col[3];
1429 bool view3d_camera_border_hack_test = false;
1432 /* ****************** draw clip data *************** */
1434 static void draw_bundle_sphere(void)
1436 static GLuint displist = 0;
1438 if (displist == 0) {
1439 GLUquadricObj *qobj;
1441 displist = glGenLists(1);
1442 glNewList(displist, GL_COMPILE);
1444 qobj = gluNewQuadric();
1445 gluQuadricDrawStyle(qobj, GLU_FILL);
1446 glShadeModel(GL_SMOOTH);
1447 gluSphere(qobj, 0.05, 8, 8);
1448 glShadeModel(GL_FLAT);
1449 gluDeleteQuadric(qobj);
1454 glCallList(displist);
1457 static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
1458 MovieClip *clip, MovieTrackingObject *tracking_object,
1459 const short dflag, const unsigned char ob_wire_col[4],
1460 int *global_track_index, bool draw_selected)
1462 MovieTracking *tracking = &clip->tracking;
1463 MovieTrackingTrack *track;
1464 float mat[4][4], imat[4][4];
1465 unsigned char col_unsel[4], col_sel[4];
1466 int tracknr = *global_track_index;
1467 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
1468 float camera_size[3];
1470 UI_GetThemeColor4ubv(TH_TEXT, col_unsel);
1471 UI_GetThemeColor4ubv(TH_SELECT, col_sel);
1473 BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
1475 /* we're compensating camera size for bundles size,
1476 * to make it so bundles are always displayed with the same size
1478 copy_v3_v3(camera_size, base->object->size);
1479 if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
1480 mul_v3_fl(camera_size, tracking_object->scale);
1484 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1485 /* current ogl matrix is translated in camera space, bundles should
1486 * be rendered in world space, so camera matrix should be "removed"
1487 * from current ogl matrix */
1488 invert_m4_m4(imat, base->object->obmat);
1490 glMultMatrixf(imat);
1496 BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, scene->r.cfra, obmat);
1498 invert_m4_m4(imat, obmat);
1499 glMultMatrixf(imat);
1502 for (track = tracksbase->first; track; track = track->next) {
1503 int selected = TRACK_SELECTED(track);
1505 if (draw_selected && !selected)
1508 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1511 if (dflag & DRAW_PICKING)
1512 glLoadName(base->selcol + (tracknr << 16));
1515 glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
1516 glScalef(v3d->bundle_size / 0.05f / camera_size[0],
1517 v3d->bundle_size / 0.05f / camera_size[1],
1518 v3d->bundle_size / 0.05f / camera_size[2]);
1520 if (v3d->drawtype == OB_WIRE) {
1521 glDisable(GL_LIGHTING);
1523 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1524 if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
1525 glColor3ubv(ob_wire_col);
1528 glColor3fv(track->color);
1532 drawaxes(0.05f, v3d->bundle_drawtype);
1534 glEnable(GL_LIGHTING);
1536 else if (v3d->drawtype > OB_WIRE) {
1537 if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1538 /* selection outline */
1540 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1541 glColor3ubv(ob_wire_col);
1545 glDisable(GL_LIGHTING);
1546 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1548 draw_bundle_sphere();
1550 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1551 glEnable(GL_LIGHTING);
1555 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1556 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1557 else UI_ThemeColor(TH_BUNDLE_SOLID);
1560 draw_bundle_sphere();
1563 glDisable(GL_LIGHTING);
1565 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1567 glColor3ubv(ob_wire_col);
1570 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1571 else UI_ThemeColor(TH_WIRE);
1575 drawaxes(0.05f, v3d->bundle_drawtype);
1577 glEnable(GL_LIGHTING);
1583 if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1586 mul_v3_m4v3(pos, mat, track->bundle_pos);
1587 view3d_cached_text_draw_add(pos, track->name, 10, V3D_CACHE_TEXT_GLOBALSPACE, selected ? col_sel : col_unsel);
1593 if ((dflag & DRAW_PICKING) == 0) {
1594 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1595 MovieTrackingReconstruction *reconstruction;
1596 reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
1598 if (reconstruction->camnr) {
1599 MovieReconstructedCamera *camera = reconstruction->cameras;
1602 glDisable(GL_LIGHTING);
1603 UI_ThemeColor(TH_CAMERA_PATH);
1606 glBegin(GL_LINE_STRIP);
1607 for (a = 0; a < reconstruction->camnr; a++, camera++) {
1608 glVertex3fv(camera->mat[3]);
1613 glEnable(GL_LIGHTING);
1620 *global_track_index = tracknr;
1623 static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip,
1624 const short dflag, const unsigned char ob_wire_col[4],
1625 const bool draw_selected)
1627 MovieTracking *tracking = &clip->tracking;
1628 MovieTrackingObject *tracking_object;
1629 int global_track_index = 1;
1631 if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1634 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1637 glEnable(GL_LIGHTING);
1638 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1639 glEnable(GL_COLOR_MATERIAL);
1640 glShadeModel(GL_SMOOTH);
1642 tracking_object = tracking->objects.first;
1643 while (tracking_object) {
1644 draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
1645 dflag, ob_wire_col, &global_track_index, draw_selected);
1647 tracking_object = tracking_object->next;
1651 glShadeModel(GL_FLAT);
1652 glDisable(GL_COLOR_MATERIAL);
1653 glDisable(GL_LIGHTING);
1655 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1656 glColor3ubv(ob_wire_col);
1659 if (dflag & DRAW_PICKING)
1660 glLoadName(base->selcol);
1663 /* flag similar to draw_object() */
1664 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
1665 const short dflag, const unsigned char ob_wire_col[4])
1667 /* a standing up pyramid with (0,0,0) as top */
1669 Object *ob = base->object;
1671 float vec[4][3], asp[2], shift[2], scale[3];
1674 const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
1675 MovieClip *clip = BKE_object_movieclip_get(scene, base->object, 0);
1677 /* draw data for movie clip set as active for scene */
1679 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, false);
1680 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, true);
1683 #ifdef VIEW3D_CAMERA_BORDER_HACK
1684 if (is_view && !(G.f & G_PICKSEL)) {
1685 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1686 view3d_camera_border_hack_col[0] = ob_wire_col[0];
1687 view3d_camera_border_hack_col[1] = ob_wire_col[1];
1688 view3d_camera_border_hack_col[2] = ob_wire_col[2];
1692 glGetFloatv(GL_CURRENT_COLOR, col);
1693 rgb_float_to_uchar(view3d_camera_border_hack_col, col);
1695 view3d_camera_border_hack_test = true;
1702 scale[0] = 1.0f / len_v3(ob->obmat[0]);
1703 scale[1] = 1.0f / len_v3(ob->obmat[1]);
1704 scale[2] = 1.0f / len_v3(ob->obmat[2]);
1706 BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
1707 asp, shift, &drawsize, vec);
1709 glDisable(GL_LIGHTING);
1710 glDisable(GL_CULL_FACE);
1713 glBegin(GL_LINE_LOOP);
1714 glVertex3fv(vec[0]);
1715 glVertex3fv(vec[1]);
1716 glVertex3fv(vec[2]);
1717 glVertex3fv(vec[3]);
1725 /* center point to camera frame */
1726 glBegin(GL_LINE_STRIP);
1727 glVertex3fv(vec[1]);
1729 glVertex3fv(vec[0]);
1730 glVertex3fv(vec[3]);
1732 glVertex3fv(vec[2]);
1737 tvec[2] = vec[1][2]; /* copy the depth */
1740 /* draw an outline arrow for inactive cameras and filled
1741 * for active cameras. We actually draw both outline+filled
1742 * for active cameras so the wire can be seen side-on */
1743 for (i = 0; i < 2; i++) {
1744 if (i == 0) glBegin(GL_LINE_LOOP);
1745 else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1748 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
1749 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
1750 glVertex3fv(tvec); /* left */
1752 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
1753 glVertex3fv(tvec); /* right */
1756 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
1757 glVertex3fv(tvec); /* top */
1762 if ((dflag & DRAW_SCENESET) == 0) {
1763 if (cam->flag & (CAM_SHOWLIMITS | CAM_SHOWMIST)) {
1766 /* draw in normalized object matrix space */
1767 copy_m4_m4(nobmat, ob->obmat);
1768 normalize_m4(nobmat);
1771 glLoadMatrixf(rv3d->viewmat);
1772 glMultMatrixf(nobmat);
1774 if (cam->flag & CAM_SHOWLIMITS) {
1775 draw_limit_line(cam->clipsta, cam->clipend, dflag, 0x77FFFF);
1776 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
1777 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
1780 if (cam->flag & CAM_SHOWMIST) {
1781 World *world = scene->world;
1783 draw_limit_line(world->miststa, world->miststa + world->mistdist, dflag, 0xFFFFFF);
1791 /* flag similar to draw_object() */
1792 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
1793 Object *UNUSED(ob), int UNUSED(flag))
1795 //Speaker *spk = ob->data;
1802 for (j = 0; j < 3; j++) {
1803 vec[2] = 0.25f * j - 0.125f;
1805 glBegin(GL_LINE_LOOP);
1806 for (i = 0; i < 16; i++) {
1807 vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1808 vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1814 for (j = 0; j < 4; j++) {
1815 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1816 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1817 glBegin(GL_LINE_STRIP);
1818 for (i = 0; i < 3; i++) {
1824 vec[2] = 0.25f * i - 0.125f;
1830 glDisable(GL_BLEND);
1833 static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel)
1835 BPoint *bp = lt->def;
1836 float *co = dl ? dl->verts : NULL;
1839 const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
1840 UI_ThemeColor(color);
1842 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1843 bglBegin(GL_POINTS);
1845 for (w = 0; w < lt->pntsw; w++) {
1846 int wxt = (w == 0 || w == lt->pntsw - 1);
1847 for (v = 0; v < lt->pntsv; v++) {
1848 int vxt = (v == 0 || v == lt->pntsv - 1);
1849 for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
1850 int uxt = (u == 0 || u == lt->pntsu - 1);
1851 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1852 if (bp->hide == 0) {
1853 /* check for active BPoint and ensure selected */
1854 if ((bp == actbp) && (bp->f1 & SELECT)) {
1855 UI_ThemeColor(TH_LASTSEL_POINT);
1856 bglVertex3fv(dl ? co : bp->vec);
1857 UI_ThemeColor(color);
1859 else if ((bp->f1 & SELECT) == sel) {
1860 bglVertex3fv(dl ? co : bp->vec);
1872 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
1874 int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
1878 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
1880 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
1886 glVertex3fv(&dl->verts[index * 3]);
1889 glVertex3fv(lt->def[index].vec);
1893 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1894 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1896 Lattice *lt = ob->data;
1899 int actdef_wcol = 0;
1900 const bool is_edit = (lt->editlatt != NULL);
1902 /* now we default make displist, this will modifiers work for non animated case */
1903 if (ob->disp.first == NULL)
1904 BKE_lattice_modifiers_calc(scene, ob);
1905 dl = BKE_displist_find(&ob->disp, DL_VERTS);
1908 lt = lt->editlatt->latt;
1910 UI_ThemeColor(TH_WIRE_EDIT);
1912 if (ob->defbase.first && lt->dvert) {
1913 actdef_wcol = ob->actdef;
1914 glShadeModel(GL_SMOOTH);
1919 for (w = 0; w < lt->pntsw; w++) {
1920 int wxt = (w == 0 || w == lt->pntsw - 1);
1921 for (v = 0; v < lt->pntsv; v++) {
1922 int vxt = (v == 0 || v == lt->pntsv - 1);
1923 for (u = 0; u < lt->pntsu; u++) {
1924 int uxt = (u == 0 || u == lt->pntsu - 1);
1926 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
1927 drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol);
1928 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
1930 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1931 drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol);
1932 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
1934 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1935 drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol);
1936 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
1943 /* restoration for weight colors */
1945 glShadeModel(GL_FLAT);
1948 BPoint *actbp = BKE_lattice_active_point_get(lt);
1950 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
1952 lattice_draw_verts(lt, dl, actbp, 0);
1953 lattice_draw_verts(lt, dl, actbp, 1);
1955 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1959 /* ***************** ******************** */
1963 typedef struct drawDMVertSel_userData {
1966 unsigned char *col[3]; /* (base, sel, act) */
1968 } drawDMVertSel_userData;
1970 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
1971 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
1973 drawDMVertSel_userData *data = userData;
1974 MVert *mv = &data->mvert[index];
1976 if (!(mv->flag & ME_HIDE)) {
1977 const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
1978 if (sel != data->sel_prev) {
1979 glColor3ubv(data->col[sel]);
1980 data->sel_prev = sel;
1987 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
1989 drawDMVertSel_userData data;
1991 /* TODO define selected color */
1992 unsigned char base_col[3] = {0x0, 0x0, 0x0};
1993 unsigned char sel_col[3] = {0xd8, 0xb8, 0x0};
1994 unsigned char act_col[3] = {0xff, 0xff, 0xff};
1996 data.mvert = me->mvert;
1997 data.active = BKE_mesh_mselect_active_get(me, ME_VSEL);
1998 data.sel_prev = 0xff;
2000 data.col[0] = base_col;
2001 data.col[1] = sel_col;
2002 data.col[2] = act_col;
2005 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
2009 /* ************** DRAW MESH ****************** */
2011 /* First section is all the "simple" draw routines,
2012 * ones that just pass some sort of primitive to GL,
2013 * with perhaps various options to control lighting,
2016 * These routines should not have user interface related
2020 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
2024 copy_m3_m4(obmat, ob->obmat);
2026 data->uniform_scale = is_uniform_scaled_m3(obmat);
2028 if (!data->uniform_scale) {
2029 /* inverted matrix */
2030 invert_m3_m3(data->imat, obmat);
2032 /* transposed inverted matrix */
2033 copy_m3_m3(data->tmat, data->imat);
2034 transpose_m3(data->tmat);
2038 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2040 drawDMNormal_userData *data = userData;
2041 BMFace *efa = EDBM_face_at_index(data->em, index);
2044 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2045 if (!data->uniform_scale) {
2046 mul_v3_m3v3(n, data->tmat, (float *) no);
2048 mul_m3_v3(data->imat, n);
2055 glVertex3f(cent[0] + n[0] * data->normalsize,
2056 cent[1] + n[1] * data->normalsize,
2057 cent[2] + n[2] * data->normalsize);
2061 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2063 drawDMNormal_userData data;
2066 data.normalsize = scene->toolsettings->normalsize;
2068 calcDrawDMNormalScale(ob, &data);
2071 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2075 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2077 BMFace *efa = EDBM_face_at_index(((void **)userData)[0], index);
2078 const char sel = *(((char **)userData)[1]);
2080 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
2081 (BM_elem_flag_test(efa, BM_ELEM_SELECT) == sel))
2086 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, char sel)
2088 void *ptrs[2] = {em, &sel};
2090 bglBegin(GL_POINTS);
2091 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs, DM_FOREACH_NOP);
2095 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])
2097 drawDMNormal_userData *data = userData;
2098 BMVert *eve = EDBM_vert_at_index(data->em, index);
2100 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2104 copy_v3_v3(no, no_f);
2107 normal_short_to_float_v3(no, no_s);
2110 if (!data->uniform_scale) {
2111 mul_v3_m3v3(n, data->tmat, (float *) no);
2113 mul_m3_v3(data->imat, n);
2120 glVertex3f(co[0] + n[0] * data->normalsize,
2121 co[1] + n[1] * data->normalsize,
2122 co[2] + n[2] * data->normalsize);
2126 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2128 drawDMNormal_userData data;
2131 data.normalsize = scene->toolsettings->normalsize;
2133 calcDrawDMNormalScale(ob, &data);
2136 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2140 /* Draw verts with color set based on selection */
2141 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2142 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2144 drawDMVerts_userData *data = userData;
2145 BMVert *eve = EDBM_vert_at_index(data->em, index);
2147 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2148 /* skin nodes: draw a red circle around the root
2150 if (data->cd_vskin_offset != -1) {
2151 const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
2152 if (vs->flag & MVERT_SKIN_ROOT) {
2153 float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2156 glColor4ubv(data->th_skin_root);
2157 drawcircball(GL_LINES, co, radius, data->imat);
2159 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2160 bglBegin(GL_POINTS);
2164 /* draw active larger - need to stop/start point drawing for this :/ */
2165 if (eve == data->eve_act) {
2166 glColor4ubv(data->th_editmesh_active);
2170 glPointSize(data->th_vertex_size);
2171 bglBegin(GL_POINTS);
2175 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2176 glPointSize(data->th_vertex_size);
2177 bglBegin(GL_POINTS);
2185 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
2188 drawDMVerts_userData data;
2190 data.eve_act = eve_act;
2193 /* Cache theme values */
2194 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2195 UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2196 UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2197 UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2198 data.th_vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2200 /* For skin root drawing */
2201 data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
2202 /* view-aligned matrix */
2203 mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2204 invert_m4(data.imat);
2206 bglBegin(GL_POINTS);
2207 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
2211 /* Draw edges with color set based on selection */
2212 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2215 //unsigned char **cols = userData, *col;
2216 drawDMEdgesSel_userData *data = userData;
2219 eed = EDBM_edge_at_index(data->em, index);
2221 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2222 if (eed == data->eed_act) {
2223 glColor4ubv(data->actCol);
2226 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2230 col = data->baseCol;
2232 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2234 return DM_DRAW_OPTION_SKIP;
2238 return DM_DRAW_OPTION_NORMAL;
2241 return DM_DRAW_OPTION_SKIP;
2244 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2245 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2247 drawDMEdgesSel_userData data;
2249 data.baseCol = baseCol;
2250 data.selCol = selCol;
2251 data.actCol = actCol;
2253 data.eed_act = eed_act;
2254 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2258 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2260 if (BM_elem_flag_test(EDBM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2261 return DM_DRAW_OPTION_SKIP;
2263 return DM_DRAW_OPTION_NORMAL;
2266 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2268 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
2271 /* Draw edges with color interpolated based on selection */
2272 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2274 if (BM_elem_flag_test(EDBM_edge_at_index(((void **)userData)[0], index), BM_ELEM_HIDDEN))
2275 return DM_DRAW_OPTION_SKIP;
2277 return DM_DRAW_OPTION_NORMAL;
2279 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2281 BMEdge *eed = EDBM_edge_at_index(((void **)userData)[0], index);
2282 unsigned char **cols = userData;
2283 unsigned char *col0 = cols[(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1];
2284 unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1];
2286 glColor4ub(col0[0] + (col1[0] - col0[0]) * t,
2287 col0[1] + (col1[1] - col0[1]) * t,
2288 col0[2] + (col1[2] - col0[2]) * t,
2289 col0[3] + (col1[3] - col0[3]) * t);
2292 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2294 void *cols[3] = {em, baseCol, selCol};
2296 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2299 /* Draw only seam edges */
2300 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2302 BMEdge *eed = EDBM_edge_at_index(userData, index);
2304 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
2305 return DM_DRAW_OPTION_NORMAL;
2307 return DM_DRAW_OPTION_SKIP;
2310 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2312 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
2315 /* Draw only sharp edges */
2316 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2318 BMEdge *eed = EDBM_edge_at_index(userData, index);
2320 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
2321 return DM_DRAW_OPTION_NORMAL;
2323 return DM_DRAW_OPTION_SKIP;
2326 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2328 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
2331 #ifdef WITH_FREESTYLE
2333 static int draw_dm_test_freestyle_edge_mark(BMEditMesh *em, BMEdge *eed)
2335 FreestyleEdge *fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
2338 return (fed->flag & FREESTYLE_EDGE_MARK) != 0;
2341 /* Draw only Freestyle feature edges */
2342 static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
2344 BMEdge *eed = EDBM_edge_at_index(userData, index);
2346 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && draw_dm_test_freestyle_edge_mark(userData, eed))
2347 return DM_DRAW_OPTION_NORMAL;
2349 return DM_DRAW_OPTION_SKIP;
2352 static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
2354 dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em);
2357 static int draw_dm_test_freestyle_face_mark(BMEditMesh *em, BMFace *efa)
2359 FreestyleFace *ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
2362 return (ffa->flag & FREESTYLE_FACE_MARK) != 0;
2367 /* Draw faces with color set based on selection
2368 * return 2 for the active face so it renders with stipple enabled */
2369 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
2371 drawDMFacesSel_userData *data = userData;
2372 BMFace *efa = EDBM_face_at_index(data->em, index);
2375 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2376 if (efa == data->efa_act) {
2377 glColor4ubv(data->cols[2]);
2378 return DM_DRAW_OPTION_STIPPLE;
2381 #ifdef WITH_FREESTYLE
2382 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->em, efa) ? 3 : 0];
2384 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2387 return DM_DRAW_OPTION_SKIP;
2389 return DM_DRAW_OPTION_NORMAL;
2392 return DM_DRAW_OPTION_SKIP;
2395 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2398 drawDMFacesSel_userData *data = userData;
2403 unsigned char *col, *next_col;
2405 if (!data->orig_index_mf_to_mpoly)
2408 i = DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, index);
2409 efa = (i != ORIGINDEX_NONE) ? EDBM_face_at_index(data->em, i) : NULL;
2410 i = DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, next_index);
2411 next_efa = (i != ORIGINDEX_NONE) ? EDBM_face_at_index(data->em, i) : NULL;
2413 if (ELEM(NULL, efa, next_efa))
2416 if (efa == next_efa)
2419 if (efa == data->efa_act || next_efa == data->efa_act)
2422 #ifdef WITH_FREESTYLE
2423 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->em, efa) ? 3 : 0];
2424 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->em, efa) ? 3 : 0];
2426 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2427 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
2430 if (col[3] == 0 || next_col[3] == 0)
2433 return col == next_col;
2436 /* also draws the active face */
2437 #ifdef WITH_FREESTYLE
2438 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2439 unsigned char *selCol, unsigned char *actCol, unsigned char *markCol, BMFace *efa_act)
2441 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2442 unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
2445 drawDMFacesSel_userData data;
2447 data.cols[0] = baseCol;
2449 data.cols[1] = selCol;
2450 data.cols[2] = actCol;
2451 #ifdef WITH_FREESTYLE
2452 data.cols[3] = markCol;
2454 data.efa_act = efa_act;
2456 data.orig_index_mf_to_mpoly = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
2457 data.orig_index_mp_to_orig = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
2458 if ((data.orig_index_mf_to_mpoly && data.orig_index_mp_to_orig) == false) {
2459 data.orig_index_mf_to_mpoly = data.orig_index_mp_to_orig = NULL;
2462 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
2465 static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
2467 drawDMLayer_userData *data = userData;
2468 BMEditMesh *em = data->em;
2469 BMEdge *eed = EDBM_edge_at_index(em, index);
2471 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2472 const float crease = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
2473 if (crease != 0.0f) {
2474 UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_CREASE, crease);
2475 return DM_DRAW_OPTION_NORMAL;
2478 return DM_DRAW_OPTION_SKIP;
2480 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
2482 drawDMLayer_userData data;
2485 data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
2487 if (data.cd_layer_offset != -1) {
2489 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
2494 static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
2496 drawDMLayer_userData *data = userData;
2497 BMEditMesh *em = data->em;
2498 BMEdge *eed = EDBM_edge_at_index(em, index);
2500 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2501 const float bweight = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
2502 if (bweight != 0.0f) {
2503 UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, bweight);
2504 return DM_DRAW_OPTION_NORMAL;
2507 return DM_DRAW_OPTION_SKIP;
2509 static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
2510 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2512 drawDMLayer_userData *data = userData;
2513 BMEditMesh *em = data->em;
2514 BMVert *eve = EDBM_vert_at_index(em, index);
2516 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2517 const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
2518 if (bweight != 0.0f) {
2519 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, bweight);
2524 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2526 ToolSettings *ts = scene->toolsettings;
2528 if (ts->selectmode & SCE_SELECT_VERTEX) {
2529 drawDMLayer_userData data;
2532 data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT);
2534 if (data.cd_layer_offset != -1) {
2535 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2536 bglBegin(GL_POINTS);
2537 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
2542 drawDMLayer_userData data;
2545 data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
2547 if (data.cd_layer_offset != -1) {
2549 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
2555 /* Second section of routines: Combine first sets to form fancy
2556 * drawing routines (for example rendering twice to get overlays).
2558 * Also includes routines that are basic drawing but are too
2559 * specialized to be split out (like drawing creases or measurements).
2562 /* EditMesh drawing routines*/
2564 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
2565 BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act,
2568 ToolSettings *ts = scene->toolsettings;
2571 if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */
2573 for (sel = 0; sel < 2; sel++) {
2574 unsigned char col[4], fcol[4];
2577 UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
2578 UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE_EDIT, fcol);
2580 for (pass = 0; pass < 2; pass++) {
2581 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2582 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2585 if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
2586 glDisable(GL_DEPTH_TEST);
2594 size = (size > 2.1f ? size / 2.0f : size);
2595 fsize = (fsize > 2.1f ? fsize / 2.0f : fsize);
2596 col[3] = fcol[3] = 100;
2599 col[3] = fcol[3] = 255;
2602 if (ts->selectmode & SCE_SELECT_VERTEX) {
2605 draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
2608 if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2611 draw_dm_face_centers(em, cageDM, sel);
2615 glDisable(GL_BLEND);
2616 glEnable(GL_DEPTH_TEST);
2621 if (v3d->zbuf) glDepthMask(1);
2625 static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
2626 Mesh *me, DerivedMesh *cageDM, short sel_only,
2629 ToolSettings *ts = scene->toolsettings;
2631 unsigned char wireCol[4], selCol[4], actCol[4];
2633 /* since this function does transparent... */
2634 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2635 UI_GetThemeColor4ubv(TH_WIRE_EDIT, wireCol);
2636 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2638 /* when sel only is used, don't render wire, only selected, this is used for
2639 * textured draw mode when the 'edges' option is disabled */
2643 for (pass = 0; pass < 2; pass++) {
2644 /* show wires in transparent when no zbuf clipping for select */
2646 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) {
2648 glDisable(GL_DEPTH_TEST);
2650 if (!sel_only) wireCol[3] = 85;
2658 if (!sel_only) wireCol[3] = 255;
2661 if (ts->selectmode == SCE_SELECT_FACE) {
2662 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2664 else if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) {
2665 if (cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2666 glShadeModel(GL_SMOOTH);
2667 draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
2668 glShadeModel(GL_FLAT);
2671 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2676 glColor4ubv(wireCol);
2677 draw_dm_edges(em, cageDM);
2682 glDisable(GL_BLEND);
2683 glEnable(GL_DEPTH_TEST);
2688 static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit)
2690 const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
2691 Mesh *me = ob->data;
2692 float v1[3], v2[3], v3[3], vmid[3], fvec[3];
2693 char numstr[32]; /* Stores the measurement display text here */
2694 const char *conv_float; /* Use a float conversion matching the grid size */
2695 unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */
2696 float area; /* area of the face */
2697 float grid = unit->system ? unit->scale_length : v3d->grid;
2698 const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
2699 const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0;
2700 const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0;
2701 float clip_planes[4][4];
2702 /* allow for displaying shape keys and deform mods */
2703 DerivedMesh *dm = EDBM_mesh_deform_dm_get(em);
2707 /* make the precision of the display value proportionate to the gridsize */
2709 if (grid <= 0.01f) conv_float = "%.6g";
2710 else if (grid <= 0.1f) conv_float = "%.5g";
2711 else if (grid <= 1.0f) conv_float = "%.4g";
2712 else if (grid <= 10.0f) conv_float = "%.3g";
2713 else conv_float = "%.2g";
2715 if (me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_EDGEANG)) {
2717 bglMats mats = {{0}};
2718 const rcti rect = {0, ar->winx, 0, ar->winy};
2720 view3d_get_transformation(ar, ar->regiondata, em->ob, &mats);
2721 ED_view3d_clipping_calc(&bb, clip_planes, &mats, &rect);
2724 if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2727 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2730 BM_mesh_elem_index_ensure(em->bm, BM_VERT);
2733 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2734 /* draw selected edges, or edges next to selected verts while draging */
2735 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
2736 (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
2737 BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
2739 float v1_clip[3], v2_clip[3];
2742 dm->getVertCo(dm, BM_elem_index_get(eed->v1), v1);
2743 dm->getVertCo(dm, BM_elem_index_get(eed->v2), v2);
2746 copy_v3_v3(v1, eed->v1->co);
2747 copy_v3_v3(v2, eed->v2->co);
2750 copy_v3_v3(v1_clip, v1);
2751 copy_v3_v3(v2_clip, v2);
2753 if (clip_segment_v3_plane_n(v1_clip, v2_clip, clip_planes, 4)) {
2755 mid_v3_v3v3(vmid, v1_clip, v2_clip);
2758 mul_mat3_m4_v3(ob->obmat, v1);
2759 mul_mat3_m4_v3(ob->obmat, v2);
2763 bUnit_AsString(numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
2764 unit->system, B_UNIT_LENGTH, do_split, false);
2767 BLI_snprintf(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
2770 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col);
2776 if (me->drawflag & ME_DRAWEXTRA_EDGEANG) {
2777 const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
2780 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
2783 BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
2786 // invert_m4_m4(ob->imat, ob->obmat); // this is already called
2788 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2790 if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
2791 /* draw selected edges, or edges next to selected verts while draging */
2792 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
2793 (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
2794 BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
2795 /* special case, this is useful to show when vertes connected to this edge via a
2796 * face are being transformed */
2797 BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
2798 BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
2799 BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
2800 BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)
2803 float v1_clip[3], v2_clip[3];
2806 dm->getVertCo(dm, BM_elem_index_get(eed->v1), v1);
2807 dm->getVertCo(dm, BM_elem_index_get(eed->v2), v2);
2810 copy_v3_v3(v1, eed->v1->co);
2811 copy_v3_v3(v2, eed->v2->co);
2814 copy_v3_v3(v1_clip, v1);
2815 copy_v3_v3(v2_clip, v2);
2817 if (clip_segment_v3_plane_n(v1_clip, v2_clip, clip_planes, 4)) {
2818 float no_a[3], no_b[3];
2821 mid_v3_v3v3(vmid, v1_clip, v2_clip);
2824 dm->getPolyNo(dm, BM_elem_index_get(l_a->f), no_a);
2825 dm->getPolyNo(dm, BM_elem_index_get(l_b->f), no_b);
2828 copy_v3_v3(no_a, l_a->f->no);
2829 copy_v3_v3(no_b, l_b->f->no);
2833 mul_mat3_m4_v3(ob->imat, no_a);
2834 mul_mat3_m4_v3(ob->imat, no_b);
2839 angle = angle_normalized_v3v3(no_a, no_b);
2841 BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
2843 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col);
2850 if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2851 /* would be nice to use BM_face_calc_area, but that is for 2d faces
2852 * so instead add up tessellation triangle areas */
2856 #define DRAW_EM_MEASURE_STATS_FACEAREA() \
2857 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \
2858 mul_v3_fl(vmid, 1.0f / (float)n); \
2859 if (unit->system) { \
2860 bUnit_AsString(numstr, sizeof(numstr), \
2861 (double)(area * unit->scale_length * unit->scale_length), \
2862 3, unit->system, B_UNIT_AREA, do_split, false); \
2863 view3d_cached_text_draw_add(vmid, numstr, 0, \
2864 /* Metric system uses unicode "squared" sign! */ \
2865 txt_flag ^ V3D_CACHE_TEXT_ASCII, col); \
2868 BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
2869 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col); \
2873 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2876 BM_mesh_elem_index_ensure(em->bm, BM_VERT);
2883 for (i = 0; i < em->tottri; i++) {
2884 BMLoop **l = em->looptris[i];
2885 if (f && l[0]->f != f) {
2886 DRAW_EM_MEASURE_STATS_FACEAREA();
2895 dm->getVertCo(dm, BM_elem_index_get(l[0]->v), v1);
2896 dm->getVertCo(dm, BM_elem_index_get(l[1]->v), v2);
2897 dm->getVertCo(dm, BM_elem_index_get(l[2]->v), v3);
2900 copy_v3_v3(v1, l[0]->v->co);
2901 copy_v3_v3(v2, l[1]->v->co);
2902 copy_v3_v3(v3, l[2]->v->co);
2905 add_v3_v3(vmid, v1);
2906 add_v3_v3(vmid, v2);
2907 add_v3_v3(vmid, v3);
2910 mul_mat3_m4_v3(ob->obmat, v1);
2911 mul_mat3_m4_v3(ob->obmat, v2);
2912 mul_mat3_m4_v3(ob->obmat, v3);
2914 area += area_tri_v3(v1, v2, v3);
2918 DRAW_EM_MEASURE_STATS_FACEAREA();
2920 #undef DRAW_EM_MEASURE_STATS_FACEAREA
2923 if (me->drawflag & ME_DRAWEXTRA_FACEANG) {
2925 const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
2927 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2930 BM_mesh_elem_index_ensure(em->bm, BM_VERT);
2933 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2934 const int is_face_sel = BM_elem_flag_test(efa, BM_ELEM_SELECT);
2936 if (is_face_sel || do_moving) {
2939 bool is_first = true;
2941 BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
2942 if (is_face_sel || (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT))) {
2946 /* lazy init center calc */
2949 BMLoop *l_iter, *l_first;
2952 l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
2954 dm->getVertCo(dm, BM_elem_index_get(l_iter->v), tvec);
2955 add_v3_v3(vmid, tvec);
2956 } while ((l_iter = l_iter->next) != l_first);
2957 mul_v3_fl(vmid, 1.0f / (float)efa->len);
2960 BM_face_calc_center_bounds(efa, vmid);
2966 dm->getVertCo(dm, BM_elem_index_get(loop->prev->v), v1);
2967 dm->getVertCo(dm, BM_elem_index_get(loop->v), v2);
2968 dm->getVertCo(dm, BM_elem_index_get(loop->next->v), v3);
2971 copy_v3_v3(v1, loop->prev->v->co);
2972 copy_v3_v3(v2, loop->v->co);
2973 copy_v3_v3(v3, loop->next->v->co);
2976 copy_v3_v3(v2_local, v2);
2979 mul_mat3_m4_v3(ob->obmat, v1);
2980 mul_mat3_m4_v3(ob->obmat, v2);
2981 mul_mat3_m4_v3(ob->obmat, v3);
2984 angle = angle_v3v3v3(v1, v2, v3);
2986 BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
2987 interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
2988 view3d_cached_text_draw_add(fvec, numstr, 0, txt_flag, col);
2996 static void draw_em_indices(BMEditMesh *em)
2998 const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
3005 unsigned char col[4];
3010 /* For now, reuse appropriate theme colors from stats text colors */
3012 if (em->selectmode & SCE_SELECT_VERTEX) {
3013 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
3014 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
3015 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
3016 BLI_snprintf(numstr, sizeof(numstr), "%d", i);
3017 view3d_cached_text_draw_add(v->co, numstr, 0, txt_flag, col);
3023 if (em->selectmode & SCE_SELECT_EDGE) {
3025 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
3026 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
3027 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
3028 BLI_snprintf(numstr, sizeof(numstr), "%d", i);
3029 mid_v3_v3v3(pos, e->v1->co, e->v2->co);
3030 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
3036 if (em->selectmode & SCE_SELECT_FACE) {
3038 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
3039 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3040 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
3041 BM_face_calc_center_mean(f, pos);
3042 BLI_snprintf(numstr, sizeof(numstr), "%d", i);
3043 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
3050 static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
3052 BMEditMesh *em = userData;
3055 if (UNLIKELY(index >= em->bm->totface))
3056 return DM_DRAW_OPTION_NORMAL;
3058 efa = EDBM_face_at_index(em, index);
3059 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
3060 GPU_enable_material(efa->mat_nr + 1, NULL);
3061 return DM_DRAW_OPTION_NORMAL;
3064 return DM_DRAW_OPTION_SKIP;
3068 static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
3070 BMEditMesh *em = userData;
3073 if (UNLIKELY(index >= em->bm->totface))
3074 return DM_DRAW_OPTION_NORMAL;
3076 efa = EDBM_face_at_index(em, index);
3078 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
3079 return DM_DRAW_OPTION_NORMAL;
3082 return DM_DRAW_OPTION_SKIP;
3086 static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
3087 Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt)
3090 RegionView3D *rv3d = ar->regiondata;
3091 Mesh *me = ob->data;
3092 BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, true); /* annoying but active faces is stored differently */
3093 BMEdge *eed_act = NULL;
3094 BMVert *eve_act = NULL;
3095 bool use_occlude_wire = (v3d->flag2 & V3D_OCCLUDE_WIRE) && (dt > OB_WIRE);
3097 // BLI_assert(!cageDM || !(cageDM->dirty & DM_DIRTY_NORMALS));
3098 BLI_assert(!finalDM || !(finalDM->dirty & DM_DIRTY_NORMALS));
3100 if (em->bm->selected.last) {
3101 BMEditSelection *ese = em-&g