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_mf_to_mpoly;
180 const int *orig_index_mp_to_orig;
181 } drawDMFacesSel_userData;
183 typedef struct drawDMNormal_userData {
189 } drawDMNormal_userData;
191 typedef struct drawMVertOffset_userData {
194 } drawMVertOffset_userData;
196 typedef struct drawDMLayer_userData {
199 } drawDMLayer_userData;
201 typedef struct drawBMOffset_userData {
204 } drawBMOffset_userData;
206 typedef struct drawBMSelect_userData {
209 } drawBMSelect_userData;
211 static void draw_bounding_volume(Object *ob, char type);
213 static void drawcube_size(float size);
214 static void drawcircle_size(float size);
215 static void draw_empty_sphere(float size);
216 static void draw_empty_cone(float size);
217 static void draw_box(float vec[8][3], bool solid);
219 static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
221 float col_wire[3], col_bg[3], col[3];
223 rgb_uchar_to_float(col_wire, ob_wire_col);
225 UI_GetThemeColor3fv(theme_id, col_bg);
226 interp_v3_v3v3(col, col_bg, col_wire, fac);
230 /* this condition has been made more complex since editmode can draw textures */
231 bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
233 /* texture and material draw modes */
234 if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
239 if ((v3d->drawtype == OB_SOLID) &&
240 (v3d->flag2 & V3D_SOLID_TEX) &&
241 (BKE_scene_use_new_shading_nodes(scene) == false))
246 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) {
253 static bool check_object_draw_editweight(Mesh *me, DerivedMesh *finalDM)
255 if (me->drawflag & ME_DRAWEIGHT) {
256 /* editmesh handles its own weight drawing */
257 if (finalDM->type != DM_TYPE_EDITBMESH) {
265 static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
267 if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
270 if (G.f & G_BACKBUFSEL)
273 if ((vd->flag & V3D_ZBUF_SELECT) == 0)
276 /* if its drawing textures with zbuf sel, then don't draw dots */
277 if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
280 if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
286 /* ************************ */
288 /* check for glsl drawing */
290 bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
292 if (!GPU_glsl_support())
296 if (!check_object_draw_texture(scene, v3d, dt))
298 if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
301 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
304 if (BKE_scene_use_new_shading_nodes(scene))
307 return ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) ||
308 (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 const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
2056 MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
2058 const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
2059 const bool is_stereo3d_cameras = (ob == scene->camera) &&
2060 (scene->r.scemode & R_MULTIVIEW) &&
2061 (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) &&
2062 (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
2064 /* draw data for movie clip set as active for scene */
2066 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, false);
2067 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, true);
2070 #ifdef VIEW3D_CAMERA_BORDER_HACK
2071 if (is_view && !(G.f & G_PICKSEL)) {
2072 if ((dflag & DRAW_CONSTCOLOR) == 0) {
2073 view3d_camera_border_hack_col[0] = ob_wire_col[0];
2074 view3d_camera_border_hack_col[1] = ob_wire_col[1];
2075 view3d_camera_border_hack_col[2] = ob_wire_col[2];
2079 glGetFloatv(GL_CURRENT_COLOR, col);
2080 rgb_float_to_uchar(view3d_camera_border_hack_col, col);
2082 view3d_camera_border_hack_test = true;
2089 scale[0] = 1.0f / len_v3(ob->obmat[0]);
2090 scale[1] = 1.0f / len_v3(ob->obmat[1]);
2091 scale[2] = 1.0f / len_v3(ob->obmat[2]);
2093 BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
2094 asp, shift, &drawsize, vec);
2096 glDisable(GL_LIGHTING);
2097 glDisable(GL_CULL_FACE);
2100 if (!is_stereo3d_cameras)
2101 drawcamera_frame(vec, GL_LINE_LOOP);
2108 /* center point to camera frame */
2109 if (!is_stereo3d_cameras)
2110 drawcamera_framelines(vec, tvec);
2113 tvec[2] = vec[1][2]; /* copy the depth */
2115 /* draw an outline arrow for inactive cameras and filled
2116 * for active cameras. We actually draw both outline+filled
2117 * for active cameras so the wire can be seen side-on */
2118 for (i = 0; i < 2; i++) {
2119 if (i == 0) glBegin(GL_LINE_LOOP);
2120 else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
2123 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
2124 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
2125 glVertex3fv(tvec); /* left */
2127 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
2128 glVertex3fv(tvec); /* right */
2131 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
2132 glVertex3fv(tvec); /* top */
2137 if ((dflag & DRAW_SCENESET) == 0) {
2138 if (cam->flag & (CAM_SHOWLIMITS | CAM_SHOWMIST)) {
2141 /* draw in normalized object matrix space */
2142 copy_m4_m4(nobmat, ob->obmat);
2143 normalize_m4(nobmat);
2146 glLoadMatrixf(rv3d->viewmat);
2147 glMultMatrixf(nobmat);
2149 if (cam->flag & CAM_SHOWLIMITS) {
2150 draw_limit_line(cam->clipsta, cam->clipend, dflag, 0x77FFFF);
2151 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
2152 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
2155 if (cam->flag & CAM_SHOWMIST) {
2156 World *world = scene->world;
2158 draw_limit_line(world->miststa, world->miststa + world->mistdist, dflag, 0xFFFFFF);
2165 /* stereo cameras drawing */
2167 drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
2171 /* flag similar to draw_object() */
2172 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
2173 Object *UNUSED(ob), int UNUSED(flag))
2180 for (j = 0; j < 3; j++) {
2181 vec[2] = 0.25f * j - 0.125f;
2183 glBegin(GL_LINE_LOOP);
2184 for (i = 0; i < 16; i++) {
2185 vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
2186 vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
2192 for (j = 0; j < 4; j++) {
2193 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
2194 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
2195 glBegin(GL_LINE_STRIP);
2196 for (i = 0; i < 3; i++) {
2202 vec[2] = 0.25f * i - 0.125f;
2208 glDisable(GL_BLEND);
2211 static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel)
2213 BPoint *bp = lt->def;
2214 const float *co = dl ? dl->verts : NULL;
2217 const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
2218 UI_ThemeColor(color);
2220 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
2221 bglBegin(GL_POINTS);
2223 for (w = 0; w < lt->pntsw; w++) {
2224 int wxt = (w == 0 || w == lt->pntsw - 1);
2225 for (v = 0; v < lt->pntsv; v++) {
2226 int vxt = (v == 0 || v == lt->pntsv - 1);
2227 for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
2228 int uxt = (u == 0 || u == lt->pntsu - 1);
2229 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
2230 if (bp->hide == 0) {
2231 /* check for active BPoint and ensure selected */
2232 if ((bp == actbp) && (bp->f1 & SELECT)) {
2233 UI_ThemeColor(TH_ACTIVE_VERT);
2234 bglVertex3fv(dl ? co : bp->vec);
2235 UI_ThemeColor(color);
2237 else if ((bp->f1 & SELECT) == sel) {
2238 bglVertex3fv(dl ? co : bp->vec);
2250 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
2252 int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
2256 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
2258 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
2264 glVertex3fv(&dl->verts[index * 3]);
2267 glVertex3fv(lt->def[index].vec);
2271 #ifdef SEQUENCER_DAG_WORKAROUND
2272 static void ensure_curve_cache(Scene *scene, Object *object)
2274 bool need_recalc = object->curve_cache == NULL;
2275 /* Render thread might have freed the curve cache if the
2276 * object is not visible. If the object is also used for
2277 * particles duplication, then render thread might have
2278 * also created curve_cache with only bevel and path
2281 * So check for curve_cache != NULL is not fully correct
2282 * here, we also need to check whether display list is
2285 * The trick below tries to optimize calls to displist
2286 * creation for cases curve is empty. Meaning, if the curve
2287 * is empty (without splines) bevel list would also be empty.
2288 * And the thing is, render thread always leaves bevel list
2289 * in a proper state. So if bevel list is here and display
2290 * list is not we need to make display list.
2292 if (need_recalc == false) {
2293 need_recalc = object->curve_cache->disp.first == NULL &&
2294 object->curve_cache->bev.first != NULL;
2297 switch (object->type) {
2301 BKE_displist_make_curveTypes(scene, object, false);
2304 BKE_displist_make_mball(G.main->eval_ctx, scene, object);
2307 BKE_lattice_modifiers_calc(scene, object);
2314 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
2315 static void drawlattice(View3D *v3d, Object *ob)
2317 Lattice *lt = ob->data;
2320 int actdef_wcol = 0;
2321 const bool is_edit = (lt->editlatt != NULL);
2323 dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS);
2326 lt = lt->editlatt->latt;
2328 UI_ThemeColor(TH_WIRE_EDIT);
2330 if (ob->defbase.first && lt->dvert) {
2331 actdef_wcol = ob->actdef;
2332 glShadeModel(GL_SMOOTH);
2337 for (w = 0; w < lt->pntsw; w++) {
2338 int wxt = (w == 0 || w == lt->pntsw - 1);
2339 for (v = 0; v < lt->pntsv; v++) {
2340 int vxt = (v == 0 || v == lt->pntsv - 1);
2341 for (u = 0; u < lt->pntsu; u++) {
2342 int uxt = (u == 0 || u == lt->pntsu - 1);
2344 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
2345 drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol);
2346 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
2348 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2349 drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol);
2350 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
2352 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2353 drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol);
2354 drawlattice__point(lt, dl, u, v, w, actdef_wcol);
2361 /* restoration for weight colors */
2363 glShadeModel(GL_FLAT);
2366 BPoint *actbp = BKE_lattice_active_point_get(lt);
2368 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2370 lattice_draw_verts(lt, dl, actbp, 0);
2371 lattice_draw_verts(lt, dl, actbp, 1);
2373 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2377 /* ***************** ******************** */
2381 typedef struct drawDMVertSel_userData {
2384 unsigned char *col[3]; /* (base, sel, act) */
2386 } drawDMVertSel_userData;
2388 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
2389 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2391 drawDMVertSel_userData *data = userData;
2392 MVert *mv = &data->mvert[index];
2394 if (!(mv->flag & ME_HIDE)) {
2395 const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
2396 if (sel != data->sel_prev) {
2397 glColor3ubv(data->col[sel]);
2398 data->sel_prev = sel;
2405 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
2407 drawDMVertSel_userData data;
2409 /* TODO define selected color */
2410 unsigned char base_col[3] = {0x0, 0x0, 0x0};
2411 unsigned char sel_col[3] = {0xd8, 0xb8, 0x0};
2412 unsigned char act_col[3] = {0xff, 0xff, 0xff};
2414 data.mvert = me->mvert;
2415 data.active = BKE_mesh_mselect_active_get(me, ME_VSEL);
2416 data.sel_prev = 0xff;
2418 data.col[0] = base_col;
2419 data.col[1] = sel_col;
2420 data.col[2] = act_col;
2423 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
2427 /* ************** DRAW MESH ****************** */
2429 /* First section is all the "simple" draw routines,
2430 * ones that just pass some sort of primitive to GL,
2431 * with perhaps various options to control lighting,
2434 * These routines should not have user interface related
2438 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
2442 copy_m3_m4(obmat, ob->obmat);
2444 data->uniform_scale = is_uniform_scaled_m3(obmat);
2446 if (!data->uniform_scale) {
2447 /* inverted matrix */
2448 invert_m3_m3(data->imat, obmat);
2450 /* transposed inverted matrix */
2451 transpose_m3_m3(data->tmat, data->imat);
2455 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2457 drawDMNormal_userData *data = userData;
2458 BMFace *efa = BM_face_at_index(data->bm, index);
2461 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2462 if (!data->uniform_scale) {
2463 mul_v3_m3v3(n, data->tmat, no);
2465 mul_m3_v3(data->imat, n);
2472 glVertex3f(cent[0] + n[0] * data->normalsize,
2473 cent[1] + n[1] * data->normalsize,
2474 cent[2] + n[2] * data->normalsize);
2478 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2480 drawDMNormal_userData data;
2483 data.normalsize = scene->toolsettings->normalsize;
2485 calcDrawDMNormalScale(ob, &data);
2488 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2492 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2494 drawBMSelect_userData *data = userData;
2495 BMFace *efa = BM_face_at_index(data->bm, index);
2497 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
2498 (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
2503 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select)
2505 drawBMSelect_userData data = {em->bm, select};
2507 bglBegin(GL_POINTS);
2508 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
2512 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])
2514 drawDMNormal_userData *data = userData;
2515 BMVert *eve = BM_vert_at_index(data->bm, index);
2517 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2521 copy_v3_v3(no, no_f);
2524 normal_short_to_float_v3(no, no_s);
2527 if (!data->uniform_scale) {
2528 mul_v3_m3v3(n, data->tmat, no);
2530 mul_m3_v3(data->imat, n);
2537 glVertex3f(co[0] + n[0] * data->normalsize,
2538 co[1] + n[1] * data->normalsize,
2539 co[2] + n[2] * data->normalsize);
2543 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2545 drawDMNormal_userData data;
2548 data.normalsize = scene->toolsettings->normalsize;
2550 calcDrawDMNormalScale(ob, &data);
2553 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2557 /* Draw verts with color set based on selection */
2558 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2559 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2561 drawDMVerts_userData *data = userData;
2562 BMVert *eve = BM_vert_at_index(data->bm, index);
2564 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2565 /* skin nodes: draw a red circle around the root node(s) */
2566 if (data->cd_vskin_offset != -1) {
2567 const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
2568 if (vs->flag & MVERT_SKIN_ROOT) {
2569 float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2572 glColor4ubv(data->th_skin_root);
2573 drawcircball(GL_LINES, co, radius, data->imat);
2575 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2576 bglBegin(GL_POINTS);
2580 /* draw active larger - need to stop/start point drawing for this :/ */
2581 if (eve == data->eve_act) {
2582 glColor4ubv(data->th_editmesh_active);
2586 glPointSize(data->th_vertex_size);
2587 bglBegin(GL_POINTS);
2591 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2592 glPointSize(data->th_vertex_size);
2593 bglBegin(GL_POINTS);
2601 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
2604 drawDMVerts_userData data;
2606 data.eve_act = eve_act;
2609 /* Cache theme values */
2610 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2611 UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2612 UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2613 UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2614 data.th_vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2616 /* For skin root drawing */
2617 data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
2618 /* view-aligned matrix */
2619 mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2620 invert_m4(data.imat);
2622 bglBegin(GL_POINTS);
2623 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
2627 /* Draw edges with color set based on selection */
2628 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2631 drawDMEdgesSel_userData *data = userData;
2634 eed = BM_edge_at_index(data->bm, index);
2636 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2637 if (eed == data->eed_act) {
2638 glColor4ubv(data->actCol);
2641 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2645 col = data->baseCol;
2647 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2649 return DM_DRAW_OPTION_SKIP;
2653 return DM_DRAW_OPTION_NORMAL;
2656 return DM_DRAW_OPTION_SKIP;
2659 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2660 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2662 drawDMEdgesSel_userData data;
2664 data.baseCol = baseCol;
2665 data.selCol = selCol;
2666 data.actCol = actCol;
2668 data.eed_act = eed_act;
2669 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2673 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2675 if (BM_elem_flag_test(BM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2676 return DM_DRAW_OPTION_SKIP;
2678 return DM_DRAW_OPTION_NORMAL;
2681 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2683 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em->bm);
2686 /* Draw edges with color interpolated based on selection */
2687 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2689 drawDMEdgesSelInterp_userData *data = userData;
2690 if (BM_elem_flag_test(BM_edge_at_index(data->bm, index), BM_ELEM_HIDDEN))
2691 return DM_DRAW_OPTION_SKIP;
2693 return DM_DRAW_OPTION_NORMAL;
2695 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2697 drawDMEdgesSelInterp_userData *data = userData;
2698 BMEdge *eed = BM_edge_at_index(data->bm, index);
2699 unsigned char **cols = userData;
2700 unsigned int col0_id = (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1;
2701 unsigned int col1_id = (BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1;
2702 unsigned char *col0 = cols[col0_id];
2703 unsigned char *col1 = cols[col1_id];
2704 unsigned char *col_pt;
2706 if (col0_id == col1_id) {
2709 else if (t == 0.0f) {
2712 else if (t == 1.0f) {
2716 unsigned char col_blend[4];
2717 interp_v4_v4v4_uchar(col_blend, col0, col1, t);
2718 glColor4ubv(col_blend);
2719 data->lastCol = NULL;
2723 if (data->lastCol != col_pt) {
2724 data->lastCol = col_pt;
2725 glColor4ubv(col_pt);
2729 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2731 drawDMEdgesSelInterp_userData data;
2733 data.baseCol = baseCol;
2734 data.selCol = selCol;
2735 data.lastCol = NULL;
2737 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, &data);
2740 static void bm_color_from_weight(float col[3], BMVert *vert, drawDMEdgesWeightInterp_userData *data)
2742 MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, data->cd_dvert_offset);
2743 float weight = defvert_find_weight(dvert, data->vgroup_index);
2745 if ((weight == 0.0f) &&
2746 ((data->weight_user == OB_DRAW_GROUPUSER_ACTIVE) ||
2747 ((data->weight_user == OB_DRAW_GROUPUSER_ALL) && defvert_is_weight_zero(dvert, data->defgroup_tot))))
2749 copy_v3_v3(col, data->alert_color);
2752 weight_to_rgb(col, weight);
2756 static void draw_dm_edges_nop_interp__setDrawInterpOptions(void *UNUSED(userData), int UNUSED(index), float UNUSED(t))
2761 static void draw_dm_edges_weight_interp__setDrawInterpOptions(void *userData, int index, float t)
2763 drawDMEdgesWeightInterp_userData *data = userData;
2764 BMEdge *eed = BM_edge_at_index(data->bm, index);
2768 bm_color_from_weight(col, eed->v1, data);
2770 else if (t == 1.0f) {
2771 bm_color_from_weight(col, eed->v2, data);
2777 bm_color_from_weight(col_v1, eed->v1, data);
2778 bm_color_from_weight(col_v2, eed->v2, data);
2779 interp_v3_v3v3(col, col_v1, col_v2, t);
2785 static void draw_dm_edges_weight_interp(BMEditMesh *em, DerivedMesh *dm, const char weight_user)
2787 drawDMEdgesWeightInterp_userData data;
2788 Object *ob = em->ob;
2791 data.cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2792 data.defgroup_tot = BLI_listbase_count(&ob->defbase);
2793 data.vgroup_index = ob->actdef - 1;
2794 data.weight_user = weight_user;
2795 UI_GetThemeColor3fv(TH_VERTEX_UNREFERENCED, data.alert_color);
2797 if ((data.vgroup_index != -1) && (data.cd_dvert_offset != -1)) {
2799 dm->drawMappedEdgesInterp(
2801 draw_dm_edges_sel_interp__setDrawOptions,
2802 draw_dm_edges_weight_interp__setDrawInterpOptions,
2804 glDisable(GL_BLEND);
2809 if (data.weight_user == OB_DRAW_GROUPUSER_NONE) {
2810 weight_to_rgb(col, 0.0f);
2813 copy_v3_v3(col, data.alert_color);
2817 dm->drawMappedEdgesInterp(
2819 draw_dm_edges_sel_interp__setDrawOptions,
2820 draw_dm_edges_nop_interp__setDrawInterpOptions,
2826 static bool draw_dm_edges_weight_check(Mesh *me, View3D *v3d)
2828 if (me->drawflag & ME_DRAWEIGHT) {
2829 if ((v3d->drawtype == OB_WIRE) ||
2830 (v3d->flag2 & V3D_SOLID_MATCAP) ||
2831 ((v3d->flag2 & V3D_OCCLUDE_WIRE) && (v3d->drawtype > OB_WIRE)))
2840 /* Draw only seam edges */
2841 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2843 BMEdge *eed = BM_edge_at_index(userData, index);
2845 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
2846 return DM_DRAW_OPTION_NORMAL;
2848 return DM_DRAW_OPTION_SKIP;
2851 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2853 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em->bm);
2856 /* Draw only sharp edges */
2857 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2859 BMEdge *eed = BM_edge_at_index(userData, index);
2861 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
2862 return DM_DRAW_OPTION_NORMAL;
2864 return DM_DRAW_OPTION_SKIP;
2867 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2869 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em->bm);
2872 #ifdef WITH_FREESTYLE
2874 static int draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed)
2876 FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
2879 return (fed->flag & FREESTYLE_EDGE_MARK) != 0;
2882 /* Draw only Freestyle feature edges */
2883 static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
2885 BMEdge *eed = BM_edge_at_index(userData, index);
2887 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && draw_dm_test_freestyle_edge_mark(userData, eed))
2888 return DM_DRAW_OPTION_NORMAL;
2890 return DM_DRAW_OPTION_SKIP;
2893 static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
2895 dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em->bm);
2898 static int draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa)
2900 FreestyleFace *ffa = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
2903 return (ffa->flag & FREESTYLE_FACE_MARK) != 0;
2908 /* Draw loop normals. */
2909 static void draw_dm_loop_normals__mapFunc(void *userData, int vertex_index, int face_index,
2910 const float co[3], const float no[3])
2913 const drawDMNormal_userData *data = userData;
2914 const BMVert *eve = BM_vert_at_index(data->bm, vertex_index);
2915 const BMFace *efa = BM_face_at_index(data->bm, face_index);
2918 if (!(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) || BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) {
2919 if (!data->uniform_scale) {
2920 mul_v3_m3v3(vec, (float(*)[3])data->tmat, no);
2922 mul_m3_v3((float(*)[3])data->imat, vec);
2925 copy_v3_v3(vec, no);
2927 mul_v3_fl(vec, data->normalsize);
2935 static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2937 drawDMNormal_userData data;
2940 data.normalsize = scene->toolsettings->normalsize;
2942 calcDrawDMNormalScale(ob, &data);
2945 dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2949 /* Draw faces with color set based on selection
2950 * return 2 for the active face so it renders with stipple enabled */
2951 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
2953 drawDMFacesSel_userData *data = userData;
2954 BMFace *efa = BM_face_at_index(data->bm, index);
2957 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2958 if (efa == data->efa_act) {
2959 glColor4ubv(data->cols[2]);
2960 return DM_DRAW_OPTION_STIPPLE;
2963 #ifdef WITH_FREESTYLE
2964 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
2966 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2969 return DM_DRAW_OPTION_SKIP;
2971 return DM_DRAW_OPTION_NORMAL;
2974 return DM_DRAW_OPTION_SKIP;
2977 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2980 drawDMFacesSel_userData *data = userData;
2985 unsigned char *col, *next_col;
2987 if (!data->orig_index_mf_to_mpoly)
2990 i = DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, index);
2991 efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
2992 i = DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, next_index);
2993 next_efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
2995 if (ELEM(NULL, efa, next_efa))
2998 if (efa == next_efa)
3001 if (efa == data->efa_act || next_efa == data->efa_act)
3004 #ifdef WITH_FREESTYLE
3005 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
3006 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];
3008 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
3009 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
3012 if (col[3] == 0 || next_col[3] == 0)
3015 return col == next_col;
3018 /* also draws the active face */
3019 #ifdef WITH_FREESTYLE
3020 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
3021 unsigned char *selCol, unsigned char *actCol, unsigned char *markCol, BMFace *efa_act)
3023 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
3024 unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
3027 drawDMFacesSel_userData data;
3029 data.cols[0] = baseCol;
3031 data.cols[1] = selCol;
3032 data.cols[2] = actCol;
3033 #ifdef WITH_FREESTYLE
3034 data.cols[3] = markCol;
3036 data.efa_act = efa_act;
3038 data.orig_index_mf_to_mpoly = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
3039 data.orig_index_mp_to_orig = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
3040 if ((data.orig_index_mf_to_mpoly && data.orig_index_mp_to_orig) == false) {
3041 data.orig_index_mf_to_mpoly = data.orig_index_mp_to_orig = NULL;
3044 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
3047 static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
3049 drawDMLayer_userData *data = userData;
3050 BMesh *bm = data->bm;
3051 BMEdge *eed = BM_edge_at_index(bm, index);
3053 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
3054 const float crease = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
3055 if (crease != 0.0f) {
3056 UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_CREASE, crease);
3057 return DM_DRAW_OPTION_NORMAL;
3060 return DM_DRAW_OPTION_SKIP;
3062 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
3064 drawDMLayer_userData data;
3067 data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
3069 if (data.cd_layer_offset != -1) {
3071 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
3076 static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
3078 drawDMLayer_userData *data = userData;
3079 BMesh *bm = data->bm;
3080 BMEdge *eed = BM_edge_at_index(bm, index);
3082 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
3083 const float bweight = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
3084 if (bweight != 0.0f) {
3085 UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, bweight);
3086 return DM_DRAW_OPTION_NORMAL;
3089 return DM_DRAW_OPTION_SKIP;
3091 static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
3092 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
3094 drawDMLayer_userData *data = userData;
3095 BMesh *bm = data->bm;
3096 BMVert *eve = BM_vert_at_index(bm, index);
3098 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
3099 const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
3100 if (bweight != 0.0f) {
3101 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, bweight);
3106 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
3108 ToolSettings *ts = scene->toolsettings;
3110 if (ts->selectmode & SCE_SELECT_VERTEX) {
3111 drawDMLayer_userData data;
3114 data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT);
3116 if (data.cd_layer_offset != -1) {
3117 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
3118 bglBegin(GL_POINTS);
3119 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
3124 drawDMLayer_userData data;
3127 data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
3129 if (data.cd_layer_offset != -1) {
3131 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
3137 static int draw_dm_override_material_color(int UNUSED(nr), void *UNUSED(attribs))
3142 /* Second section of routines: Combine first sets to form fancy
3143 * drawing routines (for example rendering twice to get overlays).