minor refactor for rect functions. more consistent naming.
[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
31 #include <string.h>
32 #include <math.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_camera_types.h"
37 #include "DNA_curve_types.h"
38 #include "DNA_constraint_types.h"  /* for drawing constraint */
39 #include "DNA_lamp_types.h"
40 #include "DNA_lattice_types.h"
41 #include "DNA_material_types.h"
42 #include "DNA_mesh_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_meta_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_smoke_types.h"
47 #include "DNA_speaker_types.h"
48 #include "DNA_world_types.h"
49 #include "DNA_armature_types.h"
50 #include "DNA_object_types.h"
51
52 #include "BLI_utildefines.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_math.h"
55 #include "BLI_edgehash.h"
56 #include "BLI_rand.h"
57 #include "BLI_utildefines.h"
58
59 #include "BKE_anim.h"  /* for the where_on_path function */
60 #include "BKE_armature.h"
61 #include "BKE_camera.h"
62 #include "BKE_constraint.h"  /* for the get_constraint_target function */
63 #include "BKE_curve.h"
64 #include "BKE_DerivedMesh.h"
65 #include "BKE_deform.h"
66 #include "BKE_displist.h"
67 #include "BKE_font.h"
68 #include "BKE_global.h"
69 #include "BKE_image.h"
70 #include "BKE_key.h"
71 #include "BKE_lattice.h"
72 #include "BKE_mesh.h"
73 #include "BKE_material.h"
74 #include "BKE_mball.h"
75 #include "BKE_modifier.h"
76 #include "BKE_object.h"
77 #include "BKE_paint.h"
78 #include "BKE_particle.h"
79 #include "BKE_pointcache.h"
80 #include "BKE_scene.h"
81 #include "BKE_unit.h"
82 #include "BKE_movieclip.h"
83 #include "BKE_tracking.h"
84
85 #include "BKE_tessmesh.h"
86
87 #include "smoke_API.h"
88
89 #include "IMB_imbuf.h"
90 #include "IMB_imbuf_types.h"
91
92 #include "BIF_gl.h"
93 #include "BIF_glutil.h"
94
95 #include "GPU_draw.h"
96 #include "GPU_extensions.h"
97
98 #include "ED_mesh.h"
99 #include "ED_particle.h"
100 #include "ED_screen.h"
101 #include "ED_sculpt.h"
102 #include "ED_types.h"
103 #include "ED_curve.h" /* for curve_editnurbs */
104
105 #include "UI_resources.h"
106
107 #include "WM_api.h"
108 #include "wm_subwindow.h"
109 #include "BLF_api.h"
110
111 #include "view3d_intern.h"  /* own include */
112
113 typedef enum eWireDrawMode {
114         OBDRAW_WIRE_OFF = 0,
115         OBDRAW_WIRE_ON = 1,
116         OBDRAW_WIRE_ON_DEPTH = 2
117 } eWireDrawMode;
118
119 /* user data structures for derived mesh callbacks */
120 typedef struct foreachScreenVert_userData {
121         void (*func)(void *userData, BMVert *eve, int x, int y, int index);
122         void *userData;
123         ViewContext vc;
124         eV3DClipTest clipVerts;
125 } foreachScreenVert_userData;
126
127 typedef struct foreachScreenEdge_userData {
128         void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index);
129         void *userData;
130         ViewContext vc;
131         rcti win_rect; /* copy of: vc.ar->winx/winy, use for faster tests, minx/y will always be 0 */
132         eV3DClipTest clipVerts;
133 } foreachScreenEdge_userData;
134
135 typedef struct foreachScreenFace_userData {
136         void (*func)(void *userData, BMFace *efa, int x, int y, int index);
137         void *userData;
138         ViewContext vc;
139 } foreachScreenFace_userData;
140
141 typedef struct drawDMVerts_userData {
142         BMEditMesh *em; /* BMESH BRANCH ONLY */
143
144         int sel;
145         BMVert *eve_act;
146
147         /* cached theme values */
148         unsigned char th_editmesh_active[4];
149         unsigned char th_vertex_select[4];
150         unsigned char th_vertex[4];
151         unsigned char th_skin_root[4];
152         float th_vertex_size;
153
154         /* for skin node drawing */
155         int has_vskin;
156         float imat[4][4];
157 } drawDMVerts_userData;
158
159 typedef struct drawDMEdgesSel_userData {
160         BMEditMesh *em; /* BMESH BRANCH ONLY */
161
162         unsigned char *baseCol, *selCol, *actCol;
163         BMEdge *eed_act;
164 } drawDMEdgesSel_userData;
165
166 typedef struct drawDMFacesSel_userData {
167         unsigned char *cols[3];
168
169         DerivedMesh *dm; /* BMESH BRANCH ONLY */
170         BMEditMesh *em;  /* BMESH BRANCH ONLY */
171
172         BMFace *efa_act;
173         int *orig_index;
174 } drawDMFacesSel_userData;
175
176 typedef struct drawDMNormal_userData {
177         BMEditMesh *em;
178         int uniform_scale;
179         float normalsize;
180         float tmat[3][3];
181         float imat[3][3];
182 } drawDMNormal_userData;
183
184 typedef struct bbsObmodeMeshVerts_userData {
185         void *offset;
186         MVert *mvert;
187 } bbsObmodeMeshVerts_userData;
188
189 static void draw_bounding_volume(Scene *scene, Object *ob, char type);
190
191 static void drawcube_size(float size);
192 static void drawcircle_size(float size);
193 static void draw_empty_sphere(float size);
194 static void draw_empty_cone(float size);
195
196 /* this condition has been made more complex since editmode can draw textures */
197 static int check_object_draw_texture(Scene *scene, View3D *v3d, int drawtype)
198 {
199         /* texture and material draw modes */
200         if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID)
201                 return TRUE;
202
203         /* textured solid */
204         if (v3d->drawtype == OB_SOLID && (v3d->flag2 & V3D_SOLID_TEX) && !BKE_scene_use_new_shading_nodes(scene))
205                 return TRUE;
206         
207         return FALSE;
208 }
209
210 static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
211 {
212         if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0)
213                 return 0;
214
215         if (G.f & G_BACKBUFSEL)
216                 return 0;
217
218         if ((vd->flag & V3D_ZBUF_SELECT) == 0)
219                 return 1;
220
221         /* if its drawing textures with zbuf sel, then don't draw dots */
222         if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
223                 return 0;
224
225         if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
226                 return 0;
227
228         return 1;
229 }
230
231 /* ************* only use while object drawing **************
232  * or after running ED_view3d_init_mats_rv3d
233  * */
234 static void view3d_project_short_clip(ARegion *ar, const float vec[3], short adr[2], int is_local)
235 {
236         RegionView3D *rv3d = ar->regiondata;
237         float fx, fy, vec4[4];
238         
239         adr[0] = IS_CLIPPED;
240         
241         /* clipplanes in eye space */
242         if (rv3d->rflag & RV3D_CLIPPING) {
243                 if (ED_view3d_clipping_test(rv3d, vec, is_local))
244                         return;
245         }
246         
247         copy_v3_v3(vec4, vec);
248         vec4[3] = 1.0;
249         
250         mul_m4_v4(rv3d->persmatob, vec4);
251         
252         /* clipplanes in window space */
253         if (vec4[3] > (float)BL_NEAR_CLIP) {    /* is the NEAR clipping cutoff for picking */
254                 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
255                 
256                 if (fx > 0 && fx < ar->winx) {
257                         
258                         fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
259                         
260                         if (fy > 0.0f && fy < (float)ar->winy) {
261                                 adr[0] = (short)floorf(fx);
262                                 adr[1] = (short)floorf(fy);
263                         }
264                 }
265         }
266 }
267
268 /* BMESH NOTE: this function is unused in bmesh only */
269
270 /* only use while object drawing */
271 static void UNUSED_FUNCTION(view3d_project_short_noclip) (ARegion * ar, const float vec[3], short adr[2])
272 {
273         RegionView3D *rv3d = ar->regiondata;
274         float fx, fy, vec4[4];
275         
276         adr[0] = IS_CLIPPED;
277         
278         copy_v3_v3(vec4, vec);
279         vec4[3] = 1.0;
280         
281         mul_m4_v4(rv3d->persmatob, vec4);
282         
283         if (vec4[3] > (float)BL_NEAR_CLIP) {    /* is the NEAR clipping cutoff for picking */
284                 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
285                 
286                 if (fx > -32700 && fx < 32700) {
287                         
288                         fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
289                         
290                         if (fy > -32700.0f && fy < 32700.0f) {
291                                 adr[0] = (short)floorf(fx);
292                                 adr[1] = (short)floorf(fy);
293                         }
294                 }
295         }
296 }
297
298 /* same as view3d_project_short_clip but use persmat instead of persmatob for projection */
299 static void view3d_project_short_clip_persmat(ARegion *ar, const float vec[3], short adr[2], int is_local)
300 {
301         RegionView3D *rv3d = ar->regiondata;
302         float fx, fy, vec4[4];
303
304         adr[0] = IS_CLIPPED;
305
306         /* clipplanes in eye space */
307         if (rv3d->rflag & RV3D_CLIPPING) {
308                 if (ED_view3d_clipping_test(rv3d, vec, is_local))
309                         return;
310         }
311
312         copy_v3_v3(vec4, vec);
313         vec4[3] = 1.0;
314
315         mul_m4_v4(rv3d->persmat, vec4);
316
317         /* clipplanes in window space */
318         if (vec4[3] > (float)BL_NEAR_CLIP) {    /* is the NEAR clipping cutoff for picking */
319                 fx = (ar->winx / 2) * (1 + vec4[0] / vec4[3]);
320
321                 if (fx > 0 && fx < ar->winx) {
322
323                         fy = (ar->winy / 2) * (1 + vec4[1] / vec4[3]);
324
325                         if (fy > 0.0f && fy < (float)ar->winy) {
326                                 adr[0] = (short)floorf(fx);
327                                 adr[1] = (short)floorf(fy);
328                         }
329                 }
330         }
331 }
332 /* ************************ */
333
334 /* check for glsl drawing */
335
336 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const short dt)
337 {
338         if (!GPU_glsl_support())
339                 return 0;
340         if (G.f & G_PICKSEL)
341                 return 0;
342         if (!check_object_draw_texture(scene, v3d, dt))
343                 return 0;
344         if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
345                 return 0;
346         if (BKE_scene_use_new_shading_nodes(scene))
347                 return 0;
348         
349         return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
350 }
351
352 static int check_alpha_pass(Base *base)
353 {
354         if (base->flag & OB_FROMDUPLI)
355                 return 0;
356
357         if (G.f & G_PICKSEL)
358                 return 0;
359         
360         return (base->object->dtx & OB_DRAWTRANSP);
361 }
362
363 /***/
364 static unsigned int colortab[24] =
365 {0x0,       0xFF88FF, 0xFFBBFF,
366  0x403000,  0xFFFF88, 0xFFFFBB,
367  0x104040,  0x66CCCC, 0x77CCCC,
368  0x104010,  0x55BB55, 0x66FF66,
369  0xFFFFFF};
370
371
372 static float cube[8][3] = {
373         {-1.0, -1.0, -1.0},
374         {-1.0, -1.0,  1.0},
375         {-1.0,  1.0,  1.0},
376         {-1.0,  1.0, -1.0},
377         { 1.0, -1.0, -1.0},
378         { 1.0, -1.0,  1.0},
379         { 1.0,  1.0,  1.0},
380         { 1.0,  1.0, -1.0},
381 };
382
383 /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
384 /* 32 values of sin function (still same result!) */
385 #define CIRCLE_RESOL 32
386
387 static const float sinval[CIRCLE_RESOL] = {
388         0.00000000,
389         0.20129852,
390         0.39435585,
391         0.57126821,
392         0.72479278,
393         0.84864425,
394         0.93775213,
395         0.98846832,
396         0.99871650,
397         0.96807711,
398         0.89780453,
399         0.79077573,
400         0.65137248,
401         0.48530196,
402         0.29936312,
403         0.10116832,
404         -0.10116832,
405         -0.29936312,
406         -0.48530196,
407         -0.65137248,
408         -0.79077573,
409         -0.89780453,
410         -0.96807711,
411         -0.99871650,
412         -0.98846832,
413         -0.93775213,
414         -0.84864425,
415         -0.72479278,
416         -0.57126821,
417         -0.39435585,
418         -0.20129852,
419         0.00000000
420 };
421
422 /* 32 values of cos function (still same result!) */
423 static const float cosval[CIRCLE_RESOL] = {
424         1.00000000,
425         0.97952994,
426         0.91895781,
427         0.82076344,
428         0.68896691,
429         0.52896401,
430         0.34730525,
431         0.15142777,
432         -0.05064916,
433         -0.25065253,
434         -0.44039415,
435         -0.61210598,
436         -0.75875812,
437         -0.87434661,
438         -0.95413925,
439         -0.99486932,
440         -0.99486932,
441         -0.95413925,
442         -0.87434661,
443         -0.75875812,
444         -0.61210598,
445         -0.44039415,
446         -0.25065253,
447         -0.05064916,
448         0.15142777,
449         0.34730525,
450         0.52896401,
451         0.68896691,
452         0.82076344,
453         0.91895781,
454         0.97952994,
455         1.00000000
456 };
457
458 static void draw_xyz_wire(const float c[3], float size, int axis)
459 {
460         float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
461         float dim = size * 0.1f;
462         float dx[3], dy[3], dz[3];
463
464         dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
465         dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
466         dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
467
468         switch (axis) {
469                 case 0:     /* x axis */
470                         glBegin(GL_LINES);
471                         
472                         /* bottom left to top right */
473                         sub_v3_v3v3(v1, c, dx);
474                         sub_v3_v3(v1, dy);
475                         add_v3_v3v3(v2, c, dx);
476                         add_v3_v3(v2, dy);
477                         
478                         glVertex3fv(v1);
479                         glVertex3fv(v2);
480                         
481                         /* top left to bottom right */
482                         mul_v3_fl(dy, 2.f);
483                         add_v3_v3(v1, dy);
484                         sub_v3_v3(v2, dy);
485                         
486                         glVertex3fv(v1);
487                         glVertex3fv(v2);
488                         
489                         glEnd();
490                         break;
491                 case 1:     /* y axis */
492                         glBegin(GL_LINES);
493                         
494                         /* bottom left to top right */
495                         mul_v3_fl(dx, 0.75f);
496                         sub_v3_v3v3(v1, c, dx);
497                         sub_v3_v3(v1, dy);
498                         add_v3_v3v3(v2, c, dx);
499                         add_v3_v3(v2, dy);
500                         
501                         glVertex3fv(v1);
502                         glVertex3fv(v2);
503                         
504                         /* top left to center */
505                         mul_v3_fl(dy, 2.f);
506                         add_v3_v3(v1, dy);
507                         copy_v3_v3(v2, c);
508                         
509                         glVertex3fv(v1);
510                         glVertex3fv(v2);
511                         
512                         glEnd();
513                         break;
514                 case 2:     /* z axis */
515                         glBegin(GL_LINE_STRIP);
516                         
517                         /* start at top left */
518                         sub_v3_v3v3(v1, c, dx);
519                         add_v3_v3v3(v1, c, dz);
520                         
521                         glVertex3fv(v1);
522                         
523                         mul_v3_fl(dx, 2.f);
524                         add_v3_v3(v1, dx);
525
526                         glVertex3fv(v1);
527                         
528                         mul_v3_fl(dz, 2.f);
529                         sub_v3_v3(v1, dx);
530                         sub_v3_v3(v1, dz);
531                         
532                         glVertex3fv(v1);
533                         
534                         add_v3_v3(v1, dx);
535                 
536                         glVertex3fv(v1);
537                         
538                         glEnd();
539                         break;
540         }
541         
542 }
543
544 void drawaxes(float size, char drawtype)
545 {
546         int axis;
547         float v1[3] = {0.0, 0.0, 0.0};
548         float v2[3] = {0.0, 0.0, 0.0};
549         float v3[3] = {0.0, 0.0, 0.0};
550         
551         switch (drawtype) {
552
553                 case OB_PLAINAXES:
554                         for (axis = 0; axis < 3; axis++) {
555                                 glBegin(GL_LINES);
556
557                                 v1[axis] = size;
558                                 v2[axis] = -size;
559                                 glVertex3fv(v1);
560                                 glVertex3fv(v2);
561
562                                 /* reset v1 & v2 to zero */
563                                 v1[axis] = v2[axis] = 0.0f;
564
565                                 glEnd();
566                         }
567                         break;
568                 case OB_SINGLE_ARROW:
569
570                         glBegin(GL_LINES);
571                         /* in positive z direction only */
572                         v1[2] = size;
573                         glVertex3fv(v1);
574                         glVertex3fv(v2);
575                         glEnd();
576
577                         /* square pyramid */
578                         glBegin(GL_TRIANGLES);
579
580                         v2[0] = size * 0.035f; v2[1] = size * 0.035f;
581                         v3[0] = size * -0.035f; v3[1] = size * 0.035f;
582                         v2[2] = v3[2] = size * 0.75f;
583
584                         for (axis = 0; axis < 4; axis++) {
585                                 if (axis % 2 == 1) {
586                                         v2[0] = -v2[0];
587                                         v3[1] = -v3[1];
588                                 }
589                                 else {
590                                         v2[1] = -v2[1];
591                                         v3[0] = -v3[0];
592                                 }
593
594                                 glVertex3fv(v1);
595                                 glVertex3fv(v2);
596                                 glVertex3fv(v3);
597
598                         }
599                         glEnd();
600
601                         break;
602                 case OB_CUBE:
603                         drawcube_size(size);
604                         break;
605
606                 case OB_CIRCLE:
607                         drawcircle_size(size);
608                         break;
609
610                 case OB_EMPTY_SPHERE:
611                         draw_empty_sphere(size);
612                         break;
613
614                 case OB_EMPTY_CONE:
615                         draw_empty_cone(size);
616                         break;
617
618                 case OB_ARROWS:
619                 default:
620                 {
621                         for (axis = 0; axis < 3; axis++) {
622                                 const int arrow_axis = (axis == 0) ? 1 : 0;
623
624                                 glBegin(GL_LINES);
625
626                                 v2[axis] = size;
627                                 glVertex3fv(v1);
628                                 glVertex3fv(v2);
629                                 
630                                 v1[axis] = size * 0.85f;
631                                 v1[arrow_axis] = -size * 0.08f;
632                                 glVertex3fv(v1);
633                                 glVertex3fv(v2);
634                                 
635                                 v1[arrow_axis] = size * 0.08f;
636                                 glVertex3fv(v1);
637                                 glVertex3fv(v2);
638
639                                 glEnd();
640                                 
641                                 v2[axis] += size * 0.125f;
642
643                                 draw_xyz_wire(v2, size, axis);
644
645
646                                 /* reset v1 & v2 to zero */
647                                 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
648                         }
649                         break;
650                 }
651         }
652 }
653
654
655 /* Function to draw an Image on a empty Object */
656 static void draw_empty_image(Object *ob)
657 {
658         Image *ima = (Image *)ob->data;
659         ImBuf *ibuf = ima ? BKE_image_get_ibuf(ima, NULL) : NULL;
660
661         float scale, ofs_x, ofs_y, sca_x, sca_y;
662         int ima_x, ima_y;
663
664         if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
665                 IMB_rect_from_float(ibuf);
666         }
667
668         /* Get the buffer dimensions so we can fallback to fake ones */
669         if (ibuf && ibuf->rect) {
670                 ima_x = ibuf->x;
671                 ima_y = ibuf->y;
672         }
673         else {
674                 ima_x = 1;
675                 ima_y = 1;
676         }
677
678         /* Get the image aspect even if the buffer is invalid */
679         if (ima) {
680                 if (ima->aspx > ima->aspy) {
681                         sca_x = 1.0f;
682                         sca_y = ima->aspy / ima->aspx;
683                 }
684                 else if (ima->aspx < ima->aspy) {
685                         sca_x = ima->aspx / ima->aspy;
686                         sca_y = 1.0f;
687                 }
688                 else {
689                         sca_x = 1.0f;
690                         sca_y = 1.0f;
691                 }
692         }
693         else {
694                 sca_x = 1.0f;
695                 sca_y = 1.0f;
696         }
697
698         /* Calculate the scale center based on objects origin */
699         ofs_x = ob->ima_ofs[0] * ima_x;
700         ofs_y = ob->ima_ofs[1] * ima_y;
701
702         glMatrixMode(GL_MODELVIEW);
703         glPushMatrix();
704
705         /* Make sure we are drawing at the origin */
706         glTranslatef(0.0f,  0.0f,  0.0f);
707
708         /* Calculate Image scale */
709         scale = (ob->empty_drawsize / (float)MAX2(ima_x * sca_x, ima_y * sca_y));
710
711         /* Set the object scale */
712         glScalef(scale * sca_x, scale * sca_y, 1.0f);
713
714         if (ibuf && ibuf->rect) {
715                 /* Setup GL params */
716                 glEnable(GL_BLEND);
717                 glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA);
718
719                 /* Use the object color and alpha */
720                 glColor4fv(ob->col);
721
722                 /* Draw the Image on the screen */
723                 glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
724                 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
725
726                 glDisable(GL_BLEND);
727         }
728
729         UI_ThemeColor((ob->flag & SELECT) ? TH_SELECT : TH_WIRE);
730
731         /* Calculate the outline vertex positions */
732         glBegin(GL_LINE_LOOP);
733         glVertex2f(ofs_x, ofs_y);
734         glVertex2f(ofs_x + ima_x, ofs_y);
735         glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
736         glVertex2f(ofs_x, ofs_y + ima_y);
737         glEnd();
738
739         /* Reset GL settings */
740         glMatrixMode(GL_MODELVIEW);
741         glPopMatrix();
742 }
743
744 static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[][4])
745 {
746         float vx[3], vy[3];
747         float *viter = (float *)verts;
748         unsigned int a;
749
750         mul_v3_v3fl(vx, tmat[0], rad);
751         mul_v3_v3fl(vy, tmat[1], rad);
752
753         for (a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
754                 viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
755                 viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
756                 viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
757         }
758 }
759
760 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
761 {
762         float verts[CIRCLE_RESOL][3];
763
764         circball_array_fill(verts, cent, rad, tmat);
765
766         glEnableClientState(GL_VERTEX_ARRAY);
767         glVertexPointer(3, GL_FLOAT, 0, verts);
768         glDrawArrays(mode, 0, CIRCLE_RESOL);
769         glDisableClientState(GL_VERTEX_ARRAY);
770 }
771
772 /* circle for object centers, special_color is for library or ob users */
773 static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
774 {
775         const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
776         float verts[CIRCLE_RESOL][3];
777
778         /* using gldepthfunc guarantees that it does write z values,
779          * but not checks for it, so centers remain visible independent order of drawing */
780         if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
781         glEnable(GL_BLEND);
782         
783         if (special_color) {
784                 if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
785
786                 else glColor4ub(0x55, 0xCC, 0xCC, 155);
787         }
788         else {
789                 if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
790                 else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
791                 else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
792         }
793
794         circball_array_fill(verts, co, size, rv3d->viewinv);
795
796         /* enable vertex array */
797         glEnableClientState(GL_VERTEX_ARRAY);
798         glVertexPointer(3, GL_FLOAT, 0, verts);
799
800         /* 1. draw filled, blended polygon */
801         glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
802
803         /* 2. draw outline */
804         UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
805         glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
806
807         /* finish up */
808         glDisableClientState(GL_VERTEX_ARRAY);
809
810         glDisable(GL_BLEND);
811
812         if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
813 }
814
815 /* *********** text drawing for object/particles/armature ************* */
816 static ListBase CachedText[3];
817 static int CachedTextLevel = 0;
818
819 typedef struct ViewCachedString {
820         struct ViewCachedString *next, *prev;
821         float vec[3];
822         union {
823                 unsigned char ub[4];
824                 int pack;
825         } col;
826         short sco[2];
827         short xoffs;
828         short flag;
829         int str_len, pad;
830         /* str is allocated past the end */
831 } ViewCachedString;
832
833 void view3d_cached_text_draw_begin(void)
834 {
835         ListBase *strings = &CachedText[CachedTextLevel];
836         strings->first = strings->last = NULL;
837         CachedTextLevel++;
838 }
839
840 void view3d_cached_text_draw_add(const float co[3],
841                                  const char *str,
842                                  short xoffs, short flag,
843                                  const unsigned char col[4])
844 {
845         int alloc_len = strlen(str) + 1;
846         ListBase *strings = &CachedText[CachedTextLevel - 1];
847         /* TODO, replace with more efficient malloc, perhaps memarena per draw? */
848         ViewCachedString *vos = MEM_callocN(sizeof(ViewCachedString) + alloc_len, "ViewCachedString");
849
850         BLI_addtail(strings, vos);
851         copy_v3_v3(vos->vec, co);
852         vos->col.pack = *((int *)col);
853         vos->xoffs = xoffs;
854         vos->flag = flag;
855         vos->str_len = alloc_len - 1;
856
857         /* allocate past the end */
858         memcpy(++vos, str, alloc_len);
859 }
860
861 void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
862 {
863         RegionView3D *rv3d = ar->regiondata;
864         ListBase *strings = &CachedText[CachedTextLevel - 1];
865         ViewCachedString *vos;
866         int tot = 0;
867         
868         /* project first and test */
869         for (vos = strings->first; vos; vos = vos->next) {
870                 if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
871                         mul_m4_v3(mat, vos->vec);
872
873                 if (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE)
874                         view3d_project_short_clip_persmat(ar, vos->vec, vos->sco, (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0);
875                 else
876                         view3d_project_short_clip(ar, vos->vec, vos->sco, (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0);
877
878                 if (vos->sco[0] != IS_CLIPPED)
879                         tot++;
880         }
881
882         if (tot) {
883                 int col_pack_prev = 0;
884
885 #if 0
886                 bglMats mats; /* ZBuffer depth vars */
887                 double ux, uy, uz;
888                 float depth;
889
890                 if (v3d->zbuf)
891                         bgl_get_mats(&mats);
892 #endif
893                 if (rv3d->rflag & RV3D_CLIPPING) {
894                         ED_view3d_clipping_disable();
895                 }
896
897                 glMatrixMode(GL_PROJECTION);
898                 glPushMatrix();
899                 glMatrixMode(GL_MODELVIEW);
900                 glPushMatrix();
901                 ED_region_pixelspace(ar);
902                 
903                 if (depth_write) {
904                         if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
905                 }
906                 else {
907                         glDepthMask(0);
908                 }
909                 
910                 for (vos = strings->first; vos; vos = vos->next) {
911                         /* too slow, reading opengl info while drawing is very bad,
912                          * better to see if we can use the zbuffer while in pixel space - campbell */
913 #if 0
914                         if (v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
915                                 gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
916                                 glReadPixels(ar->winrct.xmin + vos->mval[0] + vos->xoffs, ar->winrct.ymin + vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
917
918                                 if (uz > depth)
919                                         continue;
920                         }
921 #endif
922                         if (vos->sco[0] != IS_CLIPPED) {
923                                 const char *str = (char *)(vos + 1);
924
925                                 if (col_pack_prev != vos->col.pack) {
926                                         glColor3ubv(vos->col.ub);
927                                         col_pack_prev = vos->col.pack;
928                                 }
929
930                                 ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
931                                  BLF_draw_default_ascii :
932                                  BLF_draw_default
933                                 )( (float)vos->sco[0] + vos->xoffs,
934                                    (float)vos->sco[1],
935                                    (depth_write) ? 0.0f : 2.0f,
936                                    str,
937                                    vos->str_len);
938                         }
939                 }
940                 
941                 if (depth_write) {
942                         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
943                 }
944                 else glDepthMask(1);
945                 
946                 glMatrixMode(GL_PROJECTION);
947                 glPopMatrix();
948                 glMatrixMode(GL_MODELVIEW);
949                 glPopMatrix();
950
951                 if (rv3d->rflag & RV3D_CLIPPING) {
952                         ED_view3d_clipping_enable();
953                 }
954         }
955         
956         if (strings->first)
957                 BLI_freelistN(strings);
958         
959         CachedTextLevel--;
960 }
961
962 /* ******************** primitive drawing ******************* */
963
964 static void drawcube(void)
965 {
966
967         glBegin(GL_LINE_STRIP);
968         glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
969         glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
970         glVertex3fv(cube[7]); glVertex3fv(cube[4]);
971         glEnd();
972
973         glBegin(GL_LINE_STRIP);
974         glVertex3fv(cube[1]); glVertex3fv(cube[5]);
975         glEnd();
976
977         glBegin(GL_LINE_STRIP);
978         glVertex3fv(cube[2]); glVertex3fv(cube[6]);
979         glEnd();
980
981         glBegin(GL_LINE_STRIP);
982         glVertex3fv(cube[3]); glVertex3fv(cube[7]);
983         glEnd();
984 }
985
986 /* draws a cube on given the scaling of the cube, assuming that 
987  * all required matrices have been set (used for drawing empties)
988  */
989 static void drawcube_size(float size)
990 {
991         glBegin(GL_LINE_STRIP);
992         glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size);
993         glVertex3f(-size, size, size); glVertex3f(-size, size, -size);
994
995         glVertex3f(-size, -size, -size); glVertex3f(size, -size, -size);
996         glVertex3f(size, -size, size); glVertex3f(size, size, size);
997
998         glVertex3f(size, size, -size); glVertex3f(size, -size, -size);
999         glEnd();
1000
1001         glBegin(GL_LINE_STRIP);
1002         glVertex3f(-size, -size, size); glVertex3f(size, -size, size);
1003         glEnd();
1004
1005         glBegin(GL_LINE_STRIP);
1006         glVertex3f(-size, size, size); glVertex3f(size, size, size);
1007         glEnd();
1008
1009         glBegin(GL_LINE_STRIP);
1010         glVertex3f(-size, size, -size); glVertex3f(size, size, -size);
1011         glEnd();
1012 }
1013
1014 /* this is an unused (old) cube-drawing function based on a given size */
1015 #if 0
1016 static void drawcube_size(const float size[3])
1017 {
1018
1019         glPushMatrix();
1020         glScalef(size[0],  size[1],  size[2]);
1021         
1022
1023         glBegin(GL_LINE_STRIP);
1024         glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
1025         glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
1026         glVertex3fv(cube[7]); glVertex3fv(cube[4]);
1027         glEnd();
1028
1029         glBegin(GL_LINE_STRIP);
1030         glVertex3fv(cube[1]); glVertex3fv(cube[5]);
1031         glEnd();
1032
1033         glBegin(GL_LINE_STRIP);
1034         glVertex3fv(cube[2]); glVertex3fv(cube[6]);
1035         glEnd();
1036
1037         glBegin(GL_LINE_STRIP);
1038         glVertex3fv(cube[3]); glVertex3fv(cube[7]);
1039         glEnd();
1040         
1041         glPopMatrix();
1042 }
1043 #endif
1044
1045 static void drawshadbuflimits(Lamp *la, float mat[][4])
1046 {
1047         float sta[3], end[3], lavec[3];
1048
1049         negate_v3_v3(lavec, mat[2]);
1050         normalize_v3(lavec);
1051
1052         madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
1053         madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
1054
1055         glBegin(GL_LINE_STRIP);
1056         glVertex3fv(sta);
1057         glVertex3fv(end);
1058         glEnd();
1059
1060         glPointSize(3.0);
1061         bglBegin(GL_POINTS);
1062         bglVertex3fv(sta);
1063         bglVertex3fv(end);
1064         bglEnd();
1065         glPointSize(1.0);
1066 }
1067
1068
1069
1070 static void spotvolume(float lvec[3], float vvec[3], const float inp)
1071 {
1072         /* camera is at 0,0,0 */
1073         float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
1074
1075         normalize_v3(lvec);
1076         normalize_v3(vvec);             /* is this the correct vector ? */
1077
1078         cross_v3_v3v3(temp, vvec, lvec);      /* equation for a plane through vvec en lvec */
1079         cross_v3_v3v3(plane, lvec, temp);     /* a plane perpendicular to this, parrallel with lvec */
1080
1081         /* vectors are exactly aligned, use the X axis, this is arbitrary */
1082         if (normalize_v3(plane) == 0.0f)
1083                 plane[1] = 1.0f;
1084
1085         /* now we've got two equations: one of a cone and one of a plane, but we have
1086          * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
1087
1088         /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
1089         /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
1090
1091         /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
1092         
1093         q[1] =  plane[1];
1094         q[2] = -plane[0];
1095         q[3] =  0;
1096         normalize_v3(&q[1]);
1097
1098         angle = saacos(plane[2]) / 2.0f;
1099         co = cosf(angle);
1100         si = sqrtf(1 - co * co);
1101
1102         q[0] =  co;
1103         q[1] *= si;
1104         q[2] *= si;
1105         q[3] =  0;
1106
1107         quat_to_mat3(mat1, q);
1108
1109         /* rotate lamp vector now over acos(inp) degrees */
1110         copy_v3_v3(vvec, lvec);
1111
1112         unit_m3(mat2);
1113         co = inp;
1114         si = sqrtf(1.0f - inp * inp);
1115
1116         mat2[0][0] =  co;
1117         mat2[1][0] = -si;
1118         mat2[0][1] =  si;
1119         mat2[1][1] =  co;
1120         mul_m3_m3m3(mat3, mat2, mat1);
1121
1122         mat2[1][0] =  si;
1123         mat2[0][1] = -si;
1124         mul_m3_m3m3(mat4, mat2, mat1);
1125         transpose_m3(mat1);
1126
1127         mul_m3_m3m3(mat2, mat1, mat3);
1128         mul_m3_v3(mat2, lvec);
1129         mul_m3_m3m3(mat2, mat1, mat4);
1130         mul_m3_v3(mat2, vvec);
1131
1132         return;
1133 }
1134
1135 static void draw_spot_cone(Lamp *la, float x, float z)
1136 {
1137         z = fabs(z);
1138
1139         glBegin(GL_TRIANGLE_FAN);
1140         glVertex3f(0.0f, 0.0f, -x);
1141
1142         if (la->mode & LA_SQUARE) {
1143                 glVertex3f(z, z, 0);
1144                 glVertex3f(-z, z, 0);
1145                 glVertex3f(-z, -z, 0);
1146                 glVertex3f(z, -z, 0);
1147                 glVertex3f(z, z, 0);
1148         }
1149         else {
1150                 float angle;
1151                 int a;
1152
1153                 for (a = 0; a < 33; a++) {
1154                         angle = a * M_PI * 2 / (33 - 1);
1155                         glVertex3f(z * cosf(angle), z * sinf(angle), 0);
1156                 }
1157         }
1158
1159         glEnd();
1160 }
1161
1162 static void draw_transp_spot_volume(Lamp *la, float x, float z)
1163 {
1164         glEnable(GL_CULL_FACE);
1165         glEnable(GL_BLEND);
1166         glDepthMask(0);
1167
1168         /* draw backside darkening */
1169         glCullFace(GL_FRONT);
1170
1171         glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
1172         glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
1173
1174         draw_spot_cone(la, x, z);
1175
1176         /* draw front side lighting */
1177         glCullFace(GL_BACK);
1178
1179         glBlendFunc(GL_ONE, GL_ONE);
1180         glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
1181
1182         draw_spot_cone(la, x, z);
1183
1184         /* restore state */
1185         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1186         glDisable(GL_BLEND);
1187         glDepthMask(1);
1188         glDisable(GL_CULL_FACE);
1189         glCullFace(GL_BACK);
1190 }
1191
1192 static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
1193                      const short dt, const short dflag, const unsigned char ob_wire_col[4])
1194 {
1195         Object *ob = base->object;
1196         const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
1197         Lamp *la = ob->data;
1198         float vec[3], lvec[3], vvec[3], circrad, x, y, z;
1199         float lampsize;
1200         float imat[4][4];
1201
1202         unsigned char curcol[4];
1203         unsigned char col[4];
1204         /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
1205         /* the moment of view3d_draw_transp() call */
1206         const short is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
1207         const short drawcone = ((dt > OB_WIRE) &&
1208                                 !(G.f & G_PICKSEL) &&
1209                                 (la->type == LA_SPOT) &&
1210                                 (la->mode & LA_SHOW_CONE) &&
1211                                 !(base->flag & OB_FROMDUPLI) &&
1212                                 !is_view);
1213
1214         if (drawcone && !v3d->transp) {
1215                 /* in this case we need to draw delayed */
1216                 ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
1217                 return;
1218         }
1219         
1220         /* we first draw only the screen aligned & fixed scale stuff */
1221         glPushMatrix();
1222         glLoadMatrixf(rv3d->viewmat);
1223
1224         /* lets calculate the scale: */
1225         lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
1226
1227         /* and view aligned matrix: */
1228         copy_m4_m4(imat, rv3d->viewinv);
1229         normalize_v3(imat[0]);
1230         normalize_v3(imat[1]);
1231
1232         /* lamp center */
1233         copy_v3_v3(vec, ob->obmat[3]);
1234
1235         if ((dflag & DRAW_CONSTCOLOR) == 0) {
1236                 /* for AA effects */
1237                 curcol[0] = ob_wire_col[0];
1238                 curcol[1] = ob_wire_col[1];
1239                 curcol[2] = ob_wire_col[2];
1240                 curcol[3] = 154;
1241                 glColor4ubv(curcol);
1242         }
1243
1244         if (lampsize > 0.0f) {
1245
1246                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1247                         if (ob->id.us > 1) {
1248                                 if (ob == OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
1249                                 else glColor4ub(0x77, 0xCC, 0xCC, 155);
1250                         }
1251                 }
1252                 
1253                 /* Inner Circle */
1254                 glEnable(GL_BLEND);
1255                 drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
1256                 glDisable(GL_BLEND);
1257                 drawcircball(GL_POLYGON, vec, lampsize, imat);
1258                 
1259                 /* restore */
1260                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1261                         if (ob->id.us > 1)
1262                                 glColor4ubv(curcol);
1263                 }
1264
1265                 /* Outer circle */
1266                 circrad = 3.0f * lampsize;
1267                 setlinestyle(3);
1268
1269                 drawcircball(GL_LINE_LOOP, vec, circrad, imat);
1270
1271                 /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
1272                 if (la->type != LA_HEMI) {
1273                         if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
1274                                 drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
1275                         }
1276                 }
1277         }
1278         else {
1279                 setlinestyle(3);
1280                 circrad = 0.0f;
1281         }
1282         
1283         /* draw the pretty sun rays */
1284         if (la->type == LA_SUN) {
1285                 float v1[3], v2[3], mat[3][3];
1286                 short axis;
1287                 
1288                 /* setup a 45 degree rotation matrix */
1289                 vec_rot_to_mat3(mat, imat[2], (float)M_PI / 4.0f);
1290                 
1291                 /* vectors */
1292                 mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
1293                 mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
1294                 
1295                 /* center */
1296                 glTranslatef(vec[0], vec[1], vec[2]);
1297                 
1298                 setlinestyle(3);
1299                 
1300                 glBegin(GL_LINES);
1301                 for (axis = 0; axis < 8; axis++) {
1302                         glVertex3fv(v1);
1303                         glVertex3fv(v2);
1304                         mul_m3_v3(mat, v1);
1305                         mul_m3_v3(mat, v2);
1306                 }
1307                 glEnd();
1308                 
1309                 glTranslatef(-vec[0], -vec[1], -vec[2]);
1310
1311         }
1312         
1313         if (la->type == LA_LOCAL) {
1314                 if (la->mode & LA_SPHERE) {
1315                         drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
1316                 }
1317         }
1318         
1319         glPopMatrix();  /* back in object space */
1320         zero_v3(vec);
1321         
1322         if (is_view) {
1323                 /* skip drawing extra info */
1324         }
1325         else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
1326                 lvec[0] = lvec[1] = 0.0;
1327                 lvec[2] = 1.0;
1328                 x = rv3d->persmat[0][2];
1329                 y = rv3d->persmat[1][2];
1330                 z = rv3d->persmat[2][2];
1331                 vvec[0] = x * ob->obmat[0][0] + y * ob->obmat[0][1] + z * ob->obmat[0][2];
1332                 vvec[1] = x * ob->obmat[1][0] + y * ob->obmat[1][1] + z * ob->obmat[1][2];
1333                 vvec[2] = x * ob->obmat[2][0] + y * ob->obmat[2][1] + z * ob->obmat[2][2];
1334
1335                 y = cosf(la->spotsize * (float)(M_PI / 360.0));
1336                 spotvolume(lvec, vvec, y);
1337                 x = -la->dist;
1338                 mul_v3_fl(lvec, x);
1339                 mul_v3_fl(vvec, x);
1340
1341                 /* draw the angled sides of the cone */
1342                 glBegin(GL_LINE_STRIP);
1343                 glVertex3fv(vvec);
1344                 glVertex3fv(vec);
1345                 glVertex3fv(lvec);
1346                 glEnd();
1347                 
1348                 z = x * sqrtf(1.0f - y * y);
1349                 x *= y;
1350
1351                 /* draw the circle/square at the end of the cone */
1352                 glTranslatef(0.0, 0.0,  x);
1353                 if (la->mode & LA_SQUARE) {
1354                         float tvec[3];
1355                         float z_abs = fabs(z);
1356
1357                         tvec[0] = tvec[1] = z_abs;
1358                         tvec[2] = 0.0;
1359
1360                         glBegin(GL_LINE_LOOP);
1361                         glVertex3fv(tvec);
1362                         tvec[1] = -z_abs; /* neg */
1363                         glVertex3fv(tvec);
1364                         tvec[0] = -z_abs; /* neg */
1365                         glVertex3fv(tvec);
1366                         tvec[1] = z_abs; /* pos */
1367                         glVertex3fv(tvec);
1368                         glEnd();
1369                 }
1370                 else circ(0.0, 0.0, fabsf(z));
1371                 
1372                 /* draw the circle/square representing spotbl */
1373                 if (la->type == LA_SPOT) {
1374                         float spotblcirc = fabs(z) * (1 - pow(la->spotblend, 2));
1375                         /* hide line if it is zero size or overlaps with outer border,
1376                          * previously it adjusted to always to show it but that seems
1377                          * confusing because it doesn't show the actual blend size */
1378                         if (spotblcirc != 0 && spotblcirc != fabsf(z))
1379                                 circ(0.0, 0.0, spotblcirc);
1380                 }
1381
1382                 if (drawcone)
1383                         draw_transp_spot_volume(la, x, z);
1384
1385                 /* draw clip start, useful for wide cones where its not obvious where the start is */
1386                 glTranslatef(0.0, 0.0, -x);  /* reverse translation above */
1387                 if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
1388                         float lvec_clip[3];
1389                         float vvec_clip[3];
1390                         float clipsta_fac = la->clipsta / -x;
1391
1392                         interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
1393                         interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
1394
1395                         glBegin(GL_LINE_STRIP);
1396                         glVertex3fv(lvec_clip);
1397                         glVertex3fv(vvec_clip);
1398                         glEnd();
1399                 }
1400         }
1401         else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
1402                 
1403                 /* draw the line from the circle along the dist */
1404                 glBegin(GL_LINE_STRIP);
1405                 vec[2] = -circrad;
1406                 glVertex3fv(vec);
1407                 vec[2] = -la->dist;
1408                 glVertex3fv(vec);
1409                 glEnd();
1410                 
1411                 if (la->type == LA_HEMI) {
1412                         /* draw the hemisphere curves */
1413                         short axis, steps, dir;
1414                         float outdist, zdist, mul;
1415                         zero_v3(vec);
1416                         outdist = 0.14; mul = 1.4; dir = 1;
1417                         
1418                         setlinestyle(4);
1419                         /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
1420                         for (axis = 0; axis < 4; axis++) {
1421                                 float v[3] = {0.0, 0.0, 0.0};
1422                                 zdist = 0.02;
1423                                 
1424                                 glBegin(GL_LINE_STRIP);
1425                                 
1426                                 for (steps = 0; steps < 6; steps++) {
1427                                         if (axis == 0 || axis == 1) {       /* x axis up, x axis down */
1428                                                 /* make the arcs start at the edge of the energy circle */
1429                                                 if (steps == 0) v[0] = dir * circrad;
1430                                                 else v[0] = v[0] + dir * (steps * outdist);
1431                                         }
1432                                         else if (axis == 2 || axis == 3) {      /* y axis up, y axis down */
1433                                                 /* make the arcs start at the edge of the energy circle */
1434                                                 v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
1435                                         }
1436
1437                                         v[2] = v[2] - steps * zdist;
1438                                         
1439                                         glVertex3fv(v);
1440                                         
1441                                         zdist = zdist * mul;
1442                                 }
1443                                 
1444                                 glEnd();
1445                                 /* flip the direction */
1446                                 dir = -dir;
1447                         }
1448                 }
1449         }
1450         else if (la->type == LA_AREA) {
1451                 setlinestyle(3);
1452                 if (la->area_shape == LA_AREA_SQUARE)
1453                         fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
1454                 else if (la->area_shape == LA_AREA_RECT)
1455                         fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
1456
1457                 glBegin(GL_LINE_STRIP);
1458                 glVertex3f(0.0, 0.0, -circrad);
1459                 glVertex3f(0.0, 0.0, -la->dist);
1460                 glEnd();
1461         }
1462         
1463         /* and back to viewspace */
1464         glLoadMatrixf(rv3d->viewmat);
1465         copy_v3_v3(vec, ob->obmat[3]);
1466
1467         setlinestyle(0);
1468         
1469         if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == FALSE)) {
1470                 drawshadbuflimits(la, ob->obmat);
1471         }
1472         
1473         UI_GetThemeColor4ubv(TH_LAMP, col);
1474         glColor4ubv(col);
1475
1476         glEnable(GL_BLEND);
1477         
1478         if (vec[2] > 0) vec[2] -= circrad;
1479         else vec[2] += circrad;
1480         
1481         glBegin(GL_LINE_STRIP);
1482         glVertex3fv(vec);
1483         vec[2] = 0;
1484         glVertex3fv(vec);
1485         glEnd();
1486         
1487         glPointSize(2.0);
1488         glBegin(GL_POINTS);
1489         glVertex3fv(vec);
1490         glEnd();
1491         glPointSize(1.0);
1492         
1493         glDisable(GL_BLEND);
1494         
1495         if ((dflag & DRAW_CONSTCOLOR) == 0) {
1496                 /* restore for drawing extra stuff */
1497                 glColor3ubv(ob_wire_col);
1498         }
1499 }
1500
1501 static void draw_limit_line(float sta, float end, unsigned int col)
1502 {
1503         glBegin(GL_LINES);
1504         glVertex3f(0.0, 0.0, -sta);
1505         glVertex3f(0.0, 0.0, -end);
1506         glEnd();
1507
1508         glPointSize(3.0);
1509         glBegin(GL_POINTS);
1510         cpack(col);
1511         glVertex3f(0.0, 0.0, -sta);
1512         glVertex3f(0.0, 0.0, -end);
1513         glEnd();
1514         glPointSize(1.0);
1515 }               
1516
1517
1518 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
1519 /* qdn: now also enabled for Blender to set focus point for defocus composite node */
1520 static void draw_focus_cross(float dist, float size)
1521 {
1522         glBegin(GL_LINES);
1523         glVertex3f(-size, 0.f, -dist);
1524         glVertex3f(size, 0.f, -dist);
1525         glVertex3f(0.f, -size, -dist);
1526         glVertex3f(0.f, size, -dist);
1527         glEnd();
1528 }
1529
1530 #ifdef VIEW3D_CAMERA_BORDER_HACK
1531 unsigned char view3d_camera_border_hack_col[3];
1532 short view3d_camera_border_hack_test = FALSE;
1533 #endif
1534
1535 /* ****************** draw clip data *************** */
1536
1537 static void draw_bundle_sphere(void)
1538 {
1539         static GLuint displist = 0;
1540
1541         if (displist == 0) {
1542                 GLUquadricObj *qobj;
1543
1544                 displist = glGenLists(1);
1545                 glNewList(displist, GL_COMPILE);
1546
1547                 qobj = gluNewQuadric();
1548                 gluQuadricDrawStyle(qobj, GLU_FILL);
1549                 glShadeModel(GL_SMOOTH);
1550                 gluSphere(qobj, 0.05, 8, 8);
1551                 glShadeModel(GL_FLAT);
1552                 gluDeleteQuadric(qobj);
1553
1554                 glEndList();
1555         }
1556
1557         glCallList(displist);
1558 }
1559
1560 static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
1561                                                 MovieClip *clip, MovieTrackingObject *tracking_object,
1562                                                 const short dflag, int *global_track_index, int draw_selected)
1563 {
1564         MovieTracking *tracking = &clip->tracking;
1565         MovieTrackingTrack *track;
1566         float mat[4][4], imat[4][4];
1567         unsigned char col[4], scol[4];
1568         int tracknr = *global_track_index;
1569         ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
1570
1571         UI_GetThemeColor4ubv(TH_TEXT, col);
1572         UI_GetThemeColor4ubv(TH_SELECT, scol);
1573
1574         BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
1575
1576         glPushMatrix();
1577
1578         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1579                 /* current ogl matrix is translated in camera space, bundles should
1580                  * be rendered in world space, so camera matrix should be "removed"
1581                  * from current ogl matrix */
1582                 invert_m4_m4(imat, base->object->obmat);
1583
1584                 glMultMatrixf(imat);
1585                 glMultMatrixf(mat);
1586         }
1587         else {
1588                 float obmat[4][4];
1589
1590                 BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, scene->r.cfra, obmat);
1591
1592                 invert_m4_m4(imat, obmat);
1593                 glMultMatrixf(imat);
1594         }
1595
1596         for (track = tracksbase->first; track; track = track->next) {
1597                 int selected = TRACK_SELECTED(track);
1598
1599                 if (draw_selected && !selected)
1600                         continue;
1601
1602                 if ((track->flag & TRACK_HAS_BUNDLE) == 0)
1603                         continue;
1604
1605                 if (dflag & DRAW_PICKING)
1606                         glLoadName(base->selcol + (tracknr << 16));
1607
1608                 glPushMatrix();
1609                 glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
1610                 glScalef(v3d->bundle_size / 0.05f, v3d->bundle_size / 0.05f, v3d->bundle_size / 0.05f);
1611
1612                 if (v3d->drawtype == OB_WIRE) {
1613                         glDisable(GL_LIGHTING);
1614
1615                         if (selected) {
1616                                 if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1617                                 else UI_ThemeColor(TH_SELECT);
1618                         }
1619                         else {
1620                                 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1621                                 else UI_ThemeColor(TH_WIRE);
1622                         }
1623
1624                         drawaxes(0.05f, v3d->bundle_drawtype);
1625
1626                         glEnable(GL_LIGHTING);
1627                 }
1628                 else if (v3d->drawtype > OB_WIRE) {
1629                         if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
1630                                 /* selection outline */
1631                                 if (selected) {
1632                                         if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1633                                         else UI_ThemeColor(TH_SELECT);
1634
1635                                         glLineWidth(2.f);
1636                                         glDisable(GL_LIGHTING);
1637                                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1638
1639                                         draw_bundle_sphere();
1640
1641                                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1642                                         glEnable(GL_LIGHTING);
1643                                         glLineWidth(1.f);
1644                                 }
1645
1646                                 if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1647                                 else UI_ThemeColor(TH_BUNDLE_SOLID);
1648
1649                                 draw_bundle_sphere();
1650                         }
1651                         else {
1652                                 glDisable(GL_LIGHTING);
1653
1654                                 if (selected) {
1655                                         if (base == BASACT) UI_ThemeColor(TH_ACTIVE);
1656                                         else UI_ThemeColor(TH_SELECT);
1657                                 }
1658                                 else {
1659                                         if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
1660                                         else UI_ThemeColor(TH_WIRE);
1661                                 }
1662
1663                                 drawaxes(0.05f, v3d->bundle_drawtype);
1664
1665                                 glEnable(GL_LIGHTING);
1666                         }
1667                 }
1668
1669                 glPopMatrix();
1670
1671                 if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
1672                         float pos[3];
1673                         unsigned char tcol[4];
1674
1675                         if (selected) memcpy(tcol, scol, sizeof(tcol));
1676                         else memcpy(tcol, col, sizeof(tcol));
1677
1678                         mul_v3_m4v3(pos, mat, track->bundle_pos);
1679                         view3d_cached_text_draw_add(pos, track->name, 10, V3D_CACHE_TEXT_GLOBALSPACE, tcol);
1680                 }
1681
1682                 tracknr++;
1683         }
1684
1685         if ((dflag & DRAW_PICKING) == 0) {
1686                 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
1687                         MovieTrackingReconstruction *reconstruction;
1688                         reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
1689
1690                         if (reconstruction->camnr) {
1691                                 MovieReconstructedCamera *camera = reconstruction->cameras;
1692                                 int a = 0;
1693
1694                                 glDisable(GL_LIGHTING);
1695                                 UI_ThemeColor(TH_CAMERA_PATH);
1696                                 glLineWidth(2.0f);
1697
1698                                 glBegin(GL_LINE_STRIP);
1699                                 for (a = 0; a < reconstruction->camnr; a++, camera++) {
1700                                         glVertex3fv(camera->mat[3]);
1701                                 }
1702                                 glEnd();
1703
1704                                 glLineWidth(1.0f);
1705                                 glEnable(GL_LIGHTING);
1706                         }
1707                 }
1708         }
1709
1710         glPopMatrix();
1711
1712         *global_track_index = tracknr;
1713 }
1714
1715 static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip,
1716                                          const short dflag, const unsigned char ob_wire_col[4],
1717                                          int draw_selected)
1718 {
1719         MovieTracking *tracking = &clip->tracking;
1720         MovieTrackingObject *tracking_object;
1721         int global_track_index = 1;
1722
1723         if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
1724                 return;
1725
1726         if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1727                 return;
1728
1729         glEnable(GL_LIGHTING);
1730         glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1731         glEnable(GL_COLOR_MATERIAL);
1732         glShadeModel(GL_SMOOTH);
1733
1734         tracking_object = tracking->objects.first;
1735         while (tracking_object) {
1736                 draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
1737                                                     dflag, &global_track_index, draw_selected);
1738
1739                 tracking_object = tracking_object->next;
1740         }
1741
1742         /* restore */
1743         glShadeModel(GL_FLAT);
1744         glDisable(GL_COLOR_MATERIAL);
1745         glDisable(GL_LIGHTING);
1746
1747         if ((dflag & DRAW_CONSTCOLOR) == 0) {
1748                 glColor3ubv(ob_wire_col);
1749         }
1750
1751         if (dflag & DRAW_PICKING)
1752                 glLoadName(base->selcol);
1753 }
1754
1755 /* flag similar to draw_object() */
1756 static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
1757                        const short dflag, const unsigned char ob_wire_col[4])
1758 {
1759         /* a standing up pyramid with (0,0,0) as top */
1760         Camera *cam;
1761         Object *ob = base->object;
1762         float tvec[3];
1763         float vec[4][3], asp[2], shift[2], scale[3];
1764         int i;
1765         float drawsize;
1766         const short is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
1767         MovieClip *clip = BKE_object_movieclip_get(scene, base->object, 0);
1768
1769         /* draw data for movie clip set as active for scene */
1770         if (clip) {
1771                 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, FALSE);
1772                 draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, TRUE);
1773         }
1774
1775 #ifdef VIEW3D_CAMERA_BORDER_HACK
1776         if (is_view && !(G.f & G_PICKSEL)) {
1777                 if ((dflag & DRAW_CONSTCOLOR) == 0) {
1778                         view3d_camera_border_hack_col[0] = ob_wire_col[0];
1779                         view3d_camera_border_hack_col[1] = ob_wire_col[1];
1780                         view3d_camera_border_hack_col[2] = ob_wire_col[2];
1781                 }
1782                 else {
1783                         float col[4];
1784                         glGetFloatv(GL_CURRENT_COLOR, col);
1785                         rgb_float_to_uchar(view3d_camera_border_hack_col, col);
1786                 }
1787                 view3d_camera_border_hack_test = TRUE;
1788                 return;
1789         }
1790 #endif
1791
1792         cam = ob->data;
1793
1794         scale[0] = 1.0f / len_v3(ob->obmat[0]);
1795         scale[1] = 1.0f / len_v3(ob->obmat[1]);
1796         scale[2] = 1.0f / len_v3(ob->obmat[2]);
1797
1798         BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
1799                                  asp, shift, &drawsize, vec);
1800
1801         glDisable(GL_LIGHTING);
1802         glDisable(GL_CULL_FACE);
1803
1804         /* camera frame */
1805         glBegin(GL_LINE_LOOP);
1806         glVertex3fv(vec[0]);
1807         glVertex3fv(vec[1]);
1808         glVertex3fv(vec[2]);
1809         glVertex3fv(vec[3]);
1810         glEnd();
1811
1812         if (is_view)
1813                 return;
1814
1815         zero_v3(tvec);
1816
1817         /* center point to camera frame */
1818         glBegin(GL_LINE_STRIP);
1819         glVertex3fv(vec[1]);
1820         glVertex3fv(tvec);
1821         glVertex3fv(vec[0]);
1822         glVertex3fv(vec[3]);
1823         glVertex3fv(tvec);
1824         glVertex3fv(vec[2]);
1825         glEnd();
1826
1827
1828         /* arrow on top */
1829         tvec[2] = vec[1][2]; /* copy the depth */
1830
1831
1832         /* draw an outline arrow for inactive cameras and filled
1833          * for active cameras. We actually draw both outline+filled
1834          * for active cameras so the wire can be seen side-on */
1835         for (i = 0; i < 2; i++) {
1836                 if (i == 0) glBegin(GL_LINE_LOOP);
1837                 else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
1838                 else break;
1839
1840                 tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
1841                 tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
1842                 glVertex3fv(tvec); /* left */
1843                 
1844                 tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
1845                 glVertex3fv(tvec); /* right */
1846                 
1847                 tvec[0] = shift[0];
1848                 tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
1849                 glVertex3fv(tvec); /* top */
1850
1851                 glEnd();
1852         }
1853
1854         if (dflag == 0) {
1855                 if (cam->flag & (CAM_SHOWLIMITS + CAM_SHOWMIST)) {
1856                         float nobmat[4][4];
1857                         World *wrld;
1858
1859                         /* draw in normalized object matrix space */
1860                         copy_m4_m4(nobmat, ob->obmat);
1861                         normalize_m4(nobmat);
1862
1863                         glPushMatrix();
1864                         glLoadMatrixf(rv3d->viewmat);
1865                         glMultMatrixf(nobmat);
1866
1867                         if (cam->flag & CAM_SHOWLIMITS) {
1868                                 draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
1869                                 /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
1870                                 draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
1871                         }
1872
1873                         wrld = scene->world;
1874                         if (cam->flag & CAM_SHOWMIST)
1875                                 if (wrld) draw_limit_line(wrld->miststa, wrld->miststa + wrld->mistdist, 0xFFFFFF);
1876
1877                         glPopMatrix();
1878                 }
1879         }
1880 }
1881
1882 /* flag similar to draw_object() */
1883 static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
1884                         Object *UNUSED(ob), int UNUSED(flag))
1885 {
1886         //Speaker *spk = ob->data;
1887
1888         float vec[3];
1889         int i, j;
1890
1891         glEnable(GL_BLEND);
1892
1893         for (j = 0; j < 3; j++) {
1894                 vec[2] = 0.25f * j - 0.125f;
1895
1896                 glBegin(GL_LINE_LOOP);
1897                 for (i = 0; i < 16; i++) {
1898                         vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1899                         vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
1900                         glVertex3fv(vec);
1901                 }
1902                 glEnd();
1903         }
1904
1905         for (j = 0; j < 4; j++) {
1906                 vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
1907                 vec[1] = ((j % 2) * (j - 2)) * 0.5f;
1908                 glBegin(GL_LINE_STRIP);
1909                 for (i = 0; i < 3; i++) {
1910                         if (i == 1) {
1911                                 vec[0] *= 0.5f;
1912                                 vec[1] *= 0.5f;
1913                         }
1914
1915                         vec[2] = 0.25f * i - 0.125f;
1916                         glVertex3fv(vec);
1917                 }
1918                 glEnd();
1919         }
1920
1921         glDisable(GL_BLEND);
1922 }
1923
1924 static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
1925 {
1926         BPoint *bp = lt->def;
1927         float *co = dl ? dl->verts : NULL;
1928         int u, v, w;
1929
1930         UI_ThemeColor(sel ? TH_VERTEX_SELECT : TH_VERTEX);
1931         glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
1932         bglBegin(GL_POINTS);
1933
1934         for (w = 0; w < lt->pntsw; w++) {
1935                 int wxt = (w == 0 || w == lt->pntsw - 1);
1936                 for (v = 0; v < lt->pntsv; v++) {
1937                         int vxt = (v == 0 || v == lt->pntsv - 1);
1938                         for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
1939                                 int uxt = (u == 0 || u == lt->pntsu - 1);
1940                                 if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
1941                                         if (bp->hide == 0) {
1942                                                 if ((bp->f1 & SELECT) == sel) {
1943                                                         bglVertex3fv(dl ? co : bp->vec);
1944                                                 }
1945                                         }
1946                                 }
1947                         }
1948                 }
1949         }
1950         
1951         glPointSize(1.0);
1952         bglEnd();
1953 }
1954
1955 void lattice_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BPoint *bp, int x, int y), void *userData)
1956 {
1957         Object *obedit = vc->obedit;
1958         Lattice *lt = obedit->data;
1959         BPoint *bp = lt->editlatt->latt->def;
1960         DispList *dl = BKE_displist_find(&obedit->disp, DL_VERTS);
1961         float *co = dl ? dl->verts : NULL;
1962         int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
1963         short s[2] = {IS_CLIPPED, 0};
1964
1965         ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */
1966
1967         for (i = 0; i < N; i++, bp++, co += 3) {
1968                 if (bp->hide == 0) {
1969                         view3d_project_short_clip(vc->ar, dl ? co : bp->vec, s, TRUE);
1970                         if (s[0] != IS_CLIPPED)
1971                                 func(userData, bp, s[0], s[1]);
1972                 }
1973         }
1974 }
1975
1976 static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
1977 {
1978         int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
1979
1980         if (use_wcol) {
1981                 float col[3];
1982                 MDeformWeight *mdw = defvert_find_index(lt->dvert + index, use_wcol - 1);
1983                 
1984                 weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
1985                 glColor3fv(col);
1986
1987         }
1988         
1989         if (dl) {
1990                 glVertex3fv(&dl->verts[index * 3]);
1991         }
1992         else {
1993                 glVertex3fv(lt->def[index].vec);
1994         }
1995 }
1996
1997 /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
1998 static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
1999 {
2000         Lattice *lt = ob->data;
2001         DispList *dl;
2002         int u, v, w;
2003         int use_wcol = FALSE, is_edit = (lt->editlatt != NULL);
2004
2005         /* now we default make displist, this will modifiers work for non animated case */
2006         if (ob->disp.first == NULL)
2007                 BKE_lattice_modifiers_calc(scene, ob);
2008         dl = BKE_displist_find(&ob->disp, DL_VERTS);
2009         
2010         if (is_edit) {
2011                 lt = lt->editlatt->latt;
2012
2013                 cpack(0x004000);
2014                 
2015                 if (ob->defbase.first && lt->dvert) {
2016                         use_wcol = ob->actdef;
2017                         glShadeModel(GL_SMOOTH);
2018                 }
2019         }
2020         
2021         glBegin(GL_LINES);
2022         for (w = 0; w < lt->pntsw; w++) {
2023                 int wxt = (w == 0 || w == lt->pntsw - 1);
2024                 for (v = 0; v < lt->pntsv; v++) {
2025                         int vxt = (v == 0 || v == lt->pntsv - 1);
2026                         for (u = 0; u < lt->pntsu; u++) {
2027                                 int uxt = (u == 0 || u == lt->pntsu - 1);
2028
2029                                 if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
2030                                         drawlattice__point(lt, dl, u, v, w - 1, use_wcol);
2031                                         drawlattice__point(lt, dl, u, v, w, use_wcol);
2032                                 }
2033                                 if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2034                                         drawlattice__point(lt, dl, u, v - 1, w, use_wcol);
2035                                         drawlattice__point(lt, dl, u, v, w, use_wcol);
2036                                 }
2037                                 if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
2038                                         drawlattice__point(lt, dl, u - 1, v, w, use_wcol);
2039                                         drawlattice__point(lt, dl, u, v, w, use_wcol);
2040                                 }
2041                         }
2042                 }
2043         }
2044         glEnd();
2045         
2046         /* restoration for weight colors */
2047         if (use_wcol)
2048                 glShadeModel(GL_FLAT);
2049
2050         if (is_edit) {
2051                 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2052                 
2053                 lattice_draw_verts(lt, dl, 0);
2054                 lattice_draw_verts(lt, dl, 1);
2055                 
2056                 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2057         }
2058 }
2059
2060 /* ***************** ******************** */
2061
2062 /* Note! - foreach funcs should be called while drawing or directly after
2063  * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
2064  * but would not give correct results with dupli's for eg. which don't
2065  * use the object matrix in the usual way */
2066 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3],
2067                                             const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2068 {
2069         foreachScreenVert_userData *data = userData;
2070         BMVert *eve = EDBM_vert_at_index(data->vc.em, index);
2071
2072         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2073                 short s[2] = {IS_CLIPPED, 0};
2074
2075                 if (data->clipVerts != V3D_CLIP_TEST_OFF) {
2076                         view3d_project_short_clip(data->vc.ar, co, s, TRUE);
2077                 }
2078                 else {
2079                         float co2[2];
2080                         mul_v3_m4v3(co2, data->vc.obedit->obmat, co);
2081                         project_short_noclip(data->vc.ar, co2, s);
2082                 }
2083
2084                 if (s[0] != IS_CLIPPED)
2085                         data->func(data->userData, eve, s[0], s[1], index);
2086         }
2087 }
2088
2089 void mesh_foreachScreenVert(
2090         ViewContext *vc,
2091         void (*func)(void *userData, BMVert *eve, int x, int y, int index),
2092         void *userData, eV3DClipTest clipVerts)
2093 {
2094         foreachScreenVert_userData data;
2095         DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2096         
2097         data.vc = *vc;
2098         data.func = func;
2099         data.userData = userData;
2100         data.clipVerts = clipVerts;
2101
2102         if (clipVerts != V3D_CLIP_TEST_OFF)
2103                 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat);  /* for local clipping lookups */
2104
2105         EDBM_index_arrays_init(vc->em, 1, 0, 0);
2106         dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
2107         EDBM_index_arrays_free(vc->em);
2108
2109         dm->release(dm);
2110 }
2111
2112 /*  draw callback */
2113 static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
2114                                           const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2115 {
2116         MVert *mv = &((MVert *)userData)[index];
2117
2118         if (!(mv->flag & ME_HIDE)) {
2119                 const char sel = mv->flag & SELECT;
2120
2121                 /* TODO define selected color */
2122                 if (sel) {
2123                         glColor3f(1.0f, 1.0f, 0.0f);
2124                 }
2125                 else {
2126                         glColor3f(0.0f, 0.0f, 0.0f);
2127                 }
2128
2129                 glVertex3fv(co);
2130         }
2131 }
2132
2133 static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
2134 {
2135         glBegin(GL_POINTS);
2136         dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, me->mvert);
2137         glEnd();
2138 }
2139
2140 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const float v0co[3], const float v1co[3])
2141 {
2142         foreachScreenEdge_userData *data = userData;
2143         BMEdge *eed = EDBM_edge_at_index(data->vc.em, index);
2144
2145         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2146                 short s[2][2];
2147
2148                 if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) {
2149                         view3d_project_short_clip(data->vc.ar, v0co, s[0], TRUE);
2150                         view3d_project_short_clip(data->vc.ar, v1co, s[1], TRUE);
2151                 }
2152                 else {
2153                         float v1_co[3], v2_co[3];
2154
2155                         mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co);
2156                         mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co);
2157
2158                         project_short_noclip(data->vc.ar, v1_co, s[0]);
2159                         project_short_noclip(data->vc.ar, v2_co, s[1]);
2160
2161                         if (data->clipVerts == V3D_CLIP_TEST_REGION) {
2162                                 /* make an int copy */
2163                                 int s_int[2][2] = {{s[0][0], s[0][1]},
2164                                                    {s[1][0], s[1][1]}};
2165                                 if (!BLI_rcti_isect_segment(&data->win_rect, s_int[0], s_int[1])) {
2166                                         return;
2167                                 }
2168                         }
2169                 }
2170
2171                 data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index);
2172         }
2173 }
2174
2175 void mesh_foreachScreenEdge(
2176         ViewContext *vc,
2177         void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index),
2178         void *userData, eV3DClipTest clipVerts)
2179 {
2180         foreachScreenEdge_userData data;
2181         DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2182
2183         data.vc = *vc;
2184
2185         data.win_rect.xmin = 0;
2186         data.win_rect.ymin = 0;
2187         data.win_rect.xmax = vc->ar->winx;
2188         data.win_rect.ymax = vc->ar->winy;
2189
2190         data.func = func;
2191         data.userData = userData;
2192         data.clipVerts = clipVerts;
2193
2194         if (clipVerts != V3D_CLIP_TEST_OFF)
2195                 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat);  /* for local clipping lookups */
2196
2197         EDBM_index_arrays_init(vc->em, 0, 1, 0);
2198         dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
2199         EDBM_index_arrays_free(vc->em);
2200
2201         dm->release(dm);
2202 }
2203
2204 static void mesh_foreachScreenFace__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2205 {
2206         foreachScreenFace_userData *data = userData;
2207         BMFace *efa = EDBM_face_at_index(data->vc.em, index);
2208
2209         if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2210                 float cent2[3];
2211                 short s[2];
2212
2213                 mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent);
2214                 project_short(data->vc.ar, cent2, s);
2215
2216                 if (s[0] != IS_CLIPPED) {
2217                         data->func(data->userData, efa, s[0], s[1], index);
2218                 }
2219         }
2220 }
2221
2222 void mesh_foreachScreenFace(
2223         ViewContext *vc,
2224         void (*func)(void *userData, BMFace *efa, int x, int y, int index),
2225         void *userData)
2226 {
2227         foreachScreenFace_userData data;
2228         DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
2229
2230         data.vc = *vc;
2231         data.func = func;
2232         data.userData = userData;
2233
2234         //if (clipVerts)
2235         ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2236
2237         EDBM_index_arrays_init(vc->em, 0, 0, 1);
2238         dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
2239         EDBM_index_arrays_free(vc->em);
2240
2241         dm->release(dm);
2242 }
2243
2244 void nurbs_foreachScreenVert(
2245     ViewContext *vc,
2246     void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y),
2247     void *userData)
2248 {
2249         Curve *cu = vc->obedit->data;
2250         short s[2] = {IS_CLIPPED, 0};
2251         Nurb *nu;
2252         int i;
2253         ListBase *nurbs = BKE_curve_editNurbs_get(cu);
2254
2255         ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
2256
2257         for (nu = nurbs->first; nu; nu = nu->next) {
2258                 if (nu->type == CU_BEZIER) {
2259                         for (i = 0; i < nu->pntsu; i++) {
2260                                 BezTriple *bezt = &nu->bezt[i];
2261
2262                                 if (bezt->hide == 0) {
2263                                         
2264                                         if (cu->drawflag & CU_HIDE_HANDLES) {
2265                                                 view3d_project_short_clip(vc->ar, bezt->vec[1], s, TRUE);
2266                                                 if (s[0] != IS_CLIPPED)
2267                                                         func(userData, nu, NULL, bezt, 1, s[0], s[1]);
2268                                         }
2269                                         else {
2270                                                 view3d_project_short_clip(vc->ar, bezt->vec[0], s, TRUE);
2271                                                 if (s[0] != IS_CLIPPED)
2272                                                         func(userData, nu, NULL, bezt, 0, s[0], s[1]);
2273                                                 view3d_project_short_clip(vc->ar, bezt->vec[1], s, TRUE);
2274                                                 if (s[0] != IS_CLIPPED)
2275                                                         func(userData, nu, NULL, bezt, 1, s[0], s[1]);
2276                                                 view3d_project_short_clip(vc->ar, bezt->vec[2], s, TRUE);
2277                                                 if (s[0] != IS_CLIPPED)
2278                                                         func(userData, nu, NULL, bezt, 2, s[0], s[1]);
2279                                         }
2280                                 }
2281                         }
2282                 }
2283                 else {
2284                         for (i = 0; i < nu->pntsu * nu->pntsv; i++) {
2285                                 BPoint *bp = &nu->bp[i];
2286
2287                                 if (bp->hide == 0) {
2288                                         view3d_project_short_clip(vc->ar, bp->vec, s, TRUE);
2289                                         if (s[0] != IS_CLIPPED)
2290                                                 func(userData, nu, bp, NULL, -1, s[0], s[1]);
2291                                 }
2292                         }
2293                 }
2294         }
2295 }
2296
2297 /* ************** DRAW MESH ****************** */
2298
2299 /* First section is all the "simple" draw routines, 
2300  * ones that just pass some sort of primitive to GL,
2301  * with perhaps various options to control lighting,
2302  * color, etc.
2303  *
2304  * These routines should not have user interface related
2305  * logic!!!
2306  */
2307
2308 static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
2309 {
2310         float obmat[3][3];
2311
2312         copy_m3_m4(obmat, ob->obmat);
2313
2314         data->uniform_scale = is_uniform_scaled_m3(obmat);
2315
2316         if (!data->uniform_scale) {
2317                 /* inverted matrix */
2318                 invert_m3_m3(data->imat, obmat);
2319
2320                 /* transposed inverted matrix */
2321                 copy_m3_m3(data->tmat, data->imat);
2322                 transpose_m3(data->tmat);
2323         }
2324 }
2325
2326 static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
2327 {
2328         drawDMNormal_userData *data = userData;
2329         BMFace *efa = EDBM_face_at_index(data->em, index);
2330         float n[3];
2331
2332         if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2333                 if (!data->uniform_scale) {
2334                         mul_v3_m3v3(n, data->tmat, (float *) no);
2335                         normalize_v3(n);
2336                         mul_m3_v3(data->imat, n);
2337                 }
2338                 else {
2339                         copy_v3_v3(n, no);
2340                 }
2341
2342                 glVertex3fv(cent);
2343                 glVertex3f(cent[0] + n[0] * data->normalsize,
2344                            cent[1] + n[1] * data->normalsize,
2345                            cent[2] + n[2] * data->normalsize);
2346         }
2347 }
2348
2349 static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2350 {
2351         drawDMNormal_userData data;
2352
2353         data.em = em;
2354         data.normalsize = scene->toolsettings->normalsize;
2355
2356         calcDrawDMNormalScale(ob, &data);
2357
2358         glBegin(GL_LINES);
2359         dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data);
2360         glEnd();
2361 }
2362
2363 static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
2364 {
2365         BMFace *efa = EDBM_face_at_index(((void **)userData)[0], index);
2366         int sel = *(((int **)userData)[1]);
2367         
2368         if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT) == sel) {
2369                 bglVertex3fv(cent);
2370         }
2371 }
2372 static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel)
2373 {
2374         void *ptrs[2] = {em, &sel};
2375
2376         bglBegin(GL_POINTS);
2377         dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs);
2378         bglEnd();
2379 }
2380
2381 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])
2382 {
2383         drawDMNormal_userData *data = userData;
2384         BMVert *eve = EDBM_vert_at_index(data->em, index);
2385
2386         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2387                 float no[3], n[3];
2388
2389                 if (no_f) {
2390                         copy_v3_v3(no, no_f);
2391                 }
2392                 else {
2393                         no[0] = no_s[0] / 32767.0f;
2394                         no[1] = no_s[1] / 32767.0f;
2395                         no[2] = no_s[2] / 32767.0f;
2396                 }
2397
2398                 if (!data->uniform_scale) {
2399                         mul_v3_m3v3(n, data->tmat, (float *) no);
2400                         normalize_v3(n);
2401                         mul_m3_v3(data->imat, n);
2402                 }
2403                 else {
2404                         copy_v3_v3(n, no);
2405                 }
2406
2407                 glVertex3fv(co);
2408                 glVertex3f(co[0] + n[0] * data->normalsize,
2409                            co[1] + n[1] * data->normalsize,
2410                            co[2] + n[2] * data->normalsize);
2411         }
2412 }
2413
2414 static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
2415 {
2416         drawDMNormal_userData data;
2417
2418         data.em = em;
2419         data.normalsize = scene->toolsettings->normalsize;
2420
2421         calcDrawDMNormalScale(ob, &data);
2422
2423         glBegin(GL_LINES);
2424         dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data);
2425         glEnd();
2426 }
2427
2428 /* Draw verts with color set based on selection */
2429 static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
2430                                    const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2431 {
2432         drawDMVerts_userData *data = userData;
2433         BMVert *eve = EDBM_vert_at_index(data->em, index);
2434
2435         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
2436                 /* skin nodes: draw a red circle around the root
2437                  * node(s) */
2438                 if (data->has_vskin) {
2439                         const MVertSkin *vs = CustomData_bmesh_get(&data->em->bm->vdata,
2440                                                                    eve->head.data,
2441                                                                    CD_MVERT_SKIN);
2442                         if (vs->flag & MVERT_SKIN_ROOT) {
2443                                 float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
2444                                 bglEnd();
2445                         
2446                                 glColor4ubv(data->th_skin_root);
2447                                 drawcircball(GL_LINES, co, radius, data->imat);
2448
2449                                 glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2450                                 bglBegin(GL_POINTS);
2451                         }
2452                 }
2453
2454                 /* draw active larger - need to stop/start point drawing for this :/ */
2455                 if (eve == data->eve_act) {
2456                         glColor4ubv(data->th_editmesh_active);
2457                         
2458                         bglEnd();
2459                         
2460                         glPointSize(data->th_vertex_size);
2461                         bglBegin(GL_POINTS);
2462                         bglVertex3fv(co);
2463                         bglEnd();
2464
2465                         glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
2466                         glPointSize(data->th_vertex_size);
2467                         bglBegin(GL_POINTS);
2468                 }
2469                 else {
2470                         bglVertex3fv(co);
2471                 }
2472         }
2473 }
2474
2475 static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act,
2476                           RegionView3D *rv3d)
2477 {
2478         drawDMVerts_userData data;
2479         data.sel = sel;
2480         data.eve_act = eve_act;
2481         data.em = em;
2482
2483         /* Cache theme values */
2484         UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
2485         UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
2486         UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
2487         UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
2488         data.th_vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2489
2490         /* For skin root drawing */
2491         data.has_vskin = CustomData_has_layer(&em->bm->vdata, CD_MVERT_SKIN);
2492         /* view-aligned matrix */
2493         mult_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
2494         invert_m4(data.imat);
2495
2496         bglBegin(GL_POINTS);
2497         dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
2498         bglEnd();
2499 }
2500
2501 /* Draw edges with color set based on selection */
2502 static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
2503 {
2504         BMEdge *eed;
2505         //unsigned char **cols = userData, *col;
2506         drawDMEdgesSel_userData *data = userData;
2507         unsigned char *col;
2508
2509         eed = EDBM_edge_at_index(data->em, index);
2510
2511         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2512                 if (eed == data->eed_act) {
2513                         glColor4ubv(data->actCol);
2514                 }
2515                 else {
2516                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2517                                 col = data->selCol;
2518                         }
2519                         else {
2520                                 col = data->baseCol;
2521                         }
2522                         /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode  */
2523                         if (col[3] == 0)
2524                                 return DM_DRAW_OPTION_SKIP;
2525                         
2526                         glColor4ubv(col);
2527                 }
2528                 return DM_DRAW_OPTION_NORMAL;
2529         }
2530         else {
2531                 return DM_DRAW_OPTION_SKIP;
2532         }
2533 }
2534 static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, 
2535                               unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
2536 {
2537         drawDMEdgesSel_userData data;
2538         
2539         data.baseCol = baseCol;
2540         data.selCol = selCol;
2541         data.actCol = actCol;
2542         data.em = em;
2543         data.eed_act = eed_act;
2544         dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
2545 }
2546
2547 /* Draw edges */
2548 static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
2549 {
2550         if (BM_elem_flag_test(EDBM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
2551                 return DM_DRAW_OPTION_SKIP;
2552         else
2553                 return DM_DRAW_OPTION_NORMAL;
2554 }
2555
2556 static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm) 
2557 {
2558         dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
2559 }
2560
2561 /* Draw edges with color interpolated based on selection */
2562 static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
2563 {
2564         if (BM_elem_flag_test(EDBM_edge_at_index(((void **)userData)[0], index), BM_ELEM_HIDDEN))
2565                 return DM_DRAW_OPTION_SKIP;
2566         else
2567                 return DM_DRAW_OPTION_NORMAL;
2568 }
2569 static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
2570 {
2571         BMEdge *eed = EDBM_edge_at_index(((void **)userData)[0], index);
2572         unsigned char **cols = userData;
2573         unsigned char *col0 = cols[(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1];
2574         unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1];
2575
2576         glColor4ub(col0[0] + (col1[0] - col0[0]) * t,
2577                    col0[1] + (col1[1] - col0[1]) * t,
2578                    col0[2] + (col1[2] - col0[2]) * t,
2579                    col0[3] + (col1[3] - col0[3]) * t);
2580 }
2581
2582 static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
2583 {
2584         void *cols[3] = {em, baseCol, selCol};
2585
2586         dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
2587 }
2588
2589 /* Draw only seam edges */
2590 static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
2591 {
2592         BMEdge *eed = EDBM_edge_at_index(userData, index);
2593
2594         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
2595                 return DM_DRAW_OPTION_NORMAL;
2596         else
2597                 return DM_DRAW_OPTION_SKIP;
2598 }
2599
2600 static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
2601 {
2602         dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
2603 }
2604
2605 /* Draw only sharp edges */
2606 static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
2607 {
2608         BMEdge *eed = EDBM_edge_at_index(userData, index);
2609
2610         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
2611                 return DM_DRAW_OPTION_NORMAL;
2612         else
2613                 return DM_DRAW_OPTION_SKIP;
2614 }
2615
2616 static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
2617 {
2618         dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
2619 }
2620
2621
2622 /* Draw faces with color set based on selection
2623  * return 2 for the active face so it renders with stipple enabled */
2624 static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
2625 {
2626         drawDMFacesSel_userData *data = userData;
2627         BMFace *efa = EDBM_face_at_index(data->em, index);
2628         unsigned char *col;
2629         
2630         if (!efa)
2631                 return DM_DRAW_OPTION_SKIP;
2632         
2633         if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2634                 if (efa == data->efa_act) {
2635                         glColor4ubv(data->cols[2]);
2636                         return DM_DRAW_OPTION_STIPPLE;
2637                 }
2638                 else {
2639                         col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2640                         if (col[3] == 0)
2641                                 return DM_DRAW_OPTION_SKIP;
2642                         glColor4ubv(col);
2643                         return DM_DRAW_OPTION_NORMAL;
2644                 }
2645         }
2646         return DM_DRAW_OPTION_SKIP;
2647 }
2648
2649 static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
2650 {
2651
2652         drawDMFacesSel_userData *data = userData;
2653         BMFace *efa;
2654         BMFace *next_efa;
2655
2656         unsigned char *col, *next_col;
2657
2658         if (!data->orig_index)
2659                 return 0;
2660
2661         efa = EDBM_face_at_index(data->em, data->orig_index[index]);
2662         next_efa = EDBM_face_at_index(data->em, data->orig_index[next_index]);
2663
2664         if (efa == next_efa)
2665                 return 1;
2666
2667         if (efa == data->efa_act || next_efa == data->efa_act)
2668                 return 0;
2669
2670         col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
2671         next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
2672
2673         if (col[3] == 0 || next_col[3] == 0)
2674                 return 0;
2675
2676         return col == next_col;
2677 }
2678
2679 /* also draws the active face */
2680 static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, 
2681                               unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
2682 {
2683         drawDMFacesSel_userData data;
2684         data.dm = dm;
2685         data.cols[0] = baseCol;
2686         data.em = em;
2687         data.cols[1] = selCol;
2688         data.cols[2] = actCol;
2689         data.efa_act = efa_act;
2690         data.orig_index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
2691
2692         dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
2693 }
2694
2695 static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
2696 {
2697         BMEditMesh *em = userData;
2698         BMEdge *eed = EDBM_edge_at_index(userData, index);
2699         float *crease = eed ? (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE) : NULL;
2700         
2701         if (!crease)
2702                 return DM_DRAW_OPTION_SKIP;
2703         
2704         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *crease != 0.0f) {
2705                 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, *crease);
2706                 return DM_DRAW_OPTION_NORMAL;
2707         }
2708         else {
2709                 return DM_DRAW_OPTION_SKIP;
2710         }
2711 }
2712 static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
2713 {
2714         glLineWidth(3.0);
2715         dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em);
2716         glLineWidth(1.0);
2717 }
2718
2719 static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
2720 {
2721         BMEditMesh *em = userData;
2722         BMEdge *eed = EDBM_edge_at_index(userData, index);
2723         float *bweight = (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
2724
2725         if (!bweight)
2726                 return DM_DRAW_OPTION_SKIP;
2727         
2728         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *bweight != 0.0f) {
2729                 UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, *bweight);
2730                 return DM_DRAW_OPTION_NORMAL;
2731         }
2732         else {
2733                 return DM_DRAW_OPTION_SKIP;
2734         }
2735 }
2736 static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
2737                                       const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2738 {
2739         BMEditMesh *em = userData;
2740         BMVert *eve = EDBM_vert_at_index(userData, index);
2741         float *bweight = (float *)CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_BWEIGHT);
2742         
2743         if (!bweight)
2744                 return;
2745         
2746         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && *bweight != 0.0f) {
2747                 UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, *bweight);
2748                 bglVertex3fv(co);
2749         }
2750 }
2751 static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
2752 {
2753         ToolSettings *ts = scene->toolsettings;
2754
2755         if (ts->selectmode & SCE_SELECT_VERTEX) {
2756                 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
2757                 bglBegin(GL_POINTS);
2758                 dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em);
2759                 bglEnd();
2760         }
2761         else {
2762                 glLineWidth(3.0);
2763                 dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em);
2764                 glLineWidth(1.0);
2765         }
2766 }
2767
2768 /* Second section of routines: Combine first sets to form fancy
2769  * drawing routines (for example rendering twice to get overlays).
2770  *
2771  * Also includes routines that are basic drawing but are too
2772  * specialized to be split out (like drawing creases or measurements).
2773  */
2774
2775 /* EditMesh drawing routines*/
2776
2777 static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, 
2778                                 BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act,
2779                                                                 RegionView3D *rv3d)
2780 {
2781         ToolSettings *ts = scene->toolsettings;
2782         int sel;
2783
2784         if (v3d->zbuf) glDepthMask(0);  /* disable write in zbuffer, zbuf select */
2785
2786         for (sel = 0; sel < 2; sel++) {
2787                 unsigned char col[4], fcol[4];
2788                 int pass;
2789
2790                 UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
2791                 UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE, fcol);
2792
2793                 for (pass = 0; pass < 2; pass++) {
2794                         float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
2795                         float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
2796
2797                         if (pass == 0) {
2798                                 if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
2799                                         glDisable(GL_DEPTH_TEST);
2800
2801                                         glEnable(GL_BLEND);
2802                                 }
2803                                 else {
2804                                         continue;
2805                                 }
2806
2807                                 size = (size > 2.1f ? size / 2.0f : size);
2808                                 fsize = (fsize > 2.1f ? fsize / 2.0f : fsize);
2809                                 col[3] = fcol[3] = 100;
2810                         }
2811                         else {
2812                                 col[3] = fcol[3] = 255;
2813                         }
2814
2815                         if (ts->selectmode & SCE_SELECT_VERTEX) {
2816                                 glPointSize(size);
2817                                 glColor4ubv(col);
2818                                 draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
2819                         }
2820                         
2821                         if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
2822                                 glPointSize(fsize);
2823                                 glColor4ubv(fcol);
2824                                 draw_dm_face_centers(em, cageDM, sel);
2825                         }
2826                         
2827                         if (pass == 0) {
2828                                 glDisable(GL_BLEND);
2829                                 glEnable(GL_DEPTH_TEST);
2830                         }
2831                 }
2832         }
2833
2834         if (v3d->zbuf) glDepthMask(1);
2835         glPointSize(1.0);
2836 }
2837
2838 static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
2839                                 Mesh *me, DerivedMesh *cageDM, short sel_only,
2840                                 BMEdge *eed_act)
2841 {
2842         ToolSettings *ts = scene->toolsettings;
2843         int pass;
2844         unsigned char wireCol[4], selCol[4], actCol[4];
2845
2846         /* since this function does transparant... */
2847         UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
2848         UI_GetThemeColor4ubv(TH_WIRE, wireCol);
2849         UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
2850         
2851         /* when sel only is used, don't render wire, only selected, this is used for
2852          * textured draw mode when the 'edges' option is disabled */
2853         if (sel_only)
2854                 wireCol[3] = 0;
2855
2856         for (pass = 0; pass < 2; pass++) {
2857                 /* show wires in transparant when no zbuf clipping for select */
2858                 if (pass == 0) {
2859                         if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) {
2860                                 glEnable(GL_BLEND);
2861                                 glDisable(GL_DEPTH_TEST);
2862                                 selCol[3] = 85;
2863                                 if (!sel_only) wireCol[3] = 85;
2864                         }
2865                         else {
2866                                 continue;
2867                         }
2868                 }
2869                 else {
2870                         selCol[3] = 255;
2871                         if (!sel_only) wireCol[3] = 255;
2872                 }
2873
2874                 if (ts->selectmode == SCE_SELECT_FACE) {
2875                         draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2876                 }
2877                 else if ( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
2878                         if (cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
2879                                 glShadeModel(GL_SMOOTH);
2880                                 draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
2881                                 glShadeModel(GL_FLAT);
2882                         }
2883                         else {
2884                                 draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
2885                         }
2886                 }
2887                 else {
2888                         if (!sel_only) {
2889                                 glColor4ubv(wireCol);
2890                                 draw_dm_edges(em, cageDM);
2891                         }
2892                 }
2893
2894                 if (pass == 0) {
2895                         glDisable(GL_BLEND);
2896                         glEnable(GL_DEPTH_TEST);
2897                 }
2898         }
2899 }       
2900
2901 static void draw_em_measure_stats(View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit)
2902 {
2903         const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
2904         Mesh *me = ob->data;
2905         float v1[3], v2[3], v3[3], vmid[3], fvec[3];
2906         char numstr[32]; /* Stores the measurement display text here */
2907         const char *conv_float; /* Use a float conversion matching the grid size */
2908         unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */
2909         float area; /* area of the face */
2910         float grid = unit->system ? unit->scale_length : v3d->grid;
2911         const int do_split = unit->flag & USER_UNIT_OPT_SPLIT;
2912         const int do_global = v3d->flag & V3D_GLOBAL_STATS;
2913         const int do_moving = G.moving;
2914
2915         BMIter iter;
2916         int i;
2917
2918         /* make the precision of the pronted value proportionate to the gridsize */
2919
2920         if (grid < 0.01f) conv_float = "%.6g";
2921         else if (grid < 0.1f) conv_float = "%.5g";
2922         else if (grid < 1.0f) conv_float = "%.4g";
2923         else if (grid < 10.0f) conv_float = "%.3g";
2924         else conv_float = "%.2g";
2925         
2926         if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
2927                 BMEdge *eed;
2928
2929                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
2930
2931                 eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
2932                 for (; eed; eed = BM_iter_step(&iter)) {
2933                         /* draw selected edges, or edges next to selected verts while draging */
2934                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
2935                             (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
2936                                            BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
2937                         {
2938
2939                                 copy_v3_v3(v1, eed->v1->co);
2940                                 copy_v3_v3(v2, eed->v2->co);
2941
2942                                 mid_v3_v3v3(vmid, v1, v2);
2943
2944                                 if (do_global) {
2945                                         mul_mat3_m4_v3(ob->obmat, v1);
2946                                         mul_mat3_m4_v3(ob->obmat, v2);
2947                                 }
2948
2949                                 if (unit->system) {
2950                                         bUnit_AsString(numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
2951                                                        unit->system, B_UNIT_LENGTH, do_split, FALSE);
2952                                 }
2953                                 else {
2954                                         sprintf(numstr, conv_float, len_v3v3(v1, v2));
2955                                 }
2956
2957                                 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col);
2958                         }
2959                 }
2960         }
2961
2962         if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
2963                 /* would be nice to use BM_face_calc_area, but that is for 2d faces
2964                  * so instead add up tessellation triangle areas */
2965                 BMFace *f;
2966                 int n;
2967
2968 #define DRAW_EM_MEASURE_STATS_FACEAREA()                                      \
2969         if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {                               \
2970                 mul_v3_fl(vmid, 1.0f / (float)n);                                     \
2971                 if (unit->system)                                                     \
2972                         bUnit_AsString(numstr, sizeof(numstr),                            \
2973                                        (double)(area * unit->scale_length),               \
2974                                        3, unit->system, B_UNIT_LENGTH, do_split, FALSE);  \
2975                 else                                                                  \
2976                         BLI_snprintf(numstr, sizeof(numstr), conv_float, area);           \
2977                 view3d_cached_text_draw_add(vmid, numstr, 0, txt_flag, col);          \
2978         } (void)0
2979
2980                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
2981                 
2982                 f = NULL;
2983                 area = 0.0;
2984                 zero_v3(vmid);
2985                 n = 0;
2986                 for (i = 0; i < em->tottri; i++) {
2987                         BMLoop **l = em->looptris[i];
2988                         if (f && l[0]->f != f) {
2989                                 DRAW_EM_MEASURE_STATS_FACEAREA();
2990                                 zero_v3(vmid);
2991                                 area = 0.0;
2992                                 n = 0;
2993                         }
2994
2995                         f = l[0]->f;
2996                         copy_v3_v3(v1, l[0]->v->co);
2997                         copy_v3_v3(v2, l[1]->v->co);
2998                         copy_v3_v3(v3, l[2]->v->co);
2999                         add_v3_v3(vmid, v1);
3000                         add_v3_v3(vmid, v2);
3001                         add_v3_v3(vmid, v3);
3002                         n += 3;
3003                         if (do_global) {
3004                                 mul_mat3_m4_v3(ob->obmat, v1);
3005                                 mul_mat3_m4_v3(ob->obmat, v2);
3006                                 mul_mat3_m4_v3(ob->obmat, v3);
3007                         }
3008                         area += area_tri_v3(v1, v2, v3);
3009                 }
3010
3011                 if (f) {
3012                         DRAW_EM_MEASURE_STATS_FACEAREA();
3013                 }
3014 #undef DRAW_EM_MEASURE_STATS_FACEAREA
3015         }
3016
3017         if (me->drawflag & ME_DRAWEXTRA_FACEANG) {
3018                 BMFace *efa;
3019                 int is_rad = unit->system_rotation == USER_UNIT_ROT_RADIANS;
3020
3021                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
3022
3023
3024                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3025                         const int is_face_sel = BM_elem_flag_test(efa, BM_ELEM_SELECT);
3026
3027                         if (is_face_sel || do_moving) {
3028                                 BMIter liter;
3029                                 BMLoop *loop;
3030                                 int is_first = TRUE;
3031
3032                                 BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
3033                                         if (is_face_sel || (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT))) {
3034                                                 float angle;
3035
3036                                                 /* lazy init center calc */
3037                                                 if (is_first) {
3038                                                         BM_face_calc_center_bounds(efa, vmid);
3039                                                         /* Avoid triple matrix multiply every vertex for 'global' */
3040                                                         if (do_global) {
3041                                                                 copy_v3_v3(v1, loop->prev->v->co);
3042                                                                 copy_v3_v3(v2, loop->v->co);
3043                                                                 mul_mat3_m4_v3(ob->obmat, v1);
3044                                                                 mul_mat3_m4_v3(ob->obmat, v2);
3045                                                         }
3046                                                         is_first = FALSE;
3047                                                 }
3048
3049                                                 if (do_global) {
3050                                                         copy_v3_v3(v3, loop->next->v->co);
3051
3052                                                         mul_mat3_m4_v3(ob->obmat, v3);
3053
3054                                                         angle = angle_v3v3v3(v1, v2, v3);
3055                                                         copy_v3_v3(v1, v2);
3056                                                         copy_v3_v3(v2, v3);
3057                                                 }
3058                                                 else {
3059                                                         angle = angle_v3v3v3(loop->prev->v->co, loop->v->co, loop->next->v->co);
3060                                                 }
3061
3062                                                 BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
3063                                                 interp_v3_v3v3(fvec, vmid, loop->v->co, 0.8f);
3064                                                 view3d_cached_text_draw_add(fvec, numstr, 0, txt_flag, col);
3065                                         }
3066                                 }
3067                         }
3068                 }
3069         }
3070 }
3071
3072 static void draw_em_indices(BMEditMesh *em)
3073 {
3074         const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
3075         BMEdge *e;
3076         BMFace *f;
3077         BMVert *v;
3078         int i;
3079         char numstr[32];
3080         float pos[3];
3081         unsigned char col[4];
3082
3083         BMIter iter;
3084         BMesh *bm = em->bm;
3085
3086         /* For now, reuse appropriate theme colors from stats text colors */
3087         i = 0;
3088         if (em->selectmode & SCE_SELECT_VERTEX) {
3089                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
3090                 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
3091                         if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
3092                                 sprintf(numstr, "%d", i);
3093                                 view3d_cached_text_draw_add(v->co, numstr, 0, txt_flag, col);
3094                         }
3095                         i++;
3096                 }
3097         }
3098
3099         if (em->selectmode & SCE_SELECT_EDGE) {
3100                 i = 0;
3101                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
3102                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
3103                         if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
3104                                 sprintf(numstr, "%d", i);
3105                                 mid_v3_v3v3(pos, e->v1->co, e->v2->co);
3106                                 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
3107                         }
3108                         i++;
3109                 }
3110         }
3111
3112         if (em->selectmode & SCE_SELECT_FACE) {
3113                 i = 0;
3114                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
3115                 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3116                         if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
3117                                 BM_face_calc_center_mean(f, pos);
3118                                 sprintf(numstr, "%d", i);
3119                                 view3d_cached_text_draw_add(pos, numstr, 0, txt_flag, col);
3120                         }
3121                         i++;
3122                 }
3123         }
3124 }
3125
3126 static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
3127 {
3128         BMFace *efa = EDBM_face_at_index(userData, index);
3129
3130         if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
3131                 GPU_enable_material(efa->mat_nr + 1, NULL);
3132                 return DM_DRAW_OPTION_NORMAL;
3133         }
3134         else
3135                 return DM_DRAW_OPTION_SKIP;
3136 }
3137
3138 static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
3139 {
3140         BMFace *efa = EDBM_face_at_index(userData, index);
3141
3142         if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
3143                 return DM_DRAW_OPTION_SKIP;
3144         else
3145                 return DM_DRAW_OPTION_NORMAL;
3146 }
3147
3148 static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
3149                           Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const short dt)
3150
3151 {