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
34 #include "MEM_guardedalloc.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_curve_types.h"
38 #include "DNA_constraint_types.h" // for drawing constraint
39 #include "DNA_lamp_types.h"
40 #include "DNA_lattice_types.h"
41 #include "DNA_material_types.h"
42 #include "DNA_mesh_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_meta_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_smoke_types.h"
47 #include "DNA_speaker_types.h"
48 #include "DNA_world_types.h"
49 #include "DNA_armature_types.h"
50 #include "DNA_object_types.h"
52 #include "BLI_utildefines.h"
53 #include "BLI_blenlib.h"
55 #include "BLI_edgehash.h"
57 #include "BLI_utildefines.h"
59 #include "BKE_anim.h" //for the where_on_path function
60 #include "BKE_armature.h"
61 #include "BKE_camera.h"
62 #include "BKE_constraint.h" // for the get_constraint_target function
63 #include "BKE_curve.h"
64 #include "BKE_DerivedMesh.h"
65 #include "BKE_deform.h"
66 #include "BKE_displist.h"
68 #include "BKE_global.h"
69 #include "BKE_image.h"
71 #include "BKE_lattice.h"
73 #include "BKE_material.h"
74 #include "BKE_mball.h"
75 #include "BKE_modifier.h"
76 #include "BKE_object.h"
77 #include "BKE_paint.h"
78 #include "BKE_particle.h"
79 #include "BKE_pointcache.h"
80 #include "BKE_scene.h"
82 #include "BKE_movieclip.h"
83 #include "BKE_tracking.h"
85 #include "BKE_tessmesh.h"
87 #include "smoke_API.h"
89 #include "IMB_imbuf.h"
90 #include "IMB_imbuf_types.h"
93 #include "BIF_glutil.h"
96 #include "GPU_extensions.h"
99 #include "ED_particle.h"
100 #include "ED_screen.h"
101 #include "ED_sculpt.h"
102 #include "ED_types.h"
103 #include "ED_curve.h" /* for curve_editnurbs */
105 #include "UI_resources.h"
108 #include "wm_subwindow.h"
111 #include "view3d_intern.h" // own include
113 typedef enum eWireDrawMode {
116 OBDRAW_WIRE_ON_DEPTH = 2
119 /* user data structures for derived mesh callbacks */
120 typedef struct foreachScreenVert_userData {
121 void (*func)(void *userData, BMVert *eve, int x, int y, int index);
124 eV3DClipTest clipVerts;
125 } foreachScreenVert_userData;
127 typedef struct foreachScreenEdge_userData {
128 void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index);
131 rcti win_rect; /* copy of: vc.ar->winx/winy, use for faster tests, minx/y will always be 0 */
132 eV3DClipTest clipVerts;
133 } foreachScreenEdge_userData;
135 typedef struct foreachScreenFace_userData {
136 void (*func)(void *userData, BMFace *efa, int x, int y, int index);
139 } foreachScreenFace_userData;
141 typedef struct drawDMVerts_userData {
142 BMEditMesh *em; /* BMESH BRANCH ONLY */
147 /* cached theme values */
148 unsigned char th_editmesh_active[4];
149 unsigned char th_vertex_select[4];
150 unsigned char th_vertex[4];
151 unsigned char th_skin_root[4];
152 float th_vertex_size;
154 /* for skin node drawing */
157 } drawDMVerts_userData;
159 typedef struct drawDMEdgesSel_userData {
160 BMEditMesh *em; /* BMESH BRANCH ONLY */
162 unsigned char *baseCol, *selCol, *actCol;
164 } drawDMEdgesSel_userData;
166 typedef struct drawDMFacesSel_userData {
167 unsigned char *cols[3];
169 DerivedMesh *dm; /* BMESH BRANCH ONLY */
170 BMEditMesh *em; /* BMESH BRANCH ONLY */
174 } drawDMFacesSel_userData;
176 typedef struct drawDMNormal_userData {
182 } drawDMNormal_userData;
184 typedef struct bbsObmodeMeshVerts_userData {
187 } bbsObmodeMeshVerts_userData;
189 static void draw_bounding_volume(Scene *scene, Object *ob, char type);
191 static void drawcube_size(float size);
192 static void drawcircle_size(float size);
193 static void draw_empty_sphere(float size);
194 static void draw_empty_cone(float size);
196 /* this condition has been made more complex since editmode can draw textures */
197 static int check_object_draw_texture(Scene *scene, View3D *v3d, int drawtype)
199 /* texture and material draw modes */
200 if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID)
204 if (v3d->drawtype == OB_SOLID && (v3d->flag2 & V3D_SOLID_TEX) && !BKE_scene_use_new_shading_nodes(scene))
210 static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
212 if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
215 if (G.f & G_BACKBUFSEL)
218 if ((vd->flag & V3D_ZBUF_SELECT) == 0)
221 /* if its drawing textures with zbuf sel, then don't draw dots */
222 if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
225 if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
231 /* ************* only use while object drawing **************
232 * or after running ED_view3d_init_mats_rv3d
234 static void view3d_project_short_clip(ARegion *ar, const float vec[3], short adr[2], int is_local)
236 RegionView3D *rv3d = ar->regiondata;
237 float fx, fy, vec4[4];
241 /* clipplanes in eye space */
242 if (rv3d->rflag & RV3D_CLIPPING) {
243 if (ED_view3d_clipping_test(rv3d, vec, is_local))
247 copy_v3_v3(vec4, vec);
250 mul_m4_v4(rv3d->persmatob, vec4);
252 /* clipplanes in window space */
253 if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */
254 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
256 if (fx > 0 && fx < ar->winx) {
258 fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
260 if (fy > 0.0f && fy < (float)ar->winy) {
261 adr[0] = (short)floorf(fx);
262 adr[1] = (short)floorf(fy);
268 /* BMESH NOTE: this function is unused in bmesh only */
270 /* only use while object drawing */
271 static void UNUSED_FUNCTION(view3d_project_short_noclip) (ARegion * ar, const float vec[3], short adr[2])
273 RegionView3D *rv3d = ar->regiondata;
274 float fx, fy, vec4[4];
278 copy_v3_v3(vec4, vec);
281 mul_m4_v4(rv3d->persmatob, vec4);
283 if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */
284 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
286 if (fx > -32700 && fx < 32700) {
288 fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
290 if (fy > -32700.0f && fy < 32700.0f) {
291 adr[0] = (short)floorf(fx);
292 adr[1] = (short)floorf(fy);
298 /* same as view3d_project_short_clip but use persmat instead of persmatob for projection */
299 static void view3d_project_short_clip_persmat(ARegion *ar, const float vec[3], short adr[2], int is_local)
301 RegionView3D *rv3d = ar->regiondata;
302 float fx, fy, vec4[4];
306 /* clipplanes in eye space */
307 if (rv3d->rflag & RV3D_CLIPPING) {
308 if (ED_view3d_clipping_test(rv3d, vec, is_local))
312 copy_v3_v3(vec4, vec);
315 mul_m4_v4(rv3d->persmat, vec4);
317 /* clipplanes in window space */
318 if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */
319 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
321 if (fx > 0 && fx < ar->winx) {
323 fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
325 if (fy > 0.0f && fy < (float)ar->winy) {
326 adr[0] = (short)floorf(fx);
327 adr[1] = (short)floorf(fy);
332 /* ************************ */
334 /* check for glsl drawing */
336 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
338 if (!GPU_glsl_support())
342 if (!check_object_draw_texture(scene, v3d, dt))
344 if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
346 if (BKE_scene_use_new_shading_nodes(scene))
349 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
352 static int check_alpha_pass(Base *base)
354 if (base->flag & OB_FROMDUPLI)
360 return (base->object->dtx & OB_DRAWTRANSP);
364 static unsigned int colortab[24] =
365 {0x0, 0xFF88FF, 0xFFBBFF,
366 0x403000, 0xFFFF88, 0xFFFFBB,
367 0x104040, 0x66CCCC, 0x77CCCC,
368 0x104010, 0x55BB55, 0x66FF66,
372 static float cube[8][3] = {
383 /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
384 /* 32 values of sin function (still same result!) */
385 #define CIRCLE_RESOL 32
387 static const float sinval[CIRCLE_RESOL] = {
422 /* 32 values of cos function (still same result!) */
423 static const float cosval[CIRCLE_RESOL] = {
458 static void draw_xyz_wire(const float c[3], float size, int axis)
460 float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
461 float dim = size * 0.1f;
462 float dx[3], dy[3], dz[3];
464 dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
465 dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
466 dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
472 /* bottom left to top right */
473 sub_v3_v3v3(v1, c, dx);
475 add_v3_v3v3(v2, c, dx);
481 /* top left to bottom right */
494 /* bottom left to top right */
495 mul_v3_fl(dx, 0.75f);
496 sub_v3_v3v3(v1, c, dx);
498 add_v3_v3v3(v2, c, dx);
504 /* top left to center */
515 glBegin(GL_LINE_STRIP);
517 /* start at top left */
518 sub_v3_v3v3(v1, c, dx);
519 add_v3_v3v3(v1, c, dz);
544 void drawaxes(float size, char drawtype)
547 float v1[3] = {0.0, 0.0, 0.0};
548 float v2[3] = {0.0, 0.0, 0.0};
549 float v3[3] = {0.0, 0.0, 0.0};
554 for (axis = 0; axis < 3; axis++) {
562 /* reset v1 & v2 to zero */
563 v1[axis] = v2[axis] = 0.0f;
568 case OB_SINGLE_ARROW:
571 /* in positive z direction only */
578 glBegin(GL_TRIANGLES);
580 v2[0] = size * 0.035f; v2[1] = size * 0.035f;
581 v3[0] = size * -0.035f; v3[1] = size * 0.035f;
582 v2[2] = v3[2] = size * 0.75f;
584 for (axis = 0; axis < 4; axis++) {
607 drawcircle_size(size);
610 case OB_EMPTY_SPHERE:
611 draw_empty_sphere(size);
615 draw_empty_cone(size);
621 for (axis = 0; axis < 3; axis++) {
622 const int arrow_axis = (axis == 0) ? 1 : 0;
630 v1[axis] = size * 0.85f;
631 v1[arrow_axis] = -size * 0.08f;
635 v1[arrow_axis] = size * 0.08f;
641 v2[axis] += size * 0.125f;
643 draw_xyz_wire(v2, size, axis);
646 /* reset v1 & v2 to zero */
647 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
655 /* Function to draw an Image on a empty Object */
656 static void draw_empty_image(Object *ob)
658 Image *ima = (Image *)ob->data;
659 ImBuf *ibuf = ima ? BKE_image_get_ibuf(ima, NULL) : NULL;
661 float scale, ofs_x, ofs_y, sca_x, sca_y;
664 if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
665 IMB_rect_from_float(ibuf);
668 /* Get the buffer dimensions so we can fallback to fake ones */
669 if (ibuf && ibuf->rect) {
678 /* Get the image aspect even if the buffer is invalid */
680 if (ima->aspx > ima->aspy) {
682 sca_y = ima->aspy / ima->aspx;
684 else if (ima->aspx < ima->aspy) {
685 sca_x = ima->aspx / ima->aspy;
698 /* Calculate the scale center based on objects origin */
699 ofs_x = ob->ima_ofs[0] * ima_x;
700 ofs_y = ob->ima_ofs[1] * ima_y;
702 glMatrixMode(GL_MODELVIEW);
705 /* Make sure we are drawing at the origin */
706 glTranslatef(0.0f, 0.0f, 0.0f);
708 /* Calculate Image scale */
709 scale = (ob->empty_drawsize / (float)MAX2(ima_x * sca_x, ima_y * sca_y));
711 /* Set the object scale */
712 glScalef(scale * sca_x, scale * sca_y, 1.0f);
714 if (ibuf && ibuf->rect) {
715 /* Setup GL params */
717 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
719 /* Use the object color and alpha */
722 /* Draw the Image on the screen */
723 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
724 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
729 UI_ThemeColor((ob->flag & SELECT) ? TH_SELECT : TH_WIRE);
731 /* Calculate the outline vertex positions */
732 glBegin(GL_LINE_LOOP);
733 glVertex2f(ofs_x, ofs_y);
734 glVertex2f(ofs_x + ima_x, ofs_y);
735 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
736 glVertex2f(ofs_x, ofs_y + ima_y);
739 /* Reset GL settings */
740 glMatrixMode(GL_MODELVIEW);
744 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[][4])
747 float *viter = (float *)verts;
750 mul_v3_v3fl(vx, tmat[0], rad);
751 mul_v3_v3fl(vy, tmat[1], rad);
753 for (a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
754 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
755 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
756 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
760 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
762 float verts[CIRCLE_RESOL][3];
764 circball_array_fill(verts, cent, rad, tmat);
766 glEnableClientState(GL_VERTEX_ARRAY);
767 glVertexPointer(3, GL_FLOAT, 0, verts);
768 glDrawArrays(mode, 0, CIRCLE_RESOL);
769 glDisableClientState(GL_VERTEX_ARRAY);
772 /* circle for object centers, special_color is for library or ob users */
773 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
775 const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
776 float verts[CIRCLE_RESOL][3];
778 /* using gldepthfunc guarantees that it does write z values,
779 * but not checks for it, so centers remain visible independent order of drawing */
780 if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
784 if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
786 else glColor4ub(0x55, 0xCC, 0xCC, 155);
789 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
790 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
791 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
794 circball_array_fill(verts, co, size, rv3d->viewinv);
796 /* enable vertex array */
797 glEnableClientState(GL_VERTEX_ARRAY);
798 glVertexPointer(3, GL_FLOAT, 0, verts);
800 /* 1. draw filled, blended polygon */
801 glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
803 /* 2. draw outline */
804 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
805 glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
808 glDisableClientState(GL_VERTEX_ARRAY);
812 if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
815 /* *********** text drawing for object/particles/armature ************* */
816 static ListBase CachedText[3];
817 static int CachedTextLevel = 0;
819 typedef struct ViewCachedString {
820 struct ViewCachedString *next, *prev;
830 /* str is allocated past the end */
833 void view3d_cached_text_draw_begin(void)
835 ListBase *strings = &CachedText[CachedTextLevel];
836 strings->first = strings->last = NULL;
840 void view3d_cached_text_draw_add(const float co[3],
842 short xoffs, short flag,
843 const unsigned char col[4])
845 int alloc_len = strlen(str) + 1;
846 ListBase *strings = &CachedText[CachedTextLevel - 1];
847 /* TODO, replace with more efficient malloc, perhaps memarena per draw? */
848 ViewCachedString *vos = MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
850 BLI_addtail(strings, vos);
851 copy_v3_v3(vos->vec, co);
852 vos->col.pack = *((int *)col);
855 vos->str_len = alloc_len - 1;
857 /* allocate past the end */
858 memcpy(++vos, str, alloc_len);
861 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
863 RegionView3D *rv3d = ar->regiondata;
864 ListBase *strings = &CachedText[CachedTextLevel - 1];
865 ViewCachedString *vos;
868 /* project first and test */
869 for (vos = strings->first; vos; vos = vos->next) {
870 if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
871 mul_m4_v3(mat, vos->vec);
873 if (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE)
874 view3d_project_short_clip_persmat(ar, vos->vec, vos->sco, (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0);
876 view3d_project_short_clip(ar, vos->vec, vos->sco, (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0);
878 if (vos->sco[0] != IS_CLIPPED)
883 int col_pack_prev = 0;
886 bglMats mats; /* ZBuffer depth vars */
893 if (rv3d->rflag & RV3D_CLIPPING) {
894 ED_view3d_clipping_disable();
897 glMatrixMode(GL_PROJECTION);
899 glMatrixMode(GL_MODELVIEW);
901 ED_region_pixelspace(ar);
904 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
910 for (vos = strings->first; vos; vos = vos->next) {
911 /* too slow, reading opengl info while drawing is very bad,
912 * better to see if we can use the zbuffer while in pixel space - campbell */
914 if (v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
915 gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
916 glReadPixels(ar->winrct.xmin + vos->mval[0] + vos->xoffs, ar->winrct.ymin + vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
922 if (vos->sco[0] != IS_CLIPPED) {
923 const char *str = (char *)(vos + 1);
925 if (col_pack_prev != vos->col.pack) {
926 glColor3ubv(vos->col.ub);
927 col_pack_prev = vos->col.pack;
930 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
931 BLF_draw_default_ascii :
933 )( (float)vos->sco[0] + vos->xoffs,
935 (depth_write) ? 0.0f : 2.0f,
942 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
946 glMatrixMode(GL_PROJECTION);
948 glMatrixMode(GL_MODELVIEW);
951 if (rv3d->rflag & RV3D_CLIPPING) {
952 ED_view3d_clipping_enable();
957 BLI_freelistN(strings);
962 /* ******************** primitive drawing ******************* */
964 static void drawcube(void)
967 glBegin(GL_LINE_STRIP);
968 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
969 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
970 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
973 glBegin(GL_LINE_STRIP);
974 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
977 glBegin(GL_LINE_STRIP);
978 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
981 glBegin(GL_LINE_STRIP);
982 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
986 /* draws a cube on given the scaling of the cube, assuming that
987 * all required matrices have been set (used for drawing empties)
989 static void drawcube_size(float size)
991 glBegin(GL_LINE_STRIP);
992 glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size);
993 glVertex3f(-size, size, size); glVertex3f(-size, size, -size);
995 glVertex3f(-size, -size, -size); glVertex3f(size, -size, -size);
996 glVertex3f(size, -size, size); glVertex3f(size, size, size);
998 glVertex3f(size, size, -size); glVertex3f(size, -size, -size);
1001 glBegin(GL_LINE_STRIP);
1002 glVertex3f(-size, -size, size); glVertex3f(size, -size, size);
1005 glBegin(GL_LINE_STRIP);
1006 glVertex3f(-size, size, size); glVertex3f(size, size, size);
1009 glBegin(GL_LINE_STRIP);
1010 glVertex3f(-size, size, -size); glVertex3f(size, size, -size);
1014 /* this is an unused (old) cube-drawing function based on a given size */
1016 static void drawcube_size(const float size[3])
1020 glScalef(size[0], size[1], size[2]);
1023 glBegin(GL_LINE_STRIP);
1024 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
1025 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
1026 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
1029 glBegin(GL_LINE_STRIP);
1030 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
1033 glBegin(GL_LINE_STRIP);
1034 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
1037 glBegin(GL_LINE_STRIP);
1038 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
1045 static void drawshadbuflimits(Lamp *la, float mat[][4])
1047 float sta[3], end[3], lavec[3];
1049 negate_v3_v3(lavec, mat[2]);
1050 normalize_v3(lavec);
1052 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
1053 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
1055 glBegin(GL_LINE_STRIP);
1061 bglBegin(GL_POINTS);
1070 static void spotvolume(float lvec[3], float vvec[3], const float inp)
1072 /* camera is at 0,0,0 */
1073 float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
1076 normalize_v3(vvec); /* is this the correct vector ? */
1078 cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec en lvec */
1079 cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parrallel with lvec */
1081 /* vectors are exactly aligned, use the X axis, this is arbitrary */
1082 if (normalize_v3(plane) == 0.0f)
1085 /* now we've got two equations: one of a cone and one of a plane, but we have
1086 * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
1088 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
1089 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
1091 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
1096 normalize_v3(&q[1]);
1098 angle = saacos(plane[2]) / 2.0f;
1100 si = sqrtf(1 - co * co);
1107 quat_to_mat3(mat1, q);
1109 /* rotate lamp vector now over acos(inp) degrees */
1110 copy_v3_v3(vvec, lvec);
1114 si = sqrtf(1.0f - inp * inp);
1120 mul_m3_m3m3(mat3, mat2, mat1);
1124 mul_m3_m3m3(mat4, mat2, mat1);
1127 mul_m3_m3m3(mat2, mat1, mat3);
1128 mul_m3_v3(mat2, lvec);
1129 mul_m3_m3m3(mat2, mat1, mat4);
1130 mul_m3_v3(mat2, vvec);
1135 static void draw_spot_cone(Lamp *la, float x, float z)
1139 glBegin(GL_TRIANGLE_FAN);
1140 glVertex3f(0.0f, 0.0f, -x);
1142 if (la->mode & LA_SQUARE) {
1143 glVertex3f(z, z, 0);
1144 glVertex3f(-z, z, 0);
1145 glVertex3f(-z, -z, 0);
1146 glVertex3f(z, -z, 0);
1147 glVertex3f(z, z, 0);
1153 for (a = 0; a < 33; a++) {
1154 angle = a * M_PI * 2 / (33 - 1);
1155 glVertex3f(z * cosf(angle), z * sinf(angle), 0);
1162 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1164 glEnable(GL_CULL_FACE);
1168 /* draw backside darkening */
1169 glCullFace(GL_FRONT);
1171 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1172 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1174 draw_spot_cone(la, x, z);
1176 /* draw front side lighting */
1177 glCullFace(GL_BACK);
1179 glBlendFunc(GL_ONE, GL_ONE);
1180 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1182 draw_spot_cone(la, x, z);
1185 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1186 glDisable(GL_BLEND);
1188 glDisable(GL_CULL_FACE);
1189 glCullFace(GL_BACK);
1192 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
1194 Object *ob = base->object;
1195 const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1196 Lamp *la = ob->data;
1197 float vec[3], lvec[3], vvec[3], circrad, x, y, z;
1199 float imat[4][4], curcol[4];
1200 unsigned char col[4];
1201 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1202 /* the moment of view3d_draw_transp() call */
1203 const short is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1204 const short drawcone = ((dt > OB_WIRE) &&
1205 !(G.f & G_PICKSEL) &&
1206 (la->type == LA_SPOT) &&
1207 (la->mode & LA_SHOW_CONE) &&
1208 !(base->flag & OB_FROMDUPLI) &&
1211 if (drawcone && !v3d->transp) {
1212 /* in this case we need to draw delayed */
1213 add_view3d_after(&v3d->afterdraw_transp, base, flag);
1217 /* we first draw only the screen aligned & fixed scale stuff */
1219 glLoadMatrixf(rv3d->viewmat);
1221 /* lets calculate the scale: */
1222 lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
1224 /* and view aligned matrix: */
1225 copy_m4_m4(imat, rv3d->viewinv);
1226 normalize_v3(imat[0]);
1227 normalize_v3(imat[1]);
1230 copy_v3_v3(vec, ob->obmat[3]);
1232 /* for AA effects */
1233 glGetFloatv(GL_CURRENT_COLOR, curcol);
1237 if (lampsize > 0.0f) {
1239 if (ob->id.us > 1) {
1240 if (ob == OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1241 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1246 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1247 glDisable(GL_BLEND);
1248 drawcircball(GL_POLYGON, vec, lampsize, imat);
1255 circrad = 3.0f * lampsize;
1258 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1260 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1261 if (la->type != LA_HEMI) {
1262 if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1263 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
1272 /* draw the pretty sun rays */
1273 if (la->type == LA_SUN) {
1274 float v1[3], v2[3], mat[3][3];
1277 /* setup a 45 degree rotation matrix */
1278 vec_rot_to_mat3(mat, imat[2], (float)M_PI / 4.0f);
1281 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1282 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1285 glTranslatef(vec[0], vec[1], vec[2]);
1290 for (axis = 0; axis < 8; axis++) {
1298 glTranslatef(-vec[0], -vec[1], -vec[2]);
1302 if (la->type == LA_LOCAL) {
1303 if (la->mode & LA_SPHERE) {
1304 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1308 glPopMatrix(); /* back in object space */
1312 /* skip drawing extra info */
1314 else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
1315 lvec[0] = lvec[1] = 0.0;
1317 x = rv3d->persmat[0][2];
1318 y = rv3d->persmat[1][2];
1319 z = rv3d->persmat[2][2];
1320 vvec[0] = x * ob->obmat[0][0] + y * ob->obmat[0][1] + z * ob->obmat[0][2];
1321 vvec[1] = x * ob->obmat[1][0] + y * ob->obmat[1][1] + z * ob->obmat[1][2];
1322 vvec[2] = x * ob->obmat[2][0] + y * ob->obmat[2][1] + z * ob->obmat[2][2];
1324 y = cosf(la->spotsize * (float)(M_PI / 360.0));
1325 spotvolume(lvec, vvec, y);
1330 /* draw the angled sides of the cone */
1331 glBegin(GL_LINE_STRIP);
1337 z = x * sqrtf(1.0f - y * y);
1340 /* draw the circle/square at the end of the cone */
1341 glTranslatef(0.0, 0.0, x);
1342 if (la->mode & LA_SQUARE) {
1344 float z_abs = fabs(z);
1346 tvec[0] = tvec[1] = z_abs;
1349 glBegin(GL_LINE_LOOP);
1351 tvec[1] = -z_abs; /* neg */
1353 tvec[0] = -z_abs; /* neg */
1355 tvec[1] = z_abs; /* pos */
1359 else circ(0.0, 0.0, fabsf(z));
1361 /* draw the circle/square representing spotbl */
1362 if (la->type == LA_SPOT) {
1363 float spotblcirc = fabs(z) * (1 - pow(la->spotblend, 2));
1364 /* hide line if it is zero size or overlaps with outer border,
1365 * previously it adjusted to always to show it but that seems
1366 * confusing because it doesn't show the actual blend size */
1367 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1368 circ(0.0, 0.0, spotblcirc);
1372 draw_transp_spot_volume(la, x, z);
1374 /* draw clip start, useful for wide cones where its not obvious where the start is */
1375 glTranslatef(0.0, 0.0, -x); /* reverse translation above */
1376 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1379 float clipsta_fac = la->clipsta / -x;
1381 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1382 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1384 glBegin(GL_LINE_STRIP);
1385 glVertex3fv(lvec_clip);
1386 glVertex3fv(vvec_clip);
1390 else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1392 /* draw the line from the circle along the dist */
1393 glBegin(GL_LINE_STRIP);
1400 if (la->type == LA_HEMI) {
1401 /* draw the hemisphere curves */
1402 short axis, steps, dir;
1403 float outdist, zdist, mul;
1405 outdist = 0.14; mul = 1.4; dir = 1;
1408 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1409 for (axis = 0; axis < 4; axis++) {
1410 float v[3] = {0.0, 0.0, 0.0};
1413 glBegin(GL_LINE_STRIP);
1415 for (steps = 0; steps < 6; steps++) {
1416 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1417 /* make the arcs start at the edge of the energy circle */
1418 if (steps == 0) v[0] = dir * circrad;
1419 else v[0] = v[0] + dir * (steps * outdist);
1421 else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1422 /* make the arcs start at the edge of the energy circle */
1423 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1426 v[2] = v[2] - steps * zdist;
1430 zdist = zdist * mul;
1434 /* flip the direction */
1439 else if (la->type == LA_AREA) {
1441 if (la->area_shape == LA_AREA_SQUARE)
1442 fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
1443 else if (la->area_shape == LA_AREA_RECT)
1444 fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
1446 glBegin(GL_LINE_STRIP);
1447 glVertex3f(0.0, 0.0, -circrad);
1448 glVertex3f(0.0, 0.0, -la->dist);
1452 /* and back to viewspace */
1453 glLoadMatrixf(rv3d->viewmat);
1454 copy_v3_v3(vec, ob->obmat[3]);
1458 if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == FALSE)) {
1459 drawshadbuflimits(la, ob->obmat);
1462 UI_GetThemeColor4ubv(TH_LAMP, col);
1467 if (vec[2] > 0) vec[2] -= circrad;
1468 else vec[2] += circrad;
1470 glBegin(GL_LINE_STRIP);
1482 glDisable(GL_BLEND);
1484 /* restore for drawing extra stuff */
1489 static void draw_limit_line(float sta, float end, unsigned int col)
1492 glVertex3f(0.0, 0.0, -sta);
1493 glVertex3f(0.0, 0.0, -end);
1499 glVertex3f(0.0, 0.0, -sta);
1500 glVertex3f(0.0, 0.0, -end);
1506 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1507 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1508 static void draw_focus_cross(float dist, float size)
1511 glVertex3f(-size, 0.f, -dist);
1512 glVertex3f(size, 0.f, -dist);
1513 glVertex3f(0.f, -size, -dist);
1514 glVertex3f(0.f, size, -dist);
1518 #ifdef VIEW3D_CAMERA_BORDER_HACK
1519 float view3d_camera_border_hack_col[4];
1520 short view3d_camera_border_hack_test = FALSE;
1523 /* ****************** draw clip data *************** */
1525 static void draw_bundle_sphere(void)
1527 static GLuint displist = 0;
1529 if (displist == 0) {
1530 GLUquadricObj *qobj;
1532 displist = glGenLists(1);
1533 glNewList(displist, GL_COMPILE);
1535 qobj = gluNewQuadric();
1536 gluQuadricDrawStyle(qobj, GLU_FILL);
1537 glShadeModel(GL_SMOOTH);
1538 gluSphere(qobj, 0.05, 8, 8);
1539 glShadeModel(GL_FLAT);
1540 gluDeleteQuadric(qobj);
1545 glCallList(displist);
1548 static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
1549 MovieClip *clip, MovieTrackingObject *tracking_object, int flag,
1550 int *global_track_index, int draw_selected)
1552 MovieTracking *tracking = &clip->tracking;
1553 MovieTrackingTrack *track;
1554 float mat[4][4], imat[4][4];
1555 unsigned char col[4], scol[4];
1556 int tracknr = *global_track_index;
1557 ListBase *tracksbase = BKE_tracking_object_tracks(tracking, tracking_object);
1559 UI_GetThemeColor4ubv(TH_TEXT, col);
1560 UI_GetThemeColor4ubv(TH_SELECT, scol);
1562 BKE_get_tracking_mat(scene, base->object, mat);
1566 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1567 /* current ogl matrix is translated in camera space, bundles should
1568 * be rendered in world space, so camera matrix should be "removed"
1569 * from current ogl matrix */
1570 invert_m4_m4(imat, base->object->obmat);
1572 glMultMatrixf(imat);
1578 BKE_tracking_get_interpolated_camera(tracking, tracking_object, scene->r.cfra, obmat);
1580 invert_m4_m4(imat, obmat);
1581 glMultMatrixf(imat);
1584 for (track = tracksbase->first; track; track = track->next) {
1585 int selected = TRACK_SELECTED(track);
1587 if (draw_selected && !selected)
1590 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1593 if (flag & DRAW_PICKING)
1594 glLoadName(base->selcol + (tracknr << 16));
1597 glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
1598 glScalef(v3d->bundle_size / 0.05f, v3d->bundle_size / 0.05f, v3d->bundle_size / 0.05f);
1600 if (v3d->drawtype == OB_WIRE) {
1601 glDisable(GL_LIGHTING);
1604 if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1605 else UI_ThemeColor(TH_SELECT);
1608 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1609 else UI_ThemeColor(TH_WIRE);
1612 drawaxes(0.05f, v3d->bundle_drawtype);
1614 glEnable(GL_LIGHTING);
1616 else if (v3d->drawtype > OB_WIRE) {
1617 if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1618 /* selection outline */
1620 if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1621 else UI_ThemeColor(TH_SELECT);
1624 glDisable(GL_LIGHTING);
1625 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1627 draw_bundle_sphere();
1629 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1630 glEnable(GL_LIGHTING);
1634 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1635 else UI_ThemeColor(TH_BUNDLE_SOLID);
1637 draw_bundle_sphere();
1640 glDisable(GL_LIGHTING);
1643 if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1644 else UI_ThemeColor(TH_SELECT);
1647 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1648 else UI_ThemeColor(TH_WIRE);
1651 drawaxes(0.05f, v3d->bundle_drawtype);
1653 glEnable(GL_LIGHTING);
1659 if ((flag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1661 unsigned char tcol[4];
1663 if (selected) memcpy(tcol, scol, sizeof(tcol));
1664 else memcpy(tcol, col, sizeof(tcol));
1666 mul_v3_m4v3(pos, mat, track->bundle_pos);
1667 view3d_cached_text_draw_add(pos, track->name, 10, V3D_CACHE_TEXT_GLOBALSPACE, tcol);
1673 if ((flag & DRAW_PICKING) == 0) {
1674 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1675 MovieTrackingReconstruction *reconstruction;
1676 reconstruction = BKE_tracking_object_reconstruction(tracking, tracking_object);
1678 if (reconstruction->camnr) {
1679 MovieReconstructedCamera *camera = reconstruction->cameras;
1682 glDisable(GL_LIGHTING);
1683 UI_ThemeColor(TH_CAMERA_PATH);
1686 glBegin(GL_LINE_STRIP);
1687 for (a = 0; a < reconstruction->camnr; a++, camera++) {
1688 glVertex3fv(camera->mat[3]);
1693 glEnable(GL_LIGHTING);
1700 *global_track_index = tracknr;
1703 static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip,
1704 int flag, int draw_selected)
1706 MovieTracking *tracking = &clip->tracking;
1707 MovieTrackingObject *tracking_object;
1709 int global_track_index = 1;
1711 if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1714 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1717 glGetFloatv(GL_CURRENT_COLOR, curcol);
1719 glEnable(GL_LIGHTING);
1720 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1721 glEnable(GL_COLOR_MATERIAL);
1722 glShadeModel(GL_SMOOTH);
1724 tracking_object = tracking->objects.first;
1725 while (tracking_object) {
1726 draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
1727 flag, &global_track_index, draw_selected);
1729 tracking_object = tracking_object->next;
1733 glShadeModel(GL_FLAT);
1734 glDisable(GL_COLOR_MATERIAL);
1735 glDisable(GL_LIGHTING);
1739 if (flag & DRAW_PICKING)
1740 glLoadName(base->selcol);
1743 /* flag similar to draw_object() */
1744 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int flag)
1746 /* a standing up pyramid with (0,0,0) as top */
1748 Object *ob = base->object;
1750 float vec[4][3], asp[2], shift[2], scale[3];
1753 const short is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
1754 MovieClip *clip = BKE_object_movieclip_get(scene, base->object, 0);
1756 /* draw data for movie clip set as active for scene */
1758 draw_viewport_reconstruction(scene, base, v3d, clip, flag, FALSE);
1759 draw_viewport_reconstruction(scene, base, v3d, clip, flag, TRUE);
1762 #ifdef VIEW3D_CAMERA_BORDER_HACK
1763 if (is_view && !(G.f & G_PICKSEL)) {
1764 glGetFloatv(GL_CURRENT_COLOR, view3d_camera_border_hack_col);
1765 view3d_camera_border_hack_test = TRUE;
1772 scale[0] = 1.0f / len_v3(ob->obmat[0]);
1773 scale[1] = 1.0f / len_v3(ob->obmat[1]);
1774 scale[2] = 1.0f / len_v3(ob->obmat[2]);
1776 BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
1777 asp, shift, &drawsize, vec);
1779 glDisable(GL_LIGHTING);
1780 glDisable(GL_CULL_FACE);
1783 glBegin(GL_LINE_LOOP);
1784 glVertex3fv(vec[0]);
1785 glVertex3fv(vec[1]);
1786 glVertex3fv(vec[2]);
1787 glVertex3fv(vec[3]);
1795 /* center point to camera frame */
1796 glBegin(GL_LINE_STRIP);
1797 glVertex3fv(vec[1]);
1799 glVertex3fv(vec[0]);
1800 glVertex3fv(vec[3]);
1802 glVertex3fv(vec[2]);
1807 tvec[2] = vec[1][2]; /* copy the depth */
1810 /* draw an outline arrow for inactive cameras and filled
1811 * for active cameras. We actually draw both outline+filled
1812 * for active cameras so the wire can be seen side-on */
1813 for (i = 0; i < 2; i++) {
1814 if (i == 0) glBegin(GL_LINE_LOOP);
1815 else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1818 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
1819 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
1820 glVertex3fv(tvec); /* left */
1822 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
1823 glVertex3fv(tvec); /* right */
1826 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
1827 glVertex3fv(tvec); /* top */
1833 if (cam->flag & (CAM_SHOWLIMITS + CAM_SHOWMIST)) {
1837 /* draw in normalized object matrix space */
1838 copy_m4_m4(nobmat, ob->obmat);
1839 normalize_m4(nobmat);
1842 glLoadMatrixf(rv3d->viewmat);
1843 glMultMatrixf(nobmat);
1845 if (cam->flag & CAM_SHOWLIMITS) {
1846 draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
1847 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
1848 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
1851 wrld = scene->world;
1852 if (cam->flag & CAM_SHOWMIST)
1853 if (wrld) draw_limit_line(wrld->miststa, wrld->miststa + wrld->mistdist, 0xFFFFFF);
1860 /* flag similar to draw_object() */
1861 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
1862 Object *UNUSED(ob), int UNUSED(flag))
1864 //Speaker *spk = ob->data;
1871 for (j = 0; j < 3; j++) {
1872 vec[2] = 0.25f * j - 0.125f;
1874 glBegin(GL_LINE_LOOP);
1875 for (i = 0; i < 16; i++) {
1876 vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1877 vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1883 for (j = 0; j < 4; j++) {
1884 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1885 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1886 glBegin(GL_LINE_STRIP);
1887 for (i = 0; i < 3; i++) {
1893 vec[2] = 0.25f * i - 0.125f;
1899 glDisable(GL_BLEND);
1902 static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
1904 BPoint *bp = lt->def;
1905 float *co = dl ? dl->verts : NULL;
1908 UI_ThemeColor(sel ? TH_VERTEX_SELECT : TH_VERTEX);
1909 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1910 bglBegin(GL_POINTS);
1912 for (w = 0; w < lt->pntsw; w++) {
1913 int wxt = (w == 0 || w == lt->pntsw - 1);
1914 for (v = 0; v < lt->pntsv; v++) {
1915 int vxt = (v == 0 || v == lt->pntsv - 1);
1916 for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
1917 int uxt = (u == 0 || u == lt->pntsu - 1);
1918 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1919 if (bp->hide == 0) {
1920 if ((bp->f1 & SELECT) == sel) {
1921 bglVertex3fv(dl ? co : bp->vec);
1933 void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPoint *bp, int x, int y), void *userData)
1935 Object *obedit = vc->obedit;
1936 Lattice *lt = obedit->data;
1937 BPoint *bp = lt->editlatt->latt->def;
1938 DispList *dl = BKE_displist_find(&obedit->disp, DL_VERTS);
1939 float *co = dl ? dl->verts : NULL;
1940 int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
1941 short s[2] = {IS_CLIPPED, 0};
1943 ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */
1945 for (i = 0; i < N; i++, bp++, co += 3) {
1946 if (bp->hide == 0) {
1947 view3d_project_short_clip(vc->ar, dl ? co : bp->vec, s, TRUE);
1948 if (s[0] != IS_CLIPPED)
1949 func(userData, bp, s[0], s[1]);
1954 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
1956 int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
1960 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, use_wcol - 1);
1962 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
1968 glVertex3fv(&dl->verts[index * 3]);
1971 glVertex3fv(lt->def[index].vec);
1975 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1976 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1978 Lattice *lt = ob->data;
1981 int use_wcol = FALSE, is_edit = (lt->editlatt != NULL);
1983 /* now we default make displist, this will modifiers work for non animated case */
1984 if (ob->disp.first == NULL)
1985 BKE_lattice_modifiers_calc(scene, ob);
1986 dl = BKE_displist_find(&ob->disp, DL_VERTS);
1989 lt = lt->editlatt->latt;
1993 if (ob->defbase.first && lt->dvert) {
1994 use_wcol = ob->actdef;
1995 glShadeModel(GL_SMOOTH);
2000 for (w = 0; w < lt->pntsw; w++) {
2001 int wxt = (w == 0 || w == lt->pntsw - 1);
2002 for (v = 0; v < lt->pntsv; v++) {
2003 int vxt = (v == 0 || v == lt->pntsv - 1);
2004 for (u = 0; u < lt->pntsu; u++) {
2005 int uxt = (u == 0 || u == lt->pntsu - 1);
2007 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
2008 drawlattice__point(lt, dl, u, v, w - 1, use_wcol);
2009 drawlattice__point(lt, dl, u, v, w, use_wcol);
2011 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2012 drawlattice__point(lt, dl, u, v - 1, w, use_wcol);
2013 drawlattice__point(lt, dl, u, v, w, use_wcol);
2015 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2016 drawlattice__point(lt, dl, u - 1, v, w, use_wcol);
2017 drawlattice__point(lt, dl, u, v, w, use_wcol);
2024 /* restoration for weight colors */
2026 glShadeModel(GL_FLAT);
2029 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2031 lattice_draw_verts(lt, dl, 0);
2032 lattice_draw_verts(lt, dl, 1);
2034 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2038 /* ***************** ******************** */
2040 /* Note! - foreach funcs should be called while drawing or directly after
2041 * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
2042 * but would not give correct results with dupli's for eg. which don't
2043 * use the object matrix in the usual way */
2044 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3],
2045 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2047 foreachScreenVert_userData *data = userData;
2048 BMVert *eve = EDBM_vert_at_index(data->vc.em, index);
2050 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2051 short s[2] = {IS_CLIPPED, 0};
2053 if (data->clipVerts != V3D_CLIP_TEST_OFF) {
2054 view3d_project_short_clip(data->vc.ar, co, s, TRUE);
2058 mul_v3_m4v3(co2, data->vc.obedit->obmat, co);
2059 project_short_noclip(data->vc.ar, co2, s);
2062 if (s[0] != IS_CLIPPED)
2063 data->func(data->userData, eve, s[0], s[1], index);
2067 void mesh_foreachScreenVert(
2069 void (*func)(void *userData, BMVert *eve, int x, int y, int index),
2070 void *userData, eV3DClipTest clipVerts)
2072 foreachScreenVert_userData data;
2073 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2077 data.userData = userData;
2078 data.clipVerts = clipVerts;
2080 if (clipVerts != V3D_CLIP_TEST_OFF)
2081 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2083 EDBM_index_arrays_init(vc->em, 1, 0, 0);
2084 dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
2085 EDBM_index_arrays_free(vc->em);
2091 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
2092 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2094 MVert *mv = &((MVert *)userData)[index];
2096 if (!(mv->flag & ME_HIDE)) {
2097 const char sel = mv->flag & SELECT;
2099 // TODO define selected color
2101 glColor3f(1.0f, 1.0f, 0.0f);
2104 glColor3f(0.0f, 0.0f, 0.0f);
2111 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
2114 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, me->mvert);
2118 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const float v0co[3], const float v1co[3])
2120 foreachScreenEdge_userData *data = userData;
2121 BMEdge *eed = EDBM_edge_at_index(data->vc.em, index);
2123 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2126 if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) {
2127 view3d_project_short_clip(data->vc.ar, v0co, s[0], TRUE);
2128 view3d_project_short_clip(data->vc.ar, v1co, s[1], TRUE);
2131 float v1_co[3], v2_co[3];
2133 mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co);
2134 mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co);
2136 project_short_noclip(data->vc.ar, v1_co, s[0]);
2137 project_short_noclip(data->vc.ar, v2_co, s[1]);
2139 if (data->clipVerts == V3D_CLIP_TEST_REGION) {
2140 /* make an int copy */
2141 int s_int[2][2] = {{s[0][0], s[0][1]},
2142 {s[1][0], s[1][1]}};
2143 if (!BLI_segment_in_rcti(&data->win_rect, s_int[0], s_int[1])) {
2149 data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index);
2153 void mesh_foreachScreenEdge(
2155 void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index),
2156 void *userData, eV3DClipTest clipVerts)
2158 foreachScreenEdge_userData data;
2159 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2163 data.win_rect.xmin = 0;
2164 data.win_rect.ymin = 0;
2165 data.win_rect.xmax = vc->ar->winx;
2166 data.win_rect.ymax = vc->ar->winy;
2169 data.userData = userData;
2170 data.clipVerts = clipVerts;
2172 if (clipVerts != V3D_CLIP_TEST_OFF)
2173 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2175 EDBM_index_arrays_init(vc->em, 0, 1, 0);
2176 dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
2177 EDBM_index_arrays_free(vc->em);
2182 static void mesh_foreachScreenFace__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2184 foreachScreenFace_userData *data = userData;
2185 BMFace *efa = EDBM_face_at_index(data->vc.em, index);
2187 if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2191 mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent);
2192 project_short(data->vc.ar, cent2, s);
2194 if (s[0] != IS_CLIPPED) {
2195 data->func(data->userData, efa, s[0], s[1], index);
2200 void mesh_foreachScreenFace(
2202 void (*func)(void *userData, BMFace *efa, int x, int y, int index),
2205 foreachScreenFace_userData data;
2206 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2210 data.userData = userData;
2213 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2215 EDBM_index_arrays_init(vc->em, 0, 0, 1);
2216 dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
2217 EDBM_index_arrays_free(vc->em);
2222 void nurbs_foreachScreenVert(
2224 void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y),
2227 Curve *cu = vc->obedit->data;
2228 short s[2] = {IS_CLIPPED, 0};
2231 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
2233 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2235 for (nu = nurbs->first; nu; nu = nu->next) {
2236 if (nu->type == CU_BEZIER) {
2237 for (i = 0; i < nu->pntsu; i++) {
2238 BezTriple *bezt = &nu->bezt[i];
2240 if (bezt->hide == 0) {
2242 if (cu->drawflag & CU_HIDE_HANDLES) {
2243 view3d_project_short_clip(vc->ar, bezt->vec[1], s, TRUE);
2244 if (s[0] != IS_CLIPPED)
2245 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
2248 view3d_project_short_clip(vc->ar, bezt->vec[0], s, TRUE);
2249 if (s[0] != IS_CLIPPED)
2250 func(userData, nu, NULL, bezt, 0, s[0], s[1]);
2251 view3d_project_short_clip(vc->ar, bezt->vec[1], s, TRUE);
2252 if (s[0] != IS_CLIPPED)
2253 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
2254 view3d_project_short_clip(vc->ar, bezt->vec[2], s, TRUE);
2255 if (s[0] != IS_CLIPPED)
2256 func(userData, nu, NULL, bezt, 2, s[0], s[1]);
2262 for (i = 0; i < nu->pntsu * nu->pntsv; i++) {
2263 BPoint *bp = &nu->bp[i];
2265 if (bp->hide == 0) {
2266 view3d_project_short_clip(vc->ar, bp->vec, s, TRUE);
2267 if (s[0] != IS_CLIPPED)
2268 func(userData, nu, bp, NULL, -1, s[0], s[1]);
2275 /* ************** DRAW MESH ****************** */
2277 /* First section is all the "simple" draw routines,
2278 * ones that just pass some sort of primitive to GL,
2279 * with perhaps various options to control lighting,
2282 * These routines should not have user interface related
2286 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
2290 copy_m3_m4(obmat, ob->obmat);
2292 data->uniform_scale = is_uniform_scaled_m3(obmat);
2294 if (!data->uniform_scale) {
2295 /* inverted matrix */
2296 invert_m3_m3(data->imat, obmat);
2298 /* transposed inverted matrix */
2299 copy_m3_m3(data->tmat, data->imat);
2300 transpose_m3(data->tmat);
2304 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2306 drawDMNormal_userData *data = userData;
2307 BMFace *efa = EDBM_face_at_index(data->em, index);
2310 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2311 if (!data->uniform_scale) {
2312 mul_v3_m3v3(n, data->tmat, (float *) no);
2314 mul_m3_v3(data->imat, n);
2321 glVertex3f(cent[0] + n[0] * data->normalsize,
2322 cent[1] + n[1] * data->normalsize,
2323 cent[2] + n[2] * data->normalsize);
2327 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2329 drawDMNormal_userData data;
2332 data.normalsize = scene->toolsettings->normalsize;
2334 calcDrawDMNormalScale(ob, &data);
2337 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data);
2341 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2343 BMFace *efa = EDBM_face_at_index(((void **)userData)[0], index);
2344 int sel = *(((int **)userData)[1]);
2346 if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT) == sel) {
2350 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel)
2352 void *ptrs[2] = {em, &sel};
2354 bglBegin(GL_POINTS);
2355 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs);
2359 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])
2361 drawDMNormal_userData *data = userData;
2362 BMVert *eve = EDBM_vert_at_index(data->em, index);
2364 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2368 copy_v3_v3(no, no_f);
2371 no[0] = no_s[0] / 32767.0f;
2372 no[1] = no_s[1] / 32767.0f;
2373 no[2] = no_s[2] / 32767.0f;
2376 if (!data->uniform_scale) {
2377 mul_v3_m3v3(n, data->tmat, (float *) no);
2379 mul_m3_v3(data->imat, n);
2386 glVertex3f(co[0] + n[0] * data->normalsize,
2387 co[1] + n[1] * data->normalsize,
2388 co[2] + n[2] * data->normalsize);
2392 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2394 drawDMNormal_userData data;
2397 data.normalsize = scene->toolsettings->normalsize;
2399 calcDrawDMNormalScale(ob, &data);
2402 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data);
2406 /* Draw verts with color set based on selection */
2407 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2408 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2410 drawDMVerts_userData *data = userData;
2411 BMVert *eve = EDBM_vert_at_index(data->em, index);
2413 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2414 /* skin nodes: draw a red circle around the root
2416 if(data->has_vskin) {
2417 const MVertSkin *vs = CustomData_bmesh_get(&data->em->bm->vdata,
2420 if (vs->flag & MVERT_SKIN_ROOT) {
2421 float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2424 glColor4ubv(data->th_skin_root);
2425 drawcircball(GL_LINES, co, radius, data->imat);
2427 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2428 bglBegin(GL_POINTS);
2432 /* draw active larger - need to stop/start point drawing for this :/ */
2433 if (eve == data->eve_act) {
2434 glColor4ubv(data->th_editmesh_active);
2438 glPointSize(data->th_vertex_size);
2439 bglBegin(GL_POINTS);
2443 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2444 glPointSize(data->th_vertex_size);
2445 bglBegin(GL_POINTS);
2453 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act,
2456 drawDMVerts_userData data;
2458 data.eve_act = eve_act;
2461 /* Cache theme values */
2462 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2463 UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2464 UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2465 UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2466 data.th_vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2468 /* For skin root drawing */
2469 data.has_vskin = CustomData_has_layer(&em->bm->vdata, CD_MVERT_SKIN);
2470 /* view-aligned matrix */
2471 mult_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2472 invert_m4(data.imat);
2474 bglBegin(GL_POINTS);
2475 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
2479 /* Draw edges with color set based on selection */
2480 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2483 //unsigned char **cols = userData, *col;
2484 drawDMEdgesSel_userData *data = userData;
2487 eed = EDBM_edge_at_index(data->em, index);
2489 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2490 if (eed == data->eed_act) {
2491 glColor4ubv(data->actCol);
2494 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2498 col = data->baseCol;
2500 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2502 return DM_DRAW_OPTION_SKIP;
2506 return DM_DRAW_OPTION_NORMAL;
2509 return DM_DRAW_OPTION_SKIP;
2512 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2513 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2515 drawDMEdgesSel_userData data;
2517 data.baseCol = baseCol;
2518 data.selCol = selCol;
2519 data.actCol = actCol;
2521 data.eed_act = eed_act;
2522 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2526 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2528 if (BM_elem_flag_test(EDBM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2529 return DM_DRAW_OPTION_SKIP;
2531 return DM_DRAW_OPTION_NORMAL;
2534 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2536 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
2539 /* Draw edges with color interpolated based on selection */
2540 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2542 if (BM_elem_flag_test(EDBM_edge_at_index(((void **)userData)[0], index), BM_ELEM_HIDDEN))
2543 return DM_DRAW_OPTION_SKIP;
2545 return DM_DRAW_OPTION_NORMAL;
2547 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2549 BMEdge *eed = EDBM_edge_at_index(((void **)userData)[0], index);
2550 unsigned char **cols = userData;
2551 unsigned char *col0 = cols[(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1];
2552 unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1];
2554 glColor4ub(col0[0] + (col1[0] - col0[0]) * t,
2555 col0[1] + (col1[1] - col0[1]) * t,
2556 col0[2] + (col1[2] - col0[2]) * t,
2557 col0[3] + (col1[3] - col0[3]) * t);
2560 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2562 void *cols[3] = {em, baseCol, selCol};
2564 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2567 /* Draw only seam edges */
2568 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2570 BMEdge *eed = EDBM_edge_at_index(userData, index);
2572 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
2573 return DM_DRAW_OPTION_NORMAL;
2575 return DM_DRAW_OPTION_SKIP;
2578 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2580 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
2583 /* Draw only sharp edges */
2584 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2586 BMEdge *eed = EDBM_edge_at_index(userData, index);
2588 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
2589 return DM_DRAW_OPTION_NORMAL;
2591 return DM_DRAW_OPTION_SKIP;
2594 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2596 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
2600 /* Draw faces with color set based on selection
2601 * return 2 for the active face so it renders with stipple enabled */
2602 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
2604 drawDMFacesSel_userData *data = userData;
2605 BMFace *efa = EDBM_face_at_index(data->em, index);
2609 return DM_DRAW_OPTION_SKIP;
2611 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2612 if (efa == data->efa_act) {
2613 glColor4ubv(data->cols[2]);
2614 return DM_DRAW_OPTION_STIPPLE;
2617 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2619 return DM_DRAW_OPTION_SKIP;
2621 return DM_DRAW_OPTION_NORMAL;
2624 return DM_DRAW_OPTION_SKIP;
2627 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2630 drawDMFacesSel_userData *data = userData;
2634 unsigned char *col, *next_col;
2636 if (!data->orig_index)
2639 efa = EDBM_face_at_index(data->em, data->orig_index[index]);
2640 next_efa = EDBM_face_at_index(data->em, data->orig_index[next_index]);
2642 if (efa == next_efa)
2645 if (efa == data->efa_act || next_efa == data->efa_act)
2648 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2649 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
2651 if (col[3] == 0 || next_col[3] == 0)
2654 return col == next_col;
2657 /* also draws the active face */
2658 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2659 unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
2661 drawDMFacesSel_userData data;
2663 data.cols[0] = baseCol;
2665 data.cols[1] = selCol;
2666 data.cols[2] = actCol;
2667 data.efa_act = efa_act;
2668 data.orig_index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
2670 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
2673 static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
2675 BMEditMesh *em = userData;
2676 BMEdge *eed = EDBM_edge_at_index(userData, index);
2677 float *crease = eed ? (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE) : NULL;
2680 return DM_DRAW_OPTION_SKIP;
2682 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *crease != 0.0f) {
2683 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, *crease);
2684 return DM_DRAW_OPTION_NORMAL;
2687 return DM_DRAW_OPTION_SKIP;
2690 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
2693 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em);
2697 static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
2699 BMEditMesh *em = userData;
2700 BMEdge *eed = EDBM_edge_at_index(userData, index);
2701 float *bweight = (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
2704 return DM_DRAW_OPTION_SKIP;
2706 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *bweight != 0.0f) {
2707 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, *bweight);
2708 return DM_DRAW_OPTION_NORMAL;
2711 return DM_DRAW_OPTION_SKIP;
2714 static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
2715 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2717 BMEditMesh *em = userData;
2718 BMVert *eve = EDBM_vert_at_index(userData, index);
2719 float *bweight = (float *)CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_BWEIGHT);
2724 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && *bweight != 0.0f) {
2725 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, *bweight);
2729 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2731 ToolSettings *ts = scene->toolsettings;
2733 if (ts->selectmode & SCE_SELECT_VERTEX) {
2734 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2735 bglBegin(GL_POINTS);
2736 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em);
2741 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em);
2746 /* Second section of routines: Combine first sets to form fancy
2747 * drawing routines (for example rendering twice to get overlays).
2749 * Also includes routines that are basic drawing but are too
2750 * specialized to be split out (like drawing creases or measurements).
2753 /* EditMesh drawing routines*/
2755 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
2756 BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act,
2759 ToolSettings *ts = scene->toolsettings;
2762 if (v3d->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select
2764 for (sel = 0; sel < 2; sel++) {
2765 unsigned char col[4], fcol[4];
2768 UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
2769 UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE, fcol);
2771 for (pass = 0; pass < 2; pass++) {
2772 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2773 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2776 if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
2777 glDisable(GL_DEPTH_TEST);
2785 size = (size > 2.1f ? size / 2.0f : size);
2786 fsize = (fsize > 2.1f ? fsize / 2.0f : fsize);
2787 col[3] = fcol[3] = 100;
2790 col[3] = fcol[3] = 255;
2793 if (ts->selectmode & SCE_SELECT_VERTEX) {
2796 draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
2799 if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2802 draw_dm_face_centers(em, cageDM, sel);
2806 glDisable(GL_BLEND);
2807 glEnable(GL_DEPTH_TEST);
2812 if (v3d->zbuf) glDepthMask(1);
2816 static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
2817 Mesh *me, DerivedMesh *cageDM, short sel_only,
2820 ToolSettings *ts = scene->toolsettings;
2822 unsigned char wireCol[4], selCol[4], actCol[4];
2824 /* since this function does transparant... */
2825 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2826 UI_GetThemeColor4ubv(TH_WIRE, wireCol);
2827 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2829 /* when sel only is used, don't render wire, only selected, this is used for
2830 * textured draw mode when the 'edges' option is disabled */
2834 for (pass = 0; pass < 2; pass++) {
2835 /* show wires in transparant when no zbuf clipping for select */
2837 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) {
2839 glDisable(GL_DEPTH_TEST);
2841 if (!sel_only) wireCol[3] = 85;
2849 if (!sel_only) wireCol[3] = 255;
2852 if (ts->selectmode == SCE_SELECT_FACE) {
2853 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2855 else if ( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
2856 if (cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2857 glShadeModel(GL_SMOOTH);
2858 draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
2859 glShadeModel(GL_FLAT);
2862 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2867 glColor4ubv(wireCol);
2868 draw_dm_edges(em, cageDM);
2873 glDisable(GL_BLEND);
2874 glEnable(GL_DEPTH_TEST);
2879 static void draw_em_measure_stats(View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit)
2881 const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
2882 Mesh *me = ob->data;
2883 float v1[3], v2[3], v3[3], vmid[3], fvec[3];
2884 char numstr[32]; /* Stores the measurement display text here */
2885 const char *conv_float; /* Use a float conversion matching the grid size */
2886 unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */
2887 float area; /* area of the face */
2888 float grid = unit->system ? unit->scale_length : v3d->grid;
2889 const int do_split = unit->flag & USER_UNIT_OPT_SPLIT;
2890 const int do_global = v3d->flag & V3D_GLOBAL_STATS;
2891 const int do_moving = G.moving;
2896 /* make the precision of the pronted value proportionate to the gridsize */
2898 if (grid < 0.01f) conv_float = "%.6g";
2899 else if (grid < 0.1f) conv_float = "%.5g";
2900 else if (grid < 1.0f) conv_float = "%.4g";
2901 else if (grid < 10.0f) conv_float = "%.3g";
2902 else conv_float = "%.2g";
2904 if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2907 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2909 eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
2910 for (; eed; eed = BM_iter_step(&iter)) {
2911 /* draw selected edges, or edges next to selected verts while draging */
2912 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
2913 (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
2914 BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
2917 copy_v3_v3(v1, eed->v1->co);
2918 copy_v3_v3(v2, eed->v2->co);
2920 mid_v3_v3v3(vmid, v1, v2);
2923 mul_mat3_m4_v3(ob->obmat, v1);
2924 mul_mat3_m4_v3(ob->obmat, v2);
2928 bUnit_AsString(numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
2929 unit->system, B_UNIT_LENGTH, do_split, FALSE);
2932 sprintf(numstr, conv_float, len_v3v3(v1, v2));
2935 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col);
2940 if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2941 /* would be nice to use BM_face_calc_area, but that is for 2d faces
2942 * so instead add up tessellation triangle areas */
2946 #define DRAW_EM_MEASURE_STATS_FACEAREA() \
2947 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \
2948 mul_v3_fl(vmid, 1.0f / (float)n); \
2950 bUnit_AsString(numstr, sizeof(numstr), \
2951 (double)(area * unit->scale_length), \
2952 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); \
2954 BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
2955 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col); \
2958 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2964 for (i = 0; i < em->tottri; i++) {
2965 BMLoop **l = em->looptris[i];
2966 if (f && l[0]->f != f) {
2967 DRAW_EM_MEASURE_STATS_FACEAREA();
2974 copy_v3_v3(v1, l[0]->v->co);
2975 copy_v3_v3(v2, l[1]->v->co);
2976 copy_v3_v3(v3, l[2]->v->co);
2978 mul_mat3_m4_v3(ob->obmat, v1);
2979 mul_mat3_m4_v3(ob->obmat, v2);
2980 mul_mat3_m4_v3(ob->obmat, v3);
2982 area += area_tri_v3(v1, v2, v3);
2983 add_v3_v3(vmid, v1);
2984 add_v3_v3(vmid, v2);
2985 add_v3_v3(vmid, v3);
2990 DRAW_EM_MEASURE_STATS_FACEAREA();
2992 #undef DRAW_EM_MEASURE_STATS_FACEAREA
2995 if (me->drawflag & ME_DRAWEXTRA_FACEANG) {
2997 int is_rad = unit->system_rotation == USER_UNIT_ROT_RADIANS;
2999 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
3002 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3003 const int is_face_sel = BM_elem_flag_test(efa, BM_ELEM_SELECT);
3005 if (is_face_sel || do_moving) {
3008 int is_first = TRUE;
3010 BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
3011 if (is_face_sel || (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT))) {
3014 /* lazy init center calc */
3016 BM_face_calc_center_bounds(efa, vmid);
3017 /* Avoid triple matrix multiply every vertex for 'global' */
3019 copy_v3_v3(v1, loop->prev->v->co);
3020 copy_v3_v3(v2, loop->v->co);
3021 mul_mat3_m4_v3(ob->obmat, v1);
3022 mul_mat3_m4_v3(ob->obmat, v2);
3028 copy_v3_v3(v3, loop->next->v->co);
3030 mul_mat3_m4_v3(ob->obmat, v3);
3032 angle = angle_v3v3v3(v1, v2, v3);
3033 interp_v3_v3v3(fvec, vmid, v2, 0.8f);
3038 angle = angle_v3v3v3(loop->prev->v->co, loop->v->co, loop->next->v->co);
3039 interp_v3_v3v3(fvec, vmid, loop->v->co, 0.8f);
3042 BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
3043 view3d_cached_text_draw_add(fvec, numstr, 0, txt_flag, col);
3051 static void draw_em_indices(BMEditMesh *em)
3053 const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
3060 unsigned char col[4];
3065 /* For now, reuse appropriate theme colors from stats text colors */
3067 if (em->selectmode & SCE_SELECT_VERTEX) {
3068 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
3069 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
3070 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
3071 sprintf(numstr, "%d", i);
3072 view3d_cached_text_draw_add(v->co, numstr, 0, txt_flag, col);
3078 if (em->selectmode & SCE_SELECT_EDGE) {
3080 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
3081 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
3082 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
3083 sprintf(numstr, "%d", i);
3084 mid_v3_v3v3(pos, e->v1->co, e->v2->co);
3085 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
3091 if (em->selectmode & SCE_SELECT_FACE) {
3093 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
3094 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3095 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
3096 BM_face_calc_center_mean(f, pos);
3097 sprintf(numstr, "%d", i);
3098 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
3105 static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
3107 BMFace *efa = EDBM_face_at_index(userData, index);
3109 if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
3110 GPU_enable_material(efa->mat_nr + 1, NULL);
3111 return DM_DRAW_OPTION_NORMAL;
3114 return DM_DRAW_OPTION_SKIP;
3117 static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
3119 BMFace *efa = EDBM_face_at_index(userData, index);
3121 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
3122 return DM_DRAW_OPTION_SKIP;
3124 return DM_DRAW_OPTION_NORMAL;
3127 static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
3128 Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
3131 Mesh *me = ob->data;
3132 BMFace *efa_act = BM_active_face_get(em->bm, FALSE); /* annoying but active faces is stored differently */
3133 BMEdge *eed_act = NULL;
3134 BMVert *eve_act = NULL;
3136 if (em->bm->selected.last) {
3137 BMEditSelection *ese = em->bm->selected.last;
3138 /* face is handeled above */
3140 if (ese->type == BM_FACE) {
3141 efa_act = (BMFace *)ese->data;
3145 if (ese->htype == BM_EDGE) {
3146 eed_act = (BMEdge *)ese->ele;
3148 else if (ese->htype == BM_VERT) {
3149 eve_act = (BMVert *)ese->ele;
3153 EDBM_index_arrays_init(em, 1, 1, 1);