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