2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation, full recode and added functions
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/space_view3d/drawobject.c
30 #include "MEM_guardedalloc.h"
32 #include "DNA_camera_types.h"
33 #include "DNA_curve_types.h"
34 #include "DNA_constraint_types.h" /* for drawing constraint */
35 #include "DNA_lamp_types.h"
36 #include "DNA_lattice_types.h"
37 #include "DNA_material_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_meta_types.h"
40 #include "DNA_rigidbody_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_smoke_types.h"
43 #include "DNA_world_types.h"
44 #include "DNA_object_types.h"
46 #include "BLI_listbase.h"
47 #include "BLI_link_utils.h"
48 #include "BLI_string.h"
50 #include "BLI_memarena.h"
52 #include "BKE_anim.h" /* for the where_on_path function */
53 #include "BKE_armature.h"
54 #include "BKE_camera.h"
55 #include "BKE_colortools.h"
56 #include "BKE_constraint.h" /* for the get_constraint_target function */
57 #include "BKE_curve.h"
58 #include "BKE_DerivedMesh.h"
59 #include "BKE_deform.h"
60 #include "BKE_displist.h"
62 #include "BKE_global.h"
63 #include "BKE_image.h"
65 #include "BKE_layer.h"
66 #include "BKE_lattice.h"
69 #include "BKE_material.h"
70 #include "BKE_mball.h"
71 #include "BKE_modifier.h"
72 #include "BKE_movieclip.h"
73 #include "BKE_object.h"
74 #include "BKE_paint.h"
75 #include "BKE_particle.h"
76 #include "BKE_pointcache.h"
77 #include "BKE_scene.h"
78 #include "BKE_subsurf.h"
80 #include "BKE_tracking.h"
82 #include "BKE_editmesh.h"
84 #include "IMB_imbuf.h"
85 #include "IMB_imbuf_types.h"
88 #include "BIF_glutil.h"
91 #include "GPU_select.h"
92 #include "GPU_basic_shader.h"
93 #include "GPU_shader.h"
94 #include "GPU_immediate.h"
95 #include "GPU_immediate_util.h"
96 #include "GPU_batch.h"
97 #include "GPU_matrix.h"
100 #include "ED_particle.h"
101 #include "ED_screen.h"
102 #include "ED_sculpt.h"
103 #include "ED_types.h"
105 #include "UI_resources.h"
106 #include "UI_interface_icons.h"
111 #include "view3d_intern.h" /* bad level include */
113 #include "../../draw/intern/draw_cache_impl.h" /* bad level include (temporary) */
116 static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos);
118 /* Workaround for sequencer scene render mode.
120 * Strips doesn't use DAG to update objects or so, which
121 * might lead to situations when object is drawing without
124 * Ideally we don't want to evaluate objects from drawing,
125 * but it'll require some major sequencer re-design. So
126 * for now just fallback to legacy behavior with calling
127 * display ist creating from draw().
129 #define SEQUENCER_DAG_WORKAROUND
131 typedef enum eWireDrawMode {
134 OBDRAW_WIRE_ON_DEPTH = 2
137 typedef struct drawDMVerts_userData {
142 unsigned int pos, color;
144 /* cached theme values */
145 unsigned char th_editmesh_active[4];
146 unsigned char th_vertex_select[4];
147 unsigned char th_vertex[4];
148 unsigned char th_skin_root[4];
150 /* for skin node drawing */
153 } drawDMVerts_userData;
155 typedef struct drawDMEdgesSel_userData {
158 unsigned char *baseCol, *selCol, *actCol;
160 } drawDMEdgesSel_userData;
162 typedef struct drawDMEdgesSelInterp_userData {
165 unsigned char *baseCol, *selCol;
166 unsigned char *lastCol;
167 } drawDMEdgesSelInterp_userData;
169 typedef struct drawDMEdgesWeightInterp_userData {
176 float alert_color[3];
178 } drawDMEdgesWeightInterp_userData;
180 typedef struct drawDMFacesSel_userData {
181 #ifdef WITH_FREESTYLE
182 unsigned char *cols[4];
184 unsigned char *cols[3];
191 const int *orig_index_mp_to_orig;
192 } drawDMFacesSel_userData;
194 typedef struct drawDMNormal_userData {
201 } drawDMNormal_userData;
203 typedef struct drawMVertOffset_userData {
204 unsigned int pos, col;
207 } drawMVertOffset_userData;
209 typedef struct drawDMLayer_userData {
212 unsigned int pos, col;
213 } drawDMLayer_userData;
215 typedef struct drawBMOffset_userData {
216 unsigned int pos, col;
219 } drawBMOffset_userData;
221 typedef struct drawBMSelect_userData {
225 } drawBMSelect_userData;
228 static void drawcube_size(float size, unsigned pos);
229 static void drawcircle_size(float size, unsigned pos);
230 static void draw_empty_sphere(float size, unsigned pos);
231 static void draw_empty_cone(float size, unsigned pos);
233 static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac, float r_col[3])
235 float col_wire[3], col_bg[3];
237 rgb_uchar_to_float(col_wire, ob_wire_col);
239 UI_GetThemeColor3fv(theme_id, col_bg);
240 interp_v3_v3v3(r_col, col_bg, col_wire, fac);
243 int view3d_effective_drawtype(const struct View3D *v3d)
245 if (v3d->drawtype == OB_RENDER) {
246 return v3d->prev_drawtype;
248 return v3d->drawtype;
251 /* this condition has been made more complex since editmode can draw textures */
252 bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
254 const int v3d_drawtype = view3d_effective_drawtype(v3d);
255 /* texture and material draw modes */
256 if (ELEM(v3d_drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
261 if ((v3d_drawtype == OB_SOLID) &&
262 (v3d->flag2 & V3D_SOLID_TEX) &&
263 (BKE_scene_use_new_shading_nodes(scene) == false))
268 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) {
275 static bool check_object_draw_editweight(Mesh *me, DerivedMesh *finalDM)
277 if (me->drawflag & ME_DRAWEIGHT) {
278 /* editmesh handles its own weight drawing */
279 if (finalDM->type != DM_TYPE_EDITBMESH) {
287 static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
289 if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
292 if (G.f & G_BACKBUFSEL)
295 if ((vd->flag & V3D_ZBUF_SELECT) == 0)
298 /* if its drawing textures with zbuf sel, then don't draw dots */
299 if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
302 if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
308 /* ************************ */
310 /* check for glsl drawing */
312 bool draw_glsl_material(Scene *scene, SceneLayer *sl, Object *ob, View3D *v3d, const char dt)
316 if (!check_object_draw_texture(scene, v3d, dt))
318 if (ob == OBACT_NEW && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
321 if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
324 if (v3d->drawtype == OB_TEXTURE)
325 return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
326 else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
332 static bool check_alpha_pass(Base *base)
334 if (base->flag_legacy & OB_FROMDUPLI)
340 if (base->object->mode & OB_MODE_ALL_PAINT)
343 return (base->object->dtx & OB_DRAWTRANSP);
347 static const unsigned int colortab[] = {
348 0x0, 0x403000, 0xFFFF88
351 /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
352 /* 32 values of sin function (still same result!) */
353 #define CIRCLE_RESOL 32
355 static const float sinval[CIRCLE_RESOL] = {
390 /* 32 values of cos function (still same result!) */
391 static const float cosval[CIRCLE_RESOL] = {
427 * \param viewmat_local_unit is typically the 'rv3d->viewmatob'
428 * copied into a 3x3 matrix and normalized.
430 static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis, unsigned pos)
432 PrimitiveType line_type = PRIM_LINES;
436 float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
437 float dim = size * 0.1f;
440 dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f;
441 dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f;
445 /* bottom left to top right */
446 negate_v3_v3(v1, dx);
451 copy_v3_v3(buffer[n++], v1);
452 copy_v3_v3(buffer[n++], v2);
454 /* top left to bottom right */
459 copy_v3_v3(buffer[n++], v1);
460 copy_v3_v3(buffer[n++], v2);
464 /* bottom left to top right */
465 mul_v3_fl(dx, 0.75f);
466 negate_v3_v3(v1, dx);
471 copy_v3_v3(buffer[n++], v1);
472 copy_v3_v3(buffer[n++], v2);
474 /* top left to center */
479 copy_v3_v3(buffer[n++], v1);
480 copy_v3_v3(buffer[n++], v2);
484 line_type = PRIM_LINE_STRIP;
486 /* start at top left */
487 negate_v3_v3(v1, dx);
490 copy_v3_v3(buffer[n++], v1);
495 copy_v3_v3(buffer[n++], v1);
501 copy_v3_v3(buffer[n++], v1);
505 copy_v3_v3(buffer[n++], v1);
513 immBegin(line_type, n);
514 for (int i = 0; i < n; i++) {
515 mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
516 add_v3_v3(buffer[i], c);
517 immVertex3fv(pos, buffer[i]);
521 /* TODO: recode this function for clarity once we're not in a hurry to modernize GL usage */
524 void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4])
527 float v1[3] = {0.0, 0.0, 0.0};
528 float v2[3] = {0.0, 0.0, 0.0};
529 float v3[3] = {0.0, 0.0, 0.0};
533 unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
535 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
536 immUniformColor4ubv(color);
539 immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
544 immBegin(PRIM_LINES, 6);
545 for (axis = 0; axis < 3; axis++) {
548 immVertex3fv(pos, v1);
549 immVertex3fv(pos, v2);
551 /* reset v1 & v2 to zero */
552 v1[axis] = v2[axis] = 0.0f;
557 case OB_SINGLE_ARROW:
558 immBegin(PRIM_LINES, 2);
559 /* in positive z direction only */
561 immVertex3fv(pos, v1);
562 immVertex3fv(pos, v2);
566 immBegin(PRIM_TRIANGLES, 12);
568 v2[0] = size * 0.035f; v2[1] = size * 0.035f;
569 v3[0] = size * -0.035f; v3[1] = size * 0.035f;
570 v2[2] = v3[2] = size * 0.75f;
572 for (axis = 0; axis < 4; axis++) {
582 immVertex3fv(pos, v1);
583 immVertex3fv(pos, v2);
584 immVertex3fv(pos, v3);
590 drawcube_size(size, pos);
594 drawcircle_size(size, pos);
597 case OB_EMPTY_SPHERE:
598 draw_empty_sphere(size, pos);
602 draw_empty_cone(size, pos);
608 float viewmat_local_unit[3][3];
610 copy_m3_m4(viewmat_local_unit, (float (*)[4])viewmat_local);
611 normalize_m3(viewmat_local_unit);
613 for (axis = 0; axis < 3; axis++) {
614 const int arrow_axis = (axis == 0) ? 1 : 0;
616 immBegin(PRIM_LINES, 6);
619 immVertex3fv(pos, v1);
620 immVertex3fv(pos, v2);
622 v1[axis] = size * 0.85f;
623 v1[arrow_axis] = -size * 0.08f;
624 immVertex3fv(pos, v1);
625 immVertex3fv(pos, v2);
627 v1[arrow_axis] = size * 0.08f;
628 immVertex3fv(pos, v1);
629 immVertex3fv(pos, v2);
633 v2[axis] += size * 0.125f;
635 draw_xyz_wire(viewmat_local_unit, v2, size, axis, pos);
637 /* reset v1 & v2 to zero */
638 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
647 /* Function to draw an Image on an empty Object */
648 static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview)
650 Image *ima = ob->data;
652 const float ob_alpha = ob->col[3];
658 ImageUser iuser = *ob->iuser;
660 /* Support multi-view */
661 if (ima && (sview == STEREO_RIGHT_ID)) {
662 iuser.multiview_eye = sview;
663 iuser.flag |= IMA_SHOW_STEREO;
664 BKE_image_multiview_index(ima, &iuser);
667 if (ob_alpha > 0.0f) {
668 bindcode = GPU_verify_image(ima, &iuser, GL_TEXTURE_2D, 0, false, false, false);
669 /* don't bother drawing the image if alpha = 0 */
673 BKE_image_get_size(ima, &iuser, &w, &h);
678 /* if no image, make it a 1x1 empty square, honor scale & offset */
679 width = height = 1.0f;
682 const float aspect = height / width;
684 float left = ob->ima_ofs[0];
685 float right = ob->ima_ofs[0] + ob->empty_drawsize;
686 float top = ob->ima_ofs[1] + ob->empty_drawsize * aspect;
687 float bottom = ob->ima_ofs[1];
689 bool use_blend = false;
692 use_blend = ob_alpha < 1.0f || BKE_image_has_alpha(ima);
696 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
699 VertexFormat *format = immVertexFormat();
700 unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT);
701 unsigned int texCoord = VertexFormat_add_attrib(format, "texCoord", COMP_F32, 2, KEEP_FLOAT);
702 immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
703 immUniform1f("alpha", ob_alpha);
704 immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
706 immBegin(PRIM_TRIANGLE_FAN, 4);
707 immAttrib2f(texCoord, 0.0f, 0.0f);
708 immVertex2f(pos, left, bottom);
710 immAttrib2f(texCoord, 1.0f, 0.0f);
711 immVertex2f(pos, right, bottom);
713 immAttrib2f(texCoord, 1.0f, 1.0f);
714 immVertex2f(pos, right, top);
716 immAttrib2f(texCoord, 0.0f, 1.0f);
717 immVertex2f(pos, left, top);
722 glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */
725 /* Draw the image outline */
727 unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT);
729 const bool picking = dflag & DRAW_CONSTCOLOR;
731 /* TODO: deal with picking separately, use this function just to draw */
732 immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
737 imm_draw_line_box(pos, left, bottom, right, top);
740 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
741 immUniformColor3ubv(ob_wire_col);
742 glEnable(GL_LINE_SMOOTH);
746 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
749 imm_draw_line_box(pos, left, bottom, right, top);
751 glDisable(GL_LINE_SMOOTH);
758 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4])
761 float *viter = (float *)verts;
763 mul_v3_v3fl(vx, tmat[0], rad);
764 mul_v3_v3fl(vy, tmat[1], rad);
766 for (unsigned int a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
767 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
768 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
769 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
773 void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos)
775 float verts[CIRCLE_RESOL][3];
777 circball_array_fill(verts, cent, rad, tmat);
779 immBegin(PRIM_LINE_LOOP, CIRCLE_RESOL);
780 for (int i = 0; i < CIRCLE_RESOL; ++i) {
781 immVertex3fv(pos, verts[i]);
786 /* circle for object centers, special_color is for library or ob users */
787 static void drawcentercircle(View3D *v3d, RegionView3D *UNUSED(rv3d), const float co[3], int selstate, bool special_color)
789 const float outlineWidth = 1.0f * U.pixelsize;
790 const float size = U.obcenter_dia * U.pixelsize + outlineWidth;
793 glDisable(GL_DEPTH_TEST);
794 /* TODO(merwin): fit things like this into plates/buffers design */
798 GPU_enable_program_point_size();
800 unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
801 immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
802 immUniform1f("size", size);
805 if (selstate == ACTIVE || selstate == SELECT) immUniformColor4ub(0x88, 0xFF, 0xFF, 155);
806 else immUniformColor4ub(0x55, 0xCC, 0xCC, 155);
809 if (selstate == ACTIVE) immUniformThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
810 else if (selstate == SELECT) immUniformThemeColorShadeAlpha(TH_SELECT, 0, -80);
811 else if (selstate == DESELECT) immUniformThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
815 float outlineColor[4];
816 UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor);
817 immUniform4fv("outlineColor", outlineColor);
818 immUniform1f("outlineWidth", outlineWidth);
820 immBegin(PRIM_POINTS, 1);
821 immVertex3fv(pos, co);
826 GPU_disable_program_point_size();
830 glEnable(GL_DEPTH_TEST);
834 /* *********** text drawing for object/particles/armature ************* */
836 typedef struct ViewCachedString {
837 struct ViewCachedString *next;
848 /* str is allocated past the end */
852 /* one arena for all 3 string lists */
853 static MemArena *g_v3d_strings_arena = NULL;
854 static ViewCachedString *g_v3d_strings[3] = {NULL, NULL, NULL};
855 static int g_v3d_string_level = -1;
857 void view3d_cached_text_draw_begin(void)
859 g_v3d_string_level++;
861 BLI_assert(g_v3d_string_level >= 0);
863 if (g_v3d_string_level == 0) {
864 BLI_assert(g_v3d_strings_arena == NULL);
868 void view3d_cached_text_draw_add(const float co[3],
869 const char *str, const size_t str_len,
870 short xoffs, short flag,
871 const unsigned char col[4])
873 int alloc_len = str_len + 1;
874 ViewCachedString *vos;
876 BLI_assert(str_len == strlen(str));
878 if (g_v3d_strings_arena == NULL) {
879 g_v3d_strings_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 14), __func__);
882 vos = BLI_memarena_alloc(g_v3d_strings_arena, sizeof(ViewCachedString) + alloc_len);
884 BLI_LINKS_PREPEND(g_v3d_strings[g_v3d_string_level], vos);
886 copy_v3_v3(vos->vec, co);
887 copy_v4_v4_uchar(vos->col.ub, col);
890 vos->str_len = str_len;
892 /* allocate past the end */
893 memcpy(vos->str, str, alloc_len);
896 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write)
898 RegionView3D *rv3d = ar->regiondata;
899 ViewCachedString *vos;
902 BLI_assert(g_v3d_string_level >= 0 && g_v3d_string_level <= 2);
904 /* project first and test */
905 for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
906 if (ED_view3d_project_short_ex(ar,
907 (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
908 (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
910 V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
915 vos->sco[0] = IS_CLIPPED;
920 int col_pack_prev = 0;
922 if (rv3d->rflag & RV3D_CLIPPING) {
923 ED_view3d_clipping_disable();
926 float original_proj[4][4];
927 gpuGetProjectionMatrix(original_proj);
928 wmOrtho2_region_pixelspace(ar);
934 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
937 glDepthMask(GL_FALSE);
940 const int font_id = BLF_default();
942 for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
943 if (vos->sco[0] != IS_CLIPPED) {
944 if (col_pack_prev != vos->col.pack) {
945 BLF_color3ubv(font_id, vos->col.ub);
946 col_pack_prev = vos->col.pack;
949 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
950 BLF_draw_default_ascii :
952 )((float)(vos->sco[0] + vos->xoffs),
953 (float)(vos->sco[1]),
954 (depth_write) ? 0.0f : 2.0f,
961 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
964 glDepthMask(GL_TRUE);
968 gpuLoadProjectionMatrix(original_proj);
970 if (rv3d->rflag & RV3D_CLIPPING) {
971 ED_view3d_clipping_enable();
975 g_v3d_strings[g_v3d_string_level] = NULL;
977 if (g_v3d_string_level == 0) {
978 if (g_v3d_strings_arena) {
979 BLI_memarena_free(g_v3d_strings_arena);
980 g_v3d_strings_arena = NULL;
984 g_v3d_string_level--;
987 /* ******************** primitive drawing ******************* */
989 /* draws a cube given the scaling of the cube, assuming that
990 * all required matrices have been set (used for drawing empties)
992 static void drawcube_size(float size, unsigned pos)
994 const float verts[8][3] = {
995 {-size, -size, -size},
996 {-size, -size, size},
997 {-size, size, -size},
999 { size, -size, -size},
1000 { size, -size, size},
1001 { size, size, -size},
1005 const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6};
1008 glEnableClientState(GL_VERTEX_ARRAY);
1009 glVertexPointer(3, GL_FLOAT, 0, verts);
1010 glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
1011 glDisableClientState(GL_VERTEX_ARRAY);
1013 immBegin(PRIM_LINES, 24);
1014 for (int i = 0; i < 24; ++i) {
1015 immVertex3fv(pos, verts[indices[i]]);
1021 static void drawshadbuflimits(const Lamp *la, const float mat[4][4], unsigned pos)
1023 float sta[3], end[3], lavec[3];
1025 negate_v3_v3(lavec, mat[2]);
1026 normalize_v3(lavec);
1028 madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
1029 madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
1031 immBegin(PRIM_LINES, 2);
1032 immVertex3fv(pos, sta);
1033 immVertex3fv(pos, end);
1037 immBegin(PRIM_POINTS, 2);
1038 immVertex3fv(pos, sta);
1039 immVertex3fv(pos, end);
1043 static void spotvolume(float lvec[3], float vvec[3], const float inp)
1045 /* camera is at 0,0,0 */
1046 float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
1049 normalize_v3(vvec); /* is this the correct vector ? */
1051 cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec and lvec */
1052 cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parallel with lvec */
1054 /* vectors are exactly aligned, use the X axis, this is arbitrary */
1055 if (normalize_v3(plane) == 0.0f)
1058 /* now we've got two equations: one of a cone and one of a plane, but we have
1059 * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
1061 /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
1062 /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
1064 /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
1069 normalize_v3(&q[1]);
1071 angle = saacos(plane[2]) / 2.0f;
1073 si = sqrtf(1 - co * co);
1080 quat_to_mat3(mat1, q);
1082 /* rotate lamp vector now over acos(inp) degrees */
1083 copy_v3_v3(vvec, lvec);
1087 si = sqrtf(1.0f - inp * inp);
1093 mul_m3_m3m3(mat3, mat2, mat1);
1097 mul_m3_m3m3(mat4, mat2, mat1);
1100 mul_m3_m3m3(mat2, mat1, mat3);
1101 mul_m3_v3(mat2, lvec);
1102 mul_m3_m3m3(mat2, mat1, mat4);
1103 mul_m3_v3(mat2, vvec);
1106 static void draw_spot_cone(Lamp *la, float x, float z, unsigned pos)
1110 const bool square = (la->mode & LA_SQUARE);
1112 immBegin(PRIM_TRIANGLE_FAN, square ? 6 : 34);
1113 immVertex3f(pos, 0.0f, 0.0f, -x);
1116 immVertex3f(pos, z, z, 0);
1117 immVertex3f(pos, -z, z, 0);
1118 immVertex3f(pos, -z, -z, 0);
1119 immVertex3f(pos, z, -z, 0);
1120 immVertex3f(pos, z, z, 0);
1123 for (int a = 0; a < 33; a++) {
1124 float angle = a * M_PI * 2 / (33 - 1);
1125 immVertex3f(pos, z * cosf(angle), z * sinf(angle), 0.0f);
1132 static void draw_transp_spot_volume(Lamp *la, float x, float z, unsigned pos)
1134 glEnable(GL_CULL_FACE);
1136 glDepthMask(GL_FALSE);
1138 /* draw backside darkening */
1139 glCullFace(GL_FRONT);
1141 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1142 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1144 draw_spot_cone(la, x, z, pos);
1146 /* draw front side lighting */
1147 glCullFace(GL_BACK);
1149 glBlendFunc(GL_ONE, GL_ONE);
1150 immUniformColor3f(0.2f, 0.2f, 0.2f);
1152 draw_spot_cone(la, x, z, pos);
1155 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1156 glDisable(GL_BLEND);
1157 glDepthMask(GL_TRUE);
1158 glDisable(GL_CULL_FACE);
1161 #ifdef WITH_GAMEENGINE
1162 static void draw_transp_sun_volume(Lamp *la, unsigned pos)
1167 box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size;
1168 box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size;
1169 box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size;
1170 box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size;
1171 box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend;
1172 box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
1175 imm_draw_box(box, false, pos);
1178 glEnable(GL_CULL_FACE);
1180 glDepthMask(GL_FALSE);
1182 /* draw backside darkening */
1183 glCullFace(GL_FRONT);
1185 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1186 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1188 imm_draw_box(box, true, pos);
1190 /* draw front side lighting */
1191 glCullFace(GL_BACK);
1193 glBlendFunc(GL_ONE, GL_ONE);
1194 immUniformColor3f(0.2f, 0.2f, 0.2f);
1196 imm_draw_box(box, true, pos);
1199 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1200 glDisable(GL_BLEND);
1201 glDepthMask(GL_TRUE);
1202 glDisable(GL_CULL_FACE);
1206 void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
1207 const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
1209 Object *ob = base->object;
1210 const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1211 Lamp *la = ob->data;
1212 float vec[3], lvec[3], vvec[3], circrad;
1215 /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
1216 /* the moment of view3d_draw_transp() call */
1217 const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1218 const bool drawcone = ((dt > OB_WIRE) &&
1219 !(G.f & G_PICKSEL) &&
1220 (la->type == LA_SPOT) &&
1221 (la->mode & LA_SHOW_CONE) &&
1222 !(base->flag_legacy & OB_FROMDUPLI) &&
1225 #ifdef WITH_GAMEENGINE
1226 const bool drawshadowbox = (
1227 (rv3d->rflag & RV3D_IS_GAME_ENGINE) &&
1229 !(G.f & G_PICKSEL) &&
1230 (la->type == LA_SUN) &&
1231 ((la->mode & LA_SHAD_BUF) ||
1232 (la->mode & LA_SHAD_RAY)) &&
1233 (la->mode & LA_SHOW_SHADOW_BOX) &&
1234 !(base->flag_legacy & OB_FROMDUPLI) &&
1237 const bool drawshadowbox = false;
1240 if ((drawcone || drawshadowbox) && !v3d->transp) {
1241 /* in this case we need to draw delayed */
1242 ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
1246 /* we first draw only the screen aligned & fixed scale stuff */
1248 gpuLoadMatrix(rv3d->viewmat);
1250 /* lets calculate the scale: */
1251 const float lampsize_px = U.obcenter_dia;
1252 const float lampsize = pixsize * lampsize_px * 0.5f;
1254 /* and view aligned matrix: */
1255 copy_m4_m4(imat, rv3d->viewinv);
1256 normalize_v3(imat[0]);
1257 normalize_v3(imat[1]);
1259 const unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
1262 copy_v3_v3(vec, ob->obmat[3]);
1265 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1266 /* for AA effects */
1267 rgb_uchar_to_float(curcol, ob_wire_col);
1269 /* TODO: pay attention to GL_BLEND */
1275 if (lampsize > 0.0f) {
1276 const float outlineWidth = 1.5f * U.pixelsize;
1277 const float lampdot_size = lampsize_px * U.pixelsize + outlineWidth;
1280 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1281 const float *color = curcol;
1282 if (ob->id.us > 1) {
1283 if (is_obact || ((base->flag & BASE_SELECTED) != 0)) {
1284 static const float active_color[4] = {0.533f, 1.0f, 1.0f, 1.0f};
1285 color = active_color;
1288 static const float inactive_color[4] = {0.467f, 0.8f, 0.8f, 1.0f};
1289 color = inactive_color;
1293 GPU_enable_program_point_size();
1295 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1297 immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
1298 immUniform1f("size", lampdot_size);
1299 immUniform1f("outlineWidth", outlineWidth);
1300 immUniformColor3fvAlpha(color, 0.3f);
1301 immUniform4fv("outlineColor", color);
1303 immBegin(PRIM_POINTS, 1);
1304 immVertex3fv(pos, vec);
1309 glDisable(GL_BLEND);
1310 GPU_disable_program_point_size();
1313 /* CONSTCOLOR in effect */
1314 /* TODO: separate picking from drawing */
1315 immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
1316 /* color doesn't matter, so don't set */
1317 glPointSize(lampdot_size);
1319 immBegin(PRIM_POINTS, 1);
1320 immVertex3fv(pos, vec);
1326 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
1327 /* TODO(merwin): short term, use DEPTH_ONLY for picking
1328 * long term, separate picking from drawing
1332 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1333 immUniformColor4fv(curcol);
1337 circrad = 3.0f * lampsize;
1339 imm_drawcircball(vec, circrad, imat, pos);
1341 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1342 if (la->type != LA_HEMI) {
1343 if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1344 imm_drawcircball(vec, circrad + 3.0f * pixsize, imat, pos);
1349 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
1350 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1351 immUniformColor4fv(curcol);
1356 /* draw the pretty sun rays */
1357 if (la->type == LA_SUN) {
1358 float v1[3], v2[3], mat[3][3];
1361 /* setup a 45 degree rotation matrix */
1362 axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2);
1365 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1366 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1370 gpuTranslate3fv(vec);
1374 immBegin(PRIM_LINES, 16);
1375 for (axis = 0; axis < 8; axis++) {
1376 immVertex3fv(pos, v1);
1377 immVertex3fv(pos, v2);
1386 if (la->type == LA_LOCAL) {
1387 if (la->mode & LA_SPHERE) {
1388 imm_drawcircball(vec, la->dist, imat, pos);
1392 gpuPopMatrix(); /* back in object space */
1396 /* skip drawing extra info */
1398 else if (la->type == LA_SPOT) {
1399 float x, y, z, z_abs;
1400 copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f);
1401 copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]);
1402 mul_transposed_mat3_m4_v3(ob->obmat, vvec);
1405 y = cosf(la->spotsize * 0.5f);
1406 z = x * sqrtf(1.0f - y * y);
1408 spotvolume(lvec, vvec, y);
1416 if (la->mode & LA_SQUARE) {
1418 const float vertices[5][3] = {
1419 /* 5 of vertex coords of pyramid */
1422 {-z_abs, -z_abs, x},
1427 immBegin(PRIM_LINES, 16);
1428 for (int i = 1; i <= 4; ++i) {
1429 immVertex3fv(pos, vertices[0]); /* apex to corner */
1430 immVertex3fv(pos, vertices[i]);
1431 int next_i = (i == 4) ? 1 : (i + 1);
1432 immVertex3fv(pos, vertices[i]); /* corner to next corner */
1433 immVertex3fv(pos, vertices[next_i]);
1437 gpuTranslate3f(0.0f, 0.0f, x);
1439 /* draw the square representing spotbl */
1440 if (la->type == LA_SPOT) {
1441 float blend = z_abs * (1.0f - pow2f(la->spotblend));
1443 /* hide line if it is zero size or overlaps with outer border,
1444 * previously it adjusted to always to show it but that seems
1445 * confusing because it doesn't show the actual blend size */
1446 if (blend != 0.0f && blend != z_abs) {
1447 imm_draw_line_box_3d(pos, blend, -blend, -blend, blend);
1452 /* draw the angled sides of the cone */
1453 immBegin(PRIM_LINE_STRIP, 3);
1454 immVertex3fv(pos, vvec);
1455 immVertex3fv(pos, vec);
1456 immVertex3fv(pos, lvec);
1459 /* draw the circle at the end of the cone */
1460 gpuTranslate3f(0.0f, 0.0f, x);
1461 imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, z_abs, 32);
1463 /* draw the circle representing spotbl */
1464 if (la->type == LA_SPOT) {
1465 float blend = z_abs * (1.0f - pow2f(la->spotblend));
1467 /* hide line if it is zero size or overlaps with outer border,
1468 * previously it adjusted to always to show it but that seems
1469 * confusing because it doesn't show the actual blend size */
1470 if (blend != 0.0f && blend != z_abs) {
1471 imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, blend, 32);
1477 draw_transp_spot_volume(la, x, z, pos);
1479 /* draw clip start, useful for wide cones where its not obvious where the start is */
1480 gpuTranslate3f(0.0f, 0.0f, -x); /* reverse translation above */
1481 immBegin(PRIM_LINES, 2);
1482 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
1485 float clipsta_fac = la->clipsta / -x;
1487 interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1488 interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1490 immVertex3fv(pos, lvec_clip);
1491 immVertex3fv(pos, vvec_clip);
1493 /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
1495 immVertex3f(pos, 0.0f, 0.0f, -circrad);
1496 immVertex3f(pos, 0.0f, 0.0f, -la->dist);
1500 else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1501 /* draw the line from the circle along the dist */
1502 immBegin(PRIM_LINES, 2);
1504 immVertex3fv(pos, vec);
1506 immVertex3fv(pos, vec);
1509 if (la->type == LA_HEMI) {
1510 /* draw the hemisphere curves */
1511 short axis, steps, dir;
1512 float outdist, zdist, mul;
1514 outdist = 0.14f; mul = 1.4f; dir = 1;
1517 /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1518 for (axis = 0; axis < 4; axis++) {
1519 float v[3] = {0.0f, 0.0f, 0.0f};
1522 immBegin(PRIM_LINE_STRIP, 6);
1524 for (steps = 0; steps < 6; steps++) {
1525 if (axis == 0 || axis == 1) { /* x axis up, x axis down */
1526 /* make the arcs start at the edge of the energy circle */
1527 if (steps == 0) v[0] = dir * circrad;
1528 else v[0] = v[0] + dir * (steps * outdist);
1530 else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
1531 /* make the arcs start at the edge of the energy circle */
1532 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1535 v[2] = v[2] - steps * zdist;
1537 immVertex3fv(pos, v);
1539 zdist = zdist * mul;
1543 /* flip the direction */
1548 #ifdef WITH_GAMEENGINE
1549 if (drawshadowbox) {
1550 draw_transp_sun_volume(la, pos);
1554 else if (la->type == LA_AREA) {
1556 if (la->area_shape == LA_AREA_SQUARE)
1557 imm_draw_line_box_3d(pos, -la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
1558 else if (la->area_shape == LA_AREA_RECT)
1559 imm_draw_line_box_3d(pos, -la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
1561 immBegin(PRIM_LINES, 2);
1562 immVertex3f(pos, 0.0f, 0.0f, -circrad);
1563 immVertex3f(pos, 0.0f, 0.0f, -la->dist);
1567 /* and back to viewspace */
1569 gpuLoadMatrix(rv3d->viewmat);
1570 copy_v3_v3(vec, ob->obmat[3]);
1574 if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) {
1575 drawshadbuflimits(la, ob->obmat, pos);
1578 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1579 immUniformThemeColor(TH_LAMP);
1584 if (vec[2] > 0) vec[2] -= circrad;
1585 else vec[2] += circrad;
1587 immBegin(PRIM_LINES, 2);
1588 immVertex3fv(pos, vec);
1590 immVertex3fv(pos, vec);
1594 immBegin(PRIM_POINTS, 1);
1595 immVertex3fv(pos, vec);
1598 glDisable(GL_BLEND);
1604 static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3], unsigned pos)
1606 immBegin(PRIM_LINES, 2);
1607 immVertex3f(pos, 0.0f, 0.0f, -sta);
1608 immVertex3f(pos, 0.0f, 0.0f, -end);
1611 if (!(dflag & DRAW_PICKING)) {
1613 /* would like smooth round points here, but that means binding another shader...
1614 * if it's really desired, pull these points into their own function to be called after */
1615 immBegin(PRIM_POINTS, 2);
1616 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1617 immUniformColor3ubv(col);
1619 immVertex3f(pos, 0.0f, 0.0f, -sta);
1620 immVertex3f(pos, 0.0f, 0.0f, -end);
1626 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1627 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1628 static void draw_focus_cross(float dist, float size, unsigned pos)
1630 immBegin(PRIM_LINES, 4);
1631 immVertex3f(pos, -size, 0.0f, -dist);
1632 immVertex3f(pos, size, 0.0f, -dist);
1633 immVertex3f(pos, 0.0f, -size, -dist);
1634 immVertex3f(pos, 0.0f, size, -dist);
1638 #ifdef VIEW3D_CAMERA_BORDER_HACK
1639 unsigned char view3d_camera_border_hack_col[3];
1640 bool view3d_camera_border_hack_test = false;
1643 /* ****************** draw clip data *************** */
1645 static void draw_viewport_object_reconstruction(
1646 Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d,
1647 MovieClip *clip, MovieTrackingObject *tracking_object,
1648 const short dflag, const unsigned char ob_wire_col[4],
1649 int *global_track_index, bool draw_selected)
1651 MovieTracking *tracking = &clip->tracking;
1652 MovieTrackingTrack *track;
1653 float mat[4][4], imat[4][4];
1654 unsigned char col_unsel[4], col_sel[4];
1655 int tracknr = *global_track_index;
1656 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
1657 float camera_size[3];
1659 UI_GetThemeColor4ubv(TH_TEXT, col_unsel);
1660 UI_GetThemeColor4ubv(TH_SELECT, col_sel);
1662 BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
1664 /* we're compensating camera size for bundles size,
1665 * to make it so bundles are always displayed with the same size */
1666 copy_v3_v3(camera_size, base->object->size);
1667 if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
1668 mul_v3_fl(camera_size, tracking_object->scale);
1672 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1673 /* current ogl matrix is translated in camera space, bundles should
1674 * be rendered in world space, so camera matrix should be "removed"
1675 * from current ogl matrix */
1676 invert_m4_m4(imat, base->object->obmat);
1678 gpuMultMatrix(imat);
1683 int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra);
1685 BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat);
1687 invert_m4_m4(imat, obmat);
1688 gpuMultMatrix(imat);
1691 for (track = tracksbase->first; track; track = track->next) {
1692 bool selected = TRACK_SELECTED(track);
1694 if (draw_selected && !selected)
1697 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1700 if (dflag & DRAW_PICKING)
1701 GPU_select_load_id(base->selcol + (tracknr << 16));
1704 gpuTranslate3fv(track->bundle_pos);
1705 gpuScale3f(v3d->bundle_size / 0.05f / camera_size[0],
1706 v3d->bundle_size / 0.05f / camera_size[1],
1707 v3d->bundle_size / 0.05f / camera_size[2]);
1709 const int v3d_drawtype = view3d_effective_drawtype(v3d);
1710 if (v3d_drawtype == OB_WIRE) {
1711 unsigned char color[4];
1712 const unsigned char *color_ptr = NULL;
1713 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1714 if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
1715 color_ptr = ob_wire_col;
1718 rgba_float_to_uchar(color, track->color);
1723 drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
1725 else if (v3d_drawtype > OB_WIRE) {
1726 if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1729 gpuScaleUniform(0.05f);
1731 /* selection outline */
1733 batch = Batch_get_sphere_wire(1);
1735 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1736 Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
1737 Batch_Uniform4f(batch, "color",
1738 ob_wire_col[0]/255.f,
1739 ob_wire_col[1]/255.f,
1740 ob_wire_col[2]/255.f, 1.0f);
1743 Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
1750 batch = Batch_get_sphere(0);
1752 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1753 const float light[3] = {0.0f, 0.0f, 1.0f};
1755 Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
1756 Batch_Uniform3fv(batch, "light", light);
1758 if (track->flag & TRACK_CUSTOMCOLOR) copy_v3_v3(col, track->color);
1759 else UI_GetThemeColor3fv(TH_BUNDLE_SOLID, col);
1760 Batch_Uniform4f(batch, "color", col[0], col[1], col[2], 1.0f);
1763 Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
1769 unsigned char color[4];
1770 const unsigned char *color_ptr = NULL;
1771 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1773 color_ptr = ob_wire_col;
1776 if (track->flag & TRACK_CUSTOMCOLOR) rgba_float_to_uchar(color, track->color);
1777 else UI_GetThemeColor4ubv(TH_WIRE, color);
1783 drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
1789 if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1792 mul_v3_m4v3(pos, mat, track->bundle_pos);
1793 view3d_cached_text_draw_add(pos,
1794 track->name, strlen(track->name),
1795 10, V3D_CACHE_TEXT_GLOBALSPACE,
1796 selected ? col_sel : col_unsel);
1802 if ((dflag & DRAW_PICKING) == 0) {
1803 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1804 MovieTrackingReconstruction *reconstruction;
1805 reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
1807 if (reconstruction->camnr >= 2) {
1808 MovieReconstructedCamera *camera = reconstruction->cameras;
1809 unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
1811 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
1812 immUniformThemeColor(TH_CAMERA_PATH);
1816 immBegin(PRIM_LINE_STRIP, reconstruction->camnr);
1817 for (int a = 0; a < reconstruction->camnr; a++, camera++) {
1818 immVertex3fv(pos, camera->mat[3]);
1829 *global_track_index = tracknr;
1832 static void draw_viewport_reconstruction(
1833 Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
1834 const short dflag, const unsigned char ob_wire_col[4],
1835 const bool draw_selected)
1837 MovieTracking *tracking = &clip->tracking;
1838 MovieTrackingObject *tracking_object;
1839 int global_track_index = 1;
1841 if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1844 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1847 GPU_basic_shader_colors(NULL, NULL, 0, 1.0f);
1848 GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
1850 tracking_object = tracking->objects.first;
1851 while (tracking_object) {
1852 draw_viewport_object_reconstruction(
1853 scene, base, v3d, rv3d, clip, tracking_object,
1854 dflag, ob_wire_col, &global_track_index, draw_selected);
1856 tracking_object = tracking_object->next;
1860 GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
1862 if (dflag & DRAW_PICKING)
1863 GPU_select_load_id(base->selcol);
1867 static void drawcamera_frame(float vec[4][3], bool filled, unsigned pos)
1869 immBegin(filled ? PRIM_TRIANGLE_FAN : PRIM_LINE_LOOP, 4);
1870 immVertex3fv(pos, vec[0]);
1871 immVertex3fv(pos, vec[1]);
1872 immVertex3fv(pos, vec[2]);
1873 immVertex3fv(pos, vec[3]);
1877 /* center point to camera frame */
1878 static void drawcamera_framelines(float vec[4][3], float origin[3], unsigned pos)
1880 immBegin(PRIM_LINES, 8);
1881 immVertex3fv(pos, origin);
1882 immVertex3fv(pos, vec[0]);
1883 immVertex3fv(pos, origin);
1884 immVertex3fv(pos, vec[1]);
1885 immVertex3fv(pos, origin);
1886 immVertex3fv(pos, vec[2]);
1887 immVertex3fv(pos, origin);
1888 immVertex3fv(pos, vec[3]);
1892 static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], bool filled, unsigned pos)
1894 drawcamera_frame(near_plane, filled, pos);
1895 drawcamera_frame(far_plane, filled, pos);
1898 immBegin(PRIM_TRIANGLE_STRIP, 10);
1900 immVertex3fv(pos, near_plane[0]);
1901 immVertex3fv(pos, far_plane[0]);
1902 immVertex3fv(pos, near_plane[1]);
1903 immVertex3fv(pos, far_plane[1]);
1904 immVertex3fv(pos, near_plane[2]);
1905 immVertex3fv(pos, far_plane[2]);
1906 immVertex3fv(pos, near_plane[3]);
1907 immVertex3fv(pos, far_plane[3]);
1908 immVertex3fv(pos, near_plane[0]);
1909 immVertex3fv(pos, far_plane[0]);
1914 immBegin(PRIM_LINES, 8);
1915 for (int i = 0; i < 4; ++i) {
1916 immVertex3fv(pos, near_plane[i]);
1917 immVertex3fv(pos, far_plane[i]);
1923 static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
1925 return (ob == v3d->camera) &&
1926 (scene->r.scemode & R_MULTIVIEW) != 0 &&
1927 (v3d->stereo3d_flag);
1930 static void drawcamera_stereo3d(
1931 Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
1932 float vec[4][3], float drawsize, const float scale[3], unsigned pos)
1935 float vec_lr[2][4][3];
1936 const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
1937 float origin[2][3] = {{0}};
1939 const Camera *cam_lr[2];
1940 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
1942 const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
1943 const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
1944 const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME);
1948 /* caller bound GPU_SHADER_3D_UNIFORM_COLOR, passed in pos attribute ID */
1950 for (int i = 0; i < 2; i++) {
1951 ob = BKE_camera_multiview_render(scene, ob, names[i]);
1952 cam_lr[i] = ob->data;
1954 gpuLoadMatrix(rv3d->viewmat);
1955 BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
1956 gpuMultMatrix(obmat);
1958 copy_m3_m3(vec_lr[i], vec);
1959 copy_v3_v3(vec_lr[i][3], vec[3]);
1961 if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
1962 const float shift_x =
1963 ((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) *
1964 (drawsize * scale[0] * fac));
1966 for (int j = 0; j < 4; j++) {
1967 vec_lr[i][j][0] += shift_x;
1971 if (is_stereo3d_cameras) {
1973 drawcamera_frame(vec_lr[i], false, pos);
1975 /* center point to camera frame */
1976 drawcamera_framelines(vec_lr[i], tvec, pos);
1979 /* connecting line */
1980 mul_m4_v3(obmat, origin[i]);
1982 /* convergence plane */
1983 if (is_stereo3d_plane || is_stereo3d_volume) {
1984 for (int j = 0; j < 4; j++) {
1985 mul_m4_v3(obmat, vec_lr[i][j]);
1990 /* the remaining drawing takes place in the view space */
1991 gpuLoadMatrix(rv3d->viewmat);
1993 if (is_stereo3d_cameras) {
1994 /* draw connecting lines */
1995 glLineStipple(2, 0xAAAA);
1996 glEnable(GL_LINE_STIPPLE);
1998 immBegin(PRIM_LINES, 2);
1999 immVertex3fv(pos, origin[0]);
2000 immVertex3fv(pos, origin[1]);
2003 glDisable(GL_LINE_STIPPLE);
2006 /* draw convergence plane */
2007 if (is_stereo3d_plane) {
2008 float axis_center[3], screen_center[3];
2009 float world_plane[4][3];
2010 float local_plane[4][3];
2013 mid_v3_v3v3(axis_center, origin[0], origin[1]);
2015 for (int i = 0; i < 4; i++) {
2016 mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]);
2017 sub_v3_v3v3(local_plane[i], world_plane[i], axis_center);
2020 mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]);
2021 offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center);
2023 for (int i = 0; i < 4; i++) {
2024 mul_v3_fl(local_plane[i], offset);
2025 add_v3_v3(local_plane[i], axis_center);
2028 immUniformColor3f(0.0f, 0.0f, 0.0f);
2031 drawcamera_frame(local_plane, false, pos);
2033 if (v3d->stereo3d_convergence_alpha > 0.0f) {
2035 glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */
2037 immUniformColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
2039 drawcamera_frame(local_plane, true, pos);
2041 glDisable(GL_BLEND);
2042 glDepthMask(GL_TRUE); /* restore write in zbuffer */
2046 /* draw convergence plane */
2047 if (is_stereo3d_volume) {
2048 float screen_center[3];
2049 float near_plane[4][3], far_plane[4][3];
2051 for (int i = 0; i < 2; i++) {
2052 mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]);
2054 float offset = len_v3v3(screen_center, origin[i]);
2056 for (int j = 0; j < 4; j++) {
2057 sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]);
2058 mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset);
2059 add_v3_v3(near_plane[j], origin[i]);
2061 sub_v3_v3v3(far_plane[j], vec_lr[i][j], origin[i]);
2062 mul_v3_fl(far_plane[j], cam_lr[i]->clipend / offset);
2063 add_v3_v3(far_plane[j], origin[i]);
2067 immUniformColor3f(0.0f, 0.0f, 0.0f);
2069 drawcamera_volume(near_plane, far_plane, false, pos);
2071 if (v3d->stereo3d_volume_alpha > 0.0f) {
2073 glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */
2076 immUniformColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
2078 immUniformColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
2080 drawcamera_volume(near_plane, far_plane, true, pos);
2082 glDisable(GL_BLEND);
2083 glDepthMask(GL_TRUE); /* restore write in zbuffer */
2089 /* flag similar to draw_object() */
2090 void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
2091 const short dflag, const unsigned char ob_wire_col[4])
2093 /* a standing up pyramid with (0,0,0) as top */
2095 Object *ob = base->object;
2097 float vec[4][3], asp[2], shift[2], scale[3];
2098 MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
2100 const bool is_active = (ob == v3d->camera);
2101 const bool is_view = (rv3d->persp == RV3D_CAMOB && is_active);
2102 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2103 const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
2104 const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
2105 const bool is_stereo3d_cameras = (ob == scene->camera) &&
2108 (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
2109 const bool is_selection_camera_stereo = (G.f & G_PICKSEL) &&
2110 is_view && is_multiview &&
2113 /* draw data for movie clip set as active for scene */
2115 draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, false);
2116 draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, true);
2119 #ifdef VIEW3D_CAMERA_BORDER_HACK
2120 if (is_view && !(G.f & G_PICKSEL)) {
2121 if ((dflag & DRAW_CONSTCOLOR) == 0) {
2122 view3d_camera_border_hack_col[0] = ob_wire_col[0];
2123 view3d_camera_border_hack_col[1] = ob_wire_col[1];
2124 view3d_camera_border_hack_col[2] = ob_wire_col[2];
2128 glGetFloatv(GL_CURRENT_COLOR, col);
2129 rgb_float_to_uchar(view3d_camera_border_hack_col, col);
2131 view3d_camera_border_hack_test = true;
2138 /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here */
2139 if (is_selection_camera_stereo) {
2145 scale[0] = 1.0f / len_v3(ob->obmat[0]);
2146 scale[1] = 1.0f / len_v3(ob->obmat[1]);
2147 scale[2] = 1.0f / len_v3(ob->obmat[2]);
2151 BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
2152 asp, shift, &drawsize, vec);
2154 unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
2155 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2157 immUniformColor3ubv(ob_wire_col);
2162 if (!is_stereo3d_cameras) {
2163 /* make sure selection uses the same matrix for camera as the one used while viewing */
2164 if (is_selection_camera_stereo) {
2166 bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
2169 gpuLoadMatrix(rv3d->viewmat);
2170 BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
2171 gpuMultMatrix(obmat);
2173 drawcamera_frame(vec, false, pos);
2177 drawcamera_frame(vec, false, pos);
2188 /* center point to camera frame */
2189 if (!is_stereo3d_cameras)
2190 drawcamera_framelines(vec, tvec, pos);
2193 tvec[2] = vec[1][2]; /* copy the depth */
2195 /* draw an outline arrow for inactive cameras and filled
2196 * for active cameras. We actually draw both outline+filled
2197 * for active cameras so the wire can be seen side-on */
2198 for (int i = 0; i < 2; i++) {
2199 if (i == 0) immBegin(PRIM_LINE_LOOP, 3);
2200 else if (i == 1 && is_active) {
2201 glDisable(GL_CULL_FACE); /* TODO: declarative state tracking */
2202 immBegin(PRIM_TRIANGLES, 3);
2206 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
2207 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
2208 immVertex3fv(pos, tvec); /* left */
2210 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
2211 immVertex3fv(pos, tvec); /* right */
2214 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
2215 immVertex3fv(pos, tvec); /* top */
2220 if ((dflag & DRAW_SCENESET) == 0) {
2221 if (cam->flag & (CAM_SHOWLIMITS | CAM_SHOWMIST)) {
2224 /* draw in normalized object matrix space */
2225 copy_m4_m4(nobmat, ob->obmat);
2226 normalize_m4(nobmat);
2228 gpuLoadMatrix(rv3d->viewmat);
2229 gpuMultMatrix(nobmat);
2231 if (cam->flag & CAM_SHOWLIMITS) {
2232 const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120};
2234 draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col), pos);
2235 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
2236 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize, pos);
2239 if (cam->flag & CAM_SHOWMIST) {
2240 World *world = scene->world;
2241 const unsigned char col[3] = {128, 128, 128}, col_hi[3] = {255, 255, 255};
2244 draw_limit_line(world->miststa, world->miststa + world->mistdist,
2245 dflag, (is_active ? col_hi : col), pos);
2251 /* stereo cameras drawing */
2253 drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale, pos);
2259 /* flag similar to draw_object() */
2260 void drawspeaker(const unsigned char ob_wire_col[3])
2262 VertexFormat *format = immVertexFormat();
2263 unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2265 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2268 immUniformColor3ubv(ob_wire_col);
2273 const int segments = 16;
2275 for (int j = 0; j < 3; j++) {
2276 float z = 0.25f * j - 0.125f;
2278 immBegin(PRIM_LINE_LOOP, segments);
2279 for (int i = 0; i < segments; i++) {
2280 float x = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
2281 float y = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
2282 immVertex3f(pos, x, y, z);
2287 for (int j = 0; j < 4; j++) {
2288 float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
2289 float y = ((j % 2) * (j - 2)) * 0.5f;
2290 immBegin(PRIM_LINE_STRIP, 3);
2291 for (int i = 0; i < 3; i++) {
2297 float z = 0.25f * i - 0.125f;
2298 immVertex3f(pos, x, y, z);
2306 static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel,
2307 unsigned int pos, unsigned int color)
2309 BPoint *bp = lt->def;
2310 const float *co = dl ? dl->verts : NULL;
2311 float active_color[4], draw_color[4];
2313 UI_GetThemeColor4fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, draw_color);
2314 UI_GetThemeColor4fv(TH_ACTIVE_VERT, active_color);
2316 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
2317 immBeginAtMost(PRIM_POINTS, lt->pntsw * lt->pntsv * lt->pntsu);
2319 for (int w = 0; w < lt->pntsw; w++) {
2320 int wxt = (w == 0 || w == lt->pntsw - 1);
2321 for (int v = 0; v < lt->pntsv; v++) {
2322 int vxt = (v == 0 || v == lt->pntsv - 1);
2323 for (int u = 0; u < lt->pntsu; u++, bp++, co += 3) {
2324 int uxt = (u == 0 || u == lt->pntsu - 1);
2325 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
2326 if (bp->hide == 0) {
2327 /* check for active BPoint and ensure selected */
2328 if ((bp == actbp) && (bp->f1 & SELECT)) {
2329 immAttrib4fv(color, active_color);
2330 immVertex3fv(pos, dl ? co : bp->vec);
2332 else if ((bp->f1 & SELECT) == sel) {
2333 immAttrib4fv(color, draw_color);
2334 immVertex3fv(pos, dl ? co : bp->vec);
2345 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol,
2346 unsigned int pos, unsigned int color)
2348 int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
2352 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
2353 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
2354 immAttrib3fv(color, col);
2358 immVertex3fv(pos, &dl->verts[index * 3]);
2361 immVertex3fv(pos, lt->def[index].vec);
2365 #ifdef SEQUENCER_DAG_WORKAROUND
2366 static void ensure_curve_cache(Scene *scene, Object *object)
2368 bool need_recalc = object->curve_cache == NULL;
2369 /* Render thread might have freed the curve cache if the
2370 * object is not visible. If the object is also used for
2371 * particles duplication, then render thread might have
2372 * also created curve_cache with only bevel and path
2375 * So check for curve_cache != NULL is not fully correct
2376 * here, we also need to check whether display list is
2379 * The trick below tries to optimize calls to displist
2380 * creation for cases curve is empty. Meaning, if the curve
2381 * is empty (without splines) bevel list would also be empty.
2382 * And the thing is, render thread always leaves bevel list
2383 * in a proper state. So if bevel list is here and display
2384 * list is not we need to make display list.
2386 if (need_recalc == false) {
2387 need_recalc = object->curve_cache->disp.first == NULL &&
2388 object->curve_cache->bev.first != NULL;
2391 switch (object->type) {
2395 BKE_displist_make_curveTypes(scene, object, false);
2398 BKE_displist_make_mball(G.main->eval_ctx, scene, object);
2401 BKE_lattice_modifiers_calc(scene, object);
2408 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
2409 static void drawlattice(View3D *v3d, Object *ob, const short dflag, const unsigned char ob_wire_col[4])
2411 Lattice *lt = ob->data;
2414 int actdef_wcol = 0;
2415 const bool is_edit = (lt->editlatt != NULL);
2417 dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS);
2420 lt = lt->editlatt->latt;
2422 if (ob->defbase.first && lt->dvert) {
2423 actdef_wcol = ob->actdef;
2427 VertexFormat *format = immVertexFormat();
2428 unsigned int color, pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2431 color = VertexFormat_add_attrib(format, "color", COMP_F32, 3, KEEP_FLOAT);
2432 immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
2435 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2438 immUniformThemeColor(TH_WIRE_EDIT);
2441 if ((dflag & DRAW_CONSTCOLOR) == 0) {
2442 immUniformColor3ubv(ob_wire_col);
2445 immUniformColor3f(0.0f, 0.0f, 0.0f);
2451 immBeginAtMost(PRIM_LINES, lt->pntsw * lt->pntsv * lt->pntsu * 6);
2453 for (w = 0; w < lt->pntsw; w++) {
2454 int wxt = (w == 0 || w == lt->pntsw - 1);
2455 for (v = 0; v < lt->pntsv; v++) {
2456 int vxt = (v == 0 || v == lt->pntsv - 1);
2457 for (u = 0; u < lt->pntsu; u++) {
2458 int uxt = (u == 0 || u == lt->pntsu - 1);
2460 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
2461 drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol, pos, color);
2462 drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
2464 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2465 drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol, pos, color);
2466 drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
2468 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2469 drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol, pos, color);
2470 drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
2480 BPoint *actbp = BKE_lattice_active_point_get(lt);
2482 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2484 VertexFormat *v_format = immVertexFormat();
2485 unsigned int v_pos = VertexFormat_add_attrib(v_format, "pos", COMP_F32, 3, KEEP_FLOAT);
2486 unsigned int v_color = VertexFormat_add_attrib(v_format, "color", COMP_F32, 4, KEEP_FLOAT);
2488 immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
2490 lattice_draw_verts(lt, dl, actbp, 0, v_pos, v_color);
2491 lattice_draw_verts(lt, dl, actbp, 1, v_pos, v_color);
2495 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2499 /* ***************** ******************** */
2503 typedef struct drawDMVertSel_userData {
2506 unsigned char *col[3]; /* (base, sel, act) */
2508 unsigned int pos, color;
2509 } drawDMVertSel_userData;
2511 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
2512 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2514 drawDMVertSel_userData *data = userData;
2515 MVert *mv = &data->mvert[index];
2517 if (!(mv->flag & ME_HIDE)) {
2518 const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
2519 if (sel != data->sel_prev) {
2520 immAttrib3ubv(data->color, data->col[sel]);
2521 data->sel_prev = sel;
2524 immVertex3fv(data->pos, co);
2528 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
2530 drawDMVertSel_userData data;
2531 VertexFormat *format = immVertexFormat();
2533 /* TODO define selected color */
2534 unsigned char base_col[3] = {0x0, 0x0, 0x0};
2535 unsigned char sel_col[3] = {0xd8, 0xb8, 0x0};
2536 unsigned char act_col[3] = {0xff, 0xff, 0xff};
2538 data.mvert = me->mvert;
2539 data.active = BKE_mesh_mselect_active_get(me, ME_VSEL);
2540 data.sel_prev = 0xff;
2542 data.col[0] = base_col;
2543 data.col[1] = sel_col;
2544 data.col[2] = act_col;
2546 data.color = VertexFormat_add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT);
2547 data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2549 if (dm->getNumVerts(dm) == 0) return;
2551 immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
2553 immBeginAtMost(PRIM_POINTS, dm->getNumVerts(dm));
2554 dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
2560 /* ************** DRAW MESH ****************** */
2562 /* First section is all the "simple" draw routines,
2563 * ones that just pass some sort of primitive to GL,
2564 * with perhaps various options to control lighting,
2567 * These routines should not have user interface related
2571 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
2575 copy_m3_m4(obmat, ob->obmat);
2577 data->uniform_scale = is_uniform_scaled_m3(obmat);
2579 if (!data->uniform_scale) {
2580 /* inverted matrix */
2581 invert_m3_m3(data->imat, obmat);
2583 /* transposed inverted matrix */
2584 transpose_m3_m3(data->tmat, data->imat);
2588 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2590 drawDMNormal_userData *data = userData;
2591 BMFace *efa = BM_face_at_index(data->bm, index);
2594 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2595 if (!data->uniform_scale) {
2596 mul_v3_m3v3(n, data->tmat, no);
2598 mul_m3_v3(data->imat, n);
2604 immVertex3fv(data->pos, cent);
2605 immVertex3f(data->pos, cent[0] + n[0] * data->normalsize,
2606 cent[1] + n[1] * data->normalsize,
2607 cent[2] + n[2] * data->normalsize);
2611 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
2613 VertexFormat *format = immVertexFormat();
2614 drawDMNormal_userData data;
2617 data.normalsize = scene->toolsettings->normalsize;
2618 data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2620 calcDrawDMNormalScale(ob, &data);
2622 if (dm->getNumPolys(dm) == 0) return;
2624 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2625 immUniformThemeColor(theme_id);
2627 immBeginAtMost(PRIM_LINES, dm->getNumPolys(dm) * 2);
2628 dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2634 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2636 drawBMSelect_userData *data = userData;
2637 BMFace *efa = BM_face_at_index(data->bm, index);
2639 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
2640 (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
2642 immVertex3fv(data->pos, cent);
2645 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select, const unsigned char fcol[3])
2647 VertexFormat *format = immVertexFormat();
2649 drawBMSelect_userData data;
2651 data.select = select;
2652 data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2654 if (dm->getNumPolys(dm) == 0) return;
2656 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2657 immUniformColor3ubv(fcol);
2659 immBeginAtMost(PRIM_POINTS, dm->getNumPolys(dm));
2660 dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
2666 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])
2668 drawDMNormal_userData *data = userData;
2669 BMVert *eve = BM_vert_at_index(data->bm, index);
2671 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2675 copy_v3_v3(no, no_f);
2678 normal_short_to_float_v3(no, no_s);
2681 if (!data->uniform_scale) {
2682 mul_v3_m3v3(n, data->tmat, no);
2684 mul_m3_v3(data->imat, n);
2690 immVertex3fv(data->pos, co);
2691 immVertex3f(data->pos, co[0] + n[0] * data->normalsize,
2692 co[1] + n[1] * data->normalsize,
2693 co[2] + n[2] * data->normalsize);
2697 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
2699 drawDMNormal_userData data;
2700 VertexFormat *format = immVertexFormat();
2703 data.normalsize = scene->toolsettings->normalsize;
2704 data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2706 calcDrawDMNormalScale(ob, &data);
2708 if (dm->getNumVerts(dm) == 0) return;
2710 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2711 immUniformThemeColor(theme_id);
2713 immBeginAtMost(PRIM_LINES, dm->getNumVerts(dm) * 2);
2714 dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2720 static void draw_dm_verts_skin_root__mapFunc(void *userData, int index, const float co[3],
2721 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2723 drawDMVerts_userData *data = userData;
2724 BMVert *eve = BM_vert_at_index(data->bm, index);
2726 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2727 /* skin nodes: draw a red circle around the root node(s) */
2728 const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
2729 if (vs->flag & MVERT_SKIN_ROOT) {
2730 float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2731 imm_drawcircball(co, radius, data->imat, data->pos);
2736 /* Draw verts with color set based on selection */
2737 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2738 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2740 drawDMVerts_userData *data = userData;
2741 BMVert *eve = BM_vert_at_index(data->bm, index);
2743 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2744 /* draw active in a different color - no need to stop/start point drawing for this :D */
2745 if (eve == data->eve_act) {
2746 immAttrib4ubv(data->color, data->th_editmesh_active);
2747 immVertex3fv(data->pos, co);
2750 immAttrib4ubv(data->color, data->sel ? data->th_vertex_select : data->th_vertex);
2751 immVertex3fv(data->pos, co);
2756 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
2757 RegionView3D *rv3d, const unsigned char col[4])
2759 VertexFormat *format = immVertexFormat();
2761 drawDMVerts_userData data;
2763 data.eve_act = eve_act;
2765 data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2766 data.color = VertexFormat_add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT);
2768 /* Cache theme values */
2769 UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2770 UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2771 UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2772 UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2774 /* Set correct alpha */
2775 data.th_editmesh_active[3] = data.th_vertex_select[3] = data.th_vertex[3] = data.th_skin_root[3] = col[3];
2777 /* view-aligned matrix */
2778 mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2779 invert_m4(data.imat);
2781 if (dm->getNumVerts(dm) == 0) return;
2783 immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
2785 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
2787 immBeginAtMost(PRIM_POINTS, dm->getNumVerts(dm));
2788 dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
2793 /* For skin root drawing */
2794 data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
2796 if (data.cd_vskin_offset != -1) {
2797 data.pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
2798 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2799 immUniformColor4ubv(data.th_skin_root);
2801 dm->foreachMappedVert(dm, draw_dm_verts_skin_root__mapFunc, &data, DM_FOREACH_NOP);
2807 /* Draw edges with color set based on selection */
2808 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2811 drawDMEdgesSel_userData *data = userData;
2814 eed = BM_edge_at_index(data->bm, index);
2816 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2817 if (eed == data->eed_act) {
2818 glColor4ubv(data->actCol);
2821 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2825 col = data->baseCol;
2827 /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2829 return DM_DRAW_OPTION_SKIP;
2833 return DM_DRAW_OPTION_NORMAL;
2836 return DM_DRAW_OPTION_SKIP;
2840 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2841 unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2843 drawDMEdgesSel_userData data;
2845 data.baseCol = baseCol;
2846 data.selCol = selCol;
2847 data.actCol = actCol;
2849 data.eed_act = eed_act;
2850 dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2854 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2856 if (BM_elem_flag_test(BM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2857 return DM_DRAW_OPTION_SKIP;
2859 return DM_DRAW_OPTION_NORMAL;
2862 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2864 dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em->bm);
2867 /* Draw edges with color interpolated based on selection */
2868 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2870 drawDMEdgesSelInterp_userData *data = userData;
2871 if (BM_elem_flag_test(BM_edge_at_index(data->bm, index), BM_ELEM_HIDDEN))
2872 return DM_DRAW_OPTION_SKIP;
2874 return DM_DRAW_OPTION_NORMAL;
2876 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2878 drawDMEdgesSelInterp_userData *data = userData;
2879 BMEdge *eed = BM_edge_at_index(data->bm, index);
2880 unsigned char **cols = userData;
2881 unsigned int col0_id = (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1;
2882 unsigned int col1_id = (BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1;
2883 unsigned char *col0 = cols[col0_id];
2884 unsigned char *col1 = cols[col1_id];
2885 unsigned char *col_pt;
2887 if (col0_id == col1_id) {
2890 else if (t == 0.0f) {
2893 else if (t == 1.0f) {
2897 unsigned char col_blend[4];
2898 interp_v4_v4v4_uchar(col_blend, col0, col1, t);
2899 glColor4ubv(col_blend);
2900 data->lastCol = NULL;
2904 if (data->lastCol != col_pt) {
2905 data->lastCol = col_pt;
2906 glColor4ubv(col_pt);
2910 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2912 drawDMEdgesSelInterp_userData data;
2914 data.baseCol = baseCol;
2915 data.selCol = selCol;
2916 data.lastCol = NULL;
2918 dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, &data);
2921 static void bm_color_from_weight(float col[3], BMVert *vert, drawDMEdgesWeightInterp_userData *data)
2923 MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, data->cd_dvert_offset);
2924 float weight = defvert_find_weight(dvert, data->vgroup_index);
2926 if ((weight == 0.0f) &&
2927 ((data->weight_user == OB_DRAW_GROUPUSER_ACTIVE) ||
2928 ((data->weight_user == OB_DRAW_GROUPUSER_ALL) && defvert_is_weight_zero(dvert, data->defgroup_tot))))
2930 copy_v3_v3(col, data->alert_color);
2933 weight_to_rgb(col, weight);
2937 static void draw_dm_edges_nop_interp__setDrawInterpOptions(void *UNUSED(userData), int UNUSED(index), float UNUSED(t))
2942 static void draw_dm_edges_weight_interp__setDrawInterpOptions(void *userData, int index, float t)
2944 drawDMEdgesWeightInterp_userData *data = userData;
2945 BMEdge *eed = BM_edge_at_index(data->bm, index);
2949 bm_color_from_weight(col, eed->v1, data);
2951 else if (t == 1.0f) {
2952 bm_color_from_weight(col, eed->v2, data);
2958 bm_color_from_weight(col_v1, eed->v1, data);
2959 bm_color_from_weight(col_v2, eed->v2, data);
2960 interp_v3_v3v3(col, col_v1, col_v2, t);
2966 static void draw_dm_edges_weight_interp(BMEditMesh *em, DerivedMesh *dm, const char weight_user)
2968 drawDMEdgesWeightInterp_userData data;
2969 Object *ob = em->ob;
2972 data.cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2973 data.defgroup_tot = BLI_listbase_count(&ob->defbase);
2974 data.vgroup_index = ob->actdef - 1;
2975 data.weight_user = weight_user;
2976 UI_GetThemeColor3fv(TH_VERTEX_UNREFERENCED, data.alert_color);
2978 if ((data.vgroup_index != -1) && (data.cd_dvert_offset != -1)) {
2980 dm->drawMappedEdgesInterp(
2982 draw_dm_edges_sel_interp__setDrawOptions,
2983 draw_dm_edges_weight_interp__setDrawInterpOptions,
2985 glDisable(GL_BLEND);
2990 if (data.weight_user == OB_DRAW_GROUPUSER_NONE) {
2991 weight_to_rgb(col, 0.0f);
2994 copy_v3_v3(col, data.alert_color);
2998 dm->drawMappedEdgesInterp(
3000 draw_dm_edges_sel_interp__setDrawOptions,
3001 draw_dm_edges_nop_interp__setDrawInterpOptions,
3007 static bool draw_dm_edges_weight_check(Mesh *me, View3D *v3d)
3009 if (me->drawflag & ME_DRAWEIGHT) {
3010 if ((v3d->drawtype == OB_WIRE) ||
3011 (v3d->flag2 & V3D_SOLID_MATCAP) ||
3012 ((v3d->flag2 & V3D_OCCLUDE_WIRE) && (v3d->drawtype > OB_WIRE)))
3021 /* Draw only seam edges */
3022 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
3024 BMEdge *eed = BM_edge_at_index(userData, index);
3026 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
3027 return DM_DRAW_OPTION_NORMAL;
3029 return DM_DRAW_OPTION_SKIP;
3032 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
3034 dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em->bm);
3037 /* Draw only sharp edges */
3038 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
3040 BMEdge *eed = BM_edge_at_index(userData, index);
3042 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
3043 return DM_DRAW_OPTION_NORMAL;
3045 return DM_DRAW_OPTION_SKIP;
3048 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
3050 dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em->bm);
3053 #ifdef WITH_FREESTYLE
3055 static bool draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed)
3057 FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
3060 return (fed->flag & FREESTYLE_EDGE_MARK) != 0;
3063 /* Draw only Freestyle feature edges */
3064 static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
3066 BMEdge *eed = BM_edge_at_index(userData, index);
3068 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && draw_dm_test_freestyle_edge_mark(userData, eed))
3069 return DM_DRAW_OPTION_NORMAL;
3071 return DM_DRAW_OPTION_SKIP;
3074 static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
3076 dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em->bm);
3079 static bool draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa)
3081 FreestyleFace *ffa = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
3084 return (ffa->flag & FREESTYLE_FACE_MARK) != 0;
3089 /* Draw loop normals. */
3090 static void draw_dm_loop_normals__mapFunc(void *userData, int vertex_index, int face_index,
3091 const float co[3], const float no[3])
3094 const drawDMNormal_userData *data = userData;
3095 const BMVert *eve = BM_vert_at_index(data->bm, vertex_index);
3096 const BMFace *efa = BM_face_at_index(data->bm, face_index);
3099 if (!(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) || BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) {
3100 if (!data->uniform_scale) {
3101 mul_v3_m3v3(vec, (float(*)[3])data->tmat, no);
3103 mul_m3_v3((float(*)[3])data->imat, vec);
3106 copy_v3_v3(vec, no);
3108 mul_v3_fl(vec, data->normalsize);
3110 immVertex3fv(data->pos, co);
3111 immVertex3fv(data->pos, vec);
3116 static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
3118 drawDMNormal_userData data;
3121 data.normalsize = scene->toolsettings->normalsize;
3122 data.pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
3124 if (dm->getNumLoops(dm) == 0) return;
3126 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
3127 immUniformThemeColor(theme_id);
3129 calcDrawDMNormalScale(ob, &data);
3131 immBeginAtMost(PRIM_LINES, dm->getNumLoops(dm) * 2);
3132 dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
3138 /* Draw faces with color set based on selection
3139 * return 2 for the active face so it renders with stipple enabled */
3140 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
3142 drawDMFacesSel_userData *data = userData;
3143 BMFace *efa = BM_face_at_index(data->bm, index);
3146 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
3147 if (efa == data->efa_act) {
3148 glColor4ubv(data->cols[2]);
3149 return DM_DRAW_OPTION_STIPPLE;
3152 #ifdef WITH_FREESTYLE
3153 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
3155 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
3158 return DM_DRAW_OPTION_SKIP;
3160 return DM_DRAW_OPTION_NORMAL;
3163 return DM_DRAW_OPTION_SKIP;
3166 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
3169 drawDMFacesSel_userData *data = userData;
3174 unsigned char *col, *next_col;
3176 i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[index] : index;
3177 efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
3178 i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[next_index] : next_index;
3179 next_efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
3181 if (ELEM(NULL, efa, next_efa))
3184 if (efa == next_efa)
3187 if (efa == data->efa_act || next_efa == data->efa_act)
3190 #ifdef WITH_FREESTYLE
3191 col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
3192 next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];