doxygen: add newline after \file
[blender.git] / source / blender / draw / modes / edit_mesh_mode_text.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2016, Blender Foundation.
17  */
18
19 /** \file
20  * \ingroup draw
21  */
22
23 #include "BLI_math.h"
24 #include "BLI_string.h"
25
26 #include "BKE_editmesh.h"
27 #include "BKE_global.h"
28 #include "BKE_unit.h"
29
30 #include "ED_view3d.h"
31
32 #include "DNA_mesh_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_screen_types.h"
36 #include "DNA_view3d_types.h"
37
38 #include "UI_resources.h"
39
40 #include "draw_manager_text.h"
41
42 #include "edit_mesh_mode_intern.h" /* own include */
43
44 /* Copied from drawobject.c */
45 void DRW_edit_mesh_mode_text_measure_stats(
46         ARegion *ar, View3D *v3d,
47         Object *ob, const UnitSettings *unit)
48 {
49         /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square, etc.).
50          * See bug #36090.
51          */
52         struct DRWTextStore *dt = DRW_text_cache_ensure();
53         const short txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | (unit->system ? 0 : DRW_TEXT_CACHE_ASCII);
54         Mesh *me = ob->data;
55         BMEditMesh *em = me->edit_mesh;
56         float v1[3], v2[3], v3[3], vmid[3], fvec[3];
57         char numstr[32]; /* Stores the measurement display text here */
58         size_t numstr_len;
59         const char *conv_float; /* Use a float conversion matching the grid size */
60         uchar col[4] = {0, 0, 0, 255}; /* color of the text to draw */
61         float area; /* area of the face */
62         float grid = unit->system ? unit->scale_length : v3d->grid;
63         const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0;
64         const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0;
65         /* when 2 edge-info options are enabled, space apart */
66         const bool do_edge_textpair = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG);
67         const short edge_texpair_sep = (short)(5.0f * U.ui_scale);
68         float clip_planes[4][4];
69         /* allow for displaying shape keys and deform mods */
70         BMIter iter;
71
72         /* make the precision of the display value proportionate to the gridsize */
73
74         if (grid <= 0.01f) conv_float = "%.6g";
75         else if (grid <= 0.1f) conv_float = "%.5g";
76         else if (grid <= 1.0f) conv_float = "%.4g";
77         else if (grid <= 10.0f) conv_float = "%.3g";
78         else conv_float = "%.2g";
79
80         if (v3d->overlay.edit_flag & (V3D_OVERLAY_EDIT_EDGE_LEN | V3D_OVERLAY_EDIT_EDGE_ANG | V3D_OVERLAY_EDIT_INDICES)) {
81                 BoundBox bb;
82                 const rcti rect = {0, ar->winx, 0, ar->winy};
83
84                 ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
85         }
86
87         if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) {
88                 BMEdge *eed;
89
90                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
91
92                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
93                         /* draw selected edges, or edges next to selected verts while dragging */
94                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
95                             (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
96                                            BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
97                         {
98                                 float v1_clip[3], v2_clip[3];
99
100                                 copy_v3_v3(v1, eed->v1->co);
101                                 copy_v3_v3(v2, eed->v2->co);
102
103                                 if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
104
105                                         mid_v3_v3v3(vmid, v1_clip, v2_clip);
106                                         mul_m4_v3(ob->obmat, vmid);
107
108                                         if (do_global) {
109                                                 mul_mat3_m4_v3(ob->obmat, v1);
110                                                 mul_mat3_m4_v3(ob->obmat, v2);
111                                         }
112
113                                         if (unit->system) {
114                                                 numstr_len = bUnit_AsString2(
115                                                         numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
116                                                         B_UNIT_LENGTH, unit, false);
117                                         }
118                                         else {
119                                                 numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
120                                         }
121
122                                         DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0,
123                                                            (do_edge_textpair) ? edge_texpair_sep : 0,
124                                                            txt_flag, col);
125                                 }
126                         }
127                 }
128         }
129
130         if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG) {
131                 const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
132                 BMEdge *eed;
133
134                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
135
136                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
137                         BMLoop *l_a, *l_b;
138                         if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
139                                 /* draw selected edges, or edges next to selected verts while dragging */
140                                 if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
141                                     (do_moving &&
142                                      (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
143                                       BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
144                                       /* special case, this is useful to show when verts connected to
145                                        * this edge via a face are being transformed */
146                                       BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
147                                       BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT)       ||
148                                       BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
149                                       BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)
150                                       )))
151                                 {
152                                         float v1_clip[3], v2_clip[3];
153
154                                         copy_v3_v3(v1, eed->v1->co);
155                                         copy_v3_v3(v2, eed->v2->co);
156
157                                         if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
158                                                 float no_a[3], no_b[3];
159                                                 float angle;
160
161                                                 mid_v3_v3v3(vmid, v1_clip, v2_clip);
162                                                 mul_m4_v3(ob->obmat, vmid);
163
164                                                 copy_v3_v3(no_a, l_a->f->no);
165                                                 copy_v3_v3(no_b, l_b->f->no);
166
167                                                 if (do_global) {
168                                                         mul_mat3_m4_v3(ob->imat, no_a);
169                                                         mul_mat3_m4_v3(ob->imat, no_b);
170                                                         normalize_v3(no_a);
171                                                         normalize_v3(no_b);
172                                                 }
173
174                                                 angle = angle_normalized_v3v3(no_a, no_b);
175
176                                                 numstr_len = BLI_snprintf_rlen(
177                                                         numstr, sizeof(numstr), "%.3f%s", (is_rad) ? angle : RAD2DEGF(angle),
178                                                                                           (is_rad) ? "r" : "°");
179
180                                                 DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0,
181                                                                    (do_edge_textpair) ? -edge_texpair_sep : 0,
182                                                                    txt_flag, col);
183                                         }
184                                 }
185                         }
186                 }
187         }
188
189         if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_AREA) {
190                 /* would be nice to use BM_face_calc_area, but that is for 2d faces
191                  * so instead add up tessellation triangle areas */
192
193                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
194
195                 int i, n, numtri;
196                 BMFace *f = NULL;
197                 BM_ITER_MESH_INDEX(f, &iter, em->bm, BM_FACES_OF_MESH, i) {
198                         if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
199                                 n = 0;
200                                 numtri = f->len - 2;
201                                 area = 0;
202                                 zero_v3(vmid);
203                                 BMLoop *(*l)[3] = &em->looptris[poly_to_tri_count(i, BM_elem_index_get(f->l_first))];
204                                 for (int j = 0; j < numtri; j++) {
205                                         copy_v3_v3(v1, l[j][0]->v->co);
206                                         copy_v3_v3(v2, l[j][1]->v->co);
207                                         copy_v3_v3(v3, l[j][2]->v->co);
208
209                                         add_v3_v3(vmid, v1);
210                                         add_v3_v3(vmid, v2);
211                                         add_v3_v3(vmid, v3);
212                                         n += 3;
213
214                                         if (do_global) {
215                                                 mul_mat3_m4_v3(ob->obmat, v1);
216                                                 mul_mat3_m4_v3(ob->obmat, v2);
217                                                 mul_mat3_m4_v3(ob->obmat, v3);
218                                         }
219
220                                         area += area_tri_v3(v1, v2, v3);
221                                 }
222
223                                 mul_v3_fl(vmid, 1.0f / (float)n);
224                                 mul_m4_v3(ob->obmat, vmid);
225
226                                 if (unit->system) {
227                                         numstr_len = bUnit_AsString2(
228                                                 numstr, sizeof(numstr),
229                                                 (double)(area * unit->scale_length * unit->scale_length),
230                                                 3, B_UNIT_AREA, unit, false);
231                                 }
232                                 else {
233                                         numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area);
234                                 }
235
236                                 DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, 0, txt_flag, col);
237                         }
238                 }
239         }
240
241         if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_ANG) {
242                 BMFace *efa;
243                 const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
244
245                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
246
247                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
248                         const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT);
249
250                         if (is_face_sel || do_moving) {
251                                 BMIter liter;
252                                 BMLoop *loop;
253                                 bool is_first = true;
254
255                                 BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
256                                         if (is_face_sel ||
257                                             (do_moving &&
258                                              (BM_elem_flag_test(loop->v, BM_ELEM_SELECT) ||
259                                               BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) ||
260                                               BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT))))
261                                         {
262                                                 float v2_local[3];
263
264                                                 /* lazy init center calc */
265                                                 if (is_first) {
266                                                         BM_face_calc_center_bounds(efa, vmid);
267                                                         is_first = false;
268                                                 }
269                                                 copy_v3_v3(v1, loop->prev->v->co);
270                                                 copy_v3_v3(v2, loop->v->co);
271                                                 copy_v3_v3(v3, loop->next->v->co);
272
273                                                 copy_v3_v3(v2_local, v2);
274
275                                                 if (do_global) {
276                                                         mul_mat3_m4_v3(ob->obmat, v1);
277                                                         mul_mat3_m4_v3(ob->obmat, v2);
278                                                         mul_mat3_m4_v3(ob->obmat, v3);
279                                                 }
280
281                                                 float angle = angle_v3v3v3(v1, v2, v3);
282
283                                                 numstr_len = BLI_snprintf_rlen(
284                                                         numstr, sizeof(numstr), "%.3f%s", (is_rad) ? angle : RAD2DEGF(angle),
285                                                                                           (is_rad) ? "r" : "°");
286                                                 interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
287                                                 mul_m4_v3(ob->obmat, fvec);
288                                                 DRW_text_cache_add(dt, fvec, numstr, numstr_len, 0, 0, txt_flag, col);
289                                         }
290                                 }
291                         }
292                 }
293         }
294
295         /* This option is for mesh ops and addons debugging; only available in UI if Blender starts with --debug */
296         if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_INDICES) {
297                 int i;
298
299                 /* For now, reuse an appropriate theme color */
300                 UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
301
302                 if (em->selectmode & SCE_SELECT_VERTEX) {
303                         BMVert *v;
304
305                         BM_ITER_MESH_INDEX(v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
306                                 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
307                                         float vec[3];
308                                         mul_v3_m4v3(vec, ob->obmat, v->co);
309
310                                         numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
311                                         DRW_text_cache_add(dt, vec, numstr, numstr_len, 0, 0, txt_flag, col);
312                                 }
313                         }
314                 }
315
316                 if (em->selectmode & SCE_SELECT_EDGE) {
317                         BMEdge *e;
318
319                         BM_ITER_MESH_INDEX(e, &iter, em->bm, BM_EDGES_OF_MESH, i) {
320                                 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
321                                         float v1_clip[3], v2_clip[3];
322
323                                         copy_v3_v3(v1, e->v1->co);
324                                         copy_v3_v3(v2, e->v2->co);
325
326                                         if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
327                                                 mid_v3_v3v3(vmid, v1_clip, v2_clip);
328                                                 mul_m4_v3(ob->obmat, vmid);
329
330                                                 numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
331                                                 DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, 0, txt_flag, col);
332                                         }
333                                 }
334                         }
335                 }
336
337                 if (em->selectmode & SCE_SELECT_FACE) {
338                         BMFace *f;
339
340                         BM_ITER_MESH_INDEX(f, &iter, em->bm, BM_FACES_OF_MESH, i) {
341                                 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
342                                         BM_face_calc_center_median(f, v1);
343                                         mul_m4_v3(ob->obmat, v1);
344
345                                         numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
346                                         DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col);
347                                 }
348                         }
349                 }
350         }
351 }