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_listbase.h"
47 #include "BLI_link_utils.h"
48 #include "BLI_string.h"
51 #include "BLI_memarena.h"
53 #include "BKE_anim.h" /* for the where_on_path function */
54 #include "BKE_armature.h"
55 #include "BKE_camera.h"
56 #include "BKE_constraint.h" /* for the get_constraint_target function */
57 #include "BKE_curve.h"
58 #include "BKE_DerivedMesh.h"
59 #include "BKE_deform.h"
60 #include "BKE_displist.h"
62 #include "BKE_global.h"
63 #include "BKE_image.h"
65 #include "BKE_lattice.h"
68 #include "BKE_material.h"
69 #include "BKE_mball.h"
70 #include "BKE_modifier.h"
71 #include "BKE_movieclip.h"
72 #include "BKE_object.h"
73 #include "BKE_paint.h"
74 #include "BKE_particle.h"
75 #include "BKE_pointcache.h"
76 #include "BKE_scene.h"
78 #include "BKE_tracking.h"
80 #include "BKE_editmesh.h"
82 #include "IMB_imbuf.h"
83 #include "IMB_imbuf_types.h"
86 #include "BIF_glutil.h"
89 #include "GPU_extensions.h"
92 #include "ED_particle.h"
93 #include "ED_screen.h"
94 #include "ED_sculpt.h"
97 #include "UI_resources.h"
98 #include "UI_interface_icons.h"
103 #include "view3d_intern.h" /* bad level include */
105 /* Workaround for sequencer scene render mode.
107 * Strips doesn't use DAG to update objects or so, which
108 * might lead to situations when object is drawing without
111 * Ideally we don't want to evaluate objects from drawing,
112 * but it'll require some major sequencer re-design. So
113 * for now just fallback to legacy behaior with calling
114 * display ist creating from draw().
116 #define SEQUENCER_DAG_WORKAROUND
118 typedef enum eWireDrawMode {
121 OBDRAW_WIRE_ON_DEPTH = 2
124 typedef struct drawDMVerts_userData {
130 /* cached theme values */
131 unsigned char th_editmesh_active[4];
132 unsigned char th_vertex_select[4];
133 unsigned char th_vertex[4];
134 unsigned char th_skin_root[4];
135 float th_vertex_size;
137 /* for skin node drawing */
140 } drawDMVerts_userData;
142 typedef struct drawDMEdgesSel_userData {
145 unsigned char *baseCol, *selCol, *actCol;
147 } drawDMEdgesSel_userData;
149 typedef struct drawDMFacesSel_userData {
150 #ifdef WITH_FREESTYLE
151 unsigned char *cols[4];
153 unsigned char *cols[3];
160 int *orig_index_mf_to_mpoly;
161 int *orig_index_mp_to_orig;
162 } drawDMFacesSel_userData;
164 typedef struct drawDMNormal_userData {
170 } drawDMNormal_userData;
172 typedef struct bbsObmodeMeshVerts_userData {
175 } bbsObmodeMeshVerts_userData;
177 typedef struct drawDMLayer_userData {
180 } drawDMLayer_userData;
182 static void draw_bounding_volume(Object *ob, char type);
184 static void drawcube_size(float size);
185 static void drawcircle_size(float size);
186 static void draw_empty_sphere(float size);
187 static void draw_empty_cone(float size);
189 static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
191 float col_wire[3], col_bg[3], col[3];
193 rgb_uchar_to_float(col_wire, ob_wire_col);
195 UI_GetThemeColor3fv(theme_id, col_bg);
196 interp_v3_v3v3(col, col_bg, col_wire, fac);
200 /* this condition has been made more complex since editmode can draw textures */
201 bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
203 /* texture and material draw modes */
204 if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
209 if ((v3d->drawtype == OB_SOLID) &&
210 (v3d->flag2 & V3D_SOLID_TEX) &&
211 (BKE_scene_use_new_shading_nodes(scene) == false))
216 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) {
223 static bool check_object_draw_editweight(Mesh *me, DerivedMesh *finalDM)
225 if (me->drawflag & ME_DRAWEIGHT) {
226 /* editmesh handles its own weight drawing */
227 if (finalDM->type != DM_TYPE_EDITBMESH) {
235 static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
237 if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
240 if (G.f & G_BACKBUFSEL)
243 if ((vd->flag & V3D_ZBUF_SELECT) == 0)
246 /* if its drawing textures with zbuf sel, then don't draw dots */
247 if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
250 if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
256 /* ************************ */
258 /* check for glsl drawing */
260 bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
262 if (!GPU_glsl_support())
266 if (!check_object_draw_texture(scene, v3d, dt))
268 if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
271 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
274 if (BKE_scene_use_new_shading_nodes(scene))
277 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
280 static bool check_alpha_pass(Base *base)
282 if (base->flag & OB_FROMDUPLI)
288 if (base->object->mode & OB_MODE_ALL_PAINT)
291 return (base->object->dtx & OB_DRAWTRANSP);
295 static const unsigned int colortab[] = {
296 0x0, 0x403000, 0xFFFF88
299 /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
300 /* 32 values of sin function (still same result!) */
301 #define CIRCLE_RESOL 32
303 static const float sinval[CIRCLE_RESOL] = {
338 /* 32 values of cos function (still same result!) */
339 static const float cosval[CIRCLE_RESOL] = {
374 static void draw_xyz_wire(const float c[3], float size, int axis)
376 float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
377 float dim = size * 0.1f;
378 float dx[3], dy[3], dz[3];
380 dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
381 dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
382 dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
388 /* bottom left to top right */
389 sub_v3_v3v3(v1, c, dx);
391 add_v3_v3v3(v2, c, dx);
397 /* top left to bottom right */
410 /* bottom left to top right */
411 mul_v3_fl(dx, 0.75f);
412 sub_v3_v3v3(v1, c, dx);
414 add_v3_v3v3(v2, c, dx);
420 /* top left to center */
431 glBegin(GL_LINE_STRIP);
433 /* start at top left */
434 sub_v3_v3v3(v1, c, dx);
435 add_v3_v3v3(v1, c, dz);
460 void drawaxes(float size, char drawtype)
463 float v1[3] = {0.0, 0.0, 0.0};
464 float v2[3] = {0.0, 0.0, 0.0};
465 float v3[3] = {0.0, 0.0, 0.0};
470 for (axis = 0; axis < 3; axis++) {
478 /* reset v1 & v2 to zero */
479 v1[axis] = v2[axis] = 0.0f;
484 case OB_SINGLE_ARROW:
487 /* in positive z direction only */
494 glBegin(GL_TRIANGLES);
496 v2[0] = size * 0.035f; v2[1] = size * 0.035f;
497 v3[0] = size * -0.035f; v3[1] = size * 0.035f;
498 v2[2] = v3[2] = size * 0.75f;
500 for (axis = 0; axis < 4; axis++) {
523 drawcircle_size(size);
526 case OB_EMPTY_SPHERE:
527 draw_empty_sphere(size);
531 draw_empty_cone(size);
537 for (axis = 0; axis < 3; axis++) {
538 const int arrow_axis = (axis == 0) ? 1 : 0;
546 v1[axis] = size * 0.85f;
547 v1[arrow_axis] = -size * 0.08f;
551 v1[arrow_axis] = size * 0.08f;
557 v2[axis] += size * 0.125f;
559 draw_xyz_wire(v2, size, axis);
562 /* reset v1 & v2 to zero */
563 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
571 /* Function to draw an Image on a empty Object */
572 static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
574 Image *ima = (Image *)ob->data;
575 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL);
577 float scale, ofs_x, ofs_y, sca_x, sca_y;
580 if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
581 IMB_rect_from_float(ibuf);
584 /* Get the buffer dimensions so we can fallback to fake ones */
585 if (ibuf && ibuf->rect) {
594 /* Get the image aspect even if the buffer is invalid */
596 if (ima->aspx > ima->aspy) {
598 sca_y = ima->aspy / ima->aspx;
600 else if (ima->aspx < ima->aspy) {
601 sca_x = ima->aspx / ima->aspy;
614 /* Calculate the scale center based on objects origin */
615 ofs_x = ob->ima_ofs[0] * ima_x;
616 ofs_y = ob->ima_ofs[1] * ima_y;
618 glMatrixMode(GL_MODELVIEW);
621 /* Make sure we are drawing at the origin */
622 glTranslatef(0.0f, 0.0f, 0.0f);
624 /* Calculate Image scale */
625 scale = (ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y));
627 /* Set the object scale */
628 glScalef(scale * sca_x, scale * sca_y, 1.0f);
630 if (ibuf && ibuf->rect) {
631 const bool use_clip = (U.glalphaclip != 1.0f);
632 int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP ) ? GL_NEAREST : GL_LINEAR;
633 /* Setup GL params */
635 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
638 glEnable(GL_ALPHA_TEST);
639 glAlphaFunc(GL_GREATER, U.glalphaclip);
642 /* Use the object color and alpha */
645 /* Draw the Image on the screen */
646 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
647 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
652 glDisable(GL_ALPHA_TEST);
653 glAlphaFunc(GL_GREATER, 0.0f);
657 if ((dflag & DRAW_CONSTCOLOR) == 0) {
658 glColor3ubv(ob_wire_col);
661 /* Calculate the outline vertex positions */
662 glBegin(GL_LINE_LOOP);
663 glVertex2f(ofs_x, ofs_y);
664 glVertex2f(ofs_x + ima_x, ofs_y);
665 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
666 glVertex2f(ofs_x, ofs_y + ima_y);
670 /* Reset GL settings */
671 glMatrixMode(GL_MODELVIEW);
674 BKE_image_release_ibuf(ima, ibuf, NULL);
677 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[4][4])
680 float *viter = (float *)verts;
683 mul_v3_v3fl(vx, tmat[0], rad);
684 mul_v3_v3fl(vy, tmat[1], rad);
686 for (a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
687 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
688 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
689 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
693 void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4])
695 float verts[CIRCLE_RESOL][3];
697 circball_array_fill(verts, cent, rad, tmat);
699 glEnableClientState(GL_VERTEX_ARRAY);
700 glVertexPointer(3, GL_FLOAT, 0, verts);
701 glDrawArrays(mode, 0, CIRCLE_RESOL);
702 glDisableClientState(GL_VERTEX_ARRAY);
705 /* circle for object centers, special_color is for library or ob users */
706 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
708 const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
709 float verts[CIRCLE_RESOL][3];
711 /* using gldepthfunc guarantees that it does write z values,
712 * but not checks for it, so centers remain visible independent order of drawing */
713 if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
717 if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
719 else glColor4ub(0x55, 0xCC, 0xCC, 155);
722 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
723 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
724 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
727 circball_array_fill(verts, co, size, rv3d->viewinv);
729 /* enable vertex array */
730 glEnableClientState(GL_VERTEX_ARRAY);
731 glVertexPointer(3, GL_FLOAT, 0, verts);
733 /* 1. draw filled, blended polygon */
734 glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
736 /* 2. draw outline */
737 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
738 glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
741 glDisableClientState(GL_VERTEX_ARRAY);
745 if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
748 /* *********** text drawing for object/particles/armature ************* */
750 typedef struct ViewCachedString {
751 struct ViewCachedString *next;
761 /* str is allocated past the end */
764 /* one arena for all 3 string lists */
765 static MemArena *g_v3d_strings_arena = NULL;
766 static ViewCachedString *g_v3d_strings[3] = {NULL, NULL, NULL};
767 static int g_v3d_string_level = -1;
769 void view3d_cached_text_draw_begin(void)
771 g_v3d_string_level++;
773 BLI_assert(g_v3d_string_level >= 0);
775 if (g_v3d_string_level == 0) {
776 BLI_assert(g_v3d_strings_arena == NULL);
780 void view3d_cached_text_draw_add(const float co[3],
781 const char *str, const size_t str_len,
782 short xoffs, short flag,
783 const unsigned char col[4])
785 int alloc_len = str_len + 1;
786 /* TODO, replace with more efficient malloc, perhaps memarena per draw? */
787 ViewCachedString *vos;
789 BLI_assert(str_len == strlen(str));
791 if (g_v3d_strings_arena == NULL) {
792 g_v3d_strings_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 14), __func__);
795 vos = BLI_memarena_alloc(g_v3d_strings_arena, sizeof(ViewCachedString) + alloc_len);
797 BLI_LINKS_PREPEND(g_v3d_strings[g_v3d_string_level], vos);
799 copy_v3_v3(vos->vec, co);
800 copy_v4_v4_char((char *)vos->col.ub, (const char *)col);
803 vos->str_len = str_len;
805 /* allocate past the end */
806 memcpy(vos + 1, str, alloc_len);
809 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, float mat[4][4])
811 RegionView3D *rv3d = ar->regiondata;
812 ViewCachedString *vos;
815 BLI_assert(g_v3d_string_level >= 0 && g_v3d_string_level <= 2);
817 /* project first and test */
818 for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
819 if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
820 mul_m4_v3(mat, vos->vec);
822 if (ED_view3d_project_short_ex(ar,
823 (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
824 (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
826 V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
831 vos->sco[0] = IS_CLIPPED;
836 int col_pack_prev = 0;
839 bglMats mats; /* ZBuffer depth vars */
846 if (rv3d->rflag & RV3D_CLIPPING) {
847 ED_view3d_clipping_disable();
850 glMatrixMode(GL_PROJECTION);
852 glMatrixMode(GL_MODELVIEW);
854 ED_region_pixelspace(ar);
857 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
863 for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
864 if (vos->sco[0] != IS_CLIPPED) {
865 const char *str = (char *)(vos + 1);
867 if (col_pack_prev != vos->col.pack) {
868 glColor3ubv(vos->col.ub);
869 col_pack_prev = vos->col.pack;
872 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
873 BLF_draw_default_ascii :
875 )( (float)vos->sco[0] + vos->xoffs,
877 (depth_write) ? 0.0f : 2.0f,
884 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
890 glMatrixMode(GL_PROJECTION);
892 glMatrixMode(GL_MODELVIEW);
895 if (rv3d->rflag & RV3D_CLIPPING) {
896 ED_view3d_clipping_enable();
900 g_v3d_strings[g_v3d_string_level] = NULL;
902 if (g_v3d_string_level == 0) {
903 if (g_v3d_strings_arena) {
904 BLI_memarena_free(g_v3d_strings_arena);
905 g_v3d_strings_arena = NULL;
909 g_v3d_string_level--;
912 /* ******************** primitive drawing ******************* */
914 /* draws a cube on given the scaling of the cube, assuming that
915 * all required matrices have been set (used for drawing empties)
917 static void drawcube_size(float size)
919 glBegin(GL_LINE_STRIP);
920 glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size);
921 glVertex3f(-size, size, size); glVertex3f(-size, size, -size);
923 glVertex3f(-size, -size, -size); glVertex3f(size, -size, -size);
924 glVertex3f(size, -size, size); glVertex3f(size, size, size);
926 glVertex3f(size, size, -size); glVertex3f(size, -size, -size);
929 glBegin(GL_LINE_STRIP);
930 glVertex3f(-size, -size, size); glVertex3f(size, -size, size);
933 glBegin(GL_LINE_STRIP);
934 glVertex3f(-size, size, size); glVertex3f(size, size, size);
937 glBegin(GL_LINE_STRIP);
938 glVertex3f(-size, size, -size); glVertex3f(size, size, -size);
942 /* this is an unused (old) cube-drawing function based on a given size */
944 static void drawcube_size(const float size[3])
948 glScalef(size[0], size[1], size[2]);
951 glBegin(GL_LINE_STRIP);
952 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
953 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
954 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
957 glBegin(GL_LINE_STRIP);
958 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
961 glBegin(GL_LINE_STRIP);
962 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
965 glBegin(GL_LINE_STRIP);
966 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
973 static void drawshadbuflimits(Lamp *la, float mat[4][4])
975 float sta[3], end[3], lavec[3];
977 negate_v3_v3(lavec, mat[2]);
980 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
981 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
983 glBegin(GL_LINE_STRIP);
998 static void spotvolume(float lvec[3], float vvec[3], const float inp)
1000 /* camera is at 0,0,0 */
1001 float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
1004 normalize_v3(vvec); /* is this the correct vector ? */
1006 cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec en lvec */
1007 cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parrallel with lvec */
1009 /* vectors are exactly aligned, use the X axis, this is arbitrary */
1010 if (normalize_v3(plane) == 0.0f)
1013 /* now we've got two equations: one of a cone and one of a plane, but we have
1014 * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
1016 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
1017 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
1019 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
1024 normalize_v3(&q[1]);
1026 angle = saacos(plane[2]) / 2.0f;
1028 si = sqrtf(1 - co * co);
1035 quat_to_mat3(mat1, q);
1037 /* rotate lamp vector now over acos(inp) degrees */
1038 copy_v3_v3(vvec, lvec);
1042 si = sqrtf(1.0f - inp * inp);
1048 mul_m3_m3m3(mat3, mat2, mat1);
1052 mul_m3_m3m3(mat4, mat2, mat1);
1055 mul_m3_m3m3(mat2, mat1, mat3);
1056 mul_m3_v3(mat2, lvec);
1057 mul_m3_m3m3(mat2, mat1, mat4);
1058 mul_m3_v3(mat2, vvec);
1063 static void draw_spot_cone(Lamp *la, float x, float z)
1067 glBegin(GL_TRIANGLE_FAN);
1068 glVertex3f(0.0f, 0.0f, -x);
1070 if (la->mode & LA_SQUARE) {
1071 glVertex3f(z, z, 0);
1072 glVertex3f(-z, z, 0);
1073 glVertex3f(-z, -z, 0);
1074 glVertex3f(z, -z, 0);
1075 glVertex3f(z, z, 0);
1081 for (a = 0; a < 33; a++) {
1082 angle = a * M_PI * 2 / (33 - 1);
1083 glVertex3f(z * cosf(angle), z * sinf(angle), 0);
1090 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1092 glEnable(GL_CULL_FACE);
1096 /* draw backside darkening */
1097 glCullFace(GL_FRONT);
1099 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1100 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1102 draw_spot_cone(la, x, z);
1104 /* draw front side lighting */
1105 glCullFace(GL_BACK);
1107 glBlendFunc(GL_ONE, GL_ONE);
1108 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1110 draw_spot_cone(la, x, z);
1113 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1114 glDisable(GL_BLEND);
1116 glDisable(GL_CULL_FACE);
1117 glCullFace(GL_BACK);
1120 static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
1121 const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
1123 Object *ob = base->object;
1124 const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1125 Lamp *la = ob->data;
1126 float vec[3], lvec[3], vvec[3], circrad, x, y, z;
1130 unsigned char curcol[4];
1131 unsigned char col[4];
1132 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1133 /* the moment of view3d_draw_transp() call */
1134 const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1135 const bool drawcone = ((dt > OB_WIRE) &&
1136 !(G.f & G_PICKSEL) &&
1137 (la->type == LA_SPOT) &&
1138 (la->mode & LA_SHOW_CONE) &&
1139 !(base->flag & OB_FROMDUPLI) &&
1142 if (drawcone && !v3d->transp) {
1143 /* in this case we need to draw delayed */
1144 ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
1148 /* we first draw only the screen aligned & fixed scale stuff */
1150 glLoadMatrixf(rv3d->viewmat);
1152 /* lets calculate the scale: */
1153 lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
1155 /* and view aligned matrix: */
1156 copy_m4_m4(imat, rv3d->viewinv);
1157 normalize_v3(imat[0]);
1158 normalize_v3(imat[1]);
1161 copy_v3_v3(vec, ob->obmat[3]);
1163 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1164 /* for AA effects */
1165 curcol[0] = ob_wire_col[0];
1166 curcol[1] = ob_wire_col[1];
1167 curcol[2] = ob_wire_col[2];
1169 glColor4ubv(curcol);
1172 if (lampsize > 0.0f) {
1174 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1175 if (ob->id.us > 1) {
1176 if (is_obact || (ob->flag & SELECT)) {
1177 glColor4ub(0x88, 0xFF, 0xFF, 155);
1180 glColor4ub(0x77, 0xCC, 0xCC, 155);
1187 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1188 glDisable(GL_BLEND);
1189 drawcircball(GL_POLYGON, vec, lampsize, imat);
1192 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1194 glColor4ubv(curcol);
1198 circrad = 3.0f * lampsize;
1201 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1203 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1204 if (la->type != LA_HEMI) {
1205 if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1206 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
1215 /* draw the pretty sun rays */
1216 if (la->type == LA_SUN) {
1217 float v1[3], v2[3], mat[3][3];
1220 /* setup a 45 degree rotation matrix */
1221 axis_angle_normalized_to_mat3(mat, imat[2], (float)M_PI / 4.0f);
1224 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1225 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1228 glTranslatef(vec[0], vec[1], vec[2]);
1233 for (axis = 0; axis < 8; axis++) {
1241 glTranslatef(-vec[0], -vec[1], -vec[2]);
1245 if (la->type == LA_LOCAL) {
1246 if (la->mode & LA_SPHERE) {
1247 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1251 glPopMatrix(); /* back in object space */
1255 /* skip drawing extra info */
1257 else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
1259 copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f);
1260 copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]);
1261 mul_mat3_m4_v3(ob->obmat, vvec);
1264 y = cosf(la->spotsize * 0.5f);
1265 z = x * sqrtf(1.0f - y * y);
1267 spotvolume(lvec, vvec, y);
1271 /* draw the angled sides of the cone */
1272 glBegin(GL_LINE_STRIP);
1280 /* draw the circle/square at the end of the cone */
1281 glTranslatef(0.0, 0.0, x);
1282 if (la->mode & LA_SQUARE) {
1284 float z_abs = fabsf(z);
1286 tvec[0] = tvec[1] = z_abs;
1289 glBegin(GL_LINE_LOOP);
1291 tvec[1] = -z_abs; /* neg */
1293 tvec[0] = -z_abs; /* neg */
1295 tvec[1] = z_abs; /* pos */
1300 circ(0.0, 0.0, fabsf(z));
1303 /* draw the circle/square representing spotbl */
1304 if (la->type == LA_SPOT) {
1305 float spotblcirc = fabsf(z) * (1.0f - powf(la->spotblend, 2));
1306 /* hide line if it is zero size or overlaps with outer border,
1307 * previously it adjusted to always to show it but that seems
1308 * confusing because it doesn't show the actual blend size */
1309 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1310 circ(0.0, 0.0, spotblcirc);
1314 draw_transp_spot_volume(la, x, z);
1316 /* draw clip start, useful for wide cones where its not obvious where the start is */
1317 glTranslatef(0.0, 0.0, -x); /* reverse translation above */
1318 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
1321 float clipsta_fac = la->clipsta / -x;
1323 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1324 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1326 glBegin(GL_LINE_STRIP);
1327 glVertex3fv(lvec_clip);
1328 glVertex3fv(vvec_clip);
1331 /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
1333 glBegin(GL_LINE_STRIP);
1334 glVertex3f(0.0, 0.0, -circrad);
1335 glVertex3f(0.0, 0.0, -la->dist);
1339 else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1341 /* draw the line from the circle along the dist */
1342 glBegin(GL_LINE_STRIP);
1349 if (la->type == LA_HEMI) {
1350 /* draw the hemisphere curves */
1351 short axis, steps, dir;
1352 float outdist, zdist, mul;
1354 outdist = 0.14; mul = 1.4; dir = 1;
1357 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1358 for (axis = 0; axis < 4; axis++) {
1359 float v[3] = {0.0, 0.0, 0.0};
1362 glBegin(GL_LINE_STRIP);
1364 for (steps = 0; steps < 6; steps++) {
1365 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1366 /* make the arcs start at the edge of the energy circle */
1367 if (steps == 0) v[0] = dir * circrad;
1368 else v[0] = v[0] + dir * (steps * outdist);
1370 else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1371 /* make the arcs start at the edge of the energy circle */
1372 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1375 v[2] = v[2] - steps * zdist;
1379 zdist = zdist * mul;
1383 /* flip the direction */
1388 else if (la->type == LA_AREA) {
1390 if (la->area_shape == LA_AREA_SQUARE)
1391 fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
1392 else if (la->area_shape == LA_AREA_RECT)
1393 fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
1395 glBegin(GL_LINE_STRIP);
1396 glVertex3f(0.0, 0.0, -circrad);
1397 glVertex3f(0.0, 0.0, -la->dist);
1401 /* and back to viewspace */
1403 glLoadMatrixf(rv3d->viewmat);
1404 copy_v3_v3(vec, ob->obmat[3]);
1408 if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) {
1409 drawshadbuflimits(la, ob->obmat);
1412 UI_GetThemeColor4ubv(TH_LAMP, col);
1417 if (vec[2] > 0) vec[2] -= circrad;
1418 else vec[2] += circrad;
1420 glBegin(GL_LINE_STRIP);
1432 glDisable(GL_BLEND);
1434 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1435 /* restore for drawing extra stuff */
1436 glColor3ubv(ob_wire_col);
1438 /* and finally back to org object space! */
1442 static void draw_limit_line(float sta, float end, const short dflag, unsigned int col)
1445 glVertex3f(0.0, 0.0, -sta);
1446 glVertex3f(0.0, 0.0, -end);
1449 if (!(dflag & DRAW_PICKING)) {
1453 glVertex3f(0.0, 0.0, -sta);
1454 glVertex3f(0.0, 0.0, -end);
1461 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1462 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1463 static void draw_focus_cross(float dist, float size)
1466 glVertex3f(-size, 0.f, -dist);
1467 glVertex3f(size, 0.f, -dist);
1468 glVertex3f(0.f, -size, -dist);
1469 glVertex3f(0.f, size, -dist);
1473 #ifdef VIEW3D_CAMERA_BORDER_HACK
1474 unsigned char view3d_camera_border_hack_col[3];
1475 bool view3d_camera_border_hack_test = false;
1478 /* ****************** draw clip data *************** */
1480 static void draw_bundle_sphere(void)
1482 static GLuint displist = 0;
1484 if (displist == 0) {
1485 GLUquadricObj *qobj;
1487 displist = glGenLists(1);
1488 glNewList(displist, GL_COMPILE);
1490 qobj = gluNewQuadric();
1491 gluQuadricDrawStyle(qobj, GLU_FILL);
1492 glShadeModel(GL_SMOOTH);
1493 gluSphere(qobj, 0.05, 8, 8);
1494 glShadeModel(GL_FLAT);
1495 gluDeleteQuadric(qobj);
1500 glCallList(displist);
1503 static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
1504 MovieClip *clip, MovieTrackingObject *tracking_object,
1505 const short dflag, const unsigned char ob_wire_col[4],
1506 int *global_track_index, bool draw_selected)
1508 MovieTracking *tracking = &clip->tracking;
1509 MovieTrackingTrack *track;
1510 float mat[4][4], imat[4][4];
1511 unsigned char col_unsel[4], col_sel[4];
1512 int tracknr = *global_track_index;
1513 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
1514 float camera_size[3];
1516 UI_GetThemeColor4ubv(TH_TEXT, col_unsel);
1517 UI_GetThemeColor4ubv(TH_SELECT, col_sel);
1519 BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
1521 /* we're compensating camera size for bundles size,
1522 * to make it so bundles are always displayed with the same size
1524 copy_v3_v3(camera_size, base->object->size);
1525 if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
1526 mul_v3_fl(camera_size, tracking_object->scale);
1530 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1531 /* current ogl matrix is translated in camera space, bundles should
1532 * be rendered in world space, so camera matrix should be "removed"
1533 * from current ogl matrix */
1534 invert_m4_m4(imat, base->object->obmat);
1536 glMultMatrixf(imat);
1541 int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra);
1543 BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat);
1545 invert_m4_m4(imat, obmat);
1546 glMultMatrixf(imat);
1549 for (track = tracksbase->first; track; track = track->next) {
1550 bool selected = TRACK_SELECTED(track);
1552 if (draw_selected && !selected)
1555 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1558 if (dflag & DRAW_PICKING)
1559 glLoadName(base->selcol + (tracknr << 16));
1562 glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
1563 glScalef(v3d->bundle_size / 0.05f / camera_size[0],
1564 v3d->bundle_size / 0.05f / camera_size[1],
1565 v3d->bundle_size / 0.05f / camera_size[2]);
1567 if (v3d->drawtype == OB_WIRE) {
1568 glDisable(GL_LIGHTING);
1570 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1571 if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
1572 glColor3ubv(ob_wire_col);
1575 glColor3fv(track->color);
1579 drawaxes(0.05f, v3d->bundle_drawtype);
1581 glEnable(GL_LIGHTING);
1583 else if (v3d->drawtype > OB_WIRE) {
1584 if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1585 /* selection outline */
1587 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1588 glColor3ubv(ob_wire_col);
1592 glDisable(GL_LIGHTING);
1593 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1595 draw_bundle_sphere();
1597 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1598 glEnable(GL_LIGHTING);
1602 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1603 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1604 else UI_ThemeColor(TH_BUNDLE_SOLID);
1607 draw_bundle_sphere();
1610 glDisable(GL_LIGHTING);
1612 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1614 glColor3ubv(ob_wire_col);
1617 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1618 else UI_ThemeColor(TH_WIRE);
1622 drawaxes(0.05f, v3d->bundle_drawtype);
1624 glEnable(GL_LIGHTING);
1630 if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1633 mul_v3_m4v3(pos, mat, track->bundle_pos);
1634 view3d_cached_text_draw_add(pos,
1635 track->name, strlen(track->name),
1636 10, V3D_CACHE_TEXT_GLOBALSPACE,
1637 selected ? col_sel : col_unsel);
1643 if ((dflag & DRAW_PICKING) == 0) {
1644 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1645 MovieTrackingReconstruction *reconstruction;
1646 reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
1648 if (reconstruction->camnr) {
1649 MovieReconstructedCamera *camera = reconstruction->cameras;
1652 glDisable(GL_LIGHTING);
1653 UI_ThemeColor(TH_CAMERA_PATH);
1656 glBegin(GL_LINE_STRIP);
1657 for (a = 0; a < reconstruction->camnr; a++, camera++) {
1658 glVertex3fv(camera->mat[3]);
1663 glEnable(GL_LIGHTING);
1670 *global_track_index = tracknr;
1673 static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip,
1674 const short dflag, const unsigned char ob_wire_col[4],
1675 const bool draw_selected)
1677 MovieTracking *tracking = &clip->tracking;
1678 MovieTrackingObject *tracking_object;
1679 int global_track_index = 1;
1681 if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1684 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1687 glEnable(GL_LIGHTING);
1688 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1689 glEnable(GL_COLOR_MATERIAL);
1690 glShadeModel(GL_SMOOTH);
1692 tracking_object = tracking->objects.first;
1693 while (tracking_object) {
1694 draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
1695 dflag, ob_wire_col, &global_track_index, draw_selected);
1697 tracking_object = tracking_object->next;
1701 glShadeModel(GL_FLAT);
1702 glDisable(GL_COLOR_MATERIAL);
1703 glDisable(GL_LIGHTING);
1705 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1706 glColor3ubv(ob_wire_col);
1709 if (dflag & DRAW_PICKING)
1710 glLoadName(base->selcol);
1713 /* flag similar to draw_object() */
1714 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
1715 const short dflag, const unsigned char ob_wire_col[4])
1717 /* a standing up pyramid with (0,0,0) as top */
1719 Object *ob = base->object;
1721 float vec[4][3], asp[2], shift[2], scale[3];
1724 const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
1725 MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
1727 /* draw data for movie clip set as active for scene */
1729 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, false);
1730 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, true);
1733 #ifdef VIEW3D_CAMERA_BORDER_HACK
1734 if (is_view && !(G.f & G_PICKSEL)) {
1735 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1736 view3d_camera_border_hack_col[0] = ob_wire_col[0];
1737 view3d_camera_border_hack_col[1] = ob_wire_col[1];
1738 view3d_camera_border_hack_col[2] = ob_wire_col[2];
1742 glGetFloatv(GL_CURRENT_COLOR, col);
1743 rgb_float_to_uchar(view3d_camera_border_hack_col, col);
1745 view3d_camera_border_hack_test = true;
1752 scale[0] = 1.0f / len_v3(ob->obmat[0]);
1753 scale[1] = 1.0f / len_v3(ob->obmat[1]);
1754 scale[2] = 1.0f / len_v3(ob->obmat[2]);
1756 BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
1757 asp, shift, &drawsize, vec);
1759 glDisable(GL_LIGHTING);
1760 glDisable(GL_CULL_FACE);
1763 glBegin(GL_LINE_LOOP);
1764 glVertex3fv(vec[0]);
1765 glVertex3fv(vec[1]);
1766 glVertex3fv(vec[2]);
1767 glVertex3fv(vec[3]);
1775 /* center point to camera frame */
1776 glBegin(GL_LINE_STRIP);
1777 glVertex3fv(vec[1]);
1779 glVertex3fv(vec[0]);
1780 glVertex3fv(vec[3]);
1782 glVertex3fv(vec[2]);
1787 tvec[2] = vec[1][2]; /* copy the depth */
1790 /* draw an outline arrow for inactive cameras and filled
1791 * for active cameras. We actually draw both outline+filled
1792 * for active cameras so the wire can be seen side-on */
1793 for (i = 0; i < 2; i++) {
1794 if (i == 0) glBegin(GL_LINE_LOOP);
1795 else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1798 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
1799 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
1800 glVertex3fv(tvec); /* left */
1802 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
1803 glVertex3fv(tvec); /* right */
1806 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
1807 glVertex3fv(tvec); /* top */
1812 if ((dflag & DRAW_SCENESET) == 0) {
1813 if (cam->flag & (CAM_SHOWLIMITS | CAM_SHOWMIST)) {
1816 /* draw in normalized object matrix space */
1817 copy_m4_m4(nobmat, ob->obmat);
1818 normalize_m4(nobmat);
1821 glLoadMatrixf(rv3d->viewmat);
1822 glMultMatrixf(nobmat);
1824 if (cam->flag & CAM_SHOWLIMITS) {
1825 draw_limit_line(cam->clipsta, cam->clipend, dflag, 0x77FFFF);
1826 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
1827 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
1830 if (cam->flag & CAM_SHOWMIST) {
1831 World *world = scene->world;
1833 draw_limit_line(world->miststa, world->miststa + world->mistdist, dflag, 0xFFFFFF);
1841 /* flag similar to draw_object() */
1842 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
1843 Object *UNUSED(ob), int UNUSED(flag))
1845 //Speaker *spk = ob->data;
1852 for (j = 0; j < 3; j++) {
1853 vec[2] = 0.25f * j - 0.125f;
1855 glBegin(GL_LINE_LOOP);
1856 for (i = 0; i < 16; i++) {
1857 vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1858 vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1864 for (j = 0; j < 4; j++) {
1865 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1866 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1867 glBegin(GL_LINE_STRIP);
1868 for (i = 0; i < 3; i++) {
1874 vec[2] = 0.25f * i - 0.125f;
1880 glDisable(GL_BLEND);
1883 static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel)
1885 BPoint *bp = lt->def;
1886 float *co = dl ? dl->verts : NULL;
1889 const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
1890 UI_ThemeColor(color);
1892 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1893 bglBegin(GL_POINTS);
1895 for (w = 0; w < lt->pntsw; w++) {
1896 int wxt = (w == 0 || w == lt->pntsw - 1);
1897 for (v = 0; v < lt->pntsv; v++) {
1898 int vxt = (v == 0 || v == lt->pntsv - 1);
1899 for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
1900 int uxt = (u == 0 || u == lt->pntsu - 1);
1901 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1902 if (bp->hide == 0) {
1903 /* check for active BPoint and ensure selected */
1904 if ((bp == actbp) && (bp->f1 & SELECT)) {
1905 UI_ThemeColor(TH_ACTIVE_VERT);
1906 bglVertex3fv(dl ? co : bp->vec);
1907 UI_ThemeColor(color);
1909 else if ((bp->f1 & SELECT) == sel) {
1910 bglVertex3fv(dl ? co : bp->vec);
1922 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
1924 int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
1928 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
1930 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
1936 glVertex3fv(&dl->verts[index * 3]);
1939 glVertex3fv(lt->def[index].vec);
1943 #ifdef SEQUENCER_DAG_WORKAROUND
1944 static void ensure_curve_cache(Scene *scene, Object *object)
1946 if (object->curve_cache == NULL) {
1947 switch (object->type) {
1951 BKE_displist_make_curveTypes(scene, object, false);
1954 BKE_displist_make_mball(G.main->eval_ctx, scene, object);
1957 BKE_lattice_modifiers_calc(scene, object);
1964 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1965 static void drawlattice(View3D *v3d, Object *ob)
1967 Lattice *lt = ob->data;
1970 int actdef_wcol = 0;
1971 const bool is_edit = (lt->editlatt != NULL);
1973 dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS);
1976 lt = lt->editlatt->latt;
1978 UI_ThemeColor(TH_WIRE_EDIT);
1980 if (ob->defbase.first && lt->dvert) {
1981 actdef_wcol = ob->actdef;
1982 glShadeModel(GL_SMOOTH);
1987 for (w = 0; w < lt->pntsw; w++) {
1988 int wxt = (w == 0 || w == lt->pntsw - 1);
1989 for (v = 0; v < lt->pntsv; v++) {
1990 int vxt = (v == 0 || v == lt->pntsv - 1);
1991 for (u = 0; u < lt->pntsu; u++) {
1992 int uxt = (u == 0 || u == lt->pntsu - 1);
1994 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
1995 drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol);
1996 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
1998 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1999 drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol);
2000 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
2002 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2003 drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol);
2004 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
2011 /* restoration for weight colors */
2013 glShadeModel(GL_FLAT);
2016 BPoint *actbp = BKE_lattice_active_point_get(lt);
2018 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2020 lattice_draw_verts(lt, dl, actbp, 0);
2021 lattice_draw_verts(lt, dl, actbp, 1);
2023 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2027 /* ***************** ******************** */
2031 typedef struct drawDMVertSel_userData {
2034 unsigned char *col[3]; /* (base, sel, act) */
2036 } drawDMVertSel_userData;
2038 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
2039 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2041 drawDMVertSel_userData *data = userData;
2042 MVert *mv = &data->mvert[index];
2044 if (!(mv->flag & ME_HIDE)) {
2045 const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
2046 if (sel != data->sel_prev) {
2047 glColor3ubv(data->col[sel]);
2048 data->sel_prev = sel;
2055 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
2057 drawDMVertSel_userData data;
2059 /* TODO define selected color */
2060 unsigned char base_col[3] = {0x0, 0x0, 0x0};
2061 unsigned char sel_col[3] = {0xd8, 0xb8, 0x0};
2062 unsigned char act_col[3] = {0xff, 0xff, 0xff};
2064 data.mvert = me->mvert;
2065 data.active = BKE_mesh_mselect_active_get(me, ME_VSEL);
2066 data.sel_prev = 0xff;
2068 data.col[0] = base_col;
2069 data.col[1] = sel_col;
2070 data.col[2] = act_col;
2073 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
2077 /* ************** DRAW MESH ****************** */
2079 /* First section is all the "simple" draw routines,
2080 * ones that just pass some sort of primitive to GL,
2081 * with perhaps various options to control lighting,
2084 * These routines should not have user interface related
2088 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
2092 copy_m3_m4(obmat, ob->obmat);
2094 data->uniform_scale = is_uniform_scaled_m3(obmat);
2096 if (!data->uniform_scale) {
2097 /* inverted matrix */
2098 invert_m3_m3(data->imat, obmat);
2100 /* transposed inverted matrix */
2101 copy_m3_m3(data->tmat, data->imat);
2102 transpose_m3(data->tmat);
2106 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2108 drawDMNormal_userData *data = userData;
2109 BMFace *efa = BM_face_at_index(data->bm, index);
2112 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2113 if (!data->uniform_scale) {
2114 mul_v3_m3v3(n, data->tmat, no);
2116 mul_m3_v3(data->imat, n);
2123 glVertex3f(cent[0] + n[0] * data->normalsize,
2124 cent[1] + n[1] * data->normalsize,
2125 cent[2] + n[2] * data->normalsize);
2129 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2131 drawDMNormal_userData data;
2134 data.normalsize = scene->toolsettings->normalsize;
2136 calcDrawDMNormalScale(ob, &data);
2139 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2143 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2145 BMFace *efa = BM_face_at_index(((void **)userData)[0], index);
2146 const char sel = *(((char **)userData)[1]);
2148 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
2149 (BM_elem_flag_test(efa, BM_ELEM_SELECT) == sel))
2154 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, char sel)
2156 void *ptrs[2] = {em->bm, &sel};
2158 bglBegin(GL_POINTS);
2159 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs, DM_FOREACH_NOP);
2163 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])
2165 drawDMNormal_userData *data = userData;
2166 BMVert *eve = BM_vert_at_index(data->bm, index);
2168 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2172 copy_v3_v3(no, no_f);
2175 normal_short_to_float_v3(no, no_s);
2178 if (!data->uniform_scale) {
2179 mul_v3_m3v3(n, data->tmat, no);
2181 mul_m3_v3(data->imat, n);
2188 glVertex3f(co[0] + n[0] * data->normalsize,
2189 co[1] + n[1] * data->normalsize,
2190 co[2] + n[2] * data->normalsize);
2194 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2196 drawDMNormal_userData data;
2199 data.normalsize = scene->toolsettings->normalsize;
2201 calcDrawDMNormalScale(ob, &data);
2204 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2208 /* Draw verts with color set based on selection */
2209 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2210 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2212 drawDMVerts_userData *data = userData;
2213 BMVert *eve = BM_vert_at_index(data->bm, index);
2215 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2216 /* skin nodes: draw a red circle around the root
2218 if (data->cd_vskin_offset != -1) {
2219 const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
2220 if (vs->flag & MVERT_SKIN_ROOT) {
2221 float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2224 glColor4ubv(data->th_skin_root);
2225 drawcircball(GL_LINES, co, radius, data->imat);
2227 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2228 bglBegin(GL_POINTS);
2232 /* draw active larger - need to stop/start point drawing for this :/ */
2233 if (eve == data->eve_act) {
2234 glColor4ubv(data->th_editmesh_active);
2238 glPointSize(data->th_vertex_size);
2239 bglBegin(GL_POINTS);
2243 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2244 glPointSize(data->th_vertex_size);
2245 bglBegin(GL_POINTS);
2253 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
2256 drawDMVerts_userData data;
2258 data.eve_act = eve_act;
2261 /* Cache theme values */
2262 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2263 UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2264 UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2265 UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2266 data.th_vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2268 /* For skin root drawing */
2269 data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
2270 /* view-aligned matrix */
2271 mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2272 invert_m4(data.imat);
2274 bglBegin(GL_POINTS);
2275 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
2279 /* Draw edges with color set based on selection */
2280 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2283 //unsigned char **cols = userData, *col;
2284 drawDMEdgesSel_userData *data = userData;
2287 eed = BM_edge_at_index(data->bm, index);
2289 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2290 if (eed == data->eed_act) {
2291 glColor4ubv(data->actCol);
2294 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2298 col = data->baseCol;
2300 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2302 return DM_DRAW_OPTION_SKIP;
2306 return DM_DRAW_OPTION_NORMAL;
2309 return DM_DRAW_OPTION_SKIP;
2312 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2313 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2315 drawDMEdgesSel_userData data;
2317 data.baseCol = baseCol;
2318 data.selCol = selCol;
2319 data.actCol = actCol;
2321 data.eed_act = eed_act;
2322 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2326 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2328 if (BM_elem_flag_test(BM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2329 return DM_DRAW_OPTION_SKIP;
2331 return DM_DRAW_OPTION_NORMAL;
2334 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2336 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em->bm);
2339 /* Draw edges with color interpolated based on selection */
2340 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2342 if (BM_elem_flag_test(BM_edge_at_index(((void **)userData)[0], index), BM_ELEM_HIDDEN))
2343 return DM_DRAW_OPTION_SKIP;
2345 return DM_DRAW_OPTION_NORMAL;
2347 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2349 BMEdge *eed = BM_edge_at_index(((void **)userData)[0], index);
2350 unsigned char **cols = userData;
2351 unsigned char *col0 = cols[(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1];
2352 unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1];
2354 glColor4ub(col0[0] + (col1[0] - col0[0]) * t,
2355 col0[1] + (col1[1] - col0[1]) * t,
2356 col0[2] + (col1[2] - col0[2]) * t,
2357 col0[3] + (col1[3] - col0[3]) * t);
2360 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2362 void *cols[3] = {em->bm, baseCol, selCol};
2364 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2367 /* Draw only seam edges */
2368 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2370 BMEdge *eed = BM_edge_at_index(userData, index);
2372 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
2373 return DM_DRAW_OPTION_NORMAL;
2375 return DM_DRAW_OPTION_SKIP;
2378 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2380 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em->bm);
2383 /* Draw only sharp edges */
2384 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2386 BMEdge *eed = BM_edge_at_index(userData, index);
2388 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
2389 return DM_DRAW_OPTION_NORMAL;
2391 return DM_DRAW_OPTION_SKIP;
2394 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2396 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em->bm);
2399 #ifdef WITH_FREESTYLE
2401 static int draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed)
2403 FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
2406 return (fed->flag & FREESTYLE_EDGE_MARK) != 0;
2409 /* Draw only Freestyle feature edges */
2410 static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
2412 BMEdge *eed = BM_edge_at_index(userData, index);
2414 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && draw_dm_test_freestyle_edge_mark(userData, eed))
2415 return DM_DRAW_OPTION_NORMAL;
2417 return DM_DRAW_OPTION_SKIP;
2420 static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
2422 dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em->bm);
2425 static int draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa)
2427 FreestyleFace *ffa = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
2430 return (ffa->flag & FREESTYLE_FACE_MARK) != 0;
2435 /* Draw loop normals. */
2436 static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2438 /* XXX Would it be worth adding a dm->foreachMappedLoop func just for this? I doubt it... */
2440 /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
2441 * return loop data from bmesh itself. */
2442 float (*lnors)[3] = DM_get_loop_data_layer(dm, CD_NORMAL);
2445 drawDMNormal_userData data;
2446 const MLoop *mloops = dm->getLoopArray(dm);
2447 const MVert *mverts = dm->getVertArray(dm);
2448 int i, totloops = dm->getNumLoops(dm);
2451 data.normalsize = scene->toolsettings->normalsize;
2453 calcDrawDMNormalScale(ob, &data);
2456 for (i = 0; i < totloops; i++, mloops++, lnors++) {
2458 const float *co = mverts[mloops->v].co;
2460 if (!data.uniform_scale) {
2461 mul_v3_m3v3(no, data.tmat, (float *)lnors);
2463 mul_m3_v3(data.imat, no);
2466 copy_v3_v3(no, (float *)lnors);
2468 mul_v3_fl(no, data.normalsize);
2477 /* Draw faces with color set based on selection
2478 * return 2 for the active face so it renders with stipple enabled */
2479 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
2481 drawDMFacesSel_userData *data = userData;
2482 BMFace *efa = BM_face_at_index(data->bm, index);
2485 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2486 if (efa == data->efa_act) {
2487 glColor4ubv(data->cols[2]);
2488 return DM_DRAW_OPTION_STIPPLE;
2491 #ifdef WITH_FREESTYLE
2492 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
2494 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2497 return DM_DRAW_OPTION_SKIP;
2499 return DM_DRAW_OPTION_NORMAL;
2502 return DM_DRAW_OPTION_SKIP;
2505 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2508 drawDMFacesSel_userData *data = userData;
2513 unsigned char *col, *next_col;
2515 if (!data->orig_index_mf_to_mpoly)
2518 i = DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, index);
2519 efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
2520 i = DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, next_index);
2521 next_efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
2523 if (ELEM(NULL, efa, next_efa))
2526 if (efa == next_efa)
2529 if (efa == data->efa_act || next_efa == data->efa_act)
2532 #ifdef WITH_FREESTYLE
2533 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
2534 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
2536 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2537 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
2540 if (col[3] == 0 || next_col[3] == 0)
2543 return col == next_col;
2546 /* also draws the active face */
2547 #ifdef WITH_FREESTYLE
2548 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2549 unsigned char *selCol, unsigned char *actCol, unsigned char *markCol, BMFace *efa_act)
2551 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2552 unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
2555 drawDMFacesSel_userData data;
2557 data.cols[0] = baseCol;
2559 data.cols[1] = selCol;
2560 data.cols[2] = actCol;
2561 #ifdef WITH_FREESTYLE
2562 data.cols[3] = markCol;
2564 data.efa_act = efa_act;
2566 data.orig_index_mf_to_mpoly = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
2567 data.orig_index_mp_to_orig = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
2568 if ((data.orig_index_mf_to_mpoly && data.orig_index_mp_to_orig) == false) {
2569 data.orig_index_mf_to_mpoly = data.orig_index_mp_to_orig = NULL;
2572 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
2575 static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
2577 drawDMLayer_userData *data = userData;
2578 BMesh *bm = data->bm;
2579 BMEdge *eed = BM_edge_at_index(bm, index);
2581 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2582 const float crease = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
2583 if (crease != 0.0f) {
2584 UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_CREASE, crease);
2585 return DM_DRAW_OPTION_NORMAL;
2588 return DM_DRAW_OPTION_SKIP;
2590 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
2592 drawDMLayer_userData data;
2595 data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
2597 if (data.cd_layer_offset != -1) {
2599 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
2604 static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
2606 drawDMLayer_userData *data = userData;
2607 BMesh *bm = data->bm;
2608 BMEdge *eed = BM_edge_at_index(bm, index);
2610 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2611 const float bweight = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
2612 if (bweight != 0.0f) {
2613 UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, bweight);
2614 return DM_DRAW_OPTION_NORMAL;
2617 return DM_DRAW_OPTION_SKIP;
2619 static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
2620 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2622 drawDMLayer_userData *data = userData;
2623 BMesh *bm = data->bm;
2624 BMVert *eve = BM_vert_at_index(bm, index);
2626 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2627 const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
2628 if (bweight != 0.0f) {
2629 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, bweight);
2634 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2636 ToolSettings *ts = scene->toolsettings;
2638 if (ts->selectmode & SCE_SELECT_VERTEX) {
2639 drawDMLayer_userData data;
2642 data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT);
2644 if (data.cd_layer_offset != -1) {
2645 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2646 bglBegin(GL_POINTS);
2647 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
2652 drawDMLayer_userData data;
2655 data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
2657 if (data.cd_layer_offset != -1) {
2659 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
2665 static int draw_dm_override_material_color(int UNUSED(nr), void *UNUSED(attribs))
2670 /* Second section of routines: Combine first sets to form fancy
2671 * drawing routines (for example rendering twice to get overlays).
2673 * Also includes routines that are basic drawing but are too
2674 * specialized to be split out (like drawing creases or measurements).
2677 /* EditMesh drawing routines*/
2679 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
2680 BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act,
2683 ToolSettings *ts = scene->toolsettings;
2686 if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */
2688 for (sel = 0; sel < 2; sel++) {
2689 unsigned char col[4], fcol[4];
2692 UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
2693 UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE_EDIT, fcol);
2695 for (pass = 0; pass < 2; pass++) {
2696 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2697 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2700 if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
2701 glDisable(GL_DEPTH_TEST);
2709 size = (size > 2.1f ? size / 2.0f : size);
2710 fsize = (fsize > 2.1f ? fsize / 2.0f : fsize);
2711 col[3] = fcol[3] = 100;
2714 col[3] = fcol[3] = 255;
2717 if (ts->selectmode & SCE_SELECT_VERTEX) {
2720 draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
2723 if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2726 draw_dm_face_centers(em, cageDM, sel);
2730 glDisable(GL_BLEND);
2731 glEnable(GL_DEPTH_TEST);
2736 if (v3d->zbuf) glDepthMask(1);
2740 static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
2741 Mesh *me, DerivedMesh *cageDM, short sel_only,
2744 ToolSettings *ts = scene->toolsettings;
2746 unsigned char wireCol[4], selCol[4], actCol[4];
2748 /* since this function does transparent... */
2749 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2750 UI_GetThemeColor4ubv(TH_WIRE_EDIT, wireCol);
2751 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2753 /* when sel only is used, don't render wire, only selected, this is used for
2754 * textured draw mode when the 'edges' option is disabled */
2758 for (pass = 0; pass < 2; pass++) {
2759 /* show wires in transparent when no zbuf clipping for select */
2761 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) {
2763 glDisable(GL_DEPTH_TEST);
2765 if (!sel_only) wireCol[3] = 85;
2773 if (!sel_only) wireCol[3] = 255;
2776 if (ts->selectmode == SCE_SELECT_FACE) {
2777 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2779 else if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) {
2780 if (cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2781 glShadeModel(GL_SMOOTH);
2782 draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
2783 glShadeModel(GL_FLAT);
2786 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2791 glColor4ubv(wireCol);
2792 draw_dm_edges(em, cageDM);
2797 glDisable(GL_BLEND);
2798 glEnable(GL_DEPTH_TEST);
2803 static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit)
2805 /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square, etc.).
2808 const short txt_flag = V3D_CACHE_TEXT_LOCALCLIP | (unit->system ? 0 : V3D_CACHE_TEXT_ASCII);
2809 Mesh *me = ob->data;
2810 float v1[3], v2[3], v3[3], vmid[3], fvec[3];
2811 char numstr[32]; /* Stores the measurement display text here */
2813 const char *conv_float; /* Use a float conversion matching the grid size */
2814 unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */
2815 float area; /* area of the face */
2816 float grid = unit->system ? unit->scale_length : v3d->grid;
2817 const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
2818 const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0;
2819 const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0;
2820 /* when 2 edge-info options are enabled, space apart */
2821 const bool do_edge_textpair = (me->drawflag & ME_DRAWEXTRA_EDGELEN) && (me->drawflag & ME_DRAWEXTRA_EDGEANG);
2822 const float edge_texpair_sep = 0.4f;
2823 float clip_planes[4][4];
2824 /* allow for displaying shape keys and deform mods */
2825 DerivedMesh *dm = EDBM_mesh_deform_dm_get(em);
2829 /* make the precision of the display value proportionate to the gridsize */
2831 if (grid <= 0.01f) conv_float = "%.6g";
2832 else if (grid <= 0.1f) conv_float = "%.5g";
2833 else if (grid <= 1.0f) conv_float = "%.4g";
2834 else if (grid <= 10.0f) conv_float = "%.3g";
2835 else conv_float = "%.2g";
2837 if (me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_EDGEANG)) {
2839 bglMats mats = {{0}};
2840 const rcti rect = {0, ar->winx, 0, ar->winy};
2842 view3d_get_transformation(ar, ar->regiondata, em->ob, &mats);
2843 ED_view3d_clipping_calc(&bb, clip_planes, &mats, &rect);
2846 if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2849 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2852 BM_mesh_elem_index_ensure(em->bm, BM_VERT);
2855 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2856 /* draw selected edges, or edges next to selected verts while draging */
2857 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
2858 (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
2859 BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
2861 float v1_clip[3], v2_clip[3];
2864 dm->getVertCo(dm, BM_elem_index_get(eed->v1), v1);
2865 dm->getVertCo(dm, BM_elem_index_get(eed->v2), v2);
2868 copy_v3_v3(v1, eed->v1->co);
2869 copy_v3_v3(v2, eed->v2->co);
2872 copy_v3_v3(v1_clip, v1);
2873 copy_v3_v3(v2_clip, v2);
2875 if (clip_segment_v3_plane_n(v1_clip, v2_clip, clip_planes, 4)) {
2877 if (do_edge_textpair) {
2878 interp_v3_v3v3(vmid, v1, v2, edge_texpair_sep);
2881 mid_v3_v3v3(vmid, v1_clip, v2_clip);
2885 mul_mat3_m4_v3(ob->obmat, v1);
2886 mul_mat3_m4_v3(ob->obmat, v2);
2890 numstr_len = bUnit_AsString(numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
2891 unit->system, B_UNIT_LENGTH, do_split, false);
2894 numstr_len = BLI_snprintf(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
2897 view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
2903 if (me->drawflag & ME_DRAWEXTRA_EDGEANG) {
2904 const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
2907 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
2910 BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
2913 // invert_m4_m4(ob->imat, ob->obmat); // this is already called
2915 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2917 if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
2918 /* draw selected edges, or edges next to selected verts while draging */
2919 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
2920 (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
2921 BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
2922 /* special case, this is useful to show when vertes connected to this edge via a
2923 * face are being transformed */
2924 BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
2925 BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
2926 BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
2927 BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)
2930 float v1_clip[3], v2_clip[3];
2933 dm->getVertCo(dm, BM_elem_index_get(eed->v1), v1);
2934 dm->getVertCo(dm, BM_elem_index_get(eed->v2), v2);
2937 copy_v3_v3(v1, eed->v1->co);
2938 copy_v3_v3(v2, eed->v2->co);
2941 copy_v3_v3(v1_clip, v1);
2942 copy_v3_v3(v2_clip, v2);
2944 if (clip_segment_v3_plane_n(v1_clip, v2_clip, clip_planes, 4)) {
2945 float no_a[3], no_b[3];
2948 if (do_edge_textpair) {
2949 interp_v3_v3v3(vmid, v2_clip, v1_clip, edge_texpair_sep);
2952 mid_v3_v3v3(vmid, v1_clip, v2_clip);
2956 dm->getPolyNo(dm, BM_elem_index_get(l_a->f), no_a);
2957 dm->getPolyNo(dm, BM_elem_index_get(l_b->f), no_b);
2960 copy_v3_v3(no_a, l_a->f->no);
2961 copy_v3_v3(no_b, l_b->f->no);
2965 mul_mat3_m4_v3(ob->imat, no_a);
2966 mul_mat3_m4_v3(ob->imat, no_b);
2971 angle = angle_normalized_v3v3(no_a, no_b);
2973 numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
2975 view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
2982 if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2983 /* would be nice to use BM_face_calc_area, but that is for 2d faces
2984 * so instead add up tessellation triangle areas */
2988 #define DRAW_EM_MEASURE_STATS_FACEAREA() \
2989 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \
2990 mul_v3_fl(vmid, 1.0f / (float)n); \
2991 if (unit->system) { \
2992 numstr_len = bUnit_AsString( \
2993 numstr, sizeof(numstr), \
2994 (double)(area * unit->scale_length * unit->scale_length), \
2995 3, unit->system, B_UNIT_AREA, do_split, false); \
2998 numstr_len = BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
3000 view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col); \
3003 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
3006 BM_mesh_elem_index_ensure(em->bm, BM_VERT);
3013 for (i = 0; i < em->tottri; i++) {
3014 BMLoop **l = em->looptris[i];
3015 if (f && l[0]->f != f) {
3016 DRAW_EM_MEASURE_STATS_FACEAREA();
3025 dm->getVertCo(dm, BM_elem_index_get(l[0]->v), v1);
3026 dm->getVertCo(dm, BM_elem_index_get(l[1]->v), v2);
3027 dm->getVertCo(dm, BM_elem_index_get(l[2]->v), v3);
3030 copy_v3_v3(v1, l[0]->v->co);
3031 copy_v3_v3(v2, l[1]->v->co);
3032 copy_v3_v3(v3, l[2]->v->co);
3035 add_v3_v3(vmid, v1);
3036 add_v3_v3(vmid, v2);
3037 add_v3_v3(vmid, v3);
3040 mul_mat3_m4_v3(ob->obmat, v1);
3041 mul_mat3_m4_v3(ob->obmat, v2);
3042 mul_mat3_m4_v3(ob->obmat, v3);
3044 area += area_tri_v3(v1, v2, v3);
3048 DRAW_EM_MEASURE_STATS_FACEAREA();
3050 #undef DRAW_EM_MEASURE_STATS_FACEAREA
3053 if (me->drawflag & ME_DRAWEXTRA_FACEANG) {
3055 const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
3057 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
3060 BM_mesh_elem_index_ensure(em->bm, BM_VERT);
3063 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3064 const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT);
3066 if (is_face_sel || do_moving) {
3069 bool is_first = true;
3071 BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
3072 if (is_face_sel || (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT))) {
3076 /* lazy init center calc */
3079 BMLoop *l_iter, *l_first;
3082 l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
3084 dm->getVertCo(dm, BM_elem_index_get(l_iter->v), tvec);
3085 add_v3_v3(vmid, tvec);
3086 } while ((l_iter = l_iter->next) != l_first);
3087 mul_v3_fl(vmid, 1.0f / (float)efa->len);
3090 BM_face_calc_center_bounds(efa, vmid);
3096 dm->getVertCo(dm, BM_elem_index_get(loop->prev->v), v1);
3097 dm->getVertCo(dm, BM_elem_index_get(loop->v), v2);
3098 dm->getVertCo(dm, BM_elem_index_get(loop->next->v), v3);