UVEdit: Add back uv angle stretch aspect correction
[blender.git] / source / blender / editors / uvedit / uvedit_draw.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, 2002-2009
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/uvedit/uvedit_draw.c
27  *  \ingroup eduv
28  */
29
30
31 #include <float.h>
32 #include <math.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_material_types.h"
39 #include "DNA_mesh_types.h"
40 #include "DNA_meshdata_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_space_types.h"
45
46 #include "../../draw/intern/draw_cache_impl.h"
47
48 #include "BLI_math.h"
49 #include "BLI_utildefines.h"
50 #include "BLI_buffer.h"
51 #include "BLI_bitmap.h"
52
53 #include "BKE_deform.h"
54 #include "BKE_editmesh.h"
55 #include "BKE_material.h"
56 #include "BKE_layer.h"
57
58 #include "BKE_scene.h"
59
60 #include "BIF_glutil.h"
61
62 #include "DEG_depsgraph.h"
63 #include "DEG_depsgraph_query.h"
64
65 #include "GPU_batch.h"
66 #include "GPU_immediate.h"
67 #include "GPU_immediate_util.h"
68 #include "GPU_matrix.h"
69 #include "GPU_state.h"
70 #include "GPU_draw.h"
71
72 #include "ED_image.h"
73 #include "ED_mesh.h"
74 #include "ED_uvedit.h"
75
76 #include "UI_resources.h"
77 #include "UI_interface.h"
78 #include "UI_view2d.h"
79
80 #include "uvedit_intern.h"
81
82 static int draw_uvs_face_check(const ToolSettings *ts)
83 {
84         /* checks if we are selecting only faces */
85         if (ts->uv_flag & UV_SYNC_SELECTION) {
86                 if (ts->selectmode == SCE_SELECT_FACE)
87                         return 2;
88                 else if (ts->selectmode & SCE_SELECT_FACE)
89                         return 1;
90                 else
91                         return 0;
92         }
93         else
94                 return (ts->uv_selectmode == UV_SELECT_FACE);
95 }
96
97 /* ------------------------- */
98
99 void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
100 {
101         float zoom[2], x_fac, y_fac;
102
103         UI_view2d_scale_get_inverse(&ar->v2d, &zoom[0], &zoom[1]);
104
105         mul_v2_fl(zoom, 256.0f * UI_DPI_FAC);
106         x_fac = zoom[0];
107         y_fac = zoom[1];
108
109         GPU_line_width(1.0f);
110
111         GPU_matrix_translate_2fv(cursor);
112
113         const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
114
115         immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
116
117         float viewport_size[4];
118         GPU_viewport_size_get_f(viewport_size);
119         immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
120
121         immUniform1i("colors_len", 2);  /* "advanced" mode */
122         immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
123         immUniform1f("dash_width", 8.0f);
124
125         immBegin(GPU_PRIM_LINES, 8);
126
127         immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
128         immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
129
130         immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
131         immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
132
133         immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
134         immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
135
136         immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
137         immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
138
139         immEnd();
140
141         immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2);
142         immUniform1f("dash_width", 2.0f);
143
144         immBegin(GPU_PRIM_LINES, 8);
145
146         immVertex2f(shdr_pos, -0.020f * x_fac, 0.0f);
147         immVertex2f(shdr_pos, -0.1f * x_fac, 0.0f);
148
149         immVertex2f(shdr_pos, 0.1f * x_fac, 0.0f);
150         immVertex2f(shdr_pos, 0.020f * x_fac, 0.0f);
151
152         immVertex2f(shdr_pos, 0.0f, -0.020f * y_fac);
153         immVertex2f(shdr_pos, 0.0f, -0.1f * y_fac);
154
155         immVertex2f(shdr_pos, 0.0f, 0.1f * y_fac);
156         immVertex2f(shdr_pos, 0.0f, 0.020f * y_fac);
157
158         immEnd();
159
160         immUnbindProgram();
161
162         GPU_matrix_translate_2f(-cursor[0], -cursor[1]);
163 }
164
165 static void uvedit_get_batches(
166         Object *ob, SpaceImage *sima, const ToolSettings *ts,
167         GPUBatch **faces, GPUBatch **edges, GPUBatch **verts, GPUBatch **facedots)
168 {
169         int drawfaces = draw_uvs_face_check(ts);
170         const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
171         const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
172
173         *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
174         *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
175
176         if (drawfaces) {
177                 *facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
178         }
179         else {
180                 *facedots = NULL;
181         }
182
183         if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
184                 *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_area(ob->data);
185         }
186         else if (draw_stretch) {
187                 *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_angle(ob->data);
188         }
189         else if (draw_faces) {
190                 *faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
191         }
192         else {
193                 *faces = NULL;
194         }
195
196         DRW_mesh_batch_cache_create_requested(ob, ob->data, ts, false, false);
197 }
198
199 static void draw_uvs_shadow(SpaceImage *UNUSED(sima), Scene *scene, Object *obedit, Depsgraph *depsgraph)
200 {
201         Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit);
202         float col[4];
203         UI_GetThemeColor4fv(TH_UV_SHADOW, col);
204
205         /* TODO get real modified edges. */
206         GPUBatch *edges = DRW_mesh_batch_cache_get_edituv_edges(eval_ob->data);
207
208         DRW_mesh_batch_cache_create_requested(eval_ob, eval_ob->data, scene->toolsettings, false, false);
209
210         if (edges) {
211                 GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
212                 GPU_batch_uniform_4fv(edges, "color", col);
213                 GPU_batch_draw(edges);
214         }
215 }
216
217 static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
218 {
219         Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
220         Mesh *me = eval_ob->data;
221         ToolSettings *ts = scene->toolsettings;
222         GPUBatch *geom = DRW_mesh_batch_cache_get_texpaint_loop_wire(me);
223         float col[4];
224         UI_GetThemeColor4fv(TH_UV_SHADOW, col);
225
226         if (!geom)
227                 return;
228
229         GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UNIFORM_COLOR);
230         GPU_batch_uniform_4fv(geom, "color", col);
231
232         const bool do_material_masking = (ts->uv_flag & UV_SHOW_SAME_IMAGE);
233         if (do_material_masking && me->mloopuv) {
234                 /* Render loops that have the active material. Minize draw calls. */
235                 MPoly *mpoly = me->mpoly;
236                 uint draw_start = 0;
237                 uint idx = 0;
238                 bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
239
240                 GPU_matrix_bind(geom->interface);
241
242                 /* TODO(fclem): If drawcall count becomes a problem in the future
243                  * we can use multi draw indirect drawcalls for this.
244                  * (not implemented in GPU module at the time of writing). */
245                 for (int a = 0; a < me->totpoly; a++, mpoly++) {
246                         bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
247                         if (ma_match != prev_ma_match) {
248                                 if (ma_match == false) {
249                                         GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
250                                 }
251                                 else {
252                                         draw_start = idx;
253                                 }
254                         }
255                         idx += mpoly->totloop + 1;
256                         prev_ma_match = ma_match;
257                 }
258                 if (prev_ma_match == true) {
259                         GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
260                 }
261
262                 GPU_batch_program_use_end(geom);
263         }
264         else {
265                 GPU_batch_draw(geom);
266         }
267 }
268
269 /* draws uv's in the image space */
270 static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph)
271 {
272         GPUBatch *faces, *edges, *verts, *facedots;
273         Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit);
274         const ToolSettings *ts = scene->toolsettings;
275         float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
276
277         if (sima->flag & SI_DRAWSHADOW) {
278                 /* XXX TODO: Need to check if shadow mesh is different than original mesh. */
279                 bool is_cage_like_final_meshes = true;
280
281                 /* When sync selection is enabled, all faces are drawn (except for hidden)
282                  * so if cage is the same as the final, there is no point in drawing this. */
283                 if (!((ts->uv_flag & UV_SYNC_SELECTION) && is_cage_like_final_meshes)) {
284                         draw_uvs_shadow(sima, scene, obedit, depsgraph);
285                 }
286         }
287
288         uvedit_get_batches(
289                 eval_ob, sima, ts,
290                 &faces, &edges, &verts, &facedots);
291
292
293         bool interpedges;
294         bool do_elem_order_fix = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
295         bool do_selected_edges = ((sima->flag & SI_NO_DRAWEDGES) == 0);
296         bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
297         if (ts->uv_flag & UV_SYNC_SELECTION) {
298                 interpedges = (ts->selectmode & SCE_SELECT_VERTEX) != 0;
299         }
300         else {
301                 interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX);
302         }
303
304         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
305
306         if (faces) {
307                 GPU_batch_program_set_builtin(faces, (draw_stretch)
308                                                      ? (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)
309                                                        ? GPU_SHADER_2D_UV_FACES_STRETCH_AREA
310                                                        : GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE
311                                                      : GPU_SHADER_2D_UV_FACES);
312
313                 if (!draw_stretch) {
314                         GPU_blend(true);
315
316                         UI_GetThemeColor4fv(TH_FACE, col1);
317                         UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
318                         UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
319                         col3[3] *= 0.2; /* Simulate dithering */
320                         GPU_batch_uniform_4fv(faces, "faceColor", col1);
321                         GPU_batch_uniform_4fv(faces, "selectColor", col2);
322                         GPU_batch_uniform_4fv(faces, "activeColor", col3);
323                 }
324                 else if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) {
325                         float asp[2];
326                         ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]);
327                         GPU_batch_uniform_2fv(faces, "aspect", asp);
328                 }
329
330                 GPU_batch_draw(faces);
331
332                 if (!draw_stretch) {
333                         GPU_blend(false);
334                 }
335         }
336         if (edges) {
337                 if (sima->flag & SI_SMOOTH_UV) {
338                         GPU_line_smooth(true);
339                         GPU_blend(true);
340                 }
341                 switch (sima->dt_uv) {
342                         case SI_UVDT_DASH:
343                         {
344                                 float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}};
345                                 float viewport_size[4];
346                                 GPU_viewport_size_get_f(viewport_size);
347
348                                 GPU_line_width(1.0f);
349                                 GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
350                                 GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors);
351                                 GPU_batch_uniform_2f(edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
352                                 GPU_batch_uniform_1i(edges, "colors_len", 2);  /* "advanced" mode */
353                                 GPU_batch_uniform_1f(edges, "dash_width", 4.0f);
354                                 GPU_batch_draw(edges);
355                                 break;
356                         }
357                         case SI_UVDT_BLACK:
358                         case SI_UVDT_WHITE:
359                         {
360                                 GPU_line_width(1.0f);
361                                 GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
362                                 if (sima->dt_uv == SI_UVDT_WHITE) {
363                                         GPU_batch_uniform_4f(edges, "color", 1.0f, 1.0f, 1.0f, 1.0f);
364                                 }
365                                 else {
366                                         GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
367                                 }
368                                 GPU_batch_draw(edges);
369                                 break;
370                         }
371                         case SI_UVDT_OUTLINE:
372                         {
373                                 GPU_line_width(3.0f);
374                                 GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
375                                 GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
376                                 GPU_batch_draw(edges);
377
378                                 UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
379                                 UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
380
381                                 /* We could modify the vbo's data filling instead of modifying the provoking vert. */
382                                 glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
383
384                                 GPU_line_width(1.0f);
385                                 GPU_batch_program_set_builtin(edges, (interpedges)
386                                                                      ? GPU_SHADER_2D_UV_EDGES_SMOOTH
387                                                                      : GPU_SHADER_2D_UV_EDGES);
388                                 GPU_batch_uniform_4fv(edges, "edgeColor", col1);
389                                 GPU_batch_uniform_4fv(edges, "selectColor", do_selected_edges ? col2 : col1);
390                                 GPU_batch_draw(edges);
391
392                                 if (do_elem_order_fix && do_selected_edges) {
393                                         /* We have problem in this mode when face order make some edges
394                                          * appear unselected because an adjacent face is not selected and
395                                          * render after the selected face.
396                                          * So, to avoid sorting edges by state we just render selected edges
397                                          * on top. A bit overkill but it's simple. */
398                                         GPU_blend(true);
399                                         GPU_batch_uniform_4fv(edges, "edgeColor", transparent);
400                                         GPU_batch_uniform_4fv(edges, "selectColor", col2);
401                                         GPU_batch_draw(edges);
402                                         GPU_blend(false);
403                                 }
404                                 glProvokingVertex(GL_LAST_VERTEX_CONVENTION);
405                                 break;
406                         }
407                 }
408                 if (sima->flag & SI_SMOOTH_UV) {
409                         GPU_line_smooth(false);
410                         GPU_blend(false);
411                 }
412         }
413         if (verts || facedots) {
414                 float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
415                 UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
416                 if (verts) {
417                         float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */
418                         UI_GetThemeColor4fv(TH_VERTEX, col1);
419                         GPU_blend(true);
420                         GPU_enable_program_point_size();
421
422                         GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS);
423                         GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
424                         GPU_batch_uniform_4fv(verts, "selectColor", (do_elem_order_fix) ? transparent : col2);
425                         GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
426                         GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2);
427                         GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
428                         GPU_batch_draw(verts);
429
430                         if (do_elem_order_fix) {
431                                 /* We have problem in this mode when face order make some verts
432                                  * appear unselected because an adjacent face is not selected and
433                                  * render after the selected face.
434                                  * So, to avoid sorting verts by state we just render selected verts
435                                  * on top. A bit overkill but it's simple. */
436                                 GPU_batch_uniform_4fv(verts, "vertColor", transparent);
437                                 GPU_batch_uniform_4fv(verts, "selectColor", col2);
438                                 GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
439                                 GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2);
440                                 GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
441                                 GPU_batch_draw(verts);
442                         }
443
444                         GPU_blend(false);
445                         GPU_disable_program_point_size();
446                 }
447                 if (facedots) {
448                         GPU_point_size(pointsize);
449
450                         UI_GetThemeColor4fv(TH_WIRE, col1);
451                         GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS);
452                         GPU_batch_uniform_4fv(facedots, "vertColor", col1);
453                         GPU_batch_uniform_4fv(facedots, "selectColor", col2);
454                         GPU_batch_draw(facedots);
455                 }
456         }
457 }
458
459 static void draw_uv_shadows_get(
460         SpaceImage *sima, Object *ob, Object *obedit,
461         bool *show_shadow, bool *show_texpaint)
462 {
463         *show_shadow = *show_texpaint = false;
464
465         if (ED_space_image_show_render(sima) || (sima->flag & SI_NO_DRAW_TEXPAINT))
466                 return;
467
468         if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) {
469                 struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
470
471                 *show_shadow = EDBM_uv_check(em);
472         }
473
474         *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT);
475 }
476
477 void ED_uvedit_draw_main(
478         SpaceImage *sima,
479         ARegion *ar, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *obact, Depsgraph *depsgraph)
480 {
481         ToolSettings *toolsettings = scene->toolsettings;
482         bool show_uvedit, show_uvshadow, show_texpaint_uvshadow;
483
484         show_uvedit = ED_space_image_show_uvedit(sima, obedit);
485         draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow);
486
487         if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
488                 if (show_uvshadow) {
489                         draw_uvs_shadow(sima, scene, obedit, depsgraph);
490                 }
491                 else if (show_uvedit) {
492                         uint objects_len = 0;
493                         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
494                         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
495                                 Object *ob_iter = objects[ob_index];
496                                 draw_uvs(sima, scene, ob_iter, depsgraph);
497                         }
498                         MEM_freeN(objects);
499                 }
500                 else {
501                         draw_uvs_texpaint(scene, obact, depsgraph);
502                 }
503
504                 if (show_uvedit && !(toolsettings->use_uv_sculpt))
505                         ED_image_draw_cursor(ar, sima->cursor);
506         }
507 }