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"
50 #include "BLI_memarena.h"
52 #include "BKE_anim.h" /* for the where_on_path function */
53 #include "BKE_armature.h"
54 #include "BKE_camera.h"
55 #include "BKE_colortools.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"
90 #include "GPU_select.h"
93 #include "ED_particle.h"
94 #include "ED_screen.h"
95 #include "ED_sculpt.h"
98 #include "UI_resources.h"
99 #include "UI_interface_icons.h"
104 #include "view3d_intern.h" /* bad level include */
106 /* Workaround for sequencer scene render mode.
108 * Strips doesn't use DAG to update objects or so, which
109 * might lead to situations when object is drawing without
112 * Ideally we don't want to evaluate objects from drawing,
113 * but it'll require some major sequencer re-design. So
114 * for now just fallback to legacy behavior with calling
115 * display ist creating from draw().
117 #define SEQUENCER_DAG_WORKAROUND
119 typedef enum eWireDrawMode {
122 OBDRAW_WIRE_ON_DEPTH = 2
125 typedef struct drawDMVerts_userData {
131 /* cached theme values */
132 unsigned char th_editmesh_active[4];
133 unsigned char th_vertex_select[4];
134 unsigned char th_vertex[4];
135 unsigned char th_skin_root[4];
136 float th_vertex_size;
138 /* for skin node drawing */
141 } drawDMVerts_userData;
143 typedef struct drawDMEdgesSel_userData {
146 unsigned char *baseCol, *selCol, *actCol;
148 } drawDMEdgesSel_userData;
150 typedef struct drawDMEdgesSelInterp_userData {
153 unsigned char *baseCol, *selCol;
154 unsigned char *lastCol;
155 } drawDMEdgesSelInterp_userData;
157 typedef struct drawDMEdgesWeightInterp_userData {
164 float alert_color[3];
166 } drawDMEdgesWeightInterp_userData;
168 typedef struct drawDMFacesSel_userData {
169 #ifdef WITH_FREESTYLE
170 unsigned char *cols[4];
172 unsigned char *cols[3];
179 const int *orig_index_mp_to_orig;
180 } drawDMFacesSel_userData;
182 typedef struct drawDMNormal_userData {
188 } drawDMNormal_userData;
190 typedef struct drawMVertOffset_userData {
193 } drawMVertOffset_userData;
195 typedef struct drawDMLayer_userData {
198 } drawDMLayer_userData;
200 typedef struct drawBMOffset_userData {
203 } drawBMOffset_userData;
205 typedef struct drawBMSelect_userData {
208 } drawBMSelect_userData;
210 static void draw_bounding_volume(Object *ob, char type);
212 static void drawcube_size(float size);
213 static void drawcircle_size(float size);
214 static void draw_empty_sphere(float size);
215 static void draw_empty_cone(float size);
216 static void draw_box(float vec[8][3], bool solid);
218 static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
220 float col_wire[3], col_bg[3], col[3];
222 rgb_uchar_to_float(col_wire, ob_wire_col);
224 UI_GetThemeColor3fv(theme_id, col_bg);
225 interp_v3_v3v3(col, col_bg, col_wire, fac);
229 /* this condition has been made more complex since editmode can draw textures */
230 bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
232 /* texture and material draw modes */
233 if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
238 if ((v3d->drawtype == OB_SOLID) &&
239 (v3d->flag2 & V3D_SOLID_TEX) &&
240 (BKE_scene_use_new_shading_nodes(scene) == false))
245 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) {
252 static bool check_object_draw_editweight(Mesh *me, DerivedMesh *finalDM)
254 if (me->drawflag & ME_DRAWEIGHT) {
255 /* editmesh handles its own weight drawing */
256 if (finalDM->type != DM_TYPE_EDITBMESH) {
264 static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
266 if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
269 if (G.f & G_BACKBUFSEL)
272 if ((vd->flag & V3D_ZBUF_SELECT) == 0)
275 /* if its drawing textures with zbuf sel, then don't draw dots */
276 if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
279 if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
285 /* ************************ */
287 /* check for glsl drawing */
289 bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
291 if (!GPU_glsl_support())
295 if (!check_object_draw_texture(scene, v3d, dt))
297 if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
300 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
303 if (v3d->drawtype == OB_TEXTURE)
304 return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
305 else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
311 static bool check_alpha_pass(Base *base)
313 if (base->flag & OB_FROMDUPLI)
319 if (base->object->mode & OB_MODE_ALL_PAINT)
322 return (base->object->dtx & OB_DRAWTRANSP);
326 static const unsigned int colortab[] = {
327 0x0, 0x403000, 0xFFFF88
330 /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
331 /* 32 values of sin function (still same result!) */
332 #define CIRCLE_RESOL 32
334 static const float sinval[CIRCLE_RESOL] = {
369 /* 32 values of cos function (still same result!) */
370 static const float cosval[CIRCLE_RESOL] = {
405 static void draw_xyz_wire(const float c[3], float size, int axis)
407 float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
408 float dim = size * 0.1f;
409 float dx[3], dy[3], dz[3];
411 dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f;
412 dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f;
413 dz[0] = 0.0f; dz[1] = 0.0f; dz[2] = dim;
419 /* bottom left to top right */
420 sub_v3_v3v3(v1, c, dx);
422 add_v3_v3v3(v2, c, dx);
428 /* top left to bottom right */
441 /* bottom left to top right */
442 mul_v3_fl(dx, 0.75f);
443 sub_v3_v3v3(v1, c, dx);
445 add_v3_v3v3(v2, c, dx);
451 /* top left to center */
462 glBegin(GL_LINE_STRIP);
464 /* start at top left */
465 sub_v3_v3v3(v1, c, dx);
466 add_v3_v3v3(v1, c, dz);
490 void drawaxes(float size, char drawtype)
493 float v1[3] = {0.0, 0.0, 0.0};
494 float v2[3] = {0.0, 0.0, 0.0};
495 float v3[3] = {0.0, 0.0, 0.0};
500 for (axis = 0; axis < 3; axis++) {
508 /* reset v1 & v2 to zero */
509 v1[axis] = v2[axis] = 0.0f;
514 case OB_SINGLE_ARROW:
517 /* in positive z direction only */
524 glBegin(GL_TRIANGLES);
526 v2[0] = size * 0.035f; v2[1] = size * 0.035f;
527 v3[0] = size * -0.035f; v3[1] = size * 0.035f;
528 v2[2] = v3[2] = size * 0.75f;
530 for (axis = 0; axis < 4; axis++) {
553 drawcircle_size(size);
556 case OB_EMPTY_SPHERE:
557 draw_empty_sphere(size);
561 draw_empty_cone(size);
567 for (axis = 0; axis < 3; axis++) {
568 const int arrow_axis = (axis == 0) ? 1 : 0;
576 v1[axis] = size * 0.85f;
577 v1[arrow_axis] = -size * 0.08f;
581 v1[arrow_axis] = size * 0.08f;
587 v2[axis] += size * 0.125f;
589 draw_xyz_wire(v2, size, axis);
592 /* reset v1 & v2 to zero */
593 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
601 /* Function to draw an Image on an empty Object */
602 static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
604 Image *ima = ob->data;
605 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL);
607 float scale, ofs_x, ofs_y, sca_x, sca_y;
610 if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
611 IMB_rect_from_float(ibuf);
614 /* Get the buffer dimensions so we can fallback to fake ones */
615 if (ibuf && ibuf->rect) {
624 /* Get the image aspect even if the buffer is invalid */
626 if (ima->aspx > ima->aspy) {
628 sca_y = ima->aspy / ima->aspx;
630 else if (ima->aspx < ima->aspy) {
631 sca_x = ima->aspx / ima->aspy;
644 /* Calculate the scale center based on object's origin */
645 ofs_x = ob->ima_ofs[0] * ima_x;
646 ofs_y = ob->ima_ofs[1] * ima_y;
648 glMatrixMode(GL_MODELVIEW);
651 /* Calculate Image scale */
652 scale = (ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y));
654 /* Set the object scale */
655 glScalef(scale * sca_x, scale * sca_y, 1.0f);
657 if (ibuf && ibuf->rect) {
658 const bool use_clip = (U.glalphaclip != 1.0f);
659 int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP ) ? GL_NEAREST : GL_LINEAR;
660 /* Setup GL params */
662 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
665 glEnable(GL_ALPHA_TEST);
666 glAlphaFunc(GL_GREATER, U.glalphaclip);
669 /* Use the object color and alpha */
672 /* Draw the Image on the screen */
673 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
674 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
679 glDisable(GL_ALPHA_TEST);
680 glAlphaFunc(GL_GREATER, 0.0f);
684 if ((dflag & DRAW_CONSTCOLOR) == 0) {
685 glColor3ubv(ob_wire_col);
688 /* Calculate the outline vertex positions */
689 glBegin(GL_LINE_LOOP);
690 glVertex2f(ofs_x, ofs_y);
691 glVertex2f(ofs_x + ima_x, ofs_y);
692 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
693 glVertex2f(ofs_x, ofs_y + ima_y);
697 /* Reset GL settings */
698 glMatrixMode(GL_MODELVIEW);
701 BKE_image_release_ibuf(ima, ibuf, NULL);
704 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[4][4])
707 float *viter = (float *)verts;
710 mul_v3_v3fl(vx, tmat[0], rad);
711 mul_v3_v3fl(vy, tmat[1], rad);
713 for (a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
714 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
715 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
716 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
720 void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4])
722 float verts[CIRCLE_RESOL][3];
724 circball_array_fill(verts, cent, rad, tmat);
726 glEnableClientState(GL_VERTEX_ARRAY);
727 glVertexPointer(3, GL_FLOAT, 0, verts);
728 glDrawArrays(mode, 0, CIRCLE_RESOL);
729 glDisableClientState(GL_VERTEX_ARRAY);
732 /* circle for object centers, special_color is for library or ob users */
733 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color)
735 const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
736 float verts[CIRCLE_RESOL][3];
738 /* using gldepthfunc guarantees that it does write z values,
739 * but not checks for it, so centers remain visible independent order of drawing */
740 if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
741 /* write to near buffer always */
742 glDepthRange(0.0, 0.0);
746 if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
748 else glColor4ub(0x55, 0xCC, 0xCC, 155);
751 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
752 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
753 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
756 circball_array_fill(verts, co, size, rv3d->viewinv);
758 /* enable vertex array */
759 glEnableClientState(GL_VERTEX_ARRAY);
760 glVertexPointer(3, GL_FLOAT, 0, verts);
762 /* 1. draw filled, blended polygon */
763 glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
765 /* 2. draw outline */
766 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
767 glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
770 glDisableClientState(GL_VERTEX_ARRAY);
772 glDepthRange(0.0, 1.0);
775 if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
778 /* *********** text drawing for object/particles/armature ************* */
780 typedef struct ViewCachedString {
781 struct ViewCachedString *next;
792 /* str is allocated past the end */
796 /* one arena for all 3 string lists */
797 static MemArena *g_v3d_strings_arena = NULL;
798 static ViewCachedString *g_v3d_strings[3] = {NULL, NULL, NULL};
799 static int g_v3d_string_level = -1;
801 void view3d_cached_text_draw_begin(void)
803 g_v3d_string_level++;
805 BLI_assert(g_v3d_string_level >= 0);
807 if (g_v3d_string_level == 0) {
808 BLI_assert(g_v3d_strings_arena == NULL);
812 void view3d_cached_text_draw_add(const float co[3],
813 const char *str, const size_t str_len,
814 short xoffs, short flag,
815 const unsigned char col[4])
817 int alloc_len = str_len + 1;
818 ViewCachedString *vos;
820 BLI_assert(str_len == strlen(str));
822 if (g_v3d_strings_arena == NULL) {
823 g_v3d_strings_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 14), __func__);
826 vos = BLI_memarena_alloc(g_v3d_strings_arena, sizeof(ViewCachedString) + alloc_len);
828 BLI_LINKS_PREPEND(g_v3d_strings[g_v3d_string_level], vos);
830 copy_v3_v3(vos->vec, co);
831 copy_v4_v4_char((char *)vos->col.ub, (const char *)col);
834 vos->str_len = str_len;
836 /* allocate past the end */
837 memcpy(vos->str, str, alloc_len);
840 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, float mat[4][4])
842 RegionView3D *rv3d = ar->regiondata;
843 ViewCachedString *vos;
846 BLI_assert(g_v3d_string_level >= 0 && g_v3d_string_level <= 2);
848 /* project first and test */
849 for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
850 if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
851 mul_m4_v3(mat, vos->vec);
853 if (ED_view3d_project_short_ex(ar,
854 (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
855 (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
857 V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
862 vos->sco[0] = IS_CLIPPED;
867 int col_pack_prev = 0;
870 bglMats mats; /* ZBuffer depth vars */
877 if (rv3d->rflag & RV3D_CLIPPING) {
878 ED_view3d_clipping_disable();
881 glMatrixMode(GL_PROJECTION);
883 glMatrixMode(GL_MODELVIEW);
885 wmOrtho2_region_ui(ar);
889 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
895 for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
896 if (vos->sco[0] != IS_CLIPPED) {
897 if (col_pack_prev != vos->col.pack) {
898 glColor3ubv(vos->col.ub);
899 col_pack_prev = vos->col.pack;
902 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
903 BLF_draw_default_ascii :
905 )((float)(vos->sco[0] + vos->xoffs),
906 (float)(vos->sco[1]),
907 (depth_write) ? 0.0f : 2.0f,
914 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
920 glMatrixMode(GL_PROJECTION);
922 glMatrixMode(GL_MODELVIEW);
925 if (rv3d->rflag & RV3D_CLIPPING) {
926 ED_view3d_clipping_enable();
930 g_v3d_strings[g_v3d_string_level] = NULL;
932 if (g_v3d_string_level == 0) {
933 if (g_v3d_strings_arena) {
934 BLI_memarena_free(g_v3d_strings_arena);
935 g_v3d_strings_arena = NULL;
939 g_v3d_string_level--;
942 /* ******************** primitive drawing ******************* */
944 /* draws a cube given the scaling of the cube, assuming that
945 * all required matrices have been set (used for drawing empties)
947 static void drawcube_size(float size)
949 glBegin(GL_LINE_STRIP);
950 glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size);
951 glVertex3f(-size, size, size); glVertex3f(-size, size, -size);
953 glVertex3f(-size, -size, -size); glVertex3f(size, -size, -size);
954 glVertex3f(size, -size, size); glVertex3f(size, size, size);
956 glVertex3f(size, size, -size); glVertex3f(size, -size, -size);
959 glBegin(GL_LINE_STRIP);
960 glVertex3f(-size, -size, size); glVertex3f(size, -size, size);
963 glBegin(GL_LINE_STRIP);
964 glVertex3f(-size, size, size); glVertex3f(size, size, size);
967 glBegin(GL_LINE_STRIP);
968 glVertex3f(-size, size, -size); glVertex3f(size, size, -size);
972 /* this is an unused (old) cube-drawing function based on a given size */
974 static void drawcube_size(const float size[3])
978 glScalef(size[0], size[1], size[2]);
981 glBegin(GL_LINE_STRIP);
982 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
983 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
984 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
987 glBegin(GL_LINE_STRIP);
988 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
991 glBegin(GL_LINE_STRIP);
992 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
995 glBegin(GL_LINE_STRIP);
996 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
1003 static void drawshadbuflimits(Lamp *la, float mat[4][4])
1005 float sta[3], end[3], lavec[3];
1007 negate_v3_v3(lavec, mat[2]);
1008 normalize_v3(lavec);
1010 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
1011 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
1013 glBegin(GL_LINE_STRIP);
1019 bglBegin(GL_POINTS);
1026 static void spotvolume(float lvec[3], float vvec[3], const float inp)
1028 /* camera is at 0,0,0 */
1029 float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
1032 normalize_v3(vvec); /* is this the correct vector ? */
1034 cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec and lvec */
1035 cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parallel with lvec */
1037 /* vectors are exactly aligned, use the X axis, this is arbitrary */
1038 if (normalize_v3(plane) == 0.0f)
1041 /* now we've got two equations: one of a cone and one of a plane, but we have
1042 * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
1044 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
1045 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
1047 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
1052 normalize_v3(&q[1]);
1054 angle = saacos(plane[2]) / 2.0f;
1056 si = sqrtf(1 - co * co);
1063 quat_to_mat3(mat1, q);
1065 /* rotate lamp vector now over acos(inp) degrees */
1066 copy_v3_v3(vvec, lvec);
1070 si = sqrtf(1.0f - inp * inp);
1076 mul_m3_m3m3(mat3, mat2, mat1);
1080 mul_m3_m3m3(mat4, mat2, mat1);
1083 mul_m3_m3m3(mat2, mat1, mat3);
1084 mul_m3_v3(mat2, lvec);
1085 mul_m3_m3m3(mat2, mat1, mat4);
1086 mul_m3_v3(mat2, vvec);
1091 static void draw_spot_cone(Lamp *la, float x, float z)
1095 glBegin(GL_TRIANGLE_FAN);
1096 glVertex3f(0.0f, 0.0f, -x);
1098 if (la->mode & LA_SQUARE) {
1099 glVertex3f(z, z, 0);
1100 glVertex3f(-z, z, 0);
1101 glVertex3f(-z, -z, 0);
1102 glVertex3f(z, -z, 0);
1103 glVertex3f(z, z, 0);
1109 for (a = 0; a < 33; a++) {
1110 angle = a * M_PI * 2 / (33 - 1);
1111 glVertex3f(z * cosf(angle), z * sinf(angle), 0);
1118 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1120 glEnable(GL_CULL_FACE);
1124 /* draw backside darkening */
1125 glCullFace(GL_FRONT);
1127 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1128 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1130 draw_spot_cone(la, x, z);
1132 /* draw front side lighting */
1133 glCullFace(GL_BACK);
1135 glBlendFunc(GL_ONE, GL_ONE);
1136 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1138 draw_spot_cone(la, x, z);
1141 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1142 glDisable(GL_BLEND);
1144 glDisable(GL_CULL_FACE);
1145 glCullFace(GL_BACK);
1148 #ifdef WITH_GAMEENGINE
1149 static void draw_transp_sun_volume(Lamp *la)
1154 box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size;
1155 box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size;
1156 box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size;
1157 box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size;
1158 box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend;
1159 box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
1162 draw_box(box, false);
1165 glEnable(GL_CULL_FACE);
1169 /* draw backside darkening */
1170 glCullFace(GL_FRONT);
1172 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1173 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1175 draw_box(box, true);
1177 /* draw front side lighting */
1178 glCullFace(GL_BACK);
1180 glBlendFunc(GL_ONE, GL_ONE);
1181 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1183 draw_box(box, true);
1186 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1187 glDisable(GL_BLEND);
1189 glDisable(GL_CULL_FACE);
1190 glCullFace(GL_BACK);
1194 static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
1195 const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
1197 Object *ob = base->object;
1198 const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1199 Lamp *la = ob->data;
1200 float vec[3], lvec[3], vvec[3], circrad, x, y, z;
1204 unsigned char curcol[4];
1205 unsigned char col[4];
1206 /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
1207 /* the moment of view3d_draw_transp() call */
1208 const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1209 const bool drawcone = ((dt > OB_WIRE) &&
1210 !(G.f & G_PICKSEL) &&
1211 (la->type == LA_SPOT) &&
1212 (la->mode & LA_SHOW_CONE) &&
1213 !(base->flag & OB_FROMDUPLI) &&
1216 #ifdef WITH_GAMEENGINE
1217 const bool drawshadowbox = (
1218 (rv3d->rflag & RV3D_IS_GAME_ENGINE) &&
1220 !(G.f & G_PICKSEL) &&
1221 (la->type == LA_SUN) &&
1222 ((la->mode & LA_SHAD_BUF) ||
1223 (la->mode & LA_SHAD_RAY)) &&
1224 (la->mode & LA_SHOW_SHADOW_BOX) &&
1225 !(base->flag & OB_FROMDUPLI) &&
1228 const bool drawshadowbox = false;
1231 if ((drawcone || drawshadowbox) && !v3d->transp) {
1232 /* in this case we need to draw delayed */
1233 ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
1237 /* we first draw only the screen aligned & fixed scale stuff */
1239 glLoadMatrixf(rv3d->viewmat);
1241 /* lets calculate the scale: */
1242 lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
1244 /* and view aligned matrix: */
1245 copy_m4_m4(imat, rv3d->viewinv);
1246 normalize_v3(imat[0]);
1247 normalize_v3(imat[1]);
1250 copy_v3_v3(vec, ob->obmat[3]);
1252 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1253 /* for AA effects */
1254 curcol[0] = ob_wire_col[0];
1255 curcol[1] = ob_wire_col[1];
1256 curcol[2] = ob_wire_col[2];
1258 glColor4ubv(curcol);
1261 if (lampsize > 0.0f) {
1263 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1264 if (ob->id.us > 1) {
1265 if (is_obact || (ob->flag & SELECT)) {
1266 glColor4ub(0x88, 0xFF, 0xFF, 155);
1269 glColor4ub(0x77, 0xCC, 0xCC, 155);
1276 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1277 glDisable(GL_BLEND);
1278 drawcircball(GL_POLYGON, vec, lampsize, imat);
1281 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1283 glColor4ubv(curcol);
1287 circrad = 3.0f * lampsize;
1290 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1292 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1293 if (la->type != LA_HEMI) {
1294 if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1295 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
1304 /* draw the pretty sun rays */
1305 if (la->type == LA_SUN) {
1306 float v1[3], v2[3], mat[3][3];
1309 /* setup a 45 degree rotation matrix */
1310 axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2);
1313 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1314 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1317 glTranslatef(vec[0], vec[1], vec[2]);
1322 for (axis = 0; axis < 8; axis++) {
1330 glTranslatef(-vec[0], -vec[1], -vec[2]);
1334 if (la->type == LA_LOCAL) {
1335 if (la->mode & LA_SPHERE) {
1336 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1340 glPopMatrix(); /* back in object space */
1344 /* skip drawing extra info */
1346 else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
1348 copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f);
1349 copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]);
1350 mul_transposed_mat3_m4_v3(ob->obmat, vvec);
1353 y = cosf(la->spotsize * 0.5f);
1354 z = x * sqrtf(1.0f - y * y);
1356 spotvolume(lvec, vvec, y);
1360 /* draw the angled sides of the cone */
1361 glBegin(GL_LINE_STRIP);
1369 /* draw the circle/square at the end of the cone */
1370 glTranslatef(0.0, 0.0, x);
1371 if (la->mode & LA_SQUARE) {
1373 float z_abs = fabsf(z);
1375 tvec[0] = tvec[1] = z_abs;
1378 glBegin(GL_LINE_LOOP);
1380 tvec[1] = -z_abs; /* neg */
1382 tvec[0] = -z_abs; /* neg */
1384 tvec[1] = z_abs; /* pos */
1389 circ(0.0, 0.0, fabsf(z));
1392 /* draw the circle/square representing spotbl */
1393 if (la->type == LA_SPOT) {
1394 float spotblcirc = fabsf(z) * (1.0f - pow2f(la->spotblend));
1395 /* hide line if it is zero size or overlaps with outer border,
1396 * previously it adjusted to always to show it but that seems
1397 * confusing because it doesn't show the actual blend size */
1398 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1399 circ(0.0, 0.0, spotblcirc);
1403 draw_transp_spot_volume(la, x, z);
1405 /* draw clip start, useful for wide cones where its not obvious where the start is */
1406 glTranslatef(0.0, 0.0, -x); /* reverse translation above */
1407 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
1410 float clipsta_fac = la->clipsta / -x;
1412 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1413 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1415 glBegin(GL_LINE_STRIP);
1416 glVertex3fv(lvec_clip);
1417 glVertex3fv(vvec_clip);
1420 /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
1422 glBegin(GL_LINE_STRIP);
1423 glVertex3f(0.0, 0.0, -circrad);
1424 glVertex3f(0.0, 0.0, -la->dist);
1428 else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1430 /* draw the line from the circle along the dist */
1431 glBegin(GL_LINE_STRIP);
1438 if (la->type == LA_HEMI) {
1439 /* draw the hemisphere curves */
1440 short axis, steps, dir;
1441 float outdist, zdist, mul;
1443 outdist = 0.14; mul = 1.4; dir = 1;
1446 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1447 for (axis = 0; axis < 4; axis++) {
1448 float v[3] = {0.0, 0.0, 0.0};
1451 glBegin(GL_LINE_STRIP);
1453 for (steps = 0; steps < 6; steps++) {
1454 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1455 /* make the arcs start at the edge of the energy circle */
1456 if (steps == 0) v[0] = dir * circrad;
1457 else v[0] = v[0] + dir * (steps * outdist);
1459 else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1460 /* make the arcs start at the edge of the energy circle */
1461 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1464 v[2] = v[2] - steps * zdist;
1468 zdist = zdist * mul;
1472 /* flip the direction */
1477 #ifdef WITH_GAMEENGINE
1478 if (drawshadowbox) {
1479 draw_transp_sun_volume(la);
1484 else if (la->type == LA_AREA) {
1486 if (la->area_shape == LA_AREA_SQUARE)
1487 fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
1488 else if (la->area_shape == LA_AREA_RECT)
1489 fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
1491 glBegin(GL_LINE_STRIP);
1492 glVertex3f(0.0, 0.0, -circrad);
1493 glVertex3f(0.0, 0.0, -la->dist);
1497 /* and back to viewspace */
1499 glLoadMatrixf(rv3d->viewmat);
1500 copy_v3_v3(vec, ob->obmat[3]);
1504 if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) {
1505 drawshadbuflimits(la, ob->obmat);
1508 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1509 UI_GetThemeColor4ubv(TH_LAMP, col);
1515 if (vec[2] > 0) vec[2] -= circrad;
1516 else vec[2] += circrad;
1518 glBegin(GL_LINE_STRIP);
1530 glDisable(GL_BLEND);
1532 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1533 /* restore for drawing extra stuff */
1534 glColor3ubv(ob_wire_col);
1536 /* and finally back to org object space! */
1540 static void draw_limit_line(float sta, float end, const short dflag, unsigned int col)
1543 glVertex3f(0.0, 0.0, -sta);
1544 glVertex3f(0.0, 0.0, -end);
1547 if (!(dflag & DRAW_PICKING)) {
1550 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1553 glVertex3f(0.0, 0.0, -sta);
1554 glVertex3f(0.0, 0.0, -end);
1561 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1562 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1563 static void draw_focus_cross(float dist, float size)
1566 glVertex3f(-size, 0.0f, -dist);
1567 glVertex3f(size, 0.0f, -dist);
1568 glVertex3f(0.0f, -size, -dist);
1569 glVertex3f(0.0f, size, -dist);
1573 #ifdef VIEW3D_CAMERA_BORDER_HACK
1574 unsigned char view3d_camera_border_hack_col[3];
1575 bool view3d_camera_border_hack_test = false;
1578 /* ****************** draw clip data *************** */
1580 static void draw_bundle_sphere(void)
1582 static GLuint displist = 0;
1584 if (displist == 0) {
1585 GLUquadricObj *qobj;
1587 displist = glGenLists(1);
1588 glNewList(displist, GL_COMPILE);
1590 qobj = gluNewQuadric();
1591 gluQuadricDrawStyle(qobj, GLU_FILL);
1592 glShadeModel(GL_SMOOTH);
1593 gluSphere(qobj, 0.05, 8, 8);
1594 glShadeModel(GL_FLAT);
1595 gluDeleteQuadric(qobj);
1600 glCallList(displist);
1603 static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
1604 MovieClip *clip, MovieTrackingObject *tracking_object,
1605 const short dflag, const unsigned char ob_wire_col[4],
1606 int *global_track_index, bool draw_selected)
1608 MovieTracking *tracking = &clip->tracking;
1609 MovieTrackingTrack *track;
1610 float mat[4][4], imat[4][4];
1611 unsigned char col_unsel[4], col_sel[4];
1612 int tracknr = *global_track_index;
1613 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
1614 float camera_size[3];
1616 UI_GetThemeColor4ubv(TH_TEXT, col_unsel);
1617 UI_GetThemeColor4ubv(TH_SELECT, col_sel);
1619 BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
1621 /* we're compensating camera size for bundles size,
1622 * to make it so bundles are always displayed with the same size */
1623 copy_v3_v3(camera_size, base->object->size);
1624 if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
1625 mul_v3_fl(camera_size, tracking_object->scale);
1629 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1630 /* current ogl matrix is translated in camera space, bundles should
1631 * be rendered in world space, so camera matrix should be "removed"
1632 * from current ogl matrix */
1633 invert_m4_m4(imat, base->object->obmat);
1635 glMultMatrixf(imat);
1640 int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra);
1642 BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat);
1644 invert_m4_m4(imat, obmat);
1645 glMultMatrixf(imat);
1648 for (track = tracksbase->first; track; track = track->next) {
1649 bool selected = TRACK_SELECTED(track);
1651 if (draw_selected && !selected)
1654 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1657 if (dflag & DRAW_PICKING)
1658 GPU_select_load_id(base->selcol + (tracknr << 16));
1661 glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
1662 glScalef(v3d->bundle_size / 0.05f / camera_size[0],
1663 v3d->bundle_size / 0.05f / camera_size[1],
1664 v3d->bundle_size / 0.05f / camera_size[2]);
1666 if (v3d->drawtype == OB_WIRE) {
1667 glDisable(GL_LIGHTING);
1669 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1670 if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
1671 glColor3ubv(ob_wire_col);
1674 glColor3fv(track->color);
1678 drawaxes(0.05f, v3d->bundle_drawtype);
1680 glEnable(GL_LIGHTING);
1682 else if (v3d->drawtype > OB_WIRE) {
1683 if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1684 /* selection outline */
1686 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1687 glColor3ubv(ob_wire_col);
1691 glDisable(GL_LIGHTING);
1692 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1694 draw_bundle_sphere();
1696 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1697 glEnable(GL_LIGHTING);
1701 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1702 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1703 else UI_ThemeColor(TH_BUNDLE_SOLID);
1706 draw_bundle_sphere();
1709 glDisable(GL_LIGHTING);
1711 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1713 glColor3ubv(ob_wire_col);
1716 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1717 else UI_ThemeColor(TH_WIRE);
1721 drawaxes(0.05f, v3d->bundle_drawtype);
1723 glEnable(GL_LIGHTING);
1729 if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1732 mul_v3_m4v3(pos, mat, track->bundle_pos);
1733 view3d_cached_text_draw_add(pos,
1734 track->name, strlen(track->name),
1735 10, V3D_CACHE_TEXT_GLOBALSPACE,
1736 selected ? col_sel : col_unsel);
1742 if ((dflag & DRAW_PICKING) == 0) {
1743 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1744 MovieTrackingReconstruction *reconstruction;
1745 reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
1747 if (reconstruction->camnr) {
1748 MovieReconstructedCamera *camera = reconstruction->cameras;
1751 glDisable(GL_LIGHTING);
1752 UI_ThemeColor(TH_CAMERA_PATH);
1755 glBegin(GL_LINE_STRIP);
1756 for (a = 0; a < reconstruction->camnr; a++, camera++) {
1757 glVertex3fv(camera->mat[3]);
1762 glEnable(GL_LIGHTING);
1769 *global_track_index = tracknr;
1772 static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip,
1773 const short dflag, const unsigned char ob_wire_col[4],
1774 const bool draw_selected)
1776 MovieTracking *tracking = &clip->tracking;
1777 MovieTrackingObject *tracking_object;
1778 int global_track_index = 1;
1780 if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1783 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1786 glEnable(GL_LIGHTING);
1787 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1788 glEnable(GL_COLOR_MATERIAL);
1789 glShadeModel(GL_SMOOTH);
1791 tracking_object = tracking->objects.first;
1792 while (tracking_object) {
1793 draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
1794 dflag, ob_wire_col, &global_track_index, draw_selected);
1796 tracking_object = tracking_object->next;
1800 glShadeModel(GL_FLAT);
1801 glDisable(GL_COLOR_MATERIAL);
1802 glDisable(GL_LIGHTING);
1804 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1805 glColor3ubv(ob_wire_col);
1808 if (dflag & DRAW_PICKING)
1809 GPU_select_load_id(base->selcol);
1812 static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
1815 glVertex3fv(near_plane[0]);
1816 glVertex3fv(far_plane[0]);
1817 glVertex3fv(far_plane[1]);
1818 glVertex3fv(near_plane[1]);
1822 glVertex3fv(near_plane[1]);
1823 glVertex3fv(far_plane[1]);
1824 glVertex3fv(far_plane[2]);
1825 glVertex3fv(near_plane[2]);
1829 glVertex3fv(near_plane[2]);
1830 glVertex3fv(near_plane[1]);
1831 glVertex3fv(far_plane[1]);
1832 glVertex3fv(far_plane[2]);
1836 glVertex3fv(far_plane[0]);
1837 glVertex3fv(near_plane[0]);
1838 glVertex3fv(near_plane[3]);
1839 glVertex3fv(far_plane[3]);
1844 static void drawcamera_frame(float vec[4][3], const GLenum mode)
1847 glVertex3fv(vec[0]);
1848 glVertex3fv(vec[1]);
1849 glVertex3fv(vec[2]);
1850 glVertex3fv(vec[3]);
1854 /* center point to camera frame */
1855 static void drawcamera_framelines(float vec[4][3], float origin[3])
1857 glBegin(GL_LINE_STRIP);
1858 glVertex3fv(vec[1]);
1859 glVertex3fv(origin);
1860 glVertex3fv(vec[0]);
1861 glVertex3fv(vec[3]);
1862 glVertex3fv(origin);
1863 glVertex3fv(vec[2]);
1867 static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
1869 return (ob == v3d->camera) &&
1870 (scene->r.scemode & R_MULTIVIEW) != 0 &&
1871 (v3d->stereo3d_flag);
1874 static void drawcamera_stereo3d(
1875 Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
1876 float vec[4][3], float drawsize, const float scale[3])
1880 float vec_lr[2][4][3];
1881 const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
1882 float origin[2][3] = {{0}};
1884 const Camera *cam_lr[2];
1885 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
1887 const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
1888 const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
1889 const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME);
1895 for (i = 0; i < 2; i++) {
1896 ob = BKE_camera_multiview_render(scene, ob, names[i]);
1897 cam_lr[i] = ob->data;
1899 glLoadMatrixf(rv3d->viewmat);
1900 BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
1901 glMultMatrixf(obmat);
1903 copy_m3_m3(vec_lr[i], vec);
1904 copy_v3_v3(vec_lr[i][3], vec[3]);
1906 if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
1907 const float shift_x =
1908 ((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) *
1909 (drawsize * scale[0] * fac));
1911 for (j = 0; j < 4; j++) {
1912 vec_lr[i][j][0] += shift_x;
1916 if (is_stereo3d_cameras) {
1918 drawcamera_frame(vec_lr[i], GL_LINE_LOOP);
1920 /* center point to camera frame */
1921 drawcamera_framelines(vec_lr[i], tvec);
1924 /* connecting line */
1925 mul_m4_v3(obmat, origin[i]);
1927 /* convergence plane */
1928 if (is_stereo3d_plane || is_stereo3d_volume) {
1929 for (j = 0; j < 4; j++) {
1930 mul_m4_v3(obmat, vec_lr[i][j]);
1936 /* the remaining drawing takes place in the view space */
1937 glLoadMatrixf(rv3d->viewmat);
1939 if (is_stereo3d_cameras) {
1940 /* draw connecting lines */
1941 glPushAttrib(GL_ENABLE_BIT);
1943 glLineStipple(2, 0xAAAA);
1944 glEnable(GL_LINE_STIPPLE);
1947 glVertex3fv(origin[0]);
1948 glVertex3fv(origin[1]);
1953 /* draw convergence plane*/
1954 if (is_stereo3d_plane) {
1955 float axis_center[3], screen_center[3];
1956 float world_plane[4][3];
1957 float local_plane[4][3];
1960 mid_v3_v3v3(axis_center, origin[0], origin[1]);
1962 for (i = 0; i < 4; i++) {
1963 mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]);
1964 sub_v3_v3v3(local_plane[i], world_plane[i], axis_center);
1967 mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]);
1968 offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center);
1970 for (i = 0; i < 4; i++) {
1971 mul_v3_fl(local_plane[i], offset);
1972 add_v3_v3(local_plane[i], axis_center);
1975 glColor3f(0.0f, 0.0f, 0.0f);
1978 drawcamera_frame(local_plane, GL_LINE_LOOP);
1980 if (v3d->stereo3d_convergence_alpha > 0.0f) {
1982 glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
1984 glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
1986 drawcamera_frame(local_plane, GL_QUADS);
1988 glDisable(GL_BLEND);
1989 glDepthMask(1); /* restore write in zbuffer */
1993 /* draw convergence plane*/
1994 if (is_stereo3d_volume) {
1995 float screen_center[3];
1996 float near_plane[4][3], far_plane[4][3];
2000 for (i = 0; i < 2; i++) {
2001 mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]);
2003 offset = len_v3v3(screen_center, origin[i]);
2005 for (j = 0; j < 4; j++) {
2006 sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]);
2007 mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset);
2008 add_v3_v3(near_plane[j], origin[i]);
2010 sub_v3_v3v3(far_plane[j], vec_lr[i][j], origin[i]);
2011 mul_v3_fl(far_plane[j], cam_lr[i]->clipend / offset);
2012 add_v3_v3(far_plane[j], origin[i]);
2016 glColor3f(0.0f, 0.0f, 0.0f);
2018 drawcamera_frame(near_plane, GL_LINE_LOOP);
2019 drawcamera_frame(far_plane, GL_LINE_LOOP);
2020 drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP);
2022 if (v3d->stereo3d_volume_alpha > 0.0f) {
2024 glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
2027 glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
2029 glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
2031 drawcamera_frame(near_plane, GL_QUADS);
2032 drawcamera_frame(far_plane, GL_QUADS);
2033 drawcamera_volume(near_plane, far_plane, GL_QUADS);
2035 glDisable(GL_BLEND);
2036 glDepthMask(1); /* restore write in zbuffer */
2044 /* flag similar to draw_object() */
2045 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
2046 const short dflag, const unsigned char ob_wire_col[4])
2048 /* a standing up pyramid with (0,0,0) as top */
2050 Object *ob = base->object;
2052 float vec[4][3], asp[2], shift[2], scale[3];
2055 MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
2057 const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
2058 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2059 const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
2060 const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
2061 const bool is_stereo3d_cameras = (ob == scene->camera) &&
2064 (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
2065 const bool is_selection_camera_stereo = (G.f & G_PICKSEL) &&
2066 is_view && is_multiview &&
2069 /* draw data for movie clip set as active for scene */
2071 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, false);
2072 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, true);
2075 #ifdef VIEW3D_CAMERA_BORDER_HACK
2076 if (is_view && !(G.f & G_PICKSEL)) {
2077 if ((dflag & DRAW_CONSTCOLOR) == 0) {
2078 view3d_camera_border_hack_col[0] = ob_wire_col[0];
2079 view3d_camera_border_hack_col[1] = ob_wire_col[1];
2080 view3d_camera_border_hack_col[2] = ob_wire_col[2];
2084 glGetFloatv(GL_CURRENT_COLOR, col);
2085 rgb_float_to_uchar(view3d_camera_border_hack_col, col);
2087 view3d_camera_border_hack_test = true;
2094 /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here */
2095 if (is_selection_camera_stereo) {
2101 scale[0] = 1.0f / len_v3(ob->obmat[0]);
2102 scale[1] = 1.0f / len_v3(ob->obmat[1]);
2103 scale[2] = 1.0f / len_v3(ob->obmat[2]);
2106 BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
2107 asp, shift, &drawsize, vec);
2109 glDisable(GL_LIGHTING);
2110 glDisable(GL_CULL_FACE);
2113 if (!is_stereo3d_cameras) {
2114 /* make sure selection uses the same matrix for camera as the one used while viewing */
2115 if (is_selection_camera_stereo) {
2117 bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
2120 glLoadMatrixf(rv3d->viewmat);
2121 BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
2122 glMultMatrixf(obmat);
2124 drawcamera_frame(vec, GL_LINE_LOOP);
2128 drawcamera_frame(vec, GL_LINE_LOOP);
2137 /* center point to camera frame */
2138 if (!is_stereo3d_cameras)
2139 drawcamera_framelines(vec, tvec);
2142 tvec[2] = vec[1][2]; /* copy the depth */
2144 /* draw an outline arrow for inactive cameras and filled
2145 * for active cameras. We actually draw both outline+filled
2146 * for active cameras so the wire can be seen side-on */
2147 for (i = 0; i < 2; i++) {
2148 if (i == 0) glBegin(GL_LINE_LOOP);
2149 else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
2152 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
2153 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
2154 glVertex3fv(tvec); /* left */
2156 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
2157 glVertex3fv(tvec); /* right */
2160 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
2161 glVertex3fv(tvec); /* top */
2166 if ((dflag & DRAW_SCENESET) == 0) {
2167 if (cam->flag & (CAM_SHOWLIMITS | CAM_SHOWMIST)) {
2170 /* draw in normalized object matrix space */
2171 copy_m4_m4(nobmat, ob->obmat);
2172 normalize_m4(nobmat);
2175 glLoadMatrixf(rv3d->viewmat);
2176 glMultMatrixf(nobmat);
2178 if (cam->flag & CAM_SHOWLIMITS) {
2179 draw_limit_line(cam->clipsta, cam->clipend, dflag, 0x77FFFF);
2180 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
2181 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
2184 if (cam->flag & CAM_SHOWMIST) {
2185 World *world = scene->world;
2187 draw_limit_line(world->miststa, world->miststa + world->mistdist, dflag, 0xFFFFFF);
2194 /* stereo cameras drawing */
2196 drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
2200 /* flag similar to draw_object() */
2201 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
2202 Object *UNUSED(ob), int UNUSED(flag))
2209 for (j = 0; j < 3; j++) {
2210 vec[2] = 0.25f * j - 0.125f;
2212 glBegin(GL_LINE_LOOP);
2213 for (i = 0; i < 16; i++) {
2214 vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
2215 vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
2221 for (j = 0; j < 4; j++) {
2222 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
2223 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
2224 glBegin(GL_LINE_STRIP);
2225 for (i = 0; i < 3; i++) {
2231 vec[2] = 0.25f * i - 0.125f;
2237 glDisable(GL_BLEND);
2240 static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel)
2242 BPoint *bp = lt->def;
2243 const float *co = dl ? dl->verts : NULL;
2246 const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
2247 UI_ThemeColor(color);
2249 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
2250 bglBegin(GL_POINTS);
2252 for (w = 0; w < lt->pntsw; w++) {
2253 int wxt = (w == 0 || w == lt->pntsw - 1);
2254 for (v = 0; v < lt->pntsv; v++) {
2255 int vxt = (v == 0 || v == lt->pntsv - 1);
2256 for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
2257 int uxt = (u == 0 || u == lt->pntsu - 1);
2258 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
2259 if (bp->hide == 0) {
2260 /* check for active BPoint and ensure selected */
2261 if ((bp == actbp) && (bp->f1 & SELECT)) {
2262 UI_ThemeColor(TH_ACTIVE_VERT);
2263 bglVertex3fv(dl ? co : bp->vec);
2264 UI_ThemeColor(color);
2266 else if ((bp->f1 & SELECT) == sel) {
2267 bglVertex3fv(dl ? co : bp->vec);
2279 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
2281 int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
2285 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
2287 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
2293 glVertex3fv(&dl->verts[index * 3]);
2296 glVertex3fv(lt->def[index].vec);
2300 #ifdef SEQUENCER_DAG_WORKAROUND
2301 static void ensure_curve_cache(Scene *scene, Object *object)
2303 bool need_recalc = object->curve_cache == NULL;
2304 /* Render thread might have freed the curve cache if the
2305 * object is not visible. If the object is also used for
2306 * particles duplication, then render thread might have
2307 * also created curve_cache with only bevel and path
2310 * So check for curve_cache != NULL is not fully correct
2311 * here, we also need to check whether display list is
2314 * The trick below tries to optimize calls to displist
2315 * creation for cases curve is empty. Meaning, if the curve
2316 * is empty (without splines) bevel list would also be empty.
2317 * And the thing is, render thread always leaves bevel list
2318 * in a proper state. So if bevel list is here and display
2319 * list is not we need to make display list.
2321 if (need_recalc == false) {
2322 need_recalc = object->curve_cache->disp.first == NULL &&
2323 object->curve_cache->bev.first != NULL;
2326 switch (object->type) {
2330 BKE_displist_make_curveTypes(scene, object, false);
2333 BKE_displist_make_mball(G.main->eval_ctx, scene, object);
2336 BKE_lattice_modifiers_calc(scene, object);
2343 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
2344 static void drawlattice(View3D *v3d, Object *ob)
2346 Lattice *lt = ob->data;
2349 int actdef_wcol = 0;
2350 const bool is_edit = (lt->editlatt != NULL);
2352 dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS);
2355 lt = lt->editlatt->latt;
2357 UI_ThemeColor(TH_WIRE_EDIT);
2359 if (ob->defbase.first && lt->dvert) {
2360 actdef_wcol = ob->actdef;
2361 glShadeModel(GL_SMOOTH);
2366 for (w = 0; w < lt->pntsw; w++) {
2367 int wxt = (w == 0 || w == lt->pntsw - 1);
2368 for (v = 0; v < lt->pntsv; v++) {
2369 int vxt = (v == 0 || v == lt->pntsv - 1);
2370 for (u = 0; u < lt->pntsu; u++) {
2371 int uxt = (u == 0 || u == lt->pntsu - 1);
2373 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
2374 drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol);
2375 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
2377 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2378 drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol);
2379 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
2381 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2382 drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol);
2383 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
2390 /* restoration for weight colors */
2392 glShadeModel(GL_FLAT);
2395 BPoint *actbp = BKE_lattice_active_point_get(lt);
2397 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2399 lattice_draw_verts(lt, dl, actbp, 0);
2400 lattice_draw_verts(lt, dl, actbp, 1);
2402 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2406 /* ***************** ******************** */
2410 typedef struct drawDMVertSel_userData {
2413 unsigned char *col[3]; /* (base, sel, act) */
2415 } drawDMVertSel_userData;
2417 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
2418 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2420 drawDMVertSel_userData *data = userData;
2421 MVert *mv = &data->mvert[index];
2423 if (!(mv->flag & ME_HIDE)) {
2424 const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
2425 if (sel != data->sel_prev) {
2426 glColor3ubv(data->col[sel]);
2427 data->sel_prev = sel;
2434 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
2436 drawDMVertSel_userData data;
2438 /* TODO define selected color */
2439 unsigned char base_col[3] = {0x0, 0x0, 0x0};
2440 unsigned char sel_col[3] = {0xd8, 0xb8, 0x0};
2441 unsigned char act_col[3] = {0xff, 0xff, 0xff};
2443 data.mvert = me->mvert;
2444 data.active = BKE_mesh_mselect_active_get(me, ME_VSEL);
2445 data.sel_prev = 0xff;
2447 data.col[0] = base_col;
2448 data.col[1] = sel_col;
2449 data.col[2] = act_col;
2452 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
2456 /* ************** DRAW MESH ****************** */
2458 /* First section is all the "simple" draw routines,
2459 * ones that just pass some sort of primitive to GL,
2460 * with perhaps various options to control lighting,
2463 * These routines should not have user interface related
2467 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
2471 copy_m3_m4(obmat, ob->obmat);
2473 data->uniform_scale = is_uniform_scaled_m3(obmat);
2475 if (!data->uniform_scale) {
2476 /* inverted matrix */
2477 invert_m3_m3(data->imat, obmat);
2479 /* transposed inverted matrix */
2480 transpose_m3_m3(data->tmat, data->imat);
2484 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2486 drawDMNormal_userData *data = userData;
2487 BMFace *efa = BM_face_at_index(data->bm, index);
2490 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2491 if (!data->uniform_scale) {
2492 mul_v3_m3v3(n, data->tmat, no);
2494 mul_m3_v3(data->imat, n);
2501 glVertex3f(cent[0] + n[0] * data->normalsize,
2502 cent[1] + n[1] * data->normalsize,
2503 cent[2] + n[2] * data->normalsize);
2507 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2509 drawDMNormal_userData data;
2512 data.normalsize = scene->toolsettings->normalsize;
2514 calcDrawDMNormalScale(ob, &data);
2517 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2521 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2523 drawBMSelect_userData *data = userData;
2524 BMFace *efa = BM_face_at_index(data->bm, index);
2526 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
2527 (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
2532 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select)
2534 drawBMSelect_userData data = {em->bm, select};
2536 bglBegin(GL_POINTS);
2537 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
2541 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])
2543 drawDMNormal_userData *data = userData;
2544 BMVert *eve = BM_vert_at_index(data->bm, index);
2546 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2550 copy_v3_v3(no, no_f);
2553 normal_short_to_float_v3(no, no_s);
2556 if (!data->uniform_scale) {
2557 mul_v3_m3v3(n, data->tmat, no);
2559 mul_m3_v3(data->imat, n);
2566 glVertex3f(co[0] + n[0] * data->normalsize,
2567 co[1] + n[1] * data->normalsize,
2568 co[2] + n[2] * data->normalsize);
2572 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2574 drawDMNormal_userData data;
2577 data.normalsize = scene->toolsettings->normalsize;
2579 calcDrawDMNormalScale(ob, &data);
2582 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2586 /* Draw verts with color set based on selection */
2587 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2588 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2590 drawDMVerts_userData *data = userData;
2591 BMVert *eve = BM_vert_at_index(data->bm, index);
2593 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2594 /* skin nodes: draw a red circle around the root node(s) */
2595 if (data->cd_vskin_offset != -1) {
2596 const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
2597 if (vs->flag & MVERT_SKIN_ROOT) {
2598 float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2601 glColor4ubv(data->th_skin_root);
2602 drawcircball(GL_LINES, co, radius, data->imat);
2604 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2605 bglBegin(GL_POINTS);
2609 /* draw active larger - need to stop/start point drawing for this :/ */
2610 if (eve == data->eve_act) {
2611 glColor4ubv(data->th_editmesh_active);
2615 glPointSize(data->th_vertex_size);
2616 bglBegin(GL_POINTS);
2620 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2621 glPointSize(data->th_vertex_size);
2622 bglBegin(GL_POINTS);
2630 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
2633 drawDMVerts_userData data;
2635 data.eve_act = eve_act;
2638 /* Cache theme values */
2639 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2640 UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2641 UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2642 UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2643 data.th_vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2645 /* For skin root drawing */
2646 data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
2647 /* view-aligned matrix */
2648 mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2649 invert_m4(data.imat);
2651 bglBegin(GL_POINTS);
2652 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
2656 /* Draw edges with color set based on selection */
2657 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2660 drawDMEdgesSel_userData *data = userData;
2663 eed = BM_edge_at_index(data->bm, index);
2665 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2666 if (eed == data->eed_act) {
2667 glColor4ubv(data->actCol);
2670 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2674 col = data->baseCol;
2676 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2678 return DM_DRAW_OPTION_SKIP;
2682 return DM_DRAW_OPTION_NORMAL;
2685 return DM_DRAW_OPTION_SKIP;
2688 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2689 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2691 drawDMEdgesSel_userData data;
2693 data.baseCol = baseCol;
2694 data.selCol = selCol;
2695 data.actCol = actCol;
2697 data.eed_act = eed_act;
2698 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2702 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2704 if (BM_elem_flag_test(BM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2705 return DM_DRAW_OPTION_SKIP;
2707 return DM_DRAW_OPTION_NORMAL;
2710 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2712 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em->bm);
2715 /* Draw edges with color interpolated based on selection */
2716 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2718 drawDMEdgesSelInterp_userData *data = userData;
2719 if (BM_elem_flag_test(BM_edge_at_index(data->bm, index), BM_ELEM_HIDDEN))
2720 return DM_DRAW_OPTION_SKIP;
2722 return DM_DRAW_OPTION_NORMAL;
2724 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2726 drawDMEdgesSelInterp_userData *data = userData;
2727 BMEdge *eed = BM_edge_at_index(data->bm, index);
2728 unsigned char **cols = userData;
2729 unsigned int col0_id = (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1;
2730 unsigned int col1_id = (BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1;
2731 unsigned char *col0 = cols[col0_id];
2732 unsigned char *col1 = cols[col1_id];
2733 unsigned char *col_pt;
2735 if (col0_id == col1_id) {
2738 else if (t == 0.0f) {
2741 else if (t == 1.0f) {
2745 unsigned char col_blend[4];
2746 interp_v4_v4v4_uchar(col_blend, col0, col1, t);
2747 glColor4ubv(col_blend);
2748 data->lastCol = NULL;
2752 if (data->lastCol != col_pt) {
2753 data->lastCol = col_pt;
2754 glColor4ubv(col_pt);
2758 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2760 drawDMEdgesSelInterp_userData data;
2762 data.baseCol = baseCol;
2763 data.selCol = selCol;
2764 data.lastCol = NULL;
2766 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, &data);
2769 static void bm_color_from_weight(float col[3], BMVert *vert, drawDMEdgesWeightInterp_userData *data)
2771 MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, data->cd_dvert_offset);
2772 float weight = defvert_find_weight(dvert, data->vgroup_index);
2774 if ((weight == 0.0f) &&
2775 ((data->weight_user == OB_DRAW_GROUPUSER_ACTIVE) ||
2776 ((data->weight_user == OB_DRAW_GROUPUSER_ALL) && defvert_is_weight_zero(dvert, data->defgroup_tot))))
2778 copy_v3_v3(col, data->alert_color);
2781 weight_to_rgb(col, weight);
2785 static void draw_dm_edges_nop_interp__setDrawInterpOptions(void *UNUSED(userData), int UNUSED(index), float UNUSED(t))
2790 static void draw_dm_edges_weight_interp__setDrawInterpOptions(void *userData, int index, float t)
2792 drawDMEdgesWeightInterp_userData *data = userData;
2793 BMEdge *eed = BM_edge_at_index(data->bm, index);
2797 bm_color_from_weight(col, eed->v1, data);
2799 else if (t == 1.0f) {
2800 bm_color_from_weight(col, eed->v2, data);
2806 bm_color_from_weight(col_v1, eed->v1, data);
2807 bm_color_from_weight(col_v2, eed->v2, data);
2808 interp_v3_v3v3(col, col_v1, col_v2, t);
2814 static void draw_dm_edges_weight_interp(BMEditMesh *em, DerivedMesh *dm, const char weight_user)
2816 drawDMEdgesWeightInterp_userData data;
2817 Object *ob = em->ob;
2820 data.cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2821 data.defgroup_tot = BLI_listbase_count(&ob->defbase);
2822 data.vgroup_index = ob->actdef - 1;
2823 data.weight_user = weight_user;
2824 UI_GetThemeColor3fv(TH_VERTEX_UNREFERENCED, data.alert_color);
2826 if ((data.vgroup_index != -1) && (data.cd_dvert_offset != -1)) {
2828 dm->drawMappedEdgesInterp(
2830 draw_dm_edges_sel_interp__setDrawOptions,
2831 draw_dm_edges_weight_interp__setDrawInterpOptions,
2833 glDisable(GL_BLEND);
2838 if (data.weight_user == OB_DRAW_GROUPUSER_NONE) {
2839 weight_to_rgb(col, 0.0f);
2842 copy_v3_v3(col, data.alert_color);
2846 dm->drawMappedEdgesInterp(
2848 draw_dm_edges_sel_interp__setDrawOptions,
2849 draw_dm_edges_nop_interp__setDrawInterpOptions,
2855 static bool draw_dm_edges_weight_check(Mesh *me, View3D *v3d)
2857 if (me->drawflag & ME_DRAWEIGHT) {
2858 if ((v3d->drawtype == OB_WIRE) ||
2859 (v3d->flag2 & V3D_SOLID_MATCAP) ||
2860 ((v3d->flag2 & V3D_OCCLUDE_WIRE) && (v3d->drawtype > OB_WIRE)))
2869 /* Draw only seam edges */
2870 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2872 BMEdge *eed = BM_edge_at_index(userData, index);
2874 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
2875 return DM_DRAW_OPTION_NORMAL;
2877 return DM_DRAW_OPTION_SKIP;
2880 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2882 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em->bm);
2885 /* Draw only sharp edges */
2886 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2888 BMEdge *eed = BM_edge_at_index(userData, index);
2890 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
2891 return DM_DRAW_OPTION_NORMAL;
2893 return DM_DRAW_OPTION_SKIP;
2896 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2898 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em->bm);
2901 #ifdef WITH_FREESTYLE
2903 static int draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed)
2905 FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
2908 return (fed->flag & FREESTYLE_EDGE_MARK) != 0;
2911 /* Draw only Freestyle feature edges */
2912 static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
2914 BMEdge *eed = BM_edge_at_index(userData, index);
2916 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && draw_dm_test_freestyle_edge_mark(userData, eed))
2917 return DM_DRAW_OPTION_NORMAL;
2919 return DM_DRAW_OPTION_SKIP;
2922 static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
2924 dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em->bm);
2927 static int draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa)
2929 FreestyleFace *ffa = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
2932 return (ffa->flag & FREESTYLE_FACE_MARK) != 0;
2937 /* Draw loop normals. */
2938 static void draw_dm_loop_normals__mapFunc(void *userData, int vertex_index, int face_index,
2939 const float co[3], const float no[3])
2942 const drawDMNormal_userData *data = userData;
2943 const BMVert *eve = BM_vert_at_index(data->bm, vertex_index);
2944 const BMFace *efa = BM_face_at_index(data->bm, face_index);
2947 if (!(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) || BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) {
2948 if (!data->uniform_scale) {
2949 mul_v3_m3v3(vec, (float(*)[3])data->tmat, no);
2951 mul_m3_v3((float(*)[3])data->imat, vec);
2954 copy_v3_v3(vec, no);
2956 mul_v3_fl(vec, data->normalsize);
2964 static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2966 drawDMNormal_userData data;
2969 data.normalsize = scene->toolsettings->normalsize;
2971 calcDrawDMNormalScale(ob, &data);
2974 dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2978 /* Draw faces with color set based on selection
2979 * return 2 for the active face so it renders with stipple enabled */
2980 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
2982 drawDMFacesSel_userData *data = userData;
2983 BMFace *efa = BM_face_at_index(data->bm, index);
2986 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2987 if (efa == data->efa_act) {
2988 glColor4ubv(data->cols[2]);
2989 return DM_DRAW_OPTION_STIPPLE;
2992 #ifdef WITH_FREESTYLE
2993 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
2995 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2998 return DM_DRAW_OPTION_SKIP;
3000 return DM_DRAW_OPTION_NORMAL;
3003 return DM_DRAW_OPTION_SKIP;
3006 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
3009 drawDMFacesSel_userData *data = userData;
3014 unsigned char *col, *next_col;
3016 i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[index] : index;
3017 efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
3018 i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[next_index] : next_index;
3019 next_efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
3021 if (ELEM(NULL, efa, next_efa))
3024 if (efa == next_efa)
3027 if (efa == data->efa_act || next_efa == data->efa_act)
3030 #ifdef WITH_FREESTYLE
3031 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
3032 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];
3034 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
3035 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
3038 if (col[3] == 0 || next_col[3] == 0)
3041 return col == next_col;
3044 /* also draws the active face */
3045 #ifdef WITH_FREESTYLE
3046 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
3047 unsigned char *selCol, unsigned char *actCol, unsigned char *markCol, BMFace *efa_act)
3049 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
3050 unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
3053 drawDMFacesSel_userData data;
3055 data.cols[0] = baseCol;
3057 data.cols[1] = selCol;
3058 data.cols[2] = actCol;
3059 #ifdef WITH_FREESTYLE
3060 data.cols[3] = markCol;
3062 data.efa_act = efa_act;
3064 data.orig_index_mp_to_orig = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
3066 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, NULL, draw_dm_faces_sel__compareDrawOptions, &data, 0);
3069 static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
3071 drawDMLayer_userData *data = userData;
3072 BMesh *bm = data->bm;
3073 BMEdge *eed = BM_edge_at_index(bm, index);
3075 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
3076 const float crease = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
3077 if (crease != 0.0f) {
3078 UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_CREASE, crease);
3079 return DM_DRAW_OPTION_NORMAL;
3082 return DM_DRAW_OPTION_SKIP;
3084 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
3086 drawDMLayer_userData data;
3089 data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
3091 if (data.cd_layer_offset != -1) {
3093 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
3098 static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
3100 drawDMLayer_userData *data = userData;
3101 BMesh *bm = data->bm;
3102 BMEdge *eed = BM_edge_at_index(bm, index);
3104 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
3105 const float bweight = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
3106 if (bweight != 0.0f) {
3107 UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, bweight);
3108 return DM_DRAW_OPTION_NORMAL;
3111 return DM_DRAW_OPTION_SKIP;
3113 static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
3114 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
3116 drawDMLayer_userData *data = userData;
3117 BMesh *bm = data->bm;
3118 BMVert *eve = BM_vert_at_index(bm, index);
3120 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
3121 const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
3122 if (bweight != 0.0f) {
3123 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, bweight);
3128 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
3130 ToolSettings *ts = scene->toolsettings;
3132 if (ts->selectmode & SCE_SELECT_VERTEX) {
3133 drawDMLayer_userData data;
3136 data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT);
3138 if (data.cd_layer_offset != -1) {
3139 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
3140 bglBegin(GL_POINTS);
3141 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
3146 drawDMLayer_userData data;
3149 data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
3151 if (data.cd_layer_offset != -1) {
3153 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
3159 static int draw_dm_override_material_color(int UNUSED(nr), void *UNUSED(attribs))
3164 /* Second section of routines: Combine first sets to form fancy
3165 * drawing routines (for example rendering twice to get overlays).
3167 * Also includes routines that are basic drawing but are too
3168 * specialized to be split out (like drawing creases or measurements).
3171 /* EditMesh drawing routines*/
3173 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
3174 BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act,
3177 ToolSettings *ts = scene->toolsettings;
3180 if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */
3182 for (sel = 0; sel < 2; sel++) {
3183 unsigned char col[4], fcol[4];
3186 UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
3187 UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE_EDIT, fcol);
3189 for (pass = 0; pass < 2; pass++) {
3190 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
3191 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
3194 if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
3195 glDisable(GL_DEPTH_TEST);
3203 size = (size > 2.1f ? size / 2.0f : size);
3204 fsize = (fsize > 2.1f ? fsize / 2.0f : fsize);
3205 col[3] = fcol[3] = 100;
3208 col[3] = fcol[3] = 255;
3211 if (ts->selectmode & SCE_SELECT_VERTEX) {
3214 draw_dm_verts(em, cageDM, sel, eve_act, rv3d);