Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_view3d / drawobject.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, full recode and added functions
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_view3d/drawobject.c
27  *  \ingroup spview3d
28  */
29
30 #include "MEM_guardedalloc.h"
31
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"
45
46 #include "BLI_listbase.h"
47 #include "BLI_link_utils.h"
48 #include "BLI_string.h"
49 #include "BLI_math.h"
50 #include "BLI_memarena.h"
51
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"
61 #include "BKE_font.h"
62 #include "BKE_global.h"
63 #include "BKE_image.h"
64 #include "BKE_key.h"
65 #include "BKE_lattice.h"
66 #include "BKE_main.h"
67 #include "BKE_mesh.h"
68 #include "BKE_mesh_render.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"
79 #include "BKE_unit.h"
80 #include "BKE_tracking.h"
81
82 #include "BKE_editmesh.h"
83
84 #include "IMB_imbuf.h"
85 #include "IMB_imbuf_types.h"
86
87 #include "BIF_gl.h"
88 #include "BIF_glutil.h"
89
90 #include "GPU_draw.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"
98
99 #include "ED_mesh.h"
100 #include "ED_particle.h"
101 #include "ED_screen.h"
102 #include "ED_sculpt.h"
103 #include "ED_types.h"
104
105 #include "UI_resources.h"
106 #include "UI_interface_icons.h"
107
108 #include "WM_api.h"
109 #include "BLF_api.h"
110
111 #include "view3d_intern.h"  /* bad level include */
112
113 /* prototypes */
114 static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos);
115
116 /* Workaround for sequencer scene render mode.
117  *
118  * Strips doesn't use DAG to update objects or so, which
119  * might lead to situations when object is drawing without
120  * curve cache ready.
121  *
122  * Ideally we don't want to evaluate objects from drawing,
123  * but it'll require some major sequencer re-design. So
124  * for now just fallback to legacy behavior with calling
125  * display ist creating from draw().
126  */
127 #define SEQUENCER_DAG_WORKAROUND
128
129 typedef enum eWireDrawMode {
130         OBDRAW_WIRE_OFF = 0,
131         OBDRAW_WIRE_ON = 1,
132         OBDRAW_WIRE_ON_DEPTH = 2
133 } eWireDrawMode;
134
135 typedef struct drawDMVerts_userData {
136         BMesh *bm;
137
138         BMVert *eve_act;
139         char sel;
140         unsigned int pos, color;
141
142         /* cached theme values */
143         unsigned char th_editmesh_active[4];
144         unsigned char th_vertex_select[4];
145         unsigned char th_vertex[4];
146         unsigned char th_skin_root[4];
147
148         /* for skin node drawing */
149         int cd_vskin_offset;
150         float imat[4][4];
151 } drawDMVerts_userData;
152
153 typedef struct drawDMEdgesSel_userData {
154         BMesh *bm;
155
156         unsigned char *baseCol, *selCol, *actCol;
157         BMEdge *eed_act;
158 } drawDMEdgesSel_userData;
159
160 typedef struct drawDMEdgesSelInterp_userData {
161         BMesh *bm;
162
163         unsigned char *baseCol, *selCol;
164         unsigned char *lastCol;
165 } drawDMEdgesSelInterp_userData;
166
167 typedef struct drawDMEdgesWeightInterp_userData {
168         BMesh *bm;
169
170         int cd_dvert_offset;
171         int defgroup_tot;
172         int vgroup_index;
173         char weight_user;
174         float alert_color[3];
175
176 } drawDMEdgesWeightInterp_userData;
177
178 typedef struct drawDMFacesSel_userData {
179 #ifdef WITH_FREESTYLE
180         unsigned char *cols[4];
181 #else
182         unsigned char *cols[3];
183 #endif
184
185         DerivedMesh *dm;
186         BMesh *bm;
187
188         BMFace *efa_act;
189         const int *orig_index_mp_to_orig;
190 } drawDMFacesSel_userData;
191
192 typedef struct drawDMNormal_userData {
193         unsigned int pos;
194         BMesh *bm;
195         int uniform_scale;
196         float normalsize;
197         float tmat[3][3];
198         float imat[3][3];
199 } drawDMNormal_userData;
200
201 typedef struct drawMVertOffset_userData {
202         unsigned int pos, col;
203         MVert *mvert;
204         int offset;
205 } drawMVertOffset_userData;
206
207 typedef struct drawDMLayer_userData {
208         BMesh *bm;
209         int cd_layer_offset;
210         unsigned int pos, col;
211 } drawDMLayer_userData;
212
213 typedef struct drawBMOffset_userData {
214         unsigned int pos, col;
215         BMesh *bm;
216         int offset;
217 } drawBMOffset_userData;
218
219 typedef struct drawBMSelect_userData {
220         BMesh *bm;
221         bool select;
222         unsigned int pos;
223 } drawBMSelect_userData;
224
225
226 static void drawcube_size(float size, unsigned pos);
227 static void drawcircle_size(float size, unsigned pos);
228 static void draw_empty_sphere(float size, unsigned pos);
229 static void draw_empty_cone(float size, unsigned pos);
230
231 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])
232 {
233         float col_wire[3], col_bg[3];
234
235         rgb_uchar_to_float(col_wire, ob_wire_col);
236
237         UI_GetThemeColor3fv(theme_id, col_bg);
238         interp_v3_v3v3(r_col, col_bg, col_wire, fac);
239 }
240
241 int view3d_effective_drawtype(const struct View3D *v3d)
242 {
243         if (v3d->drawtype == OB_RENDER) {
244                 return v3d->prev_drawtype;
245         }
246         return v3d->drawtype;
247 }
248
249 /* this condition has been made more complex since editmode can draw textures */
250 bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
251 {
252         const int v3d_drawtype = view3d_effective_drawtype(v3d);
253         /* texture and material draw modes */
254         if (ELEM(v3d_drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
255                 return true;
256         }
257
258         /* textured solid */
259         if ((v3d_drawtype == OB_SOLID) &&
260             (v3d->flag2 & V3D_SOLID_TEX) &&
261             (BKE_scene_use_new_shading_nodes(scene) == false))
262         {
263                 return true;
264         }
265         
266         if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) {
267                 return true;
268         }
269         
270         return false;
271 }
272
273 static bool check_object_draw_editweight(Mesh *me, DerivedMesh *finalDM)
274 {
275         if (me->drawflag & ME_DRAWEIGHT) {
276                 /* editmesh handles its own weight drawing */
277                 if (finalDM->type != DM_TYPE_EDITBMESH) {
278                         return true;
279                 }
280         }
281
282         return false;
283 }
284
285 static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
286 {
287         if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
288                 return false;
289
290         if (G.f & G_BACKBUFSEL)
291                 return false;
292
293         if ((vd->flag & V3D_ZBUF_SELECT) == 0)
294                 return true;
295
296         /* if its drawing textures with zbuf sel, then don't draw dots */
297         if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
298                 return false;
299
300         if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
301                 return false;
302
303         return true;
304 }
305
306 /* ************************ */
307
308 /* check for glsl drawing */
309
310 bool draw_glsl_material(Scene *scene, SceneLayer *sl, Object *ob, View3D *v3d, const char dt)
311 {
312         if (G.f & G_PICKSEL)
313                 return false;
314         if (!check_object_draw_texture(scene, v3d, dt))
315                 return false;
316         if (ob == OBACT_NEW && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
317                 return false;
318         
319         if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
320                 return true;
321
322         if (v3d->drawtype == OB_TEXTURE)
323                 return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
324         else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
325                 return true;
326         else
327                 return false;
328 }
329
330 static bool check_alpha_pass(Base *base)
331 {
332         if (base->flag_legacy & OB_FROMDUPLI)
333                 return false;
334
335         if (G.f & G_PICKSEL)
336                 return false;
337
338         if (base->object->mode & OB_MODE_ALL_PAINT)
339                 return false;
340
341         return (base->object->dtx & OB_DRAWTRANSP);
342 }
343
344 /***/
345 static const unsigned int colortab[] = {
346         0x0, 0x403000, 0xFFFF88
347 };
348
349 /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
350 /* 32 values of sin function (still same result!) */
351 #define CIRCLE_RESOL 32
352
353 static const float sinval[CIRCLE_RESOL] = {
354         0.00000000,
355         0.20129852,
356         0.39435585,
357         0.57126821,
358         0.72479278,
359         0.84864425,
360         0.93775213,
361         0.98846832,
362         0.99871650,
363         0.96807711,
364         0.89780453,
365         0.79077573,
366         0.65137248,
367         0.48530196,
368         0.29936312,
369         0.10116832,
370         -0.10116832,
371         -0.29936312,
372         -0.48530196,
373         -0.65137248,
374         -0.79077573,
375         -0.89780453,
376         -0.96807711,
377         -0.99871650,
378         -0.98846832,
379         -0.93775213,
380         -0.84864425,
381         -0.72479278,
382         -0.57126821,
383         -0.39435585,
384         -0.20129852,
385         0.00000000
386 };
387
388 /* 32 values of cos function (still same result!) */
389 static const float cosval[CIRCLE_RESOL] = {
390         1.00000000,
391         0.97952994,
392         0.91895781,
393         0.82076344,
394         0.68896691,
395         0.52896401,
396         0.34730525,
397         0.15142777,
398         -0.05064916,
399         -0.25065253,
400         -0.44039415,
401         -0.61210598,
402         -0.75875812,
403         -0.87434661,
404         -0.95413925,
405         -0.99486932,
406         -0.99486932,
407         -0.95413925,
408         -0.87434661,
409         -0.75875812,
410         -0.61210598,
411         -0.44039415,
412         -0.25065253,
413         -0.05064916,
414         0.15142777,
415         0.34730525,
416         0.52896401,
417         0.68896691,
418         0.82076344,
419         0.91895781,
420         0.97952994,
421         1.00000000
422 };
423
424 /**
425  * \param viewmat_local_unit is typically the 'rv3d->viewmatob'
426  * copied into a 3x3 matrix and normalized.
427  */
428 static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis, unsigned pos)
429 {
430         PrimitiveType line_type = PRIM_LINES;
431         float buffer[4][3];
432         int n = 0;
433
434         float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
435         float dim = size * 0.1f;
436         float dx[3], dy[3];
437
438         dx[0] = dim;  dx[1] = 0.0f; dx[2] = 0.0f;
439         dy[0] = 0.0f; dy[1] = dim;  dy[2] = 0.0f;
440
441         switch (axis) {
442                 case 0:     /* x axis */
443                         /* bottom left to top right */
444                         negate_v3_v3(v1, dx);
445                         sub_v3_v3(v1, dy);
446                         copy_v3_v3(v2, dx);
447                         add_v3_v3(v2, dy);
448
449                         copy_v3_v3(buffer[n++], v1);
450                         copy_v3_v3(buffer[n++], v2);
451                         
452                         /* top left to bottom right */
453                         mul_v3_fl(dy, 2.0f);
454                         add_v3_v3(v1, dy);
455                         sub_v3_v3(v2, dy);
456                         
457                         copy_v3_v3(buffer[n++], v1);
458                         copy_v3_v3(buffer[n++], v2);
459
460                         break;
461                 case 1:     /* y axis */
462                         /* bottom left to top right */
463                         mul_v3_fl(dx, 0.75f);
464                         negate_v3_v3(v1, dx);
465                         sub_v3_v3(v1, dy);
466                         copy_v3_v3(v2, dx);
467                         add_v3_v3(v2, dy);
468                         
469                         copy_v3_v3(buffer[n++], v1);
470                         copy_v3_v3(buffer[n++], v2);
471                         
472                         /* top left to center */
473                         mul_v3_fl(dy, 2.0f);
474                         add_v3_v3(v1, dy);
475                         zero_v3(v2);
476                         
477                         copy_v3_v3(buffer[n++], v1);
478                         copy_v3_v3(buffer[n++], v2);
479                         
480                         break;
481                 case 2:     /* z axis */
482                         line_type = PRIM_LINE_STRIP;
483                         
484                         /* start at top left */
485                         negate_v3_v3(v1, dx);
486                         add_v3_v3(v1, dy);
487                         
488                         copy_v3_v3(buffer[n++], v1);
489                         
490                         mul_v3_fl(dx, 2.0f);
491                         add_v3_v3(v1, dx);
492
493                         copy_v3_v3(buffer[n++], v1);
494                         
495                         mul_v3_fl(dy, 2.0f);
496                         sub_v3_v3(v1, dx);
497                         sub_v3_v3(v1, dy);
498                         
499                         copy_v3_v3(buffer[n++], v1);
500                         
501                         add_v3_v3(v1, dx);
502                 
503                         copy_v3_v3(buffer[n++], v1);
504                         
505                         break;
506                 default:
507                         BLI_assert(0);
508                         return;
509         }
510
511         immBegin(line_type, n);
512         for (int i = 0; i < n; i++) {
513                 mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
514                 add_v3_v3(buffer[i], c);
515                 immVertex3fv(pos, buffer[i]);
516         }
517         immEnd();
518
519         /* TODO: recode this function for clarity once we're not in a hurry to modernize GL usage */
520 }
521
522 void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4])
523 {
524         int axis;
525         float v1[3] = {0.0, 0.0, 0.0};
526         float v2[3] = {0.0, 0.0, 0.0};
527         float v3[3] = {0.0, 0.0, 0.0};
528
529         glLineWidth(1.0f);
530
531         unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
532         if (color) {
533                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
534                 immUniformColor4ubv(color);
535         }
536         else {
537                 immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
538         }
539
540         switch (drawtype) {
541                 case OB_PLAINAXES:
542                         immBegin(PRIM_LINES, 6);
543                         for (axis = 0; axis < 3; axis++) {
544                                 v1[axis] = size;
545                                 v2[axis] = -size;
546                                 immVertex3fv(pos, v1);
547                                 immVertex3fv(pos, v2);
548
549                                 /* reset v1 & v2 to zero */
550                                 v1[axis] = v2[axis] = 0.0f;
551                         }
552                         immEnd();
553                         break;
554
555                 case OB_SINGLE_ARROW:
556                         immBegin(PRIM_LINES, 2);
557                         /* in positive z direction only */
558                         v1[2] = size;
559                         immVertex3fv(pos, v1);
560                         immVertex3fv(pos, v2);
561                         immEnd();
562
563                         /* square pyramid */
564                         immBegin(PRIM_TRIANGLES, 12);
565
566                         v2[0] = size * 0.035f; v2[1] = size * 0.035f;
567                         v3[0] = size * -0.035f; v3[1] = size * 0.035f;
568                         v2[2] = v3[2] = size * 0.75f;
569
570                         for (axis = 0; axis < 4; axis++) {
571                                 if (axis % 2 == 1) {
572                                         v2[0] = -v2[0];
573                                         v3[1] = -v3[1];
574                                 }
575                                 else {
576                                         v2[1] = -v2[1];
577                                         v3[0] = -v3[0];
578                                 }
579
580                                 immVertex3fv(pos, v1);
581                                 immVertex3fv(pos, v2);
582                                 immVertex3fv(pos, v3);
583                         }
584                         immEnd();
585                         break;
586
587                 case OB_CUBE:
588                         drawcube_size(size, pos);
589                         break;
590
591                 case OB_CIRCLE:
592                         drawcircle_size(size, pos);
593                         break;
594
595                 case OB_EMPTY_SPHERE:
596                         draw_empty_sphere(size, pos);
597                         break;
598
599                 case OB_EMPTY_CONE:
600                         draw_empty_cone(size, pos);
601                         break;
602
603                 case OB_ARROWS:
604                 default:
605                 {
606                         float viewmat_local_unit[3][3];
607
608                         copy_m3_m4(viewmat_local_unit, (float (*)[4])viewmat_local);
609                         normalize_m3(viewmat_local_unit);
610
611                         for (axis = 0; axis < 3; axis++) {
612                                 const int arrow_axis = (axis == 0) ? 1 : 0;
613
614                                 immBegin(PRIM_LINES, 6);
615
616                                 v2[axis] = size;
617                                 immVertex3fv(pos, v1);
618                                 immVertex3fv(pos, v2);
619
620                                 v1[axis] = size * 0.85f;
621                                 v1[arrow_axis] = -size * 0.08f;
622                                 immVertex3fv(pos, v1);
623                                 immVertex3fv(pos, v2);
624
625                                 v1[arrow_axis] = size * 0.08f;
626                                 immVertex3fv(pos, v1);
627                                 immVertex3fv(pos, v2);
628
629                                 immEnd();
630
631                                 v2[axis] += size * 0.125f;
632
633                                 draw_xyz_wire(viewmat_local_unit, v2, size, axis, pos);
634
635                                 /* reset v1 & v2 to zero */
636                                 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
637                         }
638                 }
639         }
640
641         immUnbindProgram();
642 }
643
644
645 /* Function to draw an Image on an empty Object */
646 static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview)
647 {
648         Image *ima = ob->data;
649
650         const float ob_alpha = ob->col[3];
651         float width, height;
652
653         int bindcode = 0;
654
655         if (ima) {
656                 ImageUser iuser = *ob->iuser;
657
658                 /* Support multi-view */
659                 if (ima && (sview == STEREO_RIGHT_ID)) {
660                         iuser.multiview_eye = sview;
661                         iuser.flag |= IMA_SHOW_STEREO;
662                         BKE_image_multiview_index(ima, &iuser);
663                 }
664
665                 if (ob_alpha > 0.0f) {
666                         bindcode = GPU_verify_image(ima, &iuser, GL_TEXTURE_2D, 0, false, false, false);
667                         /* don't bother drawing the image if alpha = 0 */
668                 }
669
670                 int w, h;
671                 BKE_image_get_size(ima, &iuser, &w, &h);
672                 width = w;
673                 height = h;
674         }
675         else {
676                 /* if no image, make it a 1x1 empty square, honor scale & offset */
677                 width = height = 1.0f;
678         }
679
680         const float aspect = height / width;
681
682         float left = ob->ima_ofs[0];
683         float right = ob->ima_ofs[0] + ob->empty_drawsize;
684         float top = ob->ima_ofs[1] + ob->empty_drawsize * aspect;
685         float bottom = ob->ima_ofs[1];
686
687         bool use_blend = false;
688
689         if (bindcode) {
690                 use_blend = ob_alpha < 1.0f || BKE_image_has_alpha(ima);
691
692                 if (use_blend) {
693                         glEnable(GL_BLEND);
694                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
695                 }
696
697                 VertexFormat *format = immVertexFormat();
698                 unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT);
699                 unsigned int texCoord = VertexFormat_add_attrib(format, "texCoord", COMP_F32, 2, KEEP_FLOAT);
700                 immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
701                 immUniform1f("alpha", ob_alpha);
702                 immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
703
704                 immBegin(PRIM_TRIANGLE_FAN, 4);
705                 immAttrib2f(texCoord, 0.0f, 0.0f);
706                 immVertex2f(pos, left, bottom);
707
708                 immAttrib2f(texCoord, 1.0f, 0.0f);
709                 immVertex2f(pos, right, bottom);
710
711                 immAttrib2f(texCoord, 1.0f, 1.0f);
712                 immVertex2f(pos, right, top);
713
714                 immAttrib2f(texCoord, 0.0f, 1.0f);
715                 immVertex2f(pos, left, top);
716                 immEnd();
717
718                 immUnbindProgram();
719
720                 glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */
721         }
722
723         /* Draw the image outline */
724         glLineWidth(1.5f);
725         unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT);
726
727         const bool picking = dflag & DRAW_CONSTCOLOR;
728         if (picking) {
729                 /* TODO: deal with picking separately, use this function just to draw */
730                 immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
731                 if (use_blend) {
732                         glDisable(GL_BLEND);
733                 }
734
735                 imm_draw_line_box(pos, left, bottom, right, top);
736         }
737         else {
738                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
739                 immUniformColor3ubv(ob_wire_col);
740                 glEnable(GL_LINE_SMOOTH);
741
742                 if (!use_blend) {
743                         glEnable(GL_BLEND);
744                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
745                 }
746
747                 imm_draw_line_box(pos, left, bottom, right, top);
748
749                 glDisable(GL_LINE_SMOOTH);
750                 glDisable(GL_BLEND);
751         }
752
753         immUnbindProgram();
754 }
755
756 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4])
757 {
758         float vx[3], vy[3];
759         float *viter = (float *)verts;
760
761         mul_v3_v3fl(vx, tmat[0], rad);
762         mul_v3_v3fl(vy, tmat[1], rad);
763
764         for (unsigned int a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
765                 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
766                 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
767                 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
768         }
769 }
770
771 void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos)
772 {
773         float verts[CIRCLE_RESOL][3];
774
775         circball_array_fill(verts, cent, rad, tmat);
776
777         immBegin(PRIM_LINE_LOOP, CIRCLE_RESOL);
778         for (int i = 0; i < CIRCLE_RESOL; ++i) {
779                 immVertex3fv(pos, verts[i]);
780         }
781         immEnd();
782 }
783
784 /* circle for object centers, special_color is for library or ob users */
785 static void drawcentercircle(View3D *v3d, RegionView3D *UNUSED(rv3d), const float co[3], int selstate, bool special_color)
786 {
787         const float outlineWidth = 1.0f * U.pixelsize;
788         const float size = U.obcenter_dia * U.pixelsize + outlineWidth;
789
790         if (v3d->zbuf) {
791                 glDisable(GL_DEPTH_TEST);
792                 /* TODO(merwin): fit things like this into plates/buffers design */
793         }
794
795         glEnable(GL_BLEND);
796         GPU_enable_program_point_size();
797
798         unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
799         immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
800         immUniform1f("size", size);
801
802         if (special_color) {
803                 if (selstate == ACTIVE || selstate == SELECT) immUniformColor4ub(0x88, 0xFF, 0xFF, 155);
804                 else immUniformColor4ub(0x55, 0xCC, 0xCC, 155);
805         }
806         else {
807                 if (selstate == ACTIVE) immUniformThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
808                 else if (selstate == SELECT) immUniformThemeColorShadeAlpha(TH_SELECT, 0, -80);
809                 else if (selstate == DESELECT) immUniformThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
810         }
811
812         /* set up outline */
813         float outlineColor[4];
814         UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor);
815         immUniform4fv("outlineColor", outlineColor);
816         immUniform1f("outlineWidth", outlineWidth);
817
818         immBegin(PRIM_POINTS, 1);
819         immVertex3fv(pos, co);
820         immEnd();
821
822         immUnbindProgram();
823
824         GPU_disable_program_point_size();
825         glDisable(GL_BLEND);
826
827         if (v3d->zbuf) {
828                 glEnable(GL_DEPTH_TEST);
829         }
830 }
831
832 /* *********** text drawing for object/particles/armature ************* */
833
834 typedef struct ViewCachedString {
835         struct ViewCachedString *next;
836         float vec[3];
837         union {
838                 unsigned char ub[4];
839                 int pack;
840         } col;
841         short sco[2];
842         short xoffs;
843         short flag;
844         int str_len;
845
846         /* str is allocated past the end */
847         char str[0];
848 } ViewCachedString;
849
850 /* one arena for all 3 string lists */
851 static MemArena         *g_v3d_strings_arena = NULL;
852 static ViewCachedString *g_v3d_strings[3] = {NULL, NULL, NULL};
853 static int g_v3d_string_level = -1;
854
855 void view3d_cached_text_draw_begin(void)
856 {
857         g_v3d_string_level++;
858
859         BLI_assert(g_v3d_string_level >= 0);
860
861         if (g_v3d_string_level == 0) {
862                 BLI_assert(g_v3d_strings_arena == NULL);
863         }
864 }
865
866 void view3d_cached_text_draw_add(const float co[3],
867                                  const char *str, const size_t str_len,
868                                  short xoffs, short flag,
869                                  const unsigned char col[4])
870 {
871         int alloc_len = str_len + 1;
872         ViewCachedString *vos;
873
874         BLI_assert(str_len == strlen(str));
875
876         if (g_v3d_strings_arena == NULL) {
877                 g_v3d_strings_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 14), __func__);
878         }
879
880         vos = BLI_memarena_alloc(g_v3d_strings_arena, sizeof(ViewCachedString) + alloc_len);
881
882         BLI_LINKS_PREPEND(g_v3d_strings[g_v3d_string_level], vos);
883
884         copy_v3_v3(vos->vec, co);
885         copy_v4_v4_uchar(vos->col.ub, col);
886         vos->xoffs = xoffs;
887         vos->flag = flag;
888         vos->str_len = str_len;
889
890         /* allocate past the end */
891         memcpy(vos->str, str, alloc_len);
892 }
893
894 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, float mat[4][4])
895 {
896         RegionView3D *rv3d = ar->regiondata;
897         ViewCachedString *vos;
898         int tot = 0;
899         
900         BLI_assert(g_v3d_string_level >= 0 && g_v3d_string_level <= 2);
901
902         /* project first and test */
903         for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
904                 if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
905                         mul_m4_v3(mat, vos->vec);
906
907                 if (ED_view3d_project_short_ex(ar,
908                                                (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
909                                                (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
910                                                vos->vec, vos->sco,
911                                                V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
912                 {
913                         tot++;
914                 }
915                 else {
916                         vos->sco[0] = IS_CLIPPED;
917                 }
918         }
919
920         if (tot) {
921                 int col_pack_prev = 0;
922
923                 if (rv3d->rflag & RV3D_CLIPPING) {
924                         ED_view3d_clipping_disable();
925                 }
926
927                 float original_proj[4][4];
928                 gpuGetProjectionMatrix3D(original_proj);
929                 wmOrtho2_region_pixelspace(ar);
930
931                 gpuPushMatrix();
932                 gpuLoadIdentity();
933                 
934                 if (depth_write) {
935                         if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
936                 }
937                 else {
938                         glDepthMask(GL_FALSE);
939                 }
940                 
941                 for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
942                         if (vos->sco[0] != IS_CLIPPED) {
943                                 if (col_pack_prev != vos->col.pack) {
944                                         //glColor3ubv(vos->col.ub);
945                                         col_pack_prev = vos->col.pack;
946                                 }
947
948                                 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
949                                  BLF_draw_default_ascii :
950                                  BLF_draw_default
951                                  )((float)(vos->sco[0] + vos->xoffs),
952                                    (float)(vos->sco[1]),
953                                    (depth_write) ? 0.0f : 2.0f,
954                                    vos->str,
955                                    vos->str_len);
956                         }
957                 }
958
959                 if (depth_write) {
960                         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
961                 }
962                 else {
963                         glDepthMask(GL_TRUE);
964                 }
965                 
966                 gpuPopMatrix();
967                 gpuLoadProjectionMatrix3D(original_proj); /* TODO: make this more 2D friendly */
968
969                 if (rv3d->rflag & RV3D_CLIPPING) {
970                         ED_view3d_clipping_enable();
971                 }
972         }
973
974         g_v3d_strings[g_v3d_string_level] = NULL;
975
976         if (g_v3d_string_level == 0) {
977                 if (g_v3d_strings_arena) {
978                         BLI_memarena_free(g_v3d_strings_arena);
979                         g_v3d_strings_arena = NULL;
980                 }
981         }
982
983         g_v3d_string_level--;
984 }
985
986 /* ******************** primitive drawing ******************* */
987
988 /* draws a cube given the scaling of the cube, assuming that
989  * all required matrices have been set (used for drawing empties)
990  */
991 static void drawcube_size(float size, unsigned pos)
992 {
993         const float verts[8][3] = {
994                 {-size, -size, -size},
995                 {-size, -size,  size},
996                 {-size,  size, -size},
997                 {-size,  size,  size},
998                 { size, -size, -size},
999                 { size, -size,  size},
1000                 { size,  size, -size},
1001                 { size,  size,  size}
1002         };
1003
1004         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};
1005
1006 #if 0
1007         glEnableClientState(GL_VERTEX_ARRAY);
1008         glVertexPointer(3, GL_FLOAT, 0, verts);
1009         glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
1010         glDisableClientState(GL_VERTEX_ARRAY);
1011 #else
1012         immBegin(PRIM_LINES, 24);
1013         for (int i = 0; i < 24; ++i) {
1014                 immVertex3fv(pos, verts[indices[i]]);
1015         }
1016         immEnd();
1017 #endif
1018 }
1019
1020 static void drawshadbuflimits(const Lamp *la, const float mat[4][4], unsigned pos)
1021 {
1022         float sta[3], end[3], lavec[3];
1023
1024         negate_v3_v3(lavec, mat[2]);
1025         normalize_v3(lavec);
1026
1027         madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
1028         madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
1029
1030         immBegin(PRIM_LINES, 2);
1031         immVertex3fv(pos, sta);
1032         immVertex3fv(pos, end);
1033         immEnd();
1034
1035         glPointSize(3.0f);
1036         immBegin(PRIM_POINTS, 2);
1037         immVertex3fv(pos, sta);
1038         immVertex3fv(pos, end);
1039         immEnd();
1040 }
1041
1042 static void spotvolume(float lvec[3], float vvec[3], const float inp)
1043 {
1044         /* camera is at 0,0,0 */
1045         float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
1046
1047         normalize_v3(lvec);
1048         normalize_v3(vvec);             /* is this the correct vector ? */
1049
1050         cross_v3_v3v3(temp, vvec, lvec);      /* equation for a plane through vvec and lvec */
1051         cross_v3_v3v3(plane, lvec, temp);     /* a plane perpendicular to this, parallel with lvec */
1052
1053         /* vectors are exactly aligned, use the X axis, this is arbitrary */
1054         if (normalize_v3(plane) == 0.0f)
1055                 plane[1] = 1.0f;
1056
1057         /* now we've got two equations: one of a cone and one of a plane, but we have
1058          * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
1059
1060         /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
1061         /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
1062
1063         /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
1064         
1065         q[1] =  plane[1];
1066         q[2] = -plane[0];
1067         q[3] =  0;
1068         normalize_v3(&q[1]);
1069
1070         angle = saacos(plane[2]) / 2.0f;
1071         co = cosf(angle);
1072         si = sqrtf(1 - co * co);
1073
1074         q[0] =  co;
1075         q[1] *= si;
1076         q[2] *= si;
1077         q[3] =  0;
1078
1079         quat_to_mat3(mat1, q);
1080
1081         /* rotate lamp vector now over acos(inp) degrees */
1082         copy_v3_v3(vvec, lvec);
1083
1084         unit_m3(mat2);
1085         co = inp;
1086         si = sqrtf(1.0f - inp * inp);
1087
1088         mat2[0][0] =  co;
1089         mat2[1][0] = -si;
1090         mat2[0][1] =  si;
1091         mat2[1][1] =  co;
1092         mul_m3_m3m3(mat3, mat2, mat1);
1093
1094         mat2[1][0] =  si;
1095         mat2[0][1] = -si;
1096         mul_m3_m3m3(mat4, mat2, mat1);
1097         transpose_m3(mat1);
1098
1099         mul_m3_m3m3(mat2, mat1, mat3);
1100         mul_m3_v3(mat2, lvec);
1101         mul_m3_m3m3(mat2, mat1, mat4);
1102         mul_m3_v3(mat2, vvec);
1103 }
1104
1105 static void draw_spot_cone(Lamp *la, float x, float z, unsigned pos)
1106 {
1107         z = fabsf(z);
1108
1109         const bool square = (la->mode & LA_SQUARE);
1110
1111         immBegin(PRIM_TRIANGLE_FAN, square ? 6 : 34);
1112         immVertex3f(pos, 0.0f, 0.0f, -x);
1113
1114         if (square) {
1115                 immVertex3f(pos, z, z, 0);
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         }
1121         else {
1122                 for (int a = 0; a < 33; a++) {
1123                         float angle = a * M_PI * 2 / (33 - 1);
1124                         immVertex3f(pos, z * cosf(angle), z * sinf(angle), 0.0f);
1125                 }
1126         }
1127
1128         immEnd();
1129 }
1130
1131 static void draw_transp_spot_volume(Lamp *la, float x, float z, unsigned pos)
1132 {
1133         glEnable(GL_CULL_FACE);
1134         glEnable(GL_BLEND);
1135         glDepthMask(GL_FALSE);
1136
1137         /* draw backside darkening */
1138         glCullFace(GL_FRONT);
1139
1140         glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1141         immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1142
1143         draw_spot_cone(la, x, z, pos);
1144
1145         /* draw front side lighting */
1146         glCullFace(GL_BACK);
1147
1148         glBlendFunc(GL_ONE, GL_ONE);
1149         immUniformColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1150
1151         draw_spot_cone(la, x, z, pos);
1152
1153         /* restore state */
1154         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1155         glDisable(GL_BLEND);
1156         glDepthMask(GL_TRUE);
1157         glDisable(GL_CULL_FACE);
1158 }
1159
1160 #ifdef WITH_GAMEENGINE
1161 static void draw_transp_sun_volume(Lamp *la, unsigned pos)
1162 {
1163         float box[8][3];
1164
1165         /* construct box */
1166         box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size;
1167         box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size;
1168         box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size;
1169         box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size;
1170         box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend;
1171         box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
1172
1173         /* draw edges */
1174         imm_draw_box(box, false, pos);
1175
1176         /* draw faces */
1177         glEnable(GL_CULL_FACE);
1178         glEnable(GL_BLEND);
1179         glDepthMask(GL_FALSE);
1180
1181         /* draw backside darkening */
1182         glCullFace(GL_FRONT);
1183
1184         glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1185         immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1186
1187         imm_draw_box(box, true, pos);
1188
1189         /* draw front side lighting */
1190         glCullFace(GL_BACK);
1191
1192         glBlendFunc(GL_ONE, GL_ONE);
1193         immUniformColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1194
1195         imm_draw_box(box, true, pos);
1196
1197         /* restore state */
1198         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1199         glDisable(GL_BLEND);
1200         glDepthMask(GL_TRUE);
1201         glDisable(GL_CULL_FACE);
1202 }
1203 #endif
1204
1205 void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
1206               const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
1207 {
1208         Object *ob = base->object;
1209         const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1210         Lamp *la = ob->data;
1211         float vec[3], lvec[3], vvec[3], circrad;
1212         float imat[4][4];
1213
1214         /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
1215         /* the moment of view3d_draw_transp() call */
1216         const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1217         const bool drawcone = ((dt > OB_WIRE) &&
1218                                !(G.f & G_PICKSEL) &&
1219                                (la->type == LA_SPOT) &&
1220                                (la->mode & LA_SHOW_CONE) &&
1221                                !(base->flag_legacy & OB_FROMDUPLI) &&
1222                                !is_view);
1223
1224 #ifdef WITH_GAMEENGINE
1225         const bool drawshadowbox = (
1226                 (rv3d->rflag & RV3D_IS_GAME_ENGINE) &&
1227                 (dt > OB_WIRE) &&
1228                 !(G.f & G_PICKSEL) &&
1229                 (la->type == LA_SUN) &&
1230                 ((la->mode & LA_SHAD_BUF) || 
1231                 (la->mode & LA_SHAD_RAY)) &&
1232                 (la->mode & LA_SHOW_SHADOW_BOX) &&
1233                 !(base->flag_legacy & OB_FROMDUPLI) &&
1234                 !is_view);
1235 #else
1236         const bool drawshadowbox = false;
1237 #endif
1238
1239         if ((drawcone || drawshadowbox) && !v3d->transp) {
1240                 /* in this case we need to draw delayed */
1241                 ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
1242                 return;
1243         }
1244
1245         /* we first draw only the screen aligned & fixed scale stuff */
1246         gpuPushMatrix();
1247         gpuLoadMatrix3D(rv3d->viewmat);
1248
1249         /* lets calculate the scale: */
1250         const float lampsize_px = U.obcenter_dia;
1251         const float lampsize = pixsize * lampsize_px * 0.5f;
1252
1253         /* and view aligned matrix: */
1254         copy_m4_m4(imat, rv3d->viewinv);
1255         normalize_v3(imat[0]);
1256         normalize_v3(imat[1]);
1257
1258         const unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
1259
1260         /* lamp center */
1261         copy_v3_v3(vec, ob->obmat[3]);
1262
1263         float curcol[4];
1264         if ((dflag & DRAW_CONSTCOLOR) == 0) {
1265                 /* for AA effects */
1266                 rgb_uchar_to_float(curcol, ob_wire_col);
1267                 curcol[3] = 0.6f;
1268                 /* TODO: pay attention to GL_BLEND */
1269         }
1270
1271         glLineWidth(1.0f);
1272         setlinestyle(3);
1273
1274         if (lampsize > 0.0f) {
1275                 const float outlineWidth = 1.5f * U.pixelsize;
1276                 const float lampdot_size = lampsize_px * U.pixelsize + outlineWidth;
1277
1278                 /* Inner Circle */
1279                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1280                         const float *color = curcol;
1281                         if (ob->id.us > 1) {
1282                                 if (is_obact || ((base->flag & BASE_SELECTED) != 0)) {
1283                                         static const float active_color[4] = {0.533f, 1.0f, 1.0f, 1.0f};
1284                                         color = active_color;
1285                                 }
1286                                 else {
1287                                         static const float inactive_color[4] = {0.467f, 0.8f, 0.8f, 1.0f};
1288                                         color = inactive_color;
1289                                 }
1290                         }
1291
1292                         GPU_enable_program_point_size();
1293                         glEnable(GL_BLEND);
1294                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1295
1296                         immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
1297                         immUniform1f("size", lampdot_size);
1298                         immUniform1f("outlineWidth", outlineWidth);
1299                         immUniformColor3fvAlpha(color, 0.3f);
1300                         immUniform4fv("outlineColor", color);
1301
1302                         immBegin(PRIM_POINTS, 1);
1303                         immVertex3fv(pos, vec);
1304                         immEnd();
1305
1306                         immUnbindProgram();
1307
1308                         glDisable(GL_BLEND);
1309                         GPU_disable_program_point_size();
1310                 }
1311                 else {
1312                         /* CONSTCOLOR in effect */
1313                         /* TODO: separate picking from drawing */
1314                         immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
1315                         /* color doesn't matter, so don't set */
1316                         glPointSize(lampdot_size);
1317
1318                         immBegin(PRIM_POINTS, 1);
1319                         immVertex3fv(pos, vec);
1320                         immEnd();
1321
1322                         immUnbindProgram();
1323                 }
1324
1325                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
1326                 /* TODO(merwin): short term, use DEPTH_ONLY for picking
1327                  *               long term, separate picking from drawing
1328                  */
1329
1330                 /* restore */
1331                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1332                         immUniformColor4fv(curcol);
1333                 }
1334
1335                 /* Outer circle */
1336                 circrad = 3.0f * lampsize;
1337
1338                 imm_drawcircball(vec, circrad, imat, pos);
1339
1340                 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1341                 if (la->type != LA_HEMI) {
1342                         if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1343                                 imm_drawcircball(vec, circrad + 3.0f * pixsize, imat, pos);
1344                         }
1345                 }
1346         }
1347         else {
1348                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
1349                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1350                         immUniformColor4fv(curcol);
1351                 }
1352                 circrad = 0.0f;
1353         }
1354
1355         /* draw the pretty sun rays */
1356         if (la->type == LA_SUN) {
1357                 float v1[3], v2[3], mat[3][3];
1358                 short axis;
1359
1360                 /* setup a 45 degree rotation matrix */
1361                 axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2);
1362
1363                 /* vectors */
1364                 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1365                 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1366
1367                 /* center */
1368                 gpuPushMatrix();
1369                 gpuTranslate3fv(vec);
1370
1371                 setlinestyle(3);
1372
1373                 immBegin(PRIM_LINES, 16);
1374                 for (axis = 0; axis < 8; axis++) {
1375                         immVertex3fv(pos, v1);
1376                         immVertex3fv(pos, v2);
1377                         mul_m3_v3(mat, v1);
1378                         mul_m3_v3(mat, v2);
1379                 }
1380                 immEnd();
1381
1382                 gpuPopMatrix();
1383         }
1384
1385         if (la->type == LA_LOCAL) {
1386                 if (la->mode & LA_SPHERE) {
1387                         imm_drawcircball(vec, la->dist, imat, pos);
1388                 }
1389         }
1390
1391         gpuPopMatrix();  /* back in object space */
1392         zero_v3(vec);
1393
1394         if (is_view) {
1395                 /* skip drawing extra info */
1396         }
1397         else if (la->type == LA_SPOT) {
1398                 float x, y, z, z_abs;
1399                 copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f);
1400                 copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]);
1401                 mul_transposed_mat3_m4_v3(ob->obmat, vvec);
1402
1403                 x = -la->dist;
1404                 y = cosf(la->spotsize * 0.5f);
1405                 z = x * sqrtf(1.0f - y * y);
1406
1407                 spotvolume(lvec, vvec, y);
1408                 mul_v3_fl(lvec, x);
1409                 mul_v3_fl(vvec, x);
1410
1411                 x *= y;
1412
1413                 z_abs = fabsf(z);
1414
1415                 if (la->mode & LA_SQUARE) {
1416                         /* draw pyramid */
1417                         const float vertices[5][3] = {
1418                             /* 5 of vertex coords of pyramid */
1419                             {0.0f, 0.0f, 0.0f},
1420                             {z_abs, z_abs, x},
1421                             {-z_abs, -z_abs, x},
1422                             {z_abs, -z_abs, x},
1423                             {-z_abs, z_abs, x},
1424                         };
1425
1426                         immBegin(PRIM_LINES, 16);
1427                         for (int i = 1; i <= 4; ++i) {
1428                                 immVertex3fv(pos, vertices[0]); /* apex to corner */
1429                                 immVertex3fv(pos, vertices[i]);
1430                                 int next_i = (i == 4) ? 1 : (i + 1);
1431                                 immVertex3fv(pos, vertices[i]); /* corner to next corner */
1432                                 immVertex3fv(pos, vertices[next_i]);
1433                         }
1434                         immEnd();
1435
1436                         gpuTranslate3f(0.0f, 0.0f, x);
1437
1438                         /* draw the square representing spotbl */
1439                         if (la->type == LA_SPOT) {
1440                                 float blend = z_abs * (1.0f - pow2f(la->spotblend));
1441
1442                                 /* hide line if it is zero size or overlaps with outer border,
1443                                  * previously it adjusted to always to show it but that seems
1444                                  * confusing because it doesn't show the actual blend size */
1445                                 if (blend != 0.0f && blend != z_abs) {
1446                                         imm_draw_line_box_3d(pos, blend, -blend, -blend, blend);
1447                                 }
1448                         }
1449                 }
1450                 else {
1451                         /* draw the angled sides of the cone */
1452                         immBegin(PRIM_LINE_STRIP, 3);
1453                         immVertex3fv(pos, vvec);
1454                         immVertex3fv(pos, vec);
1455                         immVertex3fv(pos, lvec);
1456                         immEnd();
1457
1458                         /* draw the circle at the end of the cone */
1459                         gpuTranslate3f(0.0f, 0.0f, x);
1460                         imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, z_abs, 32);
1461
1462                         /* draw the circle representing spotbl */
1463                         if (la->type == LA_SPOT) {
1464                                 float blend = z_abs * (1.0f - pow2f(la->spotblend));
1465
1466                                 /* hide line if it is zero size or overlaps with outer border,
1467                                  * previously it adjusted to always to show it but that seems
1468                                  * confusing because it doesn't show the actual blend size */
1469                                 if (blend != 0.0f && blend != z_abs) {
1470                                         imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, blend, 32);
1471                                 }
1472                         }
1473                 }
1474
1475                 if (drawcone)
1476                         draw_transp_spot_volume(la, x, z, pos);
1477
1478                 /* draw clip start, useful for wide cones where its not obvious where the start is */
1479                 gpuTranslate3f(0.0f, 0.0f, -x);  /* reverse translation above */
1480                 immBegin(PRIM_LINES, 2);
1481                 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
1482                         float lvec_clip[3];
1483                         float vvec_clip[3];
1484                         float clipsta_fac = la->clipsta / -x;
1485
1486                         interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1487                         interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1488
1489                         immVertex3fv(pos, lvec_clip);
1490                         immVertex3fv(pos, vvec_clip);
1491                 }
1492                 /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
1493                 else {
1494                         immVertex3f(pos, 0.0f, 0.0f, -circrad);
1495                         immVertex3f(pos, 0.0f, 0.0f, -la->dist);
1496                 }
1497                 immEnd();
1498         }
1499         else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1500                 /* draw the line from the circle along the dist */
1501                 immBegin(PRIM_LINES, 2);
1502                 vec[2] = -circrad;
1503                 immVertex3fv(pos, vec);
1504                 vec[2] = -la->dist;
1505                 immVertex3fv(pos, vec);
1506                 immEnd();
1507
1508                 if (la->type == LA_HEMI) {
1509                         /* draw the hemisphere curves */
1510                         short axis, steps, dir;
1511                         float outdist, zdist, mul;
1512                         zero_v3(vec);
1513                         outdist = 0.14f; mul = 1.4f; dir = 1;
1514
1515                         setlinestyle(4);
1516                         /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1517                         for (axis = 0; axis < 4; axis++) {
1518                                 float v[3] = {0.0f, 0.0f, 0.0f};
1519                                 zdist = 0.02f;
1520
1521                                 immBegin(PRIM_LINE_STRIP, 6);
1522
1523                                 for (steps = 0; steps < 6; steps++) {
1524                                         if (axis == 0 || axis == 1) {       /* x axis up, x axis down */
1525                                                 /* make the arcs start at the edge of the energy circle */
1526                                                 if (steps == 0) v[0] = dir * circrad;
1527                                                 else v[0] = v[0] + dir * (steps * outdist);
1528                                         }
1529                                         else if (axis == 2 || axis == 3) {      /* y axis up, y axis down */
1530                                                 /* make the arcs start at the edge of the energy circle */
1531                                                 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1532                                         }
1533
1534                                         v[2] = v[2] - steps * zdist;
1535
1536                                         immVertex3fv(pos, v);
1537
1538                                         zdist = zdist * mul;
1539                                 }
1540
1541                                 immEnd();
1542                                 /* flip the direction */
1543                                 dir = -dir;
1544                         }
1545                 }
1546
1547 #ifdef WITH_GAMEENGINE
1548                 if (drawshadowbox) {
1549                         draw_transp_sun_volume(la, pos);
1550                 }
1551 #endif
1552         }
1553         else if (la->type == LA_AREA) {
1554                 setlinestyle(3);
1555                 if (la->area_shape == LA_AREA_SQUARE)
1556                         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);
1557                 else if (la->area_shape == LA_AREA_RECT)
1558                         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);
1559
1560                 immBegin(PRIM_LINES, 2);
1561                 immVertex3f(pos, 0.0f, 0.0f, -circrad);
1562                 immVertex3f(pos, 0.0f, 0.0f, -la->dist);
1563                 immEnd();
1564         }
1565
1566         /* and back to viewspace */
1567         gpuPushMatrix();
1568         gpuLoadMatrix3D(rv3d->viewmat);
1569         copy_v3_v3(vec, ob->obmat[3]);
1570
1571         setlinestyle(0);
1572
1573         if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) {
1574                 drawshadbuflimits(la, ob->obmat, pos);
1575         }
1576
1577         if ((dflag & DRAW_CONSTCOLOR) == 0) {
1578                 immUniformThemeColor(TH_LAMP);
1579         }
1580
1581         glEnable(GL_BLEND);
1582
1583         if (vec[2] > 0) vec[2] -= circrad;
1584         else vec[2] += circrad;
1585
1586         immBegin(PRIM_LINES, 2);
1587         immVertex3fv(pos, vec);
1588         vec[2] = 0;
1589         immVertex3fv(pos, vec);
1590         immEnd();
1591
1592         glPointSize(2.0f);
1593         immBegin(PRIM_POINTS, 1);
1594         immVertex3fv(pos, vec);
1595         immEnd();
1596
1597         glDisable(GL_BLEND);
1598
1599         immUnbindProgram();
1600         gpuPopMatrix();
1601 }
1602
1603 static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3], unsigned pos)
1604 {
1605         immBegin(PRIM_LINES, 2);
1606         immVertex3f(pos, 0.0f, 0.0f, -sta);
1607         immVertex3f(pos, 0.0f, 0.0f, -end);
1608         immEnd();
1609
1610         if (!(dflag & DRAW_PICKING)) {
1611                 glPointSize(3.0f);
1612                 /* would like smooth round points here, but that means binding another shader...
1613                  * if it's really desired, pull these points into their own function to be called after */
1614                 immBegin(PRIM_POINTS, 2);
1615                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1616                         immUniformColor3ubv(col);
1617                 }
1618                 immVertex3f(pos, 0.0f, 0.0f, -sta);
1619                 immVertex3f(pos, 0.0f, 0.0f, -end);
1620                 immEnd();
1621         }
1622 }
1623
1624
1625 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1626 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1627 static void draw_focus_cross(float dist, float size, unsigned pos)
1628 {
1629         immBegin(PRIM_LINES, 4);
1630         immVertex3f(pos, -size, 0.0f, -dist);
1631         immVertex3f(pos, size, 0.0f, -dist);
1632         immVertex3f(pos, 0.0f, -size, -dist);
1633         immVertex3f(pos, 0.0f, size, -dist);
1634         immEnd();
1635 }
1636
1637 #ifdef VIEW3D_CAMERA_BORDER_HACK
1638 unsigned char view3d_camera_border_hack_col[3];
1639 bool view3d_camera_border_hack_test = false;
1640 #endif
1641
1642 /* ****************** draw clip data *************** */
1643
1644 static void draw_viewport_object_reconstruction(
1645         Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d,
1646         MovieClip *clip, MovieTrackingObject *tracking_object,
1647         const short dflag, const unsigned char ob_wire_col[4],
1648         int *global_track_index, bool draw_selected)
1649 {
1650         MovieTracking *tracking = &clip->tracking;
1651         MovieTrackingTrack *track;
1652         float mat[4][4], imat[4][4];
1653         unsigned char col_unsel[4], col_sel[4];
1654         int tracknr = *global_track_index;
1655         ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
1656         float camera_size[3];
1657
1658         UI_GetThemeColor4ubv(TH_TEXT, col_unsel);
1659         UI_GetThemeColor4ubv(TH_SELECT, col_sel);
1660
1661         BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
1662
1663         /* we're compensating camera size for bundles size,
1664          * to make it so bundles are always displayed with the same size */
1665         copy_v3_v3(camera_size, base->object->size);
1666         if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
1667                 mul_v3_fl(camera_size, tracking_object->scale);
1668
1669         gpuPushMatrix();
1670
1671         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1672                 /* current ogl matrix is translated in camera space, bundles should
1673                  * be rendered in world space, so camera matrix should be "removed"
1674                  * from current ogl matrix */
1675                 invert_m4_m4(imat, base->object->obmat);
1676
1677                 gpuMultMatrix3D(imat);
1678                 gpuMultMatrix3D(mat);
1679         }
1680         else {
1681                 float obmat[4][4];
1682                 int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra);
1683
1684                 BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat);
1685
1686                 invert_m4_m4(imat, obmat);
1687                 gpuMultMatrix3D(imat);
1688         }
1689
1690         for (track = tracksbase->first; track; track = track->next) {
1691                 bool selected = TRACK_SELECTED(track);
1692
1693                 if (draw_selected && !selected)
1694                         continue;
1695
1696                 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1697                         continue;
1698
1699                 if (dflag & DRAW_PICKING)
1700                         GPU_select_load_id(base->selcol + (tracknr << 16));
1701
1702                 gpuPushMatrix();
1703                 gpuTranslate3fv(track->bundle_pos);
1704                 gpuScale3f(v3d->bundle_size / 0.05f / camera_size[0],
1705                            v3d->bundle_size / 0.05f / camera_size[1],
1706                            v3d->bundle_size / 0.05f / camera_size[2]);
1707
1708                 const int v3d_drawtype = view3d_effective_drawtype(v3d);
1709                 if (v3d_drawtype == OB_WIRE) {
1710                         unsigned char color[4];
1711                         const unsigned char *color_ptr = NULL;
1712                         if ((dflag & DRAW_CONSTCOLOR) == 0) {
1713                                 if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
1714                                         color_ptr = ob_wire_col;
1715                                 }
1716                                 else {
1717                                         rgba_float_to_uchar(color, track->color);
1718                                         color_ptr = color;
1719                                 }
1720                         }
1721
1722                         drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
1723                 }
1724                 else if (v3d_drawtype > OB_WIRE) {
1725                         if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1726                                 Batch *batch;
1727
1728                                 gpuScaleUniform(0.05f);
1729
1730                                 /* selection outline */
1731                                 if (selected) {
1732                                         batch = Batch_get_sphere_wire(1);
1733
1734                                         if ((dflag & DRAW_CONSTCOLOR) == 0) {
1735                                                 Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
1736                                                 Batch_Uniform4f(batch, "color",
1737                                                                 ob_wire_col[0]/255.f,
1738                                                                 ob_wire_col[1]/255.f,
1739                                                                 ob_wire_col[2]/255.f, 1.0f);
1740                                         }
1741                                         else {
1742                                                 Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
1743                                         }
1744                                         glLineWidth(2.0f);
1745
1746                                         Batch_draw(batch);
1747                                 }
1748
1749                                 batch = Batch_get_sphere(0);
1750
1751                                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1752                                         const float light[3] = {0.0f, 0.0f, 1.0f};
1753                                         float col[3];
1754                                         Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
1755                                         Batch_Uniform3fv(batch, "light", light);
1756
1757                                         if (track->flag & TRACK_CUSTOMCOLOR) copy_v3_v3(col, track->color);
1758                                         else UI_GetThemeColor3fv(TH_BUNDLE_SOLID, col);
1759                                         Batch_Uniform4f(batch, "color", col[0], col[1], col[2], 1.0f);
1760                                 }
1761                                 else {
1762                                         Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
1763                                 }
1764
1765                                 Batch_draw(batch);
1766                         }
1767                         else {
1768                                 unsigned char color[4];
1769                                 const unsigned char *color_ptr = NULL;
1770                                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1771                                         if (selected) {
1772                                                 color_ptr = ob_wire_col;
1773                                         }
1774                                         else {
1775                                                 if (track->flag & TRACK_CUSTOMCOLOR) rgba_float_to_uchar(color, track->color);
1776                                                 else UI_GetThemeColor4ubv(TH_WIRE, color);
1777
1778                                                 color_ptr = color;
1779                                         }
1780                                 }
1781
1782                                 drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
1783                         }
1784                 }
1785
1786                 gpuPopMatrix();
1787
1788                 if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1789                         float pos[3];
1790
1791                         mul_v3_m4v3(pos, mat, track->bundle_pos);
1792                         view3d_cached_text_draw_add(pos,
1793                                                     track->name, strlen(track->name),
1794                                                     10, V3D_CACHE_TEXT_GLOBALSPACE,
1795                                                     selected ? col_sel : col_unsel);
1796                 }
1797
1798                 tracknr++;
1799         }
1800
1801         if ((dflag & DRAW_PICKING) == 0) {
1802                 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1803                         MovieTrackingReconstruction *reconstruction;
1804                         reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
1805
1806                         if (reconstruction->camnr >= 2) {
1807                                 MovieReconstructedCamera *camera = reconstruction->cameras;
1808                                 unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
1809
1810                                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
1811                                 immUniformThemeColor(TH_CAMERA_PATH);
1812
1813                                 glLineWidth(2.0f);
1814
1815                                 immBegin(PRIM_LINE_STRIP, reconstruction->camnr);
1816                                 for (int a = 0; a < reconstruction->camnr; a++, camera++) {
1817                                         immVertex3fv(pos, camera->mat[3]);
1818                                 }
1819                                 immEnd();
1820
1821                                 immUnbindProgram();
1822                         }
1823                 }
1824         }
1825
1826         gpuPopMatrix();
1827
1828         *global_track_index = tracknr;
1829 }
1830
1831 static void draw_viewport_reconstruction(
1832         Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
1833         const short dflag, const unsigned char ob_wire_col[4],
1834         const bool draw_selected)
1835 {
1836         MovieTracking *tracking = &clip->tracking;
1837         MovieTrackingObject *tracking_object;
1838         int global_track_index = 1;
1839
1840         if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1841                 return;
1842
1843         if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1844                 return;
1845
1846         GPU_basic_shader_colors(NULL, NULL, 0, 1.0f);
1847         GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
1848
1849         tracking_object = tracking->objects.first;
1850         while (tracking_object) {
1851                 draw_viewport_object_reconstruction(
1852                         scene, base, v3d, rv3d, clip, tracking_object,
1853                         dflag, ob_wire_col, &global_track_index, draw_selected);
1854
1855                 tracking_object = tracking_object->next;
1856         }
1857
1858         /* restore */
1859         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
1860
1861         if (dflag & DRAW_PICKING)
1862                 GPU_select_load_id(base->selcol);
1863 }
1864
1865 /* camera frame */
1866 static void drawcamera_frame(float vec[4][3], bool filled, unsigned pos)
1867 {
1868         immBegin(filled ? PRIM_TRIANGLE_FAN : PRIM_LINE_LOOP, 4);
1869         immVertex3fv(pos, vec[0]);
1870         immVertex3fv(pos, vec[1]);
1871         immVertex3fv(pos, vec[2]);
1872         immVertex3fv(pos, vec[3]);
1873         immEnd();
1874 }
1875
1876 /* center point to camera frame */
1877 static void drawcamera_framelines(float vec[4][3], float origin[3], unsigned pos)
1878 {
1879         immBegin(PRIM_LINES, 8);
1880         immVertex3fv(pos, origin);
1881         immVertex3fv(pos, vec[0]);
1882         immVertex3fv(pos, origin);
1883         immVertex3fv(pos, vec[1]);
1884         immVertex3fv(pos, origin);
1885         immVertex3fv(pos, vec[2]);
1886         immVertex3fv(pos, origin);
1887         immVertex3fv(pos, vec[3]);
1888         immEnd();
1889 }
1890
1891 static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], bool filled, unsigned pos)
1892 {
1893         drawcamera_frame(near_plane, filled, pos);
1894         drawcamera_frame(far_plane, filled, pos);
1895
1896         if (filled) {
1897                 immBegin(PRIM_TRIANGLE_STRIP, 10);
1898
1899                 immVertex3fv(pos, near_plane[0]);
1900                 immVertex3fv(pos, far_plane[0]);
1901                 immVertex3fv(pos, near_plane[1]);
1902                 immVertex3fv(pos, far_plane[1]);
1903                 immVertex3fv(pos, near_plane[2]);
1904                 immVertex3fv(pos, far_plane[2]);
1905                 immVertex3fv(pos, near_plane[3]);
1906                 immVertex3fv(pos, far_plane[3]);
1907                 immVertex3fv(pos, near_plane[0]);
1908                 immVertex3fv(pos, far_plane[0]);
1909
1910                 immEnd();
1911         }
1912         else {
1913                 immBegin(PRIM_LINES, 8);
1914                 for (int i = 0; i < 4; ++i) {
1915                         immVertex3fv(pos, near_plane[i]);
1916                         immVertex3fv(pos, far_plane[i]);
1917                 }
1918                 immEnd();
1919         }
1920 }
1921
1922 static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
1923 {
1924         return (ob == v3d->camera) &&
1925                 (scene->r.scemode & R_MULTIVIEW) != 0 &&
1926                 (v3d->stereo3d_flag);
1927 }
1928
1929 static void drawcamera_stereo3d(
1930         Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
1931         float vec[4][3], float drawsize, const float scale[3], unsigned pos)
1932 {
1933         float obmat[4][4];
1934         float vec_lr[2][4][3];
1935         const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
1936         float origin[2][3] = {{0}};
1937         float tvec[3];
1938         const Camera *cam_lr[2];
1939         const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
1940
1941         const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
1942         const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
1943         const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME);
1944
1945         zero_v3(tvec);
1946
1947         /* caller bound GPU_SHADER_3D_UNIFORM_COLOR, passed in pos attribute ID */
1948
1949         for (int i = 0; i < 2; i++) {
1950                 ob = BKE_camera_multiview_render(scene, ob, names[i]);
1951                 cam_lr[i] = ob->data;
1952
1953                 gpuLoadMatrix3D(rv3d->viewmat);
1954                 BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
1955                 gpuMultMatrix3D(obmat);
1956
1957                 copy_m3_m3(vec_lr[i], vec);
1958                 copy_v3_v3(vec_lr[i][3], vec[3]);
1959
1960                 if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
1961                         const float shift_x =
1962                                 ((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) *
1963                                  (drawsize * scale[0] * fac));
1964
1965                         for (int j = 0; j < 4; j++) {
1966                                 vec_lr[i][j][0] += shift_x;
1967                         }
1968                 }
1969
1970                 if (is_stereo3d_cameras) {
1971                         /* camera frame */
1972                         drawcamera_frame(vec_lr[i], false, pos);
1973
1974                         /* center point to camera frame */
1975                         drawcamera_framelines(vec_lr[i], tvec, pos);
1976                 }
1977
1978                 /* connecting line */
1979                 mul_m4_v3(obmat, origin[i]);
1980
1981                 /* convergence plane */
1982                 if (is_stereo3d_plane || is_stereo3d_volume) {
1983                         for (int j = 0; j < 4; j++) {
1984                                 mul_m4_v3(obmat, vec_lr[i][j]);
1985                         }
1986                 }
1987         }
1988
1989         /* the remaining drawing takes place in the view space */
1990         gpuLoadMatrix3D(rv3d->viewmat);
1991
1992         if (is_stereo3d_cameras) {
1993                 /* draw connecting lines */
1994                 glLineStipple(2, 0xAAAA);
1995                 glEnable(GL_LINE_STIPPLE);
1996
1997                 immBegin(PRIM_LINES, 2);
1998                 immVertex3fv(pos, origin[0]);
1999                 immVertex3fv(pos, origin[1]);
2000                 immEnd();
2001
2002                 glDisable(GL_LINE_STIPPLE);
2003         }
2004
2005         /* draw convergence plane */
2006         if (is_stereo3d_plane) {
2007                 float axis_center[3], screen_center[3];
2008                 float world_plane[4][3];
2009                 float local_plane[4][3];
2010                 float offset;
2011
2012                 mid_v3_v3v3(axis_center, origin[0], origin[1]);
2013
2014                 for (int i = 0; i < 4; i++) {
2015                         mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]);
2016                         sub_v3_v3v3(local_plane[i], world_plane[i], axis_center);
2017                 }
2018
2019                 mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]);
2020                 offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center);
2021
2022                 for (int i = 0; i < 4; i++) {
2023                         mul_v3_fl(local_plane[i], offset);
2024                         add_v3_v3(local_plane[i], axis_center);
2025                 }
2026
2027                 immUniformColor3f(0.0f, 0.0f, 0.0f);
2028
2029                 /* camera frame */
2030                 drawcamera_frame(local_plane, false, pos);
2031
2032                 if (v3d->stereo3d_convergence_alpha > 0.0f) {
2033                         glEnable(GL_BLEND);
2034                         glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
2035
2036                         immUniformColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
2037
2038                         drawcamera_frame(local_plane, true, pos);
2039
2040                         glDisable(GL_BLEND);
2041                         glDepthMask(GL_TRUE);  /* restore write in zbuffer */
2042                 }
2043         }
2044
2045         /* draw convergence plane */
2046         if (is_stereo3d_volume) {
2047                 float screen_center[3];
2048                 float near_plane[4][3], far_plane[4][3];
2049
2050                 for (int i = 0; i < 2; i++) {
2051                         mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]);
2052
2053                         float offset = len_v3v3(screen_center, origin[i]);
2054
2055                         for (int j = 0; j < 4; j++) {
2056                                 sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]);
2057                                 mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset);
2058                                 add_v3_v3(near_plane[j], origin[i]);
2059
2060                                 sub_v3_v3v3(far_plane[j], vec_lr[i][j], origin[i]);
2061                                 mul_v3_fl(far_plane[j], cam_lr[i]->clipend / offset);
2062                                 add_v3_v3(far_plane[j], origin[i]);
2063                         }
2064
2065                         /* camera frame */
2066                         immUniformColor3f(0.0f, 0.0f, 0.0f);
2067
2068                         drawcamera_volume(near_plane, far_plane, false, pos);
2069
2070                         if (v3d->stereo3d_volume_alpha > 0.0f) {
2071                                 glEnable(GL_BLEND);
2072                                 glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
2073
2074                                 if (i == 0)
2075                                         immUniformColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
2076                                 else
2077                                         immUniformColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
2078
2079                                 drawcamera_volume(near_plane, far_plane, true, pos);
2080
2081                                 glDisable(GL_BLEND);
2082                                 glDepthMask(GL_TRUE);  /* restore write in zbuffer */
2083                         }
2084                 }
2085         }
2086 }
2087
2088 /* flag similar to draw_object() */
2089 void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
2090                 const short dflag, const unsigned char ob_wire_col[4])
2091 {
2092         /* a standing up pyramid with (0,0,0) as top */
2093         Camera *cam;
2094         Object *ob = base->object;
2095         float tvec[3];
2096         float vec[4][3], asp[2], shift[2], scale[3];
2097         MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
2098
2099         const bool is_active = (ob == v3d->camera);
2100         const bool is_view = (rv3d->persp == RV3D_CAMOB && is_active);
2101         const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2102         const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
2103         const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
2104         const bool is_stereo3d_cameras = (ob == scene->camera) &&
2105                                          is_multiview &&
2106                                          is_stereo3d_view &&
2107                                          (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
2108         const bool is_selection_camera_stereo = (G.f & G_PICKSEL) &&
2109                                                 is_view && is_multiview &&
2110                                                 is_stereo3d_view;
2111
2112         /* draw data for movie clip set as active for scene */
2113         if (clip) {
2114                 draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, false);
2115                 draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, true);
2116         }
2117
2118 #ifdef VIEW3D_CAMERA_BORDER_HACK
2119         if (is_view && !(G.f & G_PICKSEL)) {
2120                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
2121                         view3d_camera_border_hack_col[0] = ob_wire_col[0];
2122                         view3d_camera_border_hack_col[1] = ob_wire_col[1];
2123                         view3d_camera_border_hack_col[2] = ob_wire_col[2];
2124                 }
2125                 else {
2126                         float col[4];
2127                         glGetFloatv(GL_CURRENT_COLOR, col);
2128                         rgb_float_to_uchar(view3d_camera_border_hack_col, col);
2129                 }
2130                 view3d_camera_border_hack_test = true;
2131                 return;
2132         }
2133 #endif
2134
2135         cam = ob->data;
2136
2137         /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here */
2138         if (is_selection_camera_stereo) {
2139                 scale[0] = 1.0f;
2140                 scale[1] = 1.0f;
2141                 scale[2] = 1.0f;
2142         }
2143         else {
2144                 scale[0] = 1.0f / len_v3(ob->obmat[0]);
2145                 scale[1] = 1.0f / len_v3(ob->obmat[1]);
2146                 scale[2] = 1.0f / len_v3(ob->obmat[2]);
2147         }
2148
2149         float drawsize;
2150         BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
2151                                  asp, shift, &drawsize, vec);
2152
2153         unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
2154         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2155         if (ob_wire_col) {
2156                 immUniformColor3ubv(ob_wire_col);
2157         }
2158         glLineWidth(1.0f);
2159
2160         /* camera frame */
2161         if (!is_stereo3d_cameras) {
2162                 /* make sure selection uses the same matrix for camera as the one used while viewing */
2163                 if (is_selection_camera_stereo) {
2164                         float obmat[4][4];
2165                         bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
2166
2167                         gpuPushMatrix();
2168                         gpuLoadMatrix3D(rv3d->viewmat);
2169                         BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
2170                         gpuMultMatrix3D(obmat);
2171
2172                         drawcamera_frame(vec, false, pos);
2173                         gpuPopMatrix();
2174                 }
2175                 else {
2176                         drawcamera_frame(vec, false, pos);
2177                 }
2178         }
2179
2180         if (is_view) {
2181                 immUnbindProgram();
2182                 return;
2183         }
2184
2185         zero_v3(tvec);
2186
2187         /* center point to camera frame */
2188         if (!is_stereo3d_cameras)
2189                 drawcamera_framelines(vec, tvec, pos);
2190
2191         /* arrow on top */
2192         tvec[2] = vec[1][2]; /* copy the depth */
2193
2194         /* draw an outline arrow for inactive cameras and filled
2195          * for active cameras. We actually draw both outline+filled
2196          * for active cameras so the wire can be seen side-on */
2197         for (int i = 0; i < 2; i++) {
2198                 if (i == 0) immBegin(PRIM_LINE_LOOP, 3);
2199                 else if (i == 1 && is_active) {
2200                         glDisable(GL_CULL_FACE); /* TODO: declarative state tracking */
2201                         immBegin(PRIM_TRIANGLES, 3);
2202                 }
2203                 else break;
2204
2205                 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
2206                 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
2207                 immVertex3fv(pos, tvec); /* left */
2208                 
2209                 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
2210                 immVertex3fv(pos, tvec); /* right */
2211                 
2212                 tvec[0] = shift[0];
2213                 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
2214                 immVertex3fv(pos, tvec); /* top */
2215
2216                 immEnd();
2217         }
2218
2219         if ((dflag & DRAW_SCENESET) == 0) {
2220                 if (cam->flag & (CAM_SHOWLIMITS | CAM_SHOWMIST)) {
2221                         float nobmat[4][4];
2222
2223                         /* draw in normalized object matrix space */
2224                         copy_m4_m4(nobmat, ob->obmat);
2225                         normalize_m4(nobmat);
2226
2227                         gpuLoadMatrix3D(rv3d->viewmat);
2228                         gpuMultMatrix3D(nobmat);
2229
2230                         if (cam->flag & CAM_SHOWLIMITS) {
2231                                 const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120};
2232
2233                                 draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col), pos);
2234                                 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
2235                                 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize, pos);
2236                         }
2237
2238                         if (cam->flag & CAM_SHOWMIST) {
2239                                 World *world = scene->world;
2240                                 const unsigned char col[3] = {128, 128, 128}, col_hi[3] = {255, 255, 255};
2241
2242                                 if (world) {
2243                                         draw_limit_line(world->miststa, world->miststa + world->mistdist,
2244                                                         dflag, (is_active ? col_hi : col), pos);
2245                                 }
2246                         }
2247                 }
2248         }
2249
2250         /* stereo cameras drawing */
2251         if (is_stereo3d) {
2252                 drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale, pos);
2253         }
2254
2255         immUnbindProgram();
2256 }
2257
2258 /* flag similar to draw_object() */
2259 void drawspeaker(const unsigned char ob_wire_col[3])
2260 {
2261         VertexFormat *format = immVertexFormat();
2262         unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2263
2264         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2265
2266         if (ob_wire_col) {
2267                 immUniformColor3ubv(ob_wire_col);
2268         }
2269
2270         glLineWidth(1.0f);
2271
2272         const int segments = 16;
2273
2274         for (int j = 0; j < 3; j++) {
2275                 float z = 0.25f * j - 0.125f;
2276
2277                 immBegin(PRIM_LINE_LOOP, segments);
2278                 for (int i = 0; i < segments; i++) {
2279                         float x = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
2280                         float y = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
2281                         immVertex3f(pos, x, y, z);
2282                 }
2283                 immEnd();
2284         }
2285
2286         for (int j = 0; j < 4; j++) {
2287                 float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
2288                 float y = ((j % 2) * (j - 2)) * 0.5f;
2289                 immBegin(PRIM_LINE_STRIP, 3);
2290                 for (int i = 0; i < 3; i++) {
2291                         if (i == 1) {
2292                                 x *= 0.5f;
2293                                 y *= 0.5f;
2294                         }
2295
2296                         float z = 0.25f * i - 0.125f;
2297                         immVertex3f(pos, x, y, z);
2298                 }
2299                 immEnd();
2300         }
2301
2302         immUnbindProgram();
2303 }
2304
2305 static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel,
2306                                unsigned int pos, unsigned int color)
2307 {
2308         BPoint *bp = lt->def;
2309         const float *co = dl ? dl->verts : NULL;
2310         float active_color[4], draw_color[4];
2311
2312         UI_GetThemeColor4fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, draw_color);
2313         UI_GetThemeColor4fv(TH_ACTIVE_VERT, active_color);
2314
2315         glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
2316         immBeginAtMost(PRIM_POINTS, lt->pntsw * lt->pntsv * lt->pntsu);
2317
2318         for (int w = 0; w < lt->pntsw; w++) {
2319                 int wxt = (w == 0 || w == lt->pntsw - 1);
2320                 for (int v = 0; v < lt->pntsv; v++) {
2321                         int vxt = (v == 0 || v == lt->pntsv - 1);
2322                         for (int u = 0; u < lt->pntsu; u++, bp++, co += 3) {
2323                                 int uxt = (u == 0 || u == lt->pntsu - 1);
2324                                 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
2325                                         if (bp->hide == 0) {
2326                                                 /* check for active BPoint and ensure selected */
2327                                                 if ((bp == actbp) && (bp->f1 & SELECT)) {
2328                                                         immAttrib4fv(color, active_color);
2329                                                         immVertex3fv(pos, dl ? co : bp->vec);
2330                                                 }
2331                                                 else if ((bp->f1 & SELECT) == sel) {
2332                                                         immAttrib4fv(color, draw_color);
2333                                                         immVertex3fv(pos, dl ? co : bp->vec);
2334                                                 }
2335                                         }
2336                                 }
2337                         }
2338                 }
2339         }
2340         
2341         immEnd();
2342 }
2343
2344 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol,
2345                                unsigned int pos, unsigned int color)
2346 {
2347         int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
2348
2349         if (actdef_wcol) {
2350                 float col[3];
2351                 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
2352                 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
2353                 immAttrib3fv(color, col);
2354         }
2355         
2356         if (dl) {
2357                 immVertex3fv(pos, &dl->verts[index * 3]);
2358         }
2359         else {
2360                 immVertex3fv(pos, lt->def[index].vec);
2361         }
2362 }
2363
2364 #ifdef SEQUENCER_DAG_WORKAROUND
2365 static void ensure_curve_cache(Scene *scene, Object *object)
2366 {
2367         bool need_recalc = object->curve_cache == NULL;
2368         /* Render thread might have freed the curve cache if the
2369          * object is not visible. If the object is also used for
2370          * particles duplication, then render thread might have
2371          * also created curve_cache with only bevel and path
2372          * filled in.
2373          *
2374          * So check for curve_cache != NULL is not fully correct
2375          * here, we also need to check whether display list is
2376          * empty or not.
2377          *
2378          * The trick below tries to optimize calls to displist
2379          * creation for cases curve is empty. Meaning, if the curve
2380          * is empty (without splines) bevel list would also be empty.
2381          * And the thing is, render thread always leaves bevel list
2382          * in a proper state. So if bevel list is here and display
2383          * list is not we need to make display list.
2384          */
2385         if (need_recalc == false) {
2386                 need_recalc = object->curve_cache->disp.first == NULL &&
2387                               object->curve_cache->bev.first != NULL;
2388         }
2389         if (need_recalc) {
2390                 switch (object->type) {
2391                         case OB_CURVE:
2392                         case OB_SURF:
2393                         case OB_FONT:
2394                                 BKE_displist_make_curveTypes(scene, object, false);
2395                                 break;
2396                         case OB_MBALL:
2397                                 BKE_displist_make_mball(G.main->eval_ctx, scene, object);
2398                                 break;
2399                         case OB_LATTICE:
2400                                 BKE_lattice_modifiers_calc(scene, object);
2401                                 break;
2402                 }
2403         }
2404 }
2405 #endif
2406
2407 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
2408 static void drawlattice(View3D *v3d, Object *ob, const short dflag, const unsigned char ob_wire_col[4])
2409 {
2410         Lattice *lt = ob->data;
2411         DispList *dl;
2412         int u, v, w;
2413         int actdef_wcol = 0;
2414         const bool is_edit = (lt->editlatt != NULL);
2415
2416         dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS);
2417         
2418         if (is_edit) {
2419                 lt = lt->editlatt->latt;
2420
2421                 if (ob->defbase.first && lt->dvert) {
2422                         actdef_wcol = ob->actdef;
2423                 }
2424         }
2425
2426         VertexFormat *format = immVertexFormat();
2427         unsigned int color, pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2428
2429         if (actdef_wcol) {
2430                 color = VertexFormat_add_attrib(format, "color", COMP_F32, 3, KEEP_FLOAT);
2431                 immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
2432         }
2433         else {
2434                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2435
2436                 if (is_edit) {
2437                         immUniformThemeColor(TH_WIRE_EDIT);
2438                 }
2439                 else {
2440                         if ((dflag & DRAW_CONSTCOLOR) == 0) {
2441                                 immUniformColor3ubv(ob_wire_col);
2442                         }
2443                         else {
2444                                 immUniformColor3f(0.0f, 0.0f, 0.0f);
2445                         }
2446                 }
2447         }
2448
2449         glLineWidth(1.0f);
2450         immBeginAtMost(PRIM_LINES, lt->pntsw * lt->pntsv * lt->pntsu * 6);
2451
2452         for (w = 0; w < lt->pntsw; w++) {
2453                 int wxt = (w == 0 || w == lt->pntsw - 1);
2454                 for (v = 0; v < lt->pntsv; v++) {
2455                         int vxt = (v == 0 || v == lt->pntsv - 1);
2456                         for (u = 0; u < lt->pntsu; u++) {
2457                                 int uxt = (u == 0 || u == lt->pntsu - 1);
2458
2459                                 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
2460                                         drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol, pos, color);
2461                                         drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
2462                                 }
2463                                 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2464                                         drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol, pos, color);
2465                                         drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
2466                                 }
2467                                 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2468                                         drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol, pos, color);
2469                                         drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
2470                                 }
2471                         }
2472                 }
2473         }
2474
2475         immEnd();
2476         immUnbindProgram();
2477
2478         if (is_edit) {
2479                 BPoint *actbp = BKE_lattice_active_point_get(lt);
2480
2481                 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2482
2483                 VertexFormat *v_format = immVertexFormat();
2484                 unsigned int v_pos = VertexFormat_add_attrib(v_format, "pos", COMP_F32, 3, KEEP_FLOAT);
2485                 unsigned int v_color = VertexFormat_add_attrib(v_format, "color", COMP_F32, 4, KEEP_FLOAT);
2486
2487                 immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
2488
2489                 lattice_draw_verts(lt, dl, actbp, 0, v_pos, v_color);
2490                 lattice_draw_verts(lt, dl, actbp, 1, v_pos, v_color);
2491
2492                 immUnbindProgram();
2493
2494                 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2495         }
2496 }
2497
2498 /* ***************** ******************** */
2499
2500 /* draw callback */
2501
2502 typedef struct drawDMVertSel_userData {
2503         MVert *mvert;
2504         int active;
2505         unsigned char *col[3];  /* (base, sel, act) */
2506         char sel_prev;
2507         unsigned int pos, color;
2508 } drawDMVertSel_userData;
2509
2510 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
2511                                           const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2512 {
2513         drawDMVertSel_userData *data = userData;
2514         MVert *mv = &data->mvert[index];
2515
2516         if (!(mv->flag & ME_HIDE)) {
2517                 const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
2518                 if (sel != data->sel_prev) {
2519                         immAttrib3ubv(data->color, data->col[sel]);
2520                         data->sel_prev = sel;
2521                 }
2522
2523                 immVertex3fv(data->pos, co);
2524         }
2525 }
2526
2527 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
2528 {
2529         drawDMVertSel_userData data;
2530         VertexFormat *format = immVertexFormat();
2531
2532         /* TODO define selected color */
2533         unsigned char base_col[3] = {0x0, 0x0, 0x0};
2534         unsigned char sel_col[3] = {0xd8, 0xb8, 0x0};
2535         unsigned char act_col[3] = {0xff, 0xff, 0xff};
2536
2537         data.mvert = me->mvert;
2538         data.active = BKE_mesh_mselect_active_get(me, ME_VSEL);
2539         data.sel_prev = 0xff;
2540
2541         data.col[0] = base_col;
2542         data.col[1] = sel_col;
2543         data.col[2] = act_col;
2544
2545         data.color = VertexFormat_add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT);
2546         data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2547
2548         if (dm->getNumVerts(dm) == 0) return;
2549
2550         immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
2551
2552         immBeginAtMost(PRIM_POINTS, dm->getNumVerts(dm));
2553         dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
2554         immEnd();
2555
2556         immUnbindProgram();
2557 }
2558
2559 /* ************** DRAW MESH ****************** */
2560
2561 /* First section is all the "simple" draw routines,
2562  * ones that just pass some sort of primitive to GL,
2563  * with perhaps various options to control lighting,
2564  * color, etc.
2565  *
2566  * These routines should not have user interface related
2567  * logic!!!
2568  */
2569
2570 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
2571 {
2572         float obmat[3][3];
2573
2574         copy_m3_m4(obmat, ob->obmat);
2575
2576         data->uniform_scale = is_uniform_scaled_m3(obmat);
2577
2578         if (!data->uniform_scale) {
2579                 /* inverted matrix */
2580                 invert_m3_m3(data->imat, obmat);
2581
2582                 /* transposed inverted matrix */
2583                 transpose_m3_m3(data->tmat, data->imat);
2584         }
2585 }
2586
2587 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2588 {
2589         drawDMNormal_userData *data = userData;
2590         BMFace *efa = BM_face_at_index(data->bm, index);
2591         float n[3];
2592
2593         if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2594                 if (!data->uniform_scale) {
2595                         mul_v3_m3v3(n, data->tmat, no);
2596                         normalize_v3(n);
2597                         mul_m3_v3(data->imat, n);
2598                 }
2599                 else {
2600                         copy_v3_v3(n, no);
2601                 }
2602
2603                 immVertex3fv(data->pos, cent);
2604                 immVertex3f(data->pos, cent[0] + n[0] * data->normalsize,
2605                                        cent[1] + n[1] * data->normalsize,
2606                                        cent[2] + n[2] * data->normalsize);
2607         }
2608 }
2609
2610 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
2611 {
2612         VertexFormat *format = immVertexFormat();
2613         drawDMNormal_userData data;
2614
2615         data.bm = em->bm;
2616         data.normalsize = scene->toolsettings->normalsize;
2617         data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2618
2619         calcDrawDMNormalScale(ob, &data);
2620
2621         if (dm->getNumPolys(dm) == 0) return;
2622
2623         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2624         immUniformThemeColor(theme_id);
2625
2626         immBeginAtMost(PRIM_LINES, dm->getNumPolys(dm) * 2);
2627         dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2628         immEnd();
2629
2630         immUnbindProgram();
2631 }
2632
2633 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2634 {
2635         drawBMSelect_userData *data = userData;
2636         BMFace *efa = BM_face_at_index(data->bm, index);
2637         
2638         if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
2639             (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
2640         {
2641                 immVertex3fv(data->pos, cent);
2642         }
2643 }
2644 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select, const unsigned char fcol[3])
2645 {
2646         VertexFormat *format = immVertexFormat();
2647
2648         drawBMSelect_userData data;
2649         data.bm = em->bm;
2650         data.select = select;
2651         data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2652
2653         if (dm->getNumPolys(dm) == 0) return;
2654
2655         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2656         immUniformColor3ubv(fcol);
2657
2658         immBeginAtMost(PRIM_POINTS, dm->getNumPolys(dm));
2659         dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
2660         immEnd();
2661
2662         immUnbindProgram();
2663 }
2664
2665 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])
2666 {
2667         drawDMNormal_userData *data = userData;
2668         BMVert *eve = BM_vert_at_index(data->bm, index);
2669
2670         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2671                 float no[3], n[3];
2672
2673                 if (no_f) {
2674                         copy_v3_v3(no, no_f);
2675                 }
2676                 else {
2677                         normal_short_to_float_v3(no, no_s);
2678                 }
2679
2680                 if (!data->uniform_scale) {
2681                         mul_v3_m3v3(n, data->tmat, no);
2682                         normalize_v3(n);
2683                         mul_m3_v3(data->imat, n);
2684                 }
2685                 else {
2686                         copy_v3_v3(n, no);
2687                 }
2688
2689                 immVertex3fv(data->pos, co);
2690                 immVertex3f(data->pos, co[0] + n[0] * data->normalsize,
2691                                  co[1] + n[1] * data->normalsize,
2692                                  co[2] + n[2] * data->normalsize);
2693         }
2694 }
2695
2696 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
2697 {
2698         drawDMNormal_userData data;
2699         VertexFormat *format = immVertexFormat();
2700
2701         data.bm = em->bm;
2702         data.normalsize = scene->toolsettings->normalsize;
2703         data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2704
2705         calcDrawDMNormalScale(ob, &data);
2706
2707         if (dm->getNumVerts(dm) == 0) return;
2708
2709         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2710         immUniformThemeColor(theme_id);
2711
2712         immBeginAtMost(PRIM_LINES, dm->getNumVerts(dm) * 2);
2713         dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
2714         immEnd();
2715
2716         immUnbindProgram();
2717 }
2718
2719 static void draw_dm_verts_skin_root__mapFunc(void *userData, int index, const float co[3],
2720                                              const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2721 {
2722         drawDMVerts_userData *data = userData;
2723         BMVert *eve = BM_vert_at_index(data->bm, index);
2724
2725         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2726                 /* skin nodes: draw a red circle around the root node(s) */
2727                 const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
2728                 if (vs->flag & MVERT_SKIN_ROOT) {
2729                         float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2730                         imm_drawcircball(co, radius, data->imat, data->pos);
2731                 }
2732         }
2733 }
2734
2735 /* Draw verts with color set based on selection */
2736 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2737                                    const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2738 {
2739         drawDMVerts_userData *data = userData;
2740         BMVert *eve = BM_vert_at_index(data->bm, index);
2741
2742         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2743                 /* draw active in a different color - no need to stop/start point drawing for this :D */
2744                 if (eve == data->eve_act) {
2745                         immAttrib4ubv(data->color, data->th_editmesh_active);
2746                         immVertex3fv(data->pos, co);
2747                 }
2748                 else {
2749                         immAttrib4ubv(data->color, data->sel ? data->th_vertex_select : data->th_vertex);
2750                         immVertex3fv(data->pos, co);
2751                 }
2752         }
2753 }
2754
2755 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
2756                           RegionView3D *rv3d, const unsigned char col[4])
2757 {
2758         VertexFormat *format = immVertexFormat();
2759
2760         drawDMVerts_userData data;
2761         data.sel = sel;
2762         data.eve_act = eve_act;
2763         data.bm = em->bm;
2764         data.pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
2765         data.color = VertexFormat_add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT);
2766
2767         /* Cache theme values */
2768         UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2769         UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2770         UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2771         UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2772
2773         /* Set correct alpha */
2774         data.th_editmesh_active[3] = data.th_vertex_select[3] = data.th_vertex[3] = data.th_skin_root[3] = col[3];
2775
2776         /* view-aligned matrix */
2777         mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2778         invert_m4(data.imat);
2779
2780         if (dm->getNumVerts(dm) == 0) return;
2781
2782         immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
2783
2784         glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
2785
2786         immBeginAtMost(PRIM_POINTS, dm->getNumVerts(dm));
2787         dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
2788         immEnd();
2789
2790         immUnbindProgram();
2791
2792         /* For skin root drawing */
2793         data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
2794
2795         if (data.cd_vskin_offset != -1) {
2796                 data.pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
2797                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
2798                 immUniformColor4ubv(data.th_skin_root);
2799
2800                 dm->foreachMappedVert(dm, draw_dm_verts_skin_root__mapFunc, &data, DM_FOREACH_NOP);
2801
2802                 immUnbindProgram();
2803         }
2804 }
2805
2806 /* Draw edges with color set based on selection */
2807 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2808 {
2809         BMEdge *eed;
2810         drawDMEdgesSel_userData *data = userData;
2811         unsigned char *col;
2812
2813         eed = BM_edge_at_index(data->bm, index);
2814
2815         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2816                 if (eed == data->eed_act) {
2817                         glColor4ubv(data->actCol);
2818                 }
2819                 else {
2820                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2821                                 col = data->selCol;
2822                         }
2823                         else {
2824                                 col = data->baseCol;
2825                         }
2826                         /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
2827                         if (col[3] == 0)
2828                                 return DM_DRAW_OPTION_SKIP;
2829                         
2830                         glColor4ubv(col);
2831                 }
2832                 return DM_DRAW_OPTION_NORMAL;
2833         }
2834         else {
2835                 return DM_DRAW_OPTION_SKIP;
2836         }
2837 }
2838
2839 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
2840                               unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2841 {
2842         drawDMEdgesSel_userData data;
2843         
2844         data.baseCol = baseCol;
2845         data.selCol = selCol;
2846         data.actCol = actCol;
2847         data.bm = em->bm;
2848         data.eed_act = eed_act;
2849         dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2850 }
2851
2852 /* Draw edges */
2853 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2854 {
2855         if (BM_elem_flag_test(BM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2856                 return DM_DRAW_OPTION_SKIP;
2857         else
2858                 return DM_DRAW_OPTION_NORMAL;
2859 }
2860
2861 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
2862 {
2863         dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em->bm);
2864 }
2865
2866 /* Draw edges with color interpolated based on selection */
2867 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2868 {
2869         drawDMEdgesSelInterp_userData *data = userData;
2870         if (BM_elem_flag_test(BM_edge_at_index(data->bm, index), BM_ELEM_HIDDEN))
2871                 return DM_DRAW_OPTION_SKIP;
2872         else
2873                 return DM_DRAW_OPTION_NORMAL;
2874 }
2875 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2876 {
2877         drawDMEdgesSelInterp_userData *data = userData;
2878         BMEdge *eed = BM_edge_at_index(data->bm, index);
2879         unsigned char **cols = userData;
2880         unsigned int col0_id = (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1;
2881         unsigned int col1_id = (BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1;
2882         unsigned char *col0 = cols[col0_id];
2883         unsigned char *col1 = cols[col1_id];
2884         unsigned char *col_pt;
2885
2886         if (col0_id == col1_id) {
2887                 col_pt = col0;
2888         }
2889         else if (t == 0.0f) {
2890                 col_pt = col0;
2891         }
2892         else if (t == 1.0f) {
2893                 col_pt = col1;
2894         }
2895         else {
2896                 unsigned char  col_blend[4];
2897                 interp_v4_v4v4_uchar(col_blend, col0, col1, t);
2898                 glColor4ubv(col_blend);
2899                 data->lastCol = NULL;
2900                 return;
2901         }
2902
2903         if (data->lastCol != col_pt) {
2904                 data->lastCol = col_pt;
2905                 glColor4ubv(col_pt);
2906         }
2907 }
2908
2909 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2910 {
2911         drawDMEdgesSelInterp_userData data;
2912         data.bm = em->bm;
2913         data.baseCol = baseCol;
2914         data.selCol = selCol;
2915         data.lastCol = NULL;
2916
2917         dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, &data);
2918 }
2919
2920 static void bm_color_from_weight(float col[3], BMVert *vert, drawDMEdgesWeightInterp_userData *data)
2921 {
2922         MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, data->cd_dvert_offset);
2923         float weight = defvert_find_weight(dvert, data->vgroup_index);
2924
2925         if ((weight == 0.0f) &&
2926             ((data->weight_user == OB_DRAW_GROUPUSER_ACTIVE) ||
2927              ((data->weight_user == OB_DRAW_GROUPUSER_ALL) && defvert_is_weight_zero(dvert, data->defgroup_tot))))
2928         {
2929                 copy_v3_v3(col, data->alert_color);
2930         }
2931         else {
2932                 weight_to_rgb(col, weight);
2933         }
2934 }
2935
2936 static void draw_dm_edges_nop_interp__setDrawInterpOptions(void *UNUSED(userData), int UNUSED(index), float UNUSED(t))
2937 {
2938         /* pass */
2939 }
2940
2941 static void draw_dm_edges_weight_interp__setDrawInterpOptions(void *userData, int index, float t)
2942 {
2943         drawDMEdgesWeightInterp_userData *data = userData;
2944         BMEdge *eed = BM_edge_at_index(data->bm, index);
2945         float col[3];
2946
2947         if (t == 0.0f) {
2948                 bm_color_from_weight(col, eed->v1, data);
2949         }
2950         else if (t == 1.0f) {
2951                 bm_color_from_weight(col, eed->v2, data);
2952         }
2953         else {
2954                 float col_v1[3];
2955                 float col_v2[3];
2956
2957                 bm_color_from_weight(col_v1, eed->v1, data);
2958                 bm_color_from_weight(col_v2, eed->v2, data);
2959                 interp_v3_v3v3(col, col_v1, col_v2, t);
2960         }
2961
2962         glColor3fv(col);
2963 }
2964
2965 static void draw_dm_edges_weight_interp(BMEditMesh *em, DerivedMesh *dm, const char weight_user)
2966 {
2967         drawDMEdgesWeightInterp_userData data;
2968         Object *ob = em->ob;
2969
2970         data.bm = em->bm;
2971         data.cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2972         data.defgroup_tot = BLI_listbase_count(&ob->defbase);
2973         data.vgroup_index = ob->actdef - 1;
2974         data.weight_user = weight_user;
2975         UI_GetThemeColor3fv(TH_VERTEX_UNREFERENCED, data.alert_color);
2976
2977         if ((data.vgroup_index != -1) && (data.cd_dvert_offset != -1)) {
2978                 glEnable(GL_BLEND);
2979                 dm->drawMappedEdgesInterp(
2980                         dm,
2981                         draw_dm_edges_sel_interp__setDrawOptions,
2982                         draw_dm_edges_weight_interp__setDrawInterpOptions,
2983                         &data);
2984                 glDisable(GL_BLEND);
2985         }
2986         else {
2987                 float col[3];
2988
2989                 if (data.weight_user == OB_DRAW_GROUPUSER_NONE) {
2990                         weight_to_rgb(col, 0.0f);
2991                 }
2992                 else {
2993                         copy_v3_v3(col, data.alert_color);
2994                 }
2995                 glColor3fv(col);
2996
2997                 dm->drawMappedEdgesInterp(
2998                         dm,
2999                         draw_dm_edges_sel_interp__setDrawOptions,
3000                         draw_dm_edges_nop_interp__setDrawInterpOptions,
3001                         &data);
3002         }
3003
3004 }
3005
3006 static bool draw_dm_edges_weight_check(Mesh *me, View3D *v3d)
3007 {
3008         if (me->drawflag & ME_DRAWEIGHT) {
3009                 if ((v3d->drawtype == OB_WIRE) ||
3010                     (v3d->flag2 & V3D_SOLID_MATCAP) ||
3011                     ((v3d->flag2 & V3D_OCCLUDE_WIRE) && (v3d->drawtype > OB_WIRE)))
3012                 {
3013                         return true;
3014                 }
3015         }
3016
3017         return false;
3018 }
3019
3020 /* Draw only seam edges */
3021 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
3022 {
3023         BMEdge *eed = BM_edge_at_index(userData, index);
3024
3025         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
3026                 return DM_DRAW_OPTION_NORMAL;
3027         else
3028                 return DM_DRAW_OPTION_SKIP;
3029 }
3030
3031 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
3032 {
3033         dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em->bm);
3034 }
3035
3036 /* Draw only sharp edges */
3037 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
3038 {
3039         BMEdge *eed = BM_edge_at_index(userData, index);
3040
3041         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
3042                 return DM_DRAW_OPTION_NORMAL;
3043         else
3044                 return DM_DRAW_OPTION_SKIP;
3045 }
3046
3047 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
3048 {
3049         dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em->bm);
3050 }
3051
3052 #ifdef WITH_FREESTYLE
3053
3054 static bool draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed)
3055 {
3056         FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
3057         if (!fed)
3058                 return false;
3059         return (fed->flag & FREESTYLE_EDGE_MARK) != 0;
3060 }
3061
3062 /* Draw only Freestyle feature edges */
3063 static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
3064 {
3065         BMEdge *eed = BM_edge_at_index(userData, index);
3066
3067         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && draw_dm_test_freestyle_edge_mark(userData, eed))
3068                 return DM_DRAW_OPTION_NORMAL;
3069         else
3070                 return DM_DRAW_OPTION_SKIP;
3071 }
3072
3073 static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
3074 {
3075         dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em->bm);
3076 }
3077
3078 static bool draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa)
3079 {
3080         FreestyleFace *ffa = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
3081         if (!ffa)
3082                 return false;
3083         return (ffa->flag & FREESTYLE_FACE_MARK) != 0;
3084 }
3085
3086 #endif
3087
3088 /* Draw loop normals. */
3089 static void draw_dm_loop_normals__mapFunc(void *userData, int vertex_index, int face_index,
3090                                           const float co[3], const float no[3])
3091 {
3092         if (no) {
3093                 const drawDMNormal_userData *data = userData;
3094                 const BMVert *eve = BM_vert_at_index(data->bm, vertex_index);
3095                 const BMFace *efa = BM_face_at_index(data->bm, face_index);
3096                 float vec[3];
3097
3098                 if (!(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) || BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) {
3099                         if (!data->uniform_scale) {
3100                                 mul_v3_m3v3(vec, (float(*)[3])data->tmat, no);
3101                                 normalize_v3(vec);
3102                                 mul_m3_v3((float(*)[3])data->imat, vec);
3103                         }
3104                         else {
3105                                 copy_v3_v3(vec, no);
3106                         }
3107                         mul_v3_fl(vec, data->normalsize);
3108                         add_v3_v3(vec, co);
3109                         immVertex3fv(data->pos, co);
3110                         immVertex3fv(data->pos, vec);
3111                 }
3112         }
3113 }
3114
3115 static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
3116 {
3117         drawDMNormal_userData data;
3118
3119         data.bm = em->bm;
3120         data.normalsize = scene->toolsettings->normalsize;
3121         data.pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
3122
3123         if (dm->getNumLoops(dm) == 0) return;
3124
3125         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
3126         immUniformThemeColor(theme_id);
3127
3128         calcDrawDMNormalScale(ob, &data);
3129
3130         immBeginAtMost(PRIM_LINES, dm->getNumLoops(dm) * 2);
3131         dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
3132         immEnd();
3133
3134         immUnbindProgram();
3135 }
3136
3137 /* Draw faces with color set based on selection
3138  * return 2 for the active face so it renders with stipple enabled */
3139 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
3140 {
3141         drawDMFacesSel_userData *data = userData;
3142         BMFace *efa = BM_face_at_index(data->bm, index);
3143         unsigned char *col;
3144         
3145         if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
3146                 if (efa == data->efa_act) {
3147                         glColor4ubv(data->cols[2]);
3148                         return DM_DRAW_OPTION_STIPPLE;
3149                 }
3150                 else {
3151 #ifdef WITH_FREESTYLE
3152                         col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
3153 #else
3154                         col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
3155 #endif
3156                         if (col[3] == 0)
3157                                 return DM_DRAW_OPTION_SKIP;
3158                         glColor4ubv(col);
3159                         return DM_DRAW_OPTION_NORMAL;
3160                 }
3161         }
3162         return DM_DRAW_OPTION_SKIP;
3163 }
3164
3165 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
3166 {
3167
3168         drawDMFacesSel_userData *data = userData;
3169         int i;
3170         BMFace *efa;
3171         BMFace *next_efa;
3172
3173         unsigned char *col, *next_col;
3174
3175         i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[index] : index;
3176         efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
3177         i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[next_index] : next_index;
3178         next_efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
3179
3180         if (ELEM(NULL, efa, next_efa))
3181                 return 0;
3182
3183         if (efa == next_efa)
3184                 return 1;
3185
3186         if (efa == data->efa_act || next_efa == data->efa_act)
3187                 return 0;
3188
3189 #ifdef WITH_FREESTYLE
3190         col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
3191         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];
3192 #else