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