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"
51 #include "BLI_utildefines.h"
52 #include "BLI_blenlib.h"
54 #include "BLI_edgehash.h"
56 #include "BLI_utildefines.h"
58 #include "BKE_anim.h" //for the where_on_path function
59 #include "BKE_armature.h"
60 #include "BKE_camera.h"
61 #include "BKE_constraint.h" // for the get_constraint_target function
62 #include "BKE_curve.h"
63 #include "BKE_DerivedMesh.h"
64 #include "BKE_deform.h"
65 #include "BKE_displist.h"
67 #include "BKE_global.h"
68 #include "BKE_image.h"
70 #include "BKE_lattice.h"
72 #include "BKE_material.h"
73 #include "BKE_mball.h"
74 #include "BKE_modifier.h"
75 #include "BKE_object.h"
76 #include "BKE_paint.h"
77 #include "BKE_particle.h"
78 #include "BKE_pointcache.h"
79 #include "BKE_scene.h"
81 #include "BKE_movieclip.h"
82 #include "BKE_tracking.h"
84 #include "BKE_tessmesh.h"
86 #include "smoke_API.h"
88 #include "IMB_imbuf.h"
89 #include "IMB_imbuf_types.h"
92 #include "BIF_glutil.h"
95 #include "GPU_extensions.h"
98 #include "ED_particle.h"
99 #include "ED_screen.h"
100 #include "ED_sculpt.h"
101 #include "ED_types.h"
102 #include "ED_curve.h" /* for curve_editnurbs */
104 #include "UI_resources.h"
107 #include "wm_subwindow.h"
110 #include "view3d_intern.h" // own include
112 typedef enum eWireDrawMode {
115 OBDRAW_WIRE_ON_DEPTH = 2
118 /* user data structures for derived mesh callbacks */
119 typedef struct foreachScreenVert_userData {
120 void (*func)(void *userData, BMVert *eve, int x, int y, int index);
123 eV3DClipTest clipVerts;
124 } foreachScreenVert_userData;
126 typedef struct foreachScreenEdge_userData {
127 void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index);
130 rcti win_rect; /* copy of: vc.ar->winx/winy, use for faster tests, minx/y will always be 0 */
131 eV3DClipTest clipVerts;
132 } foreachScreenEdge_userData;
134 typedef struct foreachScreenFace_userData {
135 void (*func)(void *userData, BMFace *efa, int x, int y, int index);
138 } foreachScreenFace_userData;
140 typedef struct drawDMVerts_userData {
141 BMEditMesh *em; /* BMESH BRANCH ONLY */
145 } drawDMVerts_userData;
147 typedef struct drawDMEdgesSel_userData {
148 BMEditMesh *em; /* BMESH BRANCH ONLY */
150 unsigned char *baseCol, *selCol, *actCol;
152 } drawDMEdgesSel_userData;
154 typedef struct drawDMFacesSel_userData {
155 unsigned char *cols[3];
157 DerivedMesh *dm; /* BMESH BRANCH ONLY */
158 BMEditMesh *em; /* BMESH BRANCH ONLY */
162 } drawDMFacesSel_userData;
164 typedef struct drawDMNormal_userData {
167 } drawDMNormal_userData;
169 typedef struct bbsObmodeMeshVerts_userData {
172 } bbsObmodeMeshVerts_userData;
174 static void draw_bounding_volume(Scene *scene, Object *ob, char type);
176 static void drawcube_size(float size);
177 static void drawcircle_size(float size);
178 static void draw_empty_sphere(float size);
179 static void draw_empty_cone(float size);
181 /* this condition has been made more complex since editmode can draw textures */
182 static int check_object_draw_texture(Scene *scene, View3D *v3d, int drawtype)
184 /* texture and material draw modes */
185 if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID)
189 if (v3d->drawtype == OB_SOLID && (v3d->flag2 & V3D_SOLID_TEX) && !scene_use_new_shading_nodes(scene))
195 static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
197 if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
200 if (G.f & G_BACKBUFSEL)
203 if ((vd->flag & V3D_ZBUF_SELECT) == 0)
206 /* if its drawing textures with zbuf sel, then don't draw dots */
207 if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
210 if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
216 /* ************* only use while object drawing **************
217 * or after running ED_view3d_init_mats_rv3d
219 static void view3d_project_short_clip(ARegion *ar, const float vec[3], short adr[2], int is_local)
221 RegionView3D *rv3d = ar->regiondata;
222 float fx, fy, vec4[4];
226 /* clipplanes in eye space */
227 if (rv3d->rflag & RV3D_CLIPPING) {
228 if (ED_view3d_clipping_test(rv3d, vec, is_local))
232 copy_v3_v3(vec4, vec);
235 mul_m4_v4(rv3d->persmatob, vec4);
237 /* clipplanes in window space */
238 if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */
239 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
241 if (fx > 0 && fx < ar->winx) {
243 fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
245 if (fy > 0.0f && fy < (float)ar->winy) {
246 adr[0] = (short)floorf(fx);
247 adr[1] = (short)floorf(fy);
253 /* BMESH NOTE: this function is unused in bmesh only */
255 /* only use while object drawing */
256 static void UNUSED_FUNCTION(view3d_project_short_noclip) (ARegion * ar, const float vec[3], short adr[2])
258 RegionView3D *rv3d = ar->regiondata;
259 float fx, fy, vec4[4];
263 copy_v3_v3(vec4, vec);
266 mul_m4_v4(rv3d->persmatob, vec4);
268 if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */
269 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
271 if (fx > -32700 && fx < 32700) {
273 fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
275 if (fy > -32700.0f && fy < 32700.0f) {
276 adr[0] = (short)floorf(fx);
277 adr[1] = (short)floorf(fy);
283 /* same as view3d_project_short_clip but use persmat instead of persmatob for projection */
284 static void view3d_project_short_clip_persmat(ARegion *ar, const float vec[3], short adr[2], int is_local)
286 RegionView3D *rv3d = ar->regiondata;
287 float fx, fy, vec4[4];
291 /* clipplanes in eye space */
292 if (rv3d->rflag & RV3D_CLIPPING) {
293 if (ED_view3d_clipping_test(rv3d, vec, is_local))
297 copy_v3_v3(vec4, vec);
300 mul_m4_v4(rv3d->persmat, vec4);
302 /* clipplanes in window space */
303 if (vec4[3] > (float)BL_NEAR_CLIP) { /* is the NEAR clipping cutoff for picking */
304 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
306 if (fx > 0 && fx < ar->winx) {
308 fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
310 if (fy > 0.0f && fy < (float)ar->winy) {
311 adr[0] = (short)floorf(fx);
312 adr[1] = (short)floorf(fy);
317 /* ************************ */
319 /* check for glsl drawing */
321 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
323 if (!GPU_glsl_support())
327 if (!check_object_draw_texture(scene, v3d, dt))
329 if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
331 if (scene_use_new_shading_nodes(scene))
334 return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
337 static int check_alpha_pass(Base *base)
339 if (base->flag & OB_FROMDUPLI)
345 return (base->object->dtx & OB_DRAWTRANSP);
349 static unsigned int colortab[24] =
350 {0x0, 0xFF88FF, 0xFFBBFF,
351 0x403000, 0xFFFF88, 0xFFFFBB,
352 0x104040, 0x66CCCC, 0x77CCCC,
353 0x104010, 0x55BB55, 0x66FF66,
357 static float cube[8][3] = {
368 /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
369 /* 32 values of sin function (still same result!) */
370 #define CIRCLE_RESOL 32
372 static const float sinval[CIRCLE_RESOL] = {
407 /* 32 values of cos function (still same result!) */
408 static const float cosval[CIRCLE_RESOL] = {
443 static void draw_xyz_wire(const float c[3], float size, int axis)
445 float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
446 float dim = size * 0.1f;
447 float dx[3], dy[3], dz[3];
449 dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
450 dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
451 dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
457 /* bottom left to top right */
458 sub_v3_v3v3(v1, c, dx);
460 add_v3_v3v3(v2, c, dx);
466 /* top left to bottom right */
479 /* bottom left to top right */
480 mul_v3_fl(dx, 0.75f);
481 sub_v3_v3v3(v1, c, dx);
483 add_v3_v3v3(v2, c, dx);
489 /* top left to center */
500 glBegin(GL_LINE_STRIP);
502 /* start at top left */
503 sub_v3_v3v3(v1, c, dx);
504 add_v3_v3v3(v1, c, dz);
529 void drawaxes(float size, char drawtype)
532 float v1[3] = {0.0, 0.0, 0.0};
533 float v2[3] = {0.0, 0.0, 0.0};
534 float v3[3] = {0.0, 0.0, 0.0};
539 for (axis = 0; axis < 3; axis++) {
547 /* reset v1 & v2 to zero */
548 v1[axis] = v2[axis] = 0.0f;
553 case OB_SINGLE_ARROW:
556 /* in positive z direction only */
563 glBegin(GL_TRIANGLES);
565 v2[0] = size * 0.035f; v2[1] = size * 0.035f;
566 v3[0] = size * -0.035f; v3[1] = size * 0.035f;
567 v2[2] = v3[2] = size * 0.75f;
569 for (axis = 0; axis < 4; axis++) {
592 drawcircle_size(size);
595 case OB_EMPTY_SPHERE:
596 draw_empty_sphere(size);
600 draw_empty_cone(size);
606 for (axis = 0; axis < 3; axis++) {
607 const int arrow_axis = (axis == 0) ? 1 : 0;
615 v1[axis] = size * 0.85f;
616 v1[arrow_axis] = -size * 0.08f;
620 v1[arrow_axis] = size * 0.08f;
626 v2[axis] += size * 0.125f;
628 draw_xyz_wire(v2, size, axis);
631 /* reset v1 & v2 to zero */
632 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
640 /* Function to draw an Image on a empty Object */
641 static void draw_empty_image(Object *ob)
643 Image *ima = (Image *)ob->data;
644 ImBuf *ibuf = ima ? BKE_image_get_ibuf(ima, NULL) : NULL;
646 float scale, ofs_x, ofs_y, sca_x, sca_y;
649 if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
650 IMB_rect_from_float(ibuf);
653 /* Get the buffer dimensions so we can fallback to fake ones */
654 if (ibuf && ibuf->rect) {
663 /* Get the image aspect even if the buffer is invalid */
665 if (ima->aspx > ima->aspy) {
667 sca_y = ima->aspy / ima->aspx;
669 else if (ima->aspx < ima->aspy) {
670 sca_x = ima->aspx / ima->aspy;
683 /* Calculate the scale center based on objects origin */
684 ofs_x = ob->ima_ofs[0] * ima_x;
685 ofs_y = ob->ima_ofs[1] * ima_y;
687 glMatrixMode(GL_MODELVIEW);
690 /* Make sure we are drawing at the origin */
691 glTranslatef(0.0f, 0.0f, 0.0f);
693 /* Calculate Image scale */
694 scale = (ob->empty_drawsize / (float)MAX2(ima_x * sca_x, ima_y * sca_y));
696 /* Set the object scale */
697 glScalef(scale * sca_x, scale * sca_y, 1.0f);
699 if (ibuf && ibuf->rect) {
700 /* Setup GL params */
702 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
704 /* Use the object color and alpha */
707 /* Draw the Image on the screen */
708 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
709 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
714 UI_ThemeColor((ob->flag & SELECT) ? TH_SELECT : TH_WIRE);
716 /* Calculate the outline vertex positions */
717 glBegin(GL_LINE_LOOP);
718 glVertex2f(ofs_x, ofs_y);
719 glVertex2f(ofs_x + ima_x, ofs_y);
720 glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
721 glVertex2f(ofs_x, ofs_y + ima_y);
724 /* Reset GL settings */
725 glMatrixMode(GL_MODELVIEW);
729 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[][4])
732 float *viter = (float *)verts;
735 mul_v3_v3fl(vx, tmat[0], rad);
736 mul_v3_v3fl(vy, tmat[1], rad);
738 for (a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
739 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
740 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
741 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
745 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
747 float verts[CIRCLE_RESOL][3];
749 circball_array_fill(verts, cent, rad, tmat);
751 glEnableClientState(GL_VERTEX_ARRAY);
752 glVertexPointer(3, GL_FLOAT, 0, verts);
753 glDrawArrays(mode, 0, CIRCLE_RESOL);
754 glDisableClientState(GL_VERTEX_ARRAY);
757 /* circle for object centers, special_color is for library or ob users */
758 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
760 const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
761 float verts[CIRCLE_RESOL][3];
763 /* using gldepthfunc guarantees that it does write z values,
764 * but not checks for it, so centers remain visible independent order of drawing */
765 if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
769 if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
771 else glColor4ub(0x55, 0xCC, 0xCC, 155);
774 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
775 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
776 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
779 circball_array_fill(verts, co, size, rv3d->viewinv);
781 /* enable vertex array */
782 glEnableClientState(GL_VERTEX_ARRAY);
783 glVertexPointer(3, GL_FLOAT, 0, verts);
785 /* 1. draw filled, blended polygon */
786 glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
788 /* 2. draw outline */
789 UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
790 glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
793 glDisableClientState(GL_VERTEX_ARRAY);
797 if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
800 /* *********** text drawing for object/particles/armature ************* */
801 static ListBase CachedText[3];
802 static int CachedTextLevel = 0;
804 typedef struct ViewCachedString {
805 struct ViewCachedString *next, *prev;
815 /* str is allocated past the end */
818 void view3d_cached_text_draw_begin(void)
820 ListBase *strings = &CachedText[CachedTextLevel];
821 strings->first = strings->last = NULL;
825 void view3d_cached_text_draw_add(const float co[3],
827 short xoffs, short flag,
828 const unsigned char col[4])
830 int alloc_len = strlen(str) + 1;
831 ListBase *strings = &CachedText[CachedTextLevel - 1];
832 /* TODO, replace with more efficient malloc, perhaps memarena per draw? */
833 ViewCachedString *vos = MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
835 BLI_addtail(strings, vos);
836 copy_v3_v3(vos->vec, co);
837 vos->col.pack = *((int *)col);
840 vos->str_len = alloc_len - 1;
842 /* allocate past the end */
843 memcpy(++vos, str, alloc_len);
846 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
848 RegionView3D *rv3d = ar->regiondata;
849 ListBase *strings = &CachedText[CachedTextLevel - 1];
850 ViewCachedString *vos;
853 /* project first and test */
854 for (vos = strings->first; vos; vos = vos->next) {
855 if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
856 mul_m4_v3(mat, vos->vec);
858 if (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE)
859 view3d_project_short_clip_persmat(ar, vos->vec, vos->sco, (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0);
861 view3d_project_short_clip(ar, vos->vec, vos->sco, (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0);
863 if (vos->sco[0] != IS_CLIPPED)
868 int col_pack_prev = 0;
871 bglMats mats; /* ZBuffer depth vars */
878 if (rv3d->rflag & RV3D_CLIPPING) {
879 ED_view3d_clipping_disable();
882 glMatrixMode(GL_PROJECTION);
884 glMatrixMode(GL_MODELVIEW);
886 ED_region_pixelspace(ar);
889 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
895 for (vos = strings->first; vos; vos = vos->next) {
896 /* too slow, reading opengl info while drawing is very bad,
897 * better to see if we can use the zbuffer while in pixel space - campbell */
899 if (v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
900 gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
901 glReadPixels(ar->winrct.xmin + vos->mval[0] + vos->xoffs, ar->winrct.ymin + vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
907 if (vos->sco[0] != IS_CLIPPED) {
908 const char *str = (char *)(vos + 1);
910 if (col_pack_prev != vos->col.pack) {
911 glColor3ubv(vos->col.ub);
912 col_pack_prev = vos->col.pack;
915 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
916 BLF_draw_default_ascii :
918 )( (float)vos->sco[0] + vos->xoffs,
920 (depth_write) ? 0.0f : 2.0f,
927 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
931 glMatrixMode(GL_PROJECTION);
933 glMatrixMode(GL_MODELVIEW);
936 if (rv3d->rflag & RV3D_CLIPPING) {
937 ED_view3d_clipping_enable();
942 BLI_freelistN(strings);
947 /* ******************** primitive drawing ******************* */
949 static void drawcube(void)
952 glBegin(GL_LINE_STRIP);
953 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
954 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
955 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
958 glBegin(GL_LINE_STRIP);
959 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
962 glBegin(GL_LINE_STRIP);
963 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
966 glBegin(GL_LINE_STRIP);
967 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
971 /* draws a cube on given the scaling of the cube, assuming that
972 * all required matrices have been set (used for drawing empties)
974 static void drawcube_size(float size)
976 glBegin(GL_LINE_STRIP);
977 glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size);
978 glVertex3f(-size, size, size); glVertex3f(-size, size, -size);
980 glVertex3f(-size, -size, -size); glVertex3f(size, -size, -size);
981 glVertex3f(size, -size, size); glVertex3f(size, size, size);
983 glVertex3f(size, size, -size); glVertex3f(size, -size, -size);
986 glBegin(GL_LINE_STRIP);
987 glVertex3f(-size, -size, size); glVertex3f(size, -size, size);
990 glBegin(GL_LINE_STRIP);
991 glVertex3f(-size, size, size); glVertex3f(size, size, size);
994 glBegin(GL_LINE_STRIP);
995 glVertex3f(-size, size, -size); glVertex3f(size, size, -size);
999 /* this is an unused (old) cube-drawing function based on a given size */
1001 static void drawcube_size(const float size[3])
1005 glScalef(size[0], size[1], size[2]);
1008 glBegin(GL_LINE_STRIP);
1009 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
1010 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
1011 glVertex3fv(cube[7]); glVertex3fv(cube[4]);
1014 glBegin(GL_LINE_STRIP);
1015 glVertex3fv(cube[1]); glVertex3fv(cube[5]);
1018 glBegin(GL_LINE_STRIP);
1019 glVertex3fv(cube[2]); glVertex3fv(cube[6]);
1022 glBegin(GL_LINE_STRIP);
1023 glVertex3fv(cube[3]); glVertex3fv(cube[7]);
1030 static void drawshadbuflimits(Lamp *la, float mat[][4])
1032 float sta[3], end[3], lavec[3];
1034 negate_v3_v3(lavec, mat[2]);
1035 normalize_v3(lavec);
1037 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
1038 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
1040 glBegin(GL_LINE_STRIP);
1046 bglBegin(GL_POINTS);
1055 static void spotvolume(float lvec[3], float vvec[3], const float inp)
1057 /* camera is at 0,0,0 */
1058 float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
1061 normalize_v3(vvec); /* is this the correct vector ? */
1063 cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec en lvec */
1064 cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parrallel with lvec */
1066 /* vectors are exactly aligned, use the X axis, this is arbitrary */
1067 if (normalize_v3(plane) == 0.0f)
1070 /* now we've got two equations: one of a cone and one of a plane, but we have
1071 * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
1073 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
1074 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
1076 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
1081 normalize_v3(&q[1]);
1083 angle = saacos(plane[2]) / 2.0f;
1085 si = sqrtf(1 - co * co);
1092 quat_to_mat3(mat1, q);
1094 /* rotate lamp vector now over acos(inp) degrees */
1095 copy_v3_v3(vvec, lvec);
1099 si = sqrtf(1.0f - inp * inp);
1105 mul_m3_m3m3(mat3, mat2, mat1);
1109 mul_m3_m3m3(mat4, mat2, mat1);
1112 mul_m3_m3m3(mat2, mat1, mat3);
1113 mul_m3_v3(mat2, lvec);
1114 mul_m3_m3m3(mat2, mat1, mat4);
1115 mul_m3_v3(mat2, vvec);
1120 static void draw_spot_cone(Lamp *la, float x, float z)
1124 glBegin(GL_TRIANGLE_FAN);
1125 glVertex3f(0.0f, 0.0f, -x);
1127 if (la->mode & LA_SQUARE) {
1128 glVertex3f(z, z, 0);
1129 glVertex3f(-z, z, 0);
1130 glVertex3f(-z, -z, 0);
1131 glVertex3f(z, -z, 0);
1132 glVertex3f(z, z, 0);
1138 for (a = 0; a < 33; a++) {
1139 angle = a * M_PI * 2 / (33 - 1);
1140 glVertex3f(z * cosf(angle), z * sinf(angle), 0);
1147 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1149 glEnable(GL_CULL_FACE);
1153 /* draw backside darkening */
1154 glCullFace(GL_FRONT);
1156 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1157 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1159 draw_spot_cone(la, x, z);
1161 /* draw front side lighting */
1162 glCullFace(GL_BACK);
1164 glBlendFunc(GL_ONE, GL_ONE);
1165 glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1167 draw_spot_cone(la, x, z);
1170 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1171 glDisable(GL_BLEND);
1173 glDisable(GL_CULL_FACE);
1174 glCullFace(GL_BACK);
1177 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
1179 Object *ob = base->object;
1180 const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1181 Lamp *la = ob->data;
1182 float vec[3], lvec[3], vvec[3], circrad, x, y, z;
1184 float imat[4][4], curcol[4];
1185 unsigned char col[4];
1186 /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1187 /* the moment of view3d_draw_transp() call */
1188 const short is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1189 const short drawcone = ((dt > OB_WIRE) &&
1190 !(G.f & G_PICKSEL) &&
1191 (la->type == LA_SPOT) &&
1192 (la->mode & LA_SHOW_CONE) &&
1193 !(base->flag & OB_FROMDUPLI) &&
1196 if (drawcone && !v3d->transp) {
1197 /* in this case we need to draw delayed */
1198 add_view3d_after(&v3d->afterdraw_transp, base, flag);
1202 /* we first draw only the screen aligned & fixed scale stuff */
1204 glLoadMatrixf(rv3d->viewmat);
1206 /* lets calculate the scale: */
1207 lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
1209 /* and view aligned matrix: */
1210 copy_m4_m4(imat, rv3d->viewinv);
1211 normalize_v3(imat[0]);
1212 normalize_v3(imat[1]);
1215 copy_v3_v3(vec, ob->obmat[3]);
1217 /* for AA effects */
1218 glGetFloatv(GL_CURRENT_COLOR, curcol);
1222 if (lampsize > 0.0f) {
1224 if (ob->id.us > 1) {
1225 if (ob == OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1226 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1231 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1232 glDisable(GL_BLEND);
1233 drawcircball(GL_POLYGON, vec, lampsize, imat);
1240 circrad = 3.0f * lampsize;
1243 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1245 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1246 if (la->type != LA_HEMI) {
1247 if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1248 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
1257 /* draw the pretty sun rays */
1258 if (la->type == LA_SUN) {
1259 float v1[3], v2[3], mat[3][3];
1262 /* setup a 45 degree rotation matrix */
1263 vec_rot_to_mat3(mat, imat[2], (float)M_PI / 4.0f);
1266 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1267 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1270 glTranslatef(vec[0], vec[1], vec[2]);
1275 for (axis = 0; axis < 8; axis++) {
1283 glTranslatef(-vec[0], -vec[1], -vec[2]);
1287 if (la->type == LA_LOCAL) {
1288 if (la->mode & LA_SPHERE) {
1289 drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1293 glPopMatrix(); /* back in object space */
1297 /* skip drawing extra info */
1299 else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
1300 lvec[0] = lvec[1] = 0.0;
1302 x = rv3d->persmat[0][2];
1303 y = rv3d->persmat[1][2];
1304 z = rv3d->persmat[2][2];
1305 vvec[0] = x * ob->obmat[0][0] + y * ob->obmat[0][1] + z * ob->obmat[0][2];
1306 vvec[1] = x * ob->obmat[1][0] + y * ob->obmat[1][1] + z * ob->obmat[1][2];
1307 vvec[2] = x * ob->obmat[2][0] + y * ob->obmat[2][1] + z * ob->obmat[2][2];
1309 y = cosf(la->spotsize * (float)(M_PI / 360.0));
1310 spotvolume(lvec, vvec, y);
1315 /* draw the angled sides of the cone */
1316 glBegin(GL_LINE_STRIP);
1322 z = x * sqrtf(1.0f - y * y);
1325 /* draw the circle/square at the end of the cone */
1326 glTranslatef(0.0, 0.0, x);
1327 if (la->mode & LA_SQUARE) {
1329 float z_abs = fabs(z);
1331 tvec[0] = tvec[1] = z_abs;
1334 glBegin(GL_LINE_LOOP);
1336 tvec[1] = -z_abs; /* neg */
1338 tvec[0] = -z_abs; /* neg */
1340 tvec[1] = z_abs; /* pos */
1344 else circ(0.0, 0.0, fabsf(z));
1346 /* draw the circle/square representing spotbl */
1347 if (la->type == LA_SPOT) {
1348 float spotblcirc = fabs(z) * (1 - pow(la->spotblend, 2));
1349 /* hide line if it is zero size or overlaps with outer border,
1350 * previously it adjusted to always to show it but that seems
1351 * confusing because it doesn't show the actual blend size */
1352 if (spotblcirc != 0 && spotblcirc != fabsf(z))
1353 circ(0.0, 0.0, spotblcirc);
1357 draw_transp_spot_volume(la, x, z);
1359 /* draw clip start, useful for wide cones where its not obvious where the start is */
1360 glTranslatef(0.0, 0.0, -x); /* reverse translation above */
1361 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1364 float clipsta_fac = la->clipsta / -x;
1366 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1367 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1369 glBegin(GL_LINE_STRIP);
1370 glVertex3fv(lvec_clip);
1371 glVertex3fv(vvec_clip);
1375 else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1377 /* draw the line from the circle along the dist */
1378 glBegin(GL_LINE_STRIP);
1385 if (la->type == LA_HEMI) {
1386 /* draw the hemisphere curves */
1387 short axis, steps, dir;
1388 float outdist, zdist, mul;
1390 outdist = 0.14; mul = 1.4; dir = 1;
1393 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1394 for (axis = 0; axis < 4; axis++) {
1395 float v[3] = {0.0, 0.0, 0.0};
1398 glBegin(GL_LINE_STRIP);
1400 for (steps = 0; steps < 6; steps++) {
1401 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1402 /* make the arcs start at the edge of the energy circle */
1403 if (steps == 0) v[0] = dir * circrad;
1404 else v[0] = v[0] + dir * (steps * outdist);
1406 else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1407 /* make the arcs start at the edge of the energy circle */
1408 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1411 v[2] = v[2] - steps * zdist;
1415 zdist = zdist * mul;
1419 /* flip the direction */
1424 else if (la->type == LA_AREA) {
1426 if (la->area_shape == LA_AREA_SQUARE)
1427 fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
1428 else if (la->area_shape == LA_AREA_RECT)
1429 fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
1431 glBegin(GL_LINE_STRIP);
1432 glVertex3f(0.0, 0.0, -circrad);
1433 glVertex3f(0.0, 0.0, -la->dist);
1437 /* and back to viewspace */
1438 glLoadMatrixf(rv3d->viewmat);
1439 copy_v3_v3(vec, ob->obmat[3]);
1443 if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == FALSE)) {
1444 drawshadbuflimits(la, ob->obmat);
1447 UI_GetThemeColor4ubv(TH_LAMP, col);
1452 if (vec[2] > 0) vec[2] -= circrad;
1453 else vec[2] += circrad;
1455 glBegin(GL_LINE_STRIP);
1467 glDisable(GL_BLEND);
1469 /* restore for drawing extra stuff */
1474 static void draw_limit_line(float sta, float end, unsigned int col)
1477 glVertex3f(0.0, 0.0, -sta);
1478 glVertex3f(0.0, 0.0, -end);
1484 glVertex3f(0.0, 0.0, -sta);
1485 glVertex3f(0.0, 0.0, -end);
1491 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1492 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1493 static void draw_focus_cross(float dist, float size)
1496 glVertex3f(-size, 0.f, -dist);
1497 glVertex3f(size, 0.f, -dist);
1498 glVertex3f(0.f, -size, -dist);
1499 glVertex3f(0.f, size, -dist);
1503 #ifdef VIEW3D_CAMERA_BORDER_HACK
1504 float view3d_camera_border_hack_col[4];
1505 short view3d_camera_border_hack_test = FALSE;
1508 /* ****************** draw clip data *************** */
1510 static void draw_bundle_sphere(void)
1512 static GLuint displist = 0;
1514 if (displist == 0) {
1515 GLUquadricObj *qobj;
1517 displist = glGenLists(1);
1518 glNewList(displist, GL_COMPILE);
1520 qobj = gluNewQuadric();
1521 gluQuadricDrawStyle(qobj, GLU_FILL);
1522 glShadeModel(GL_SMOOTH);
1523 gluSphere(qobj, 0.05, 8, 8);
1524 glShadeModel(GL_FLAT);
1525 gluDeleteQuadric(qobj);
1530 glCallList(displist);
1533 static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
1534 MovieClip *clip, MovieTrackingObject *tracking_object, int flag,
1535 int *global_track_index, int draw_selected)
1537 MovieTracking *tracking = &clip->tracking;
1538 MovieTrackingTrack *track;
1539 float mat[4][4], imat[4][4];
1540 unsigned char col[4], scol[4];
1541 int tracknr = *global_track_index;
1542 ListBase *tracksbase = BKE_tracking_object_tracks(tracking, tracking_object);
1544 UI_GetThemeColor4ubv(TH_TEXT, col);
1545 UI_GetThemeColor4ubv(TH_SELECT, scol);
1547 BKE_get_tracking_mat(scene, base->object, mat);
1551 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1552 /* current ogl matrix is translated in camera space, bundles should
1553 * be rendered in world space, so camera matrix should be "removed"
1554 * from current ogl matrix */
1555 invert_m4_m4(imat, base->object->obmat);
1557 glMultMatrixf(imat);
1563 BKE_tracking_get_interpolated_camera(tracking, tracking_object, scene->r.cfra, obmat);
1565 invert_m4_m4(imat, obmat);
1566 glMultMatrixf(imat);
1569 for (track = tracksbase->first; track; track = track->next) {
1570 int selected = TRACK_SELECTED(track);
1572 if (draw_selected && !selected)
1575 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1578 if (flag & DRAW_PICKING)
1579 glLoadName(base->selcol + (tracknr << 16));
1582 glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
1583 glScalef(v3d->bundle_size / 0.05f, v3d->bundle_size / 0.05f, v3d->bundle_size / 0.05f);
1585 if (v3d->drawtype == OB_WIRE) {
1586 glDisable(GL_LIGHTING);
1589 if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1590 else UI_ThemeColor(TH_SELECT);
1593 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1594 else UI_ThemeColor(TH_WIRE);
1597 drawaxes(0.05f, v3d->bundle_drawtype);
1599 glEnable(GL_LIGHTING);
1601 else if (v3d->drawtype > OB_WIRE) {
1602 if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1603 /* selection outline */
1605 if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1606 else UI_ThemeColor(TH_SELECT);
1609 glDisable(GL_LIGHTING);
1610 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1612 draw_bundle_sphere();
1614 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1615 glEnable(GL_LIGHTING);
1619 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1620 else UI_ThemeColor(TH_BUNDLE_SOLID);
1622 draw_bundle_sphere();
1625 glDisable(GL_LIGHTING);
1628 if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1629 else UI_ThemeColor(TH_SELECT);
1632 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1633 else UI_ThemeColor(TH_WIRE);
1636 drawaxes(0.05f, v3d->bundle_drawtype);
1638 glEnable(GL_LIGHTING);
1644 if ((flag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1646 unsigned char tcol[4];
1648 if (selected) memcpy(tcol, scol, sizeof(tcol));
1649 else memcpy(tcol, col, sizeof(tcol));
1651 mul_v3_m4v3(pos, mat, track->bundle_pos);
1652 view3d_cached_text_draw_add(pos, track->name, 10, V3D_CACHE_TEXT_GLOBALSPACE, tcol);
1658 if ((flag & DRAW_PICKING) == 0) {
1659 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1660 MovieTrackingReconstruction *reconstruction;
1661 reconstruction = BKE_tracking_object_reconstruction(tracking, tracking_object);
1663 if (reconstruction->camnr) {
1664 MovieReconstructedCamera *camera = reconstruction->cameras;
1667 glDisable(GL_LIGHTING);
1668 UI_ThemeColor(TH_CAMERA_PATH);
1671 glBegin(GL_LINE_STRIP);
1672 for (a = 0; a < reconstruction->camnr; a++, camera++) {
1673 glVertex3fv(camera->mat[3]);
1678 glEnable(GL_LIGHTING);
1685 *global_track_index = tracknr;
1688 static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip,
1689 int flag, int draw_selected)
1691 MovieTracking *tracking = &clip->tracking;
1692 MovieTrackingObject *tracking_object;
1694 int global_track_index = 1;
1696 if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1699 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1702 glGetFloatv(GL_CURRENT_COLOR, curcol);
1704 glEnable(GL_LIGHTING);
1705 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1706 glEnable(GL_COLOR_MATERIAL);
1707 glShadeModel(GL_SMOOTH);
1709 tracking_object = tracking->objects.first;
1710 while (tracking_object) {
1711 draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
1712 flag, &global_track_index, draw_selected);
1714 tracking_object = tracking_object->next;
1718 glShadeModel(GL_FLAT);
1719 glDisable(GL_COLOR_MATERIAL);
1720 glDisable(GL_LIGHTING);
1724 if (flag & DRAW_PICKING)
1725 glLoadName(base->selcol);
1728 /* flag similar to draw_object() */
1729 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int flag)
1731 /* a standing up pyramid with (0,0,0) as top */
1733 Object *ob = base->object;
1735 float vec[4][3], asp[2], shift[2], scale[3];
1738 const short is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
1739 MovieClip *clip = object_get_movieclip(scene, base->object, 0);
1741 /* draw data for movie clip set as active for scene */
1743 draw_viewport_reconstruction(scene, base, v3d, clip, flag, FALSE);
1744 draw_viewport_reconstruction(scene, base, v3d, clip, flag, TRUE);
1747 #ifdef VIEW3D_CAMERA_BORDER_HACK
1748 if (is_view && !(G.f & G_PICKSEL)) {
1749 glGetFloatv(GL_CURRENT_COLOR, view3d_camera_border_hack_col);
1750 view3d_camera_border_hack_test = TRUE;
1757 scale[0] = 1.0f / len_v3(ob->obmat[0]);
1758 scale[1] = 1.0f / len_v3(ob->obmat[1]);
1759 scale[2] = 1.0f / len_v3(ob->obmat[2]);
1761 camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
1762 asp, shift, &drawsize, vec);
1764 glDisable(GL_LIGHTING);
1765 glDisable(GL_CULL_FACE);
1768 glBegin(GL_LINE_LOOP);
1769 glVertex3fv(vec[0]);
1770 glVertex3fv(vec[1]);
1771 glVertex3fv(vec[2]);
1772 glVertex3fv(vec[3]);
1780 /* center point to camera frame */
1781 glBegin(GL_LINE_STRIP);
1782 glVertex3fv(vec[1]);
1784 glVertex3fv(vec[0]);
1785 glVertex3fv(vec[3]);
1787 glVertex3fv(vec[2]);
1792 tvec[2] = vec[1][2]; /* copy the depth */
1795 /* draw an outline arrow for inactive cameras and filled
1796 * for active cameras. We actually draw both outline+filled
1797 * for active cameras so the wire can be seen side-on */
1798 for (i = 0; i < 2; i++) {
1799 if (i == 0) glBegin(GL_LINE_LOOP);
1800 else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1803 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
1804 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
1805 glVertex3fv(tvec); /* left */
1807 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
1808 glVertex3fv(tvec); /* right */
1811 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
1812 glVertex3fv(tvec); /* top */
1818 if (cam->flag & (CAM_SHOWLIMITS + CAM_SHOWMIST)) {
1822 /* draw in normalized object matrix space */
1823 copy_m4_m4(nobmat, ob->obmat);
1824 normalize_m4(nobmat);
1827 glLoadMatrixf(rv3d->viewmat);
1828 glMultMatrixf(nobmat);
1830 if (cam->flag & CAM_SHOWLIMITS) {
1831 draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
1832 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
1833 draw_focus_cross(object_camera_dof_distance(ob), cam->drawsize);
1836 wrld = scene->world;
1837 if (cam->flag & CAM_SHOWMIST)
1838 if (wrld) draw_limit_line(wrld->miststa, wrld->miststa + wrld->mistdist, 0xFFFFFF);
1845 /* flag similar to draw_object() */
1846 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
1847 Object *UNUSED(ob), int UNUSED(flag))
1849 //Speaker *spk = ob->data;
1856 for (j = 0; j < 3; j++) {
1857 vec[2] = 0.25f * j - 0.125f;
1859 glBegin(GL_LINE_LOOP);
1860 for (i = 0; i < 16; i++) {
1861 vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1862 vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1868 for (j = 0; j < 4; j++) {
1869 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1870 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1871 glBegin(GL_LINE_STRIP);
1872 for (i = 0; i < 3; i++) {
1878 vec[2] = 0.25f * i - 0.125f;
1884 glDisable(GL_BLEND);
1887 static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
1889 BPoint *bp = lt->def;
1890 float *co = dl ? dl->verts : NULL;
1893 UI_ThemeColor(sel ? TH_VERTEX_SELECT : TH_VERTEX);
1894 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1895 bglBegin(GL_POINTS);
1897 for (w = 0; w < lt->pntsw; w++) {
1898 int wxt = (w == 0 || w == lt->pntsw - 1);
1899 for (v = 0; v < lt->pntsv; v++) {
1900 int vxt = (v == 0 || v == lt->pntsv - 1);
1901 for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
1902 int uxt = (u == 0 || u == lt->pntsu - 1);
1903 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1904 if (bp->hide == 0) {
1905 if ((bp->f1 & SELECT) == sel) {
1906 bglVertex3fv(dl ? co : bp->vec);
1918 void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPoint *bp, int x, int y), void *userData)
1920 Object *obedit = vc->obedit;
1921 Lattice *lt = obedit->data;
1922 BPoint *bp = lt->editlatt->latt->def;
1923 DispList *dl = find_displist(&obedit->disp, DL_VERTS);
1924 float *co = dl ? dl->verts : NULL;
1925 int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
1926 short s[2] = {IS_CLIPPED, 0};
1928 ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */
1930 for (i = 0; i < N; i++, bp++, co += 3) {
1931 if (bp->hide == 0) {
1932 view3d_project_short_clip(vc->ar, dl ? co : bp->vec, s, TRUE);
1933 if (s[0] != IS_CLIPPED)
1934 func(userData, bp, s[0], s[1]);
1939 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
1941 int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
1945 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, use_wcol - 1);
1947 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
1953 glVertex3fv(&dl->verts[index * 3]);
1956 glVertex3fv(lt->def[index].vec);
1960 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1961 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1963 Lattice *lt = ob->data;
1966 int use_wcol = 0, is_edit = (lt->editlatt != NULL);
1968 /* now we default make displist, this will modifiers work for non animated case */
1969 if (ob->disp.first == NULL)
1970 lattice_calc_modifiers(scene, ob);
1971 dl = find_displist(&ob->disp, DL_VERTS);
1974 lt = lt->editlatt->latt;
1978 if (ob->defbase.first && lt->dvert) {
1979 use_wcol = ob->actdef;
1980 glShadeModel(GL_SMOOTH);
1985 for (w = 0; w < lt->pntsw; w++) {
1986 int wxt = (w == 0 || w == lt->pntsw - 1);
1987 for (v = 0; v < lt->pntsv; v++) {
1988 int vxt = (v == 0 || v == lt->pntsv - 1);
1989 for (u = 0; u < lt->pntsu; u++) {
1990 int uxt = (u == 0 || u == lt->pntsu - 1);
1992 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
1993 drawlattice__point(lt, dl, u, v, w - 1, use_wcol);
1994 drawlattice__point(lt, dl, u, v, w, use_wcol);
1996 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
1997 drawlattice__point(lt, dl, u, v - 1, w, use_wcol);
1998 drawlattice__point(lt, dl, u, v, w, use_wcol);
2000 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2001 drawlattice__point(lt, dl, u - 1, v, w, use_wcol);
2002 drawlattice__point(lt, dl, u, v, w, use_wcol);
2009 /* restoration for weight colors */
2011 glShadeModel(GL_FLAT);
2014 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2016 lattice_draw_verts(lt, dl, 0);
2017 lattice_draw_verts(lt, dl, 1);
2019 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2023 /* ***************** ******************** */
2025 /* Note! - foreach funcs should be called while drawing or directly after
2026 * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
2027 * but would not give correct results with dupli's for eg. which don't
2028 * use the object matrix in the usual way */
2029 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3],
2030 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2032 foreachScreenVert_userData *data = userData;
2033 BMVert *eve = EDBM_vert_at_index(data->vc.em, index);
2035 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2036 short s[2] = {IS_CLIPPED, 0};
2038 if (data->clipVerts != V3D_CLIP_TEST_OFF) {
2039 view3d_project_short_clip(data->vc.ar, co, s, TRUE);
2043 mul_v3_m4v3(co2, data->vc.obedit->obmat, co);
2044 project_short_noclip(data->vc.ar, co2, s);
2047 if (s[0] != IS_CLIPPED)
2048 data->func(data->userData, eve, s[0], s[1], index);
2052 void mesh_foreachScreenVert(
2054 void (*func)(void *userData, BMVert *eve, int x, int y, int index),
2055 void *userData, eV3DClipTest clipVerts)
2057 foreachScreenVert_userData data;
2058 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2062 data.userData = userData;
2063 data.clipVerts = clipVerts;
2065 if (clipVerts != V3D_CLIP_TEST_OFF)
2066 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2068 EDBM_index_arrays_init(vc->em, 1, 0, 0);
2069 dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
2070 EDBM_index_arrays_free(vc->em);
2076 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
2077 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2079 MVert *mv = &((MVert *)userData)[index];
2081 if (!(mv->flag & ME_HIDE)) {
2082 const char sel = mv->flag & SELECT;
2084 // TODO define selected color
2086 glColor3f(1.0f, 1.0f, 0.0f);
2089 glColor3f(0.0f, 0.0f, 0.0f);
2096 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
2099 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, me->mvert);
2103 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const float v0co[3], const float v1co[3])
2105 foreachScreenEdge_userData *data = userData;
2106 BMEdge *eed = EDBM_edge_at_index(data->vc.em, index);
2108 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2111 if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) {
2112 view3d_project_short_clip(data->vc.ar, v0co, s[0], TRUE);
2113 view3d_project_short_clip(data->vc.ar, v1co, s[1], TRUE);
2116 float v1_co[3], v2_co[3];
2118 mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co);
2119 mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co);
2121 project_short_noclip(data->vc.ar, v1_co, s[0]);
2122 project_short_noclip(data->vc.ar, v2_co, s[1]);
2124 if (data->clipVerts == V3D_CLIP_TEST_REGION) {
2125 /* make an int copy */
2126 int s_int[2][2] = {{s[0][0], s[0][1]},
2127 {s[1][0], s[1][1]}};
2128 if (!BLI_segment_in_rcti(&data->win_rect, s_int[0], s_int[1])) {
2134 data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index);
2138 void mesh_foreachScreenEdge(
2140 void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index),
2141 void *userData, eV3DClipTest clipVerts)
2143 foreachScreenEdge_userData data;
2144 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2148 data.win_rect.xmin = 0;
2149 data.win_rect.ymin = 0;
2150 data.win_rect.xmax = vc->ar->winx;
2151 data.win_rect.ymax = vc->ar->winy;
2154 data.userData = userData;
2155 data.clipVerts = clipVerts;
2157 if (clipVerts != V3D_CLIP_TEST_OFF)
2158 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2160 EDBM_index_arrays_init(vc->em, 0, 1, 0);
2161 dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
2162 EDBM_index_arrays_free(vc->em);
2167 static void mesh_foreachScreenFace__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2169 foreachScreenFace_userData *data = userData;
2170 BMFace *efa = EDBM_face_at_index(data->vc.em, index);
2172 if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2176 mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent);
2177 project_short(data->vc.ar, cent2, s);
2179 if (s[0] != IS_CLIPPED) {
2180 data->func(data->userData, efa, s[0], s[1], index);
2185 void mesh_foreachScreenFace(
2187 void (*func)(void *userData, BMFace *efa, int x, int y, int index),
2190 foreachScreenFace_userData data;
2191 DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2195 data.userData = userData;
2198 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2200 EDBM_index_arrays_init(vc->em, 0, 0, 1);
2201 dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
2202 EDBM_index_arrays_free(vc->em);
2207 void nurbs_foreachScreenVert(
2209 void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y),
2212 Curve *cu = vc->obedit->data;
2213 short s[2] = {IS_CLIPPED, 0};
2216 ListBase *nurbs = curve_editnurbs(cu);
2218 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2220 for (nu = nurbs->first; nu; nu = nu->next) {
2221 if (nu->type == CU_BEZIER) {
2222 for (i = 0; i < nu->pntsu; i++) {
2223 BezTriple *bezt = &nu->bezt[i];
2225 if (bezt->hide == 0) {
2227 if (cu->drawflag & CU_HIDE_HANDLES) {
2228 view3d_project_short_clip(vc->ar, bezt->vec[1], s, TRUE);
2229 if (s[0] != IS_CLIPPED)
2230 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
2233 view3d_project_short_clip(vc->ar, bezt->vec[0], s, TRUE);
2234 if (s[0] != IS_CLIPPED)
2235 func(userData, nu, NULL, bezt, 0, s[0], s[1]);
2236 view3d_project_short_clip(vc->ar, bezt->vec[1], s, TRUE);
2237 if (s[0] != IS_CLIPPED)
2238 func(userData, nu, NULL, bezt, 1, s[0], s[1]);
2239 view3d_project_short_clip(vc->ar, bezt->vec[2], s, TRUE);
2240 if (s[0] != IS_CLIPPED)
2241 func(userData, nu, NULL, bezt, 2, s[0], s[1]);
2247 for (i = 0; i < nu->pntsu * nu->pntsv; i++) {
2248 BPoint *bp = &nu->bp[i];
2250 if (bp->hide == 0) {
2251 view3d_project_short_clip(vc->ar, bp->vec, s, TRUE);
2252 if (s[0] != IS_CLIPPED)
2253 func(userData, nu, bp, NULL, -1, s[0], s[1]);
2260 /* ************** DRAW MESH ****************** */
2262 /* First section is all the "simple" draw routines,
2263 * ones that just pass some sort of primitive to GL,
2264 * with perhaps various options to control lighting,
2267 * These routines should not have user interface related
2271 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2273 drawDMNormal_userData *data = userData;
2274 BMFace *efa = EDBM_face_at_index(data->em, index);
2276 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2278 glVertex3f(cent[0] + no[0] * data->normalsize,
2279 cent[1] + no[1] * data->normalsize,
2280 cent[2] + no[2] * data->normalsize);
2283 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2285 drawDMNormal_userData data;
2288 data.normalsize = scene->toolsettings->normalsize;
2291 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data);
2295 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2297 BMFace *efa = EDBM_face_at_index(((void **)userData)[0], index);
2298 int sel = *(((int **)userData)[1]);
2300 if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT) == sel) {
2304 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel)
2306 void *ptrs[2] = {em, &sel};
2308 bglBegin(GL_POINTS);
2309 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs);
2313 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])
2315 drawDMNormal_userData *data = userData;
2316 BMVert *eve = EDBM_vert_at_index(data->em, index);
2318 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2322 glVertex3f(co[0] + no_f[0] * data->normalsize,
2323 co[1] + no_f[1] * data->normalsize,
2324 co[2] + no_f[2] * data->normalsize);
2327 glVertex3f(co[0] + no_s[0] * (data->normalsize / 32767.0f),
2328 co[1] + no_s[1] * (data->normalsize / 32767.0f),
2329 co[2] + no_s[2] * (data->normalsize / 32767.0f));
2333 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2335 drawDMNormal_userData data;
2338 data.normalsize = scene->toolsettings->normalsize;
2341 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data);
2345 /* Draw verts with color set based on selection */
2346 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2347 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2349 drawDMVerts_userData *data = userData;
2350 BMVert *eve = EDBM_vert_at_index(data->em, index);
2352 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2353 /* draw active larger - need to stop/start point drawing for this :/ */
2354 if (eve == data->eve_act) {
2355 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2356 UI_ThemeColor4(TH_EDITMESH_ACTIVE);
2361 bglBegin(GL_POINTS);
2365 UI_ThemeColor4(data->sel ? TH_VERTEX_SELECT : TH_VERTEX);
2367 bglBegin(GL_POINTS);
2375 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act)
2377 drawDMVerts_userData data;
2379 data.eve_act = eve_act;
2382 bglBegin(GL_POINTS);
2383 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
2387 /* Draw edges with color set based on selection */
2388 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2391 //unsigned char **cols = userData, *col;
2392 drawDMEdgesSel_userData *data = userData;
2395 eed = EDBM_edge_at_index(data->em, index);
2397 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2398 if (eed == data->eed_act) {
2399 glColor4ubv(data->actCol);
2402 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2406 col = data->baseCol;
2408 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2410 return DM_DRAW_OPTION_SKIP;
2414 return DM_DRAW_OPTION_NORMAL;
2417 return DM_DRAW_OPTION_SKIP;
2420 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2421 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2423 drawDMEdgesSel_userData data;
2425 data.baseCol = baseCol;
2426 data.selCol = selCol;
2427 data.actCol = actCol;
2429 data.eed_act = eed_act;
2430 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2434 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2436 if (BM_elem_flag_test(EDBM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2437 return DM_DRAW_OPTION_SKIP;
2439 return DM_DRAW_OPTION_NORMAL;
2442 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2444 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
2447 /* Draw edges with color interpolated based on selection */
2448 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2450 if (BM_elem_flag_test(EDBM_edge_at_index(((void **)userData)[0], index), BM_ELEM_HIDDEN))
2451 return DM_DRAW_OPTION_SKIP;
2453 return DM_DRAW_OPTION_NORMAL;
2455 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2457 BMEdge *eed = EDBM_edge_at_index(((void **)userData)[0], index);
2458 unsigned char **cols = userData;
2459 unsigned char *col0 = cols[(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1];
2460 unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1];
2462 glColor4ub(col0[0] + (col1[0] - col0[0]) * t,
2463 col0[1] + (col1[1] - col0[1]) * t,
2464 col0[2] + (col1[2] - col0[2]) * t,
2465 col0[3] + (col1[3] - col0[3]) * t);
2468 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2470 void *cols[3] = {em, baseCol, selCol};
2472 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2475 /* Draw only seam edges */
2476 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2478 BMEdge *eed = EDBM_edge_at_index(userData, index);
2480 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
2481 return DM_DRAW_OPTION_NORMAL;
2483 return DM_DRAW_OPTION_SKIP;
2486 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2488 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
2491 /* Draw only sharp edges */
2492 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2494 BMEdge *eed = EDBM_edge_at_index(userData, index);
2496 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
2497 return DM_DRAW_OPTION_NORMAL;
2499 return DM_DRAW_OPTION_SKIP;
2502 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2504 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
2508 /* Draw faces with color set based on selection
2509 * return 2 for the active face so it renders with stipple enabled */
2510 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
2512 drawDMFacesSel_userData *data = userData;
2513 BMFace *efa = EDBM_face_at_index(data->em, index);
2517 return DM_DRAW_OPTION_SKIP;
2519 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2520 if (efa == data->efa_act) {
2521 glColor4ubv(data->cols[2]);
2522 return DM_DRAW_OPTION_STIPPLE;
2525 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2527 return DM_DRAW_OPTION_SKIP;
2529 return DM_DRAW_OPTION_NORMAL;
2532 return DM_DRAW_OPTION_SKIP;
2535 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2538 drawDMFacesSel_userData *data = userData;
2542 unsigned char *col, *next_col;
2544 if (!data->orig_index)
2547 efa = EDBM_face_at_index(data->em, data->orig_index[index]);
2548 next_efa = EDBM_face_at_index(data->em, data->orig_index[next_index]);
2550 if (efa == next_efa)
2553 if (efa == data->efa_act || next_efa == data->efa_act)
2556 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2557 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
2559 if (col[3] == 0 || next_col[3] == 0)
2562 return col == next_col;
2565 /* also draws the active face */
2566 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2567 unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
2569 drawDMFacesSel_userData data;
2571 data.cols[0] = baseCol;
2573 data.cols[1] = selCol;
2574 data.cols[2] = actCol;
2575 data.efa_act = efa_act;
2576 data.orig_index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
2578 dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
2581 static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
2583 BMEditMesh *em = userData;
2584 BMEdge *eed = EDBM_edge_at_index(userData, index);
2585 float *crease = eed ? (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE) : NULL;
2588 return DM_DRAW_OPTION_SKIP;
2590 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *crease != 0.0f) {
2591 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, *crease);
2592 return DM_DRAW_OPTION_NORMAL;
2595 return DM_DRAW_OPTION_SKIP;
2598 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
2601 dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em);
2605 static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
2607 BMEditMesh *em = userData;
2608 BMEdge *eed = EDBM_edge_at_index(userData, index);
2609 float *bweight = (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
2612 return DM_DRAW_OPTION_SKIP;
2614 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *bweight != 0.0f) {
2615 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, *bweight);
2616 return DM_DRAW_OPTION_NORMAL;
2619 return DM_DRAW_OPTION_SKIP;
2622 static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
2623 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2625 BMEditMesh *em = userData;
2626 BMVert *eve = EDBM_vert_at_index(userData, index);
2627 float *bweight = (float *)CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_BWEIGHT);
2632 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && *bweight != 0.0f) {
2633 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, *bweight);
2637 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2639 ToolSettings *ts = scene->toolsettings;
2641 if (ts->selectmode & SCE_SELECT_VERTEX) {
2642 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2643 bglBegin(GL_POINTS);
2644 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em);
2649 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em);
2654 /* Second section of routines: Combine first sets to form fancy
2655 * drawing routines (for example rendering twice to get overlays).
2657 * Also includes routines that are basic drawing but are too
2658 * specialized to be split out (like drawing creases or measurements).
2661 /* EditMesh drawing routines*/
2663 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
2664 BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act)
2666 ToolSettings *ts = scene->toolsettings;
2669 if (v3d->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select
2671 for (sel = 0; sel < 2; sel++) {
2672 unsigned char col[4], fcol[4];
2675 UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
2676 UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE, fcol);
2678 for (pass = 0; pass < 2; pass++) {
2679 float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2680 float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2683 if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
2684 glDisable(GL_DEPTH_TEST);
2692 size = (size > 2.1f ? size / 2.0f : size);
2693 fsize = (fsize > 2.1f ? fsize / 2.0f : fsize);
2694 col[3] = fcol[3] = 100;
2697 col[3] = fcol[3] = 255;
2700 if (ts->selectmode & SCE_SELECT_VERTEX) {
2703 draw_dm_verts(em, cageDM, sel, eve_act);
2706 if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2709 draw_dm_face_centers(em, cageDM, sel);
2713 glDisable(GL_BLEND);
2714 glEnable(GL_DEPTH_TEST);
2719 if (v3d->zbuf) glDepthMask(1);
2723 static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
2724 Mesh *me, DerivedMesh *cageDM, short sel_only,
2727 ToolSettings *ts = scene->toolsettings;
2729 unsigned char wireCol[4], selCol[4], actCol[4];
2731 /* since this function does transparant... */
2732 UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2733 UI_GetThemeColor4ubv(TH_WIRE, wireCol);
2734 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2736 /* when sel only is used, don't render wire, only selected, this is used for
2737 * textured draw mode when the 'edges' option is disabled */
2741 for (pass = 0; pass < 2; pass++) {
2742 /* show wires in transparant when no zbuf clipping for select */
2744 if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) {
2746 glDisable(GL_DEPTH_TEST);
2748 if (!sel_only) wireCol[3] = 85;
2756 if (!sel_only) wireCol[3] = 255;
2759 if (ts->selectmode == SCE_SELECT_FACE) {
2760 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2762 else if ( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
2763 if (cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2764 glShadeModel(GL_SMOOTH);
2765 draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
2766 glShadeModel(GL_FLAT);
2769 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2774 glColor4ubv(wireCol);
2775 draw_dm_edges(em, cageDM);
2780 glDisable(GL_BLEND);
2781 glEnable(GL_DEPTH_TEST);
2786 static void draw_em_measure_stats(View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit)
2788 const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
2789 Mesh *me = ob->data;
2790 float v1[3], v2[3], v3[3], vmid[3], fvec[3];
2791 char numstr[32]; /* Stores the measurement display text here */
2792 const char *conv_float; /* Use a float conversion matching the grid size */
2793 unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */
2794 float area; /* area of the face */
2795 float grid = unit->system ? unit->scale_length : v3d->grid;
2796 const int do_split = unit->flag & USER_UNIT_OPT_SPLIT;
2797 const int do_global = v3d->flag & V3D_GLOBAL_STATS;
2798 const int do_moving = G.moving;
2803 /* make the precision of the pronted value proportionate to the gridsize */
2805 if (grid < 0.01f) conv_float = "%.6g";
2806 else if (grid < 0.1f) conv_float = "%.5g";
2807 else if (grid < 1.0f) conv_float = "%.4g";
2808 else if (grid < 10.0f) conv_float = "%.3g";
2809 else conv_float = "%.2g";
2811 if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2814 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2816 eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
2817 for (; eed; eed = BM_iter_step(&iter)) {
2818 /* draw selected edges, or edges next to selected verts while draging */
2819 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
2820 (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
2821 BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
2824 copy_v3_v3(v1, eed->v1->co);
2825 copy_v3_v3(v2, eed->v2->co);
2827 mid_v3_v3v3(vmid, v1, v2);
2830 mul_mat3_m4_v3(ob->obmat, v1);
2831 mul_mat3_m4_v3(ob->obmat, v2);
2835 bUnit_AsString(numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
2836 unit->system, B_UNIT_LENGTH, do_split, FALSE);
2839 sprintf(numstr, conv_float, len_v3v3(v1, v2));
2842 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col);
2847 if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2848 /* would be nice to use BM_face_calc_area, but that is for 2d faces
2849 * so instead add up tessellation triangle areas */
2853 #define DRAW_EM_MEASURE_STATS_FACEAREA() \
2854 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \
2855 mul_v3_fl(vmid, 1.0 / n); \
2857 bUnit_AsString(numstr, sizeof(numstr), area * unit->scale_length, \
2858 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); \
2860 BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
2861 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col); \
2864 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2870 for (i = 0; i < em->tottri; i++) {
2871 BMLoop **l = em->looptris[i];
2872 if (f && l[0]->f != f) {
2873 DRAW_EM_MEASURE_STATS_FACEAREA();
2880 copy_v3_v3(v1, l[0]->v->co);
2881 copy_v3_v3(v2, l[1]->v->co);
2882 copy_v3_v3(v3, l[2]->v->co);
2884 mul_mat3_m4_v3(ob->obmat, v1);
2885 mul_mat3_m4_v3(ob->obmat, v2);
2886 mul_mat3_m4_v3(ob->obmat, v3);
2888 area += area_tri_v3(v1, v2, v3);
2889 add_v3_v3(vmid, v1);
2890 add_v3_v3(vmid, v2);
2891 add_v3_v3(vmid, v3);
2896 DRAW_EM_MEASURE_STATS_FACEAREA();
2898 #undef DRAW_EM_MEASURE_STATS_FACEAREA
2901 if (me->drawflag & ME_DRAWEXTRA_FACEANG) {
2904 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2907 for (efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
2908 efa; efa = BM_iter_step(&iter))
2913 BM_face_calc_center_bounds(efa, vmid);
2915 for (loop = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
2916 loop; loop = BM_iter_step(&liter))
2918 float v1[3], v2[3], v3[3];
2920 copy_v3_v3(v1, loop->prev->v->co);
2921 copy_v3_v3(v2, loop->v->co);
2922 copy_v3_v3(v3, loop->next->v->co);
2925 mul_mat3_m4_v3(ob->obmat, v1);
2926 mul_mat3_m4_v3(ob->obmat, v2);
2927 mul_mat3_m4_v3(ob->obmat, v3);
2930 if ( (BM_elem_flag_test(efa, BM_ELEM_SELECT)) ||
2931 (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT)))
2933 BLI_snprintf(numstr, sizeof(numstr), "%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
2934 interp_v3_v3v3(fvec, vmid, v2, 0.8f);
2935 view3d_cached_text_draw_add(fvec, numstr, 0, txt_flag, col);
2942 static void draw_em_indices(BMEditMesh *em)
2944 const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
2951 unsigned char col[4];
2956 /* For now, reuse appropriate theme colors from stats text colors */
2958 if (em->selectmode & SCE_SELECT_VERTEX) {
2959 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
2960 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
2961 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
2962 sprintf(numstr, "%d", i);
2963 view3d_cached_text_draw_add(v->co, numstr, 0, txt_flag, col);
2969 if (em->selectmode & SCE_SELECT_EDGE) {
2971 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2972 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2973 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
2974 sprintf(numstr, "%d", i);
2975 mid_v3_v3v3(pos, e->v1->co, e->v2->co);
2976 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
2982 if (em->selectmode & SCE_SELECT_FACE) {
2984 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2985 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
2986 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
2987 BM_face_calc_center_mean(f, pos);
2988 sprintf(numstr, "%d", i);
2989 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
2996 static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
2998 BMFace *efa = EDBM_face_at_index(userData, index);
3000 if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
3001 GPU_enable_material(efa->mat_nr + 1, NULL);
3002 return DM_DRAW_OPTION_NORMAL;
3005 return DM_DRAW_OPTION_SKIP;
3008 static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
3010 BMFace *efa = EDBM_face_at_index(userData, index);
3012 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
3013 return DM_DRAW_OPTION_SKIP;
3015 return DM_DRAW_OPTION_NORMAL;
3018 static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
3019 Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
3022 Mesh *me = ob->data;
3023 BMFace *efa_act = BM_active_face_get(em->bm, FALSE); /* annoying but active faces is stored differently */
3024 BMEdge *eed_act = NULL;
3025 BMVert *eve_act = NULL;
3027 if (em->bm->selected.last) {
3028 BMEditSelection *ese = em->bm->selected.last;
3029 /* face is handeled above */
3031 if (ese->type == BM_FACE) {
3032 efa_act = (BMFace *)ese->data;
3036 if (ese->htype == BM_EDGE) {
3037 eed_act = (BMEdge *)ese->ele;
3039 else if (ese->htype == BM_VERT) {
3040 eve_act = (BMVert *)ese->ele;
3044 EDBM_index_arrays_init(em, 1, 1, 1);
3047 if (check_object_draw_texture(scene, v3d, dt)) {
3048 if (draw_glsl_material(scene, ob, v3d, dt)) {
3049 glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
3051 finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
3052 draw_em_fancy__setGLSLFaceOpts, em);
3053 GPU_disable_material();
3055 glFrontFace(GL_CCW);
3058 draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
3062 /* 3 floats for position,
3063 * 3 for normal and times two because the faces may actually be quads instead of triangles */
3064 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (me->flag & ME_TWOSIDED) ? GL_TRUE : GL_FALSE);
3066 glEnable(GL_LIGHTING);
3067 glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
3068 finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, 0);
3070 glFrontFace(GL_CCW);
3071 glDisable(GL_LIGHTING);
3072 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
3075 // Setup for drawing wire over, disable zbuffer
3076 // write to show selected edge wires better
3077 UI_ThemeColor(TH_WIRE);
3079 bglPolygonOffset(rv3d->dist, 1.0);
3083 if (cageDM != finalDM) {
3084 UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
3085 finalDM->drawEdges(finalDM, 1, 0);
3089 if (me->drawflag & ME_DRAWFACES) { /* transp faces */
3090 unsigned char col1[4], col2[4], col3[4];
3092 UI_GetThemeColor4ubv(TH_FACE, col1);
3093 UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
3094 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
3097 glDepthMask(0); // disable write in zbuffer, needed for nice transp
3099 /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
3100 if (check_object_draw_texture(scene, v3d, dt))
3103 draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
3105 glDisable(GL_BLEND);
3106 glDepthMask(1); // restore write in zbuffer
3109 /* even if draw faces is off it would be nice to draw the stipple face
3110 * Make all other faces zero alpha except for the active
3112 unsigned char col1[4], col2[4], col3[4];
3113 col1[3] = col2[3] = 0; /* don't draw */
3114 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
3117 glDepthMask(0); // disable write in zbuffer, needed for nice transp
3119 draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
3121 glDisable(GL_BLEND);
3122 glDepthMask(1); // restore write in zbuffer
3126 /* here starts all fancy draw-extra over */
3127 if ((me->drawflag & ME_DRAWEDGES) == 0 && check_object_draw_texture(scene, v3d, dt)) {
3128 /* we are drawing textures and 'ME_DRAWEDGES' is disabled, don't draw any edges */
3130 /* only draw selected edges otherwise there is no way of telling if a face is selected */
3131 draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
3135 if (me->drawflag & ME_DRAWSEAMS) {
3136 UI_ThemeColor(TH_EDGE_SEAM);
3139 draw_dm_edges_seams(em, cageDM);
3141 glColor3ub(0, 0, 0);
3145 if (me->drawflag & ME_DRAWSHARP) {
3146 UI_ThemeColor(TH_EDGE_SHARP);
3149 draw_dm_edges_sharp(em, cageDM);
3151 glColor3ub(0, 0, 0);
3155 if (me->drawflag & ME_DRAWCREASES && CustomData_has_layer(&em->bm->edata, CD_CREASE)) {
3156 draw_dm_creases(em, cageDM);
3158 if (me->drawflag & ME_DRAWBWEIGHTS) {
3159 draw_dm_bweights(em, scene, cageDM);
3162 draw_em_fancy_edges(em, scene, v3d, me