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