Fix T63755: Area Stretching Overlay
authorJeroen Bakker <j.bakker@atmind.nl>
Tue, 3 Sep 2019 11:42:11 +0000 (13:42 +0200)
committerJeroen Bakker <j.bakker@atmind.nl>
Wed, 4 Sep 2019 06:08:27 +0000 (08:08 +0200)
Support for UV Stretching overlay during multi object editing. The
VBO now holds the ratios per fase. In the shader these ratios will
be compared against the global ratios. The global rations are created
from all selected objects.

The current implementation does not fit well with the draw module. The
plan is to move the drawing of other spaces towards the draw manager what
leads to a better fit. Currently the details on this solution is unclear
but this requirement will become an attentionpoint in the future design.

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D5665

source/blender/draw/intern/draw_cache_extract.h
source/blender/draw/intern/draw_cache_extract_mesh.c
source/blender/draw/intern/draw_cache_impl.h
source/blender/draw/intern/draw_cache_impl_mesh.c
source/blender/editors/uvedit/uvedit_draw.c
source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl

index 9305dc6eef72c2373ef22b52b86310301ea69553..70778ca60148f0220cc432c7f80882372c3dcc54 100644 (file)
@@ -136,8 +136,8 @@ typedef enum DRWBatchFlag {
   MBC_EDIT_LNOR = (1 << 6),
   MBC_EDIT_FACEDOTS = (1 << 7),
   MBC_EDIT_MESH_ANALYSIS = (1 << 8),
-  MBC_EDITUV_FACES_STRECH_AREA = (1 << 9),
-  MBC_EDITUV_FACES_STRECH_ANGLE = (1 << 10),
+  MBC_EDITUV_FACES_STRETCH_AREA = (1 << 9),
+  MBC_EDITUV_FACES_STRETCH_ANGLE = (1 << 10),
   MBC_EDITUV_FACES = (1 << 11),
   MBC_EDITUV_EDGES = (1 << 12),
   MBC_EDITUV_VERTS = (1 << 13),
@@ -157,7 +157,7 @@ typedef enum DRWBatchFlag {
 } DRWBatchFlag;
 
 #define MBC_EDITUV \
-  (MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | \
+  (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
    MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
 
 #define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
@@ -183,8 +183,8 @@ typedef struct MeshBatchCache {
     GPUBatch *edit_fdots;
     GPUBatch *edit_mesh_analysis;
     /* Edit UVs */
-    GPUBatch *edituv_faces_strech_area;
-    GPUBatch *edituv_faces_strech_angle;
+    GPUBatch *edituv_faces_stretch_area;
+    GPUBatch *edituv_faces_stretch_angle;
     GPUBatch *edituv_faces;
     GPUBatch *edituv_edges;
     GPUBatch *edituv_verts;
@@ -234,6 +234,12 @@ typedef struct MeshBatchCache {
   /* Valid only if edge_detection is up to date. */
   bool is_manifold;
 
+  /* Total areas for drawing UV Stretching. Contains the summed area in mesh
+   * space (`tot_area`) and the summed area in uv space (`tot_uvarea`).
+   *
+   * Only valid after `DRW_mesh_batch_cache_create_requested` has been called. */
+  float tot_area, tot_uv_area;
+
   bool no_loose_wire;
 } MeshBatchCache;
 
index d952965de358dae083a1945de28520967970baaa..8bca2ad2c4500799d0f2ee063cae1fcd72e6edc0 100644 (file)
@@ -2676,7 +2676,7 @@ static void *extract_stretch_area_init(const MeshRenderData *mr, void *buf)
 {
   static GPUVertFormat format = {0};
   if (format.attr_len == 0) {
-    GPU_vertformat_attr_add(&format, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+    GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
   }
 
   GPUVertBuf *vbo = buf;
@@ -2703,7 +2703,7 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t
 
 static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
 {
-  float totarea = 0, totuvarea = 0;
+  float tot_area = 0.0f, tot_uv_area = 0.0f;
   float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__);
 
   if (mr->extract_type == MR_EXTRACT_BMESH) {
@@ -2716,8 +2716,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
     BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
       float area = BM_face_calc_area(efa);
       float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
-      totarea += area;
-      totuvarea += uvarea;
+      tot_area += area;
+      tot_uv_area += uvarea;
       area_ratio[f] = area_ratio_get(area, uvarea);
     }
   }
@@ -2727,8 +2727,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
     for (int p = 0; p < mr->poly_len; p++, mpoly++) {
       float area = BKE_mesh_calc_poly_area(mpoly, &mr->mloop[mpoly->loopstart], mr->mvert);
       float uvarea = BKE_mesh_calc_poly_uv_area(mpoly, uv_data);
-      totarea += area;
-      totuvarea += uvarea;
+      tot_area += area;
+      tot_uv_area += uvarea;
       area_ratio[p] = area_ratio_get(area, uvarea);
     }
   }
@@ -2737,21 +2737,13 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
     BLI_assert(0);
   }
 
-  float tot_ratio, inv_tot_ratio;
-  if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) {
-    tot_ratio = 0.0f;
-    inv_tot_ratio = 0.0f;
-  }
-  else {
-    tot_ratio = totarea / totuvarea;
-    inv_tot_ratio = totuvarea / totarea;
-  }
+  mr->cache->tot_area = tot_area;
+  mr->cache->tot_uv_area = tot_uv_area;
 
   /* Convert in place to avoid an extra allocation */
   uint16_t *poly_stretch = (uint16_t *)area_ratio;
   for (int p = 0; p < mr->poly_len; p++) {
-    float stretch = area_ratio_to_stretch(area_ratio[p], tot_ratio, inv_tot_ratio);
-    poly_stretch[p] = (1.0f - stretch) * 65534.0f;
+    poly_stretch[p] = area_ratio[p] * 65534.0f;
   }
 
   /* Copy face data for each loop. */
index 3e33346c7d883b372c95a846640aa2073e908c5f..970b6053cf94a63c4704c0b2a9354fd5355e807c 100644 (file)
@@ -150,8 +150,10 @@ struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me);
 /* Object mode Wireframe overlays */
 struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me);
 /* edit-mesh UV editor */
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Mesh *me,
+                                                                    float *tot_area,
+                                                                    float *tot_uv_area);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Mesh *me);
 struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Mesh *me);
 struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Mesh *me);
 struct GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(struct Mesh *me);
index 456e21db6ed26c9c01076013e208774b66244d34..96c677dc1845f85070744c761f55366150d2df6e 100644 (file)
@@ -502,14 +502,17 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
     GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points);
     GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots);
   }
-  GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_area);
-  GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_angle);
+  GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
+  GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
   GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
   GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
   GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
   GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
   GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs);
 
+  cache->tot_area = 0.0f;
+  cache->tot_uv_area = 0.0f;
+
   cache->batch_ready &= ~MBC_EDITUV;
 }
 
@@ -577,8 +580,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
         GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
         GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
       }
-      GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_area);
-      GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_angle);
+      GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
+      GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
       GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
       GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
       GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
@@ -874,20 +877,34 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me)
 /** \name UV Image editor API
  * \{ */
 
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(Mesh *me)
+/* Creates the GPUBatch for drawing the UV Stretching Area Overlay.
+ * Optional retrieves the total area or total uv area of the mesh.
+ *
+ * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
+ * only valid after calling `DRW_mesh_batch_cache_create_requested`. */
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
+                                                             float *tot_area,
+                                                             float *tot_uv_area)
 {
   MeshBatchCache *cache = mesh_batch_cache_get(me);
   texpaint_request_active_uv(cache, me);
-  mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_AREA);
-  return DRW_batch_request(&cache->batch.edituv_faces_strech_area);
+  mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
+
+  if (tot_area != NULL) {
+    *tot_area = cache->tot_area;
+  }
+  if (tot_uv_area != NULL) {
+    *tot_uv_area = cache->tot_uv_area;
+  }
+  return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
 }
 
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me)
 {
   MeshBatchCache *cache = mesh_batch_cache_get(me);
   texpaint_request_active_uv(cache, me);
-  mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_ANGLE);
-  return DRW_batch_request(&cache->batch.edituv_faces_strech_angle);
+  mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE);
+  return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle);
 }
 
 GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
@@ -1001,8 +1018,8 @@ void DRW_mesh_batch_cache_create_requested(
   }
 
   if (batch_requested &
-      (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRECH_AREA |
-       MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) {
+      (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA |
+       MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) {
     /* Modifiers will only generate an orco layer if the mesh is deformed. */
     if (cache->cd_needed.orco != 0) {
       if (CustomData_get_layer(&me->vdata, CD_ORCO) == NULL) {
@@ -1078,8 +1095,8 @@ void DRW_mesh_batch_cache_create_requested(
         /* We only clear the batches as they may already have been
          * referenced. */
         GPU_BATCH_CLEAR_SAFE(cache->batch.wire_loops_uvs);
-        GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_area);
-        GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_angle);
+        GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_area);
+        GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_angle);
         GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces);
         GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges);
         GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts);
@@ -1261,17 +1278,17 @@ void DRW_mesh_batch_cache_create_requested(
     DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.uv);
     DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.edituv_data);
   }
-  if (DRW_batch_requested(cache->batch.edituv_faces_strech_area, GPU_PRIM_TRIS)) {
-    DRW_ibo_request(cache->batch.edituv_faces_strech_area, &mbufcache->ibo.edituv_tris);
-    DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.uv);
-    DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.edituv_data);
-    DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.stretch_area);
-  }
-  if (DRW_batch_requested(cache->batch.edituv_faces_strech_angle, GPU_PRIM_TRIS)) {
-    DRW_ibo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->ibo.edituv_tris);
-    DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.uv);
-    DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.edituv_data);
-    DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.stretch_angle);
+  if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) {
+    DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->ibo.edituv_tris);
+    DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.uv);
+    DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.edituv_data);
+    DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.stretch_area);
+  }
+  if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) {
+    DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->ibo.edituv_tris);
+    DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.uv);
+    DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.edituv_data);
+    DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.stretch_angle);
   }
   if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
     DRW_ibo_request(cache->batch.edituv_edges, &mbufcache->ibo.edituv_lines);
index fe761f6570221ba54d1feffd5ff7661eec43b439..89d3b1551713aa02cf10970aebf26dc40d57b977 100644 (file)
 
 #include "uvedit_intern.h"
 
+/* Struct containing the needed batches per object.
+ * this optimizes the way how data is requested from
+ * the draw manager. */
+typedef struct UVEditGPUBatches {
+  Object *ob_eval;
+  GPUBatch *faces;
+  GPUBatch *edges;
+  GPUBatch *verts;
+  GPUBatch *facedots;
+} UVEditGPUBatches;
+
 static int draw_uvs_face_check(const ToolSettings *ts)
 {
   /* checks if we are selecting only faces */
@@ -164,40 +175,45 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
 static void uvedit_get_batches(Object *ob,
                                SpaceImage *sima,
                                const Scene *scene,
-                               GPUBatch **faces,
-                               GPUBatch **edges,
-                               GPUBatch **verts,
-                               GPUBatch **facedots)
+                               UVEditGPUBatches *batches,
+                               float *tot_area,
+                               float *tot_area_uv)
 {
   int drawfaces = draw_uvs_face_check(scene->toolsettings);
   const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
   const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
 
   DRW_mesh_batch_cache_validate(ob->data);
-  *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
-  *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
+  batches->edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
+  batches->verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
 
   if (drawfaces) {
-    *facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
+    batches->facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
   }
   else {
-    *facedots = NULL;
+    batches->facedots = NULL;
   }
 
   if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
-    *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_area(ob->data);
+    batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(ob->data, NULL, NULL);
   }
   else if (draw_stretch) {
-    *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_angle(ob->data);
+    batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob->data);
   }
   else if (draw_faces) {
-    *faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
+    batches->faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
   }
   else {
-    *faces = NULL;
+    batches->faces = NULL;
   }
 
   DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
+
+  /* after create_requested we can load the actual areas */
+  float tmp_tot_area, tmp_tot_area_uv;
+  DRW_mesh_batch_cache_get_edituv_faces_stretch_area(ob->data, &tmp_tot_area, &tmp_tot_area_uv);
+  *tot_area += tmp_tot_area;
+  *tot_area_uv += tmp_tot_area_uv;
 }
 
 static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
@@ -279,10 +295,14 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
 }
 
 /* draws uv's in the image space */
-static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph)
+static void draw_uvs(SpaceImage *sima,
+                     Scene *scene,
+                     Depsgraph *depsgraph,
+                     UVEditGPUBatches *batch,
+                     float tot_area_ratio,
+                     float tot_area_ratio_inv)
 {
-  GPUBatch *faces, *edges, *verts, *facedots;
-  Object *ob_eval = DEG_get_evaluated_object(depsgraph, obedit);
+  Object *ob_eval = batch->ob_eval;
   const ToolSettings *ts = scene->toolsettings;
   float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
 
@@ -296,12 +316,10 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
     /* When sync selection is enabled, all faces are drawn (except for hidden)
      * so if cage is the same as the final, there is no point in drawing this. */
     if (!((ts->uv_flag & UV_SYNC_SELECTION) && is_cage_like_final_meshes)) {
-      draw_uvs_shadow(sima, scene, obedit, depsgraph);
+      draw_uvs_shadow(sima, scene, ob_eval, depsgraph);
     }
   }
 
-  uvedit_get_batches(ob_eval, sima, scene, &faces, &edges, &verts, &facedots);
-
   bool interpedges;
   bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
   if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -314,8 +332,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
   GPU_blend_set_func_separate(
       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
 
-  if (faces) {
-    GPU_batch_program_set_builtin(faces,
+  if (batch->faces) {
+    GPU_batch_program_set_builtin(batch->faces,
                                   (draw_stretch) ? (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) ?
                                                    GPU_SHADER_2D_UV_FACES_STRETCH_AREA :
                                                    GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE :
@@ -328,23 +346,27 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
       UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
       UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
       col3[3] *= 0.2; /* Simulate dithering */
-      GPU_batch_uniform_4fv(faces, "faceColor", col1);
-      GPU_batch_uniform_4fv(faces, "selectColor", col2);
-      GPU_batch_uniform_4fv(faces, "activeColor", col3);
+      GPU_batch_uniform_4fv(batch->faces, "faceColor", col1);
+      GPU_batch_uniform_4fv(batch->faces, "selectColor", col2);
+      GPU_batch_uniform_4fv(batch->faces, "activeColor", col3);
     }
     else if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) {
       float asp[2];
       ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]);
-      GPU_batch_uniform_2fv(faces, "aspect", asp);
+      GPU_batch_uniform_2fv(batch->faces, "aspect", asp);
+    }
+    else if (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) {
+      GPU_batch_uniform_1f(batch->faces, "totalAreaRatio", tot_area_ratio);
+      GPU_batch_uniform_1f(batch->faces, "totalAreaRatioInv", tot_area_ratio_inv);
     }
 
-    GPU_batch_draw(faces);
+    GPU_batch_draw(batch->faces);
 
     if (!draw_stretch) {
       GPU_blend(false);
     }
   }
-  if (edges) {
+  if (batch->edges) {
     if (sima->flag & SI_SMOOTH_UV) {
       GPU_line_smooth(true);
       GPU_blend(true);
@@ -356,14 +378,16 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
         GPU_viewport_size_get_f(viewport_size);
 
         GPU_line_width(1.0f);
-        GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-        GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors);
-        GPU_batch_uniform_2f(
-            edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
-        GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */
-        GPU_batch_uniform_1f(edges, "dash_width", 4.0f);
-        GPU_batch_uniform_1f(edges, "dash_factor", 0.5f);
-        GPU_batch_draw(edges);
+        GPU_batch_program_set_builtin(batch->edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+        GPU_batch_uniform_4fv_array(batch->edges, "colors", 2, (float *)dash_colors);
+        GPU_batch_uniform_2f(batch->edges,
+                             "viewport_size",
+                             viewport_size[2] / UI_DPI_FAC,
+                             viewport_size[3] / UI_DPI_FAC);
+        GPU_batch_uniform_1i(batch->edges, "colors_len", 2); /* "advanced" mode */
+        GPU_batch_uniform_1f(batch->edges, "dash_width", 4.0f);
+        GPU_batch_uniform_1f(batch->edges, "dash_factor", 0.5f);
+        GPU_batch_draw(batch->edges);
         break;
       }
       case SI_UVDT_BLACK:
@@ -376,14 +400,14 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
         UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
 
         GPU_batch_program_set_builtin(
-            edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
+            batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
 
         if (sima->dt_uv == SI_UVDT_OUTLINE) {
           /* Black Outline. */
           GPU_line_width(3.0f);
-          GPU_batch_uniform_4f(edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
-          GPU_batch_uniform_4f(edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
-          GPU_batch_draw(edges);
+          GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
+          GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
+          GPU_batch_draw(batch->edges);
 
           UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
         }
@@ -397,9 +421,9 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
         /* Inner Line. Use depth test to insure selection is drawn on top. */
         GPU_depth_test(true);
         GPU_line_width(1.0f);
-        GPU_batch_uniform_4fv(edges, "edgeColor", col1);
-        GPU_batch_uniform_4fv(edges, "selectColor", col2);
-        GPU_batch_draw(edges);
+        GPU_batch_uniform_4fv(batch->edges, "edgeColor", col1);
+        GPU_batch_uniform_4fv(batch->edges, "selectColor", col2);
+        GPU_batch_draw(batch->edges);
         GPU_depth_test(false);
 
         glProvokingVertex(GL_LAST_VERTEX_CONVENTION);
@@ -411,44 +435,44 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
       GPU_blend(false);
     }
   }
-  if (verts || facedots) {
+  if (batch->verts || batch->facedots) {
     UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
-    if (verts) {
+    if (batch->verts) {
       const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
       const float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */
       UI_GetThemeColor4fv(TH_VERTEX, col1);
       GPU_blend(true);
       GPU_program_point_size(true);
 
-      GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS);
-      GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
-      GPU_batch_uniform_4fv(verts, "selectColor", transparent);
-      GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
-      GPU_batch_uniform_1f(verts, "pointSize", (point_size + 1.5f) * M_SQRT2);
-      GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
-      GPU_batch_draw(verts);
+      GPU_batch_program_set_builtin(batch->verts, GPU_SHADER_2D_UV_VERTS);
+      GPU_batch_uniform_4f(batch->verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
+      GPU_batch_uniform_4fv(batch->verts, "selectColor", transparent);
+      GPU_batch_uniform_4fv(batch->verts, "pinnedColor", pinned_col);
+      GPU_batch_uniform_1f(batch->verts, "pointSize", (point_size + 1.5f) * M_SQRT2);
+      GPU_batch_uniform_1f(batch->verts, "outlineWidth", 0.75f);
+      GPU_batch_draw(batch->verts);
 
       /* We have problem in this mode when face order make some verts
        * appear unselected because an adjacent face is not selected and
        * render after the selected face.
        * So, to avoid sorting verts by state we just render selected verts
        * on top. A bit overkill but it's simple. */
-      GPU_batch_uniform_4fv(verts, "vertColor", transparent);
-      GPU_batch_uniform_4fv(verts, "selectColor", col2);
-      GPU_batch_draw(verts);
+      GPU_batch_uniform_4fv(batch->verts, "vertColor", transparent);
+      GPU_batch_uniform_4fv(batch->verts, "selectColor", col2);
+      GPU_batch_draw(batch->verts);
 
       GPU_blend(false);
       GPU_program_point_size(false);
     }
-    if (facedots) {
+    if (batch->facedots) {
       const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE);
       GPU_point_size(point_size);
 
       UI_GetThemeColor4fv(TH_WIRE, col1);
-      GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS);
-      GPU_batch_uniform_4fv(facedots, "vertColor", col1);
-      GPU_batch_uniform_4fv(facedots, "selectColor", col2);
-      GPU_batch_draw(facedots);
+      GPU_batch_program_set_builtin(batch->facedots, GPU_SHADER_2D_UV_FACEDOTS);
+      GPU_batch_uniform_4fv(batch->facedots, "vertColor", col1);
+      GPU_batch_uniform_4fv(batch->facedots, "selectColor", col2);
+      GPU_batch_draw(batch->facedots);
     }
   }
 }
@@ -495,10 +519,32 @@ void ED_uvedit_draw_main(SpaceImage *sima,
         GPU_clear_depth(1.0f);
         GPU_clear(GPU_DEPTH_BIT);
       }
+
+      /* go over all objects and create the batches + add their areas to the total */
+      UVEditGPUBatches *batches = MEM_mallocN(sizeof(UVEditGPUBatches) * objects_len, __func__);
+      float tot_area = 0.0f;
+      float tot_area_uv = 0.0f;
+      float tot_area_ratio = 0.0f;
+      float tot_area_ratio_inv = 0.0f;
+
       for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
         Object *ob_iter = objects[ob_index];
-        draw_uvs(sima, scene, ob_iter, depsgraph);
+        Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
+        batches[ob_index].ob_eval = ob_eval;
+        uvedit_get_batches(ob_eval, sima, scene, &batches[ob_index], &tot_area, &tot_area_uv);
+      }
+
+      if (tot_area > FLT_EPSILON && tot_area_uv > FLT_EPSILON) {
+        tot_area_ratio = tot_area / tot_area_uv;
+        tot_area_ratio_inv = tot_area_uv / tot_area;
+      }
+
+      /* go over all batches created in the previous loop and draw them */
+      for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+        UVEditGPUBatches *batch = &batches[ob_index];
+        draw_uvs(sima, scene, depsgraph, batch, tot_area_ratio, tot_area_ratio_inv);
       }
+      MEM_freeN(batches);
       MEM_freeN(objects);
     }
     else {
index 0ce5504dfa80cf3dedcc8b7b8ff4f79c1f89a1e3..b0fa9eaed21d14a79b6c00304053f244993a7632 100644 (file)
@@ -4,12 +4,15 @@ uniform vec2 aspect;
 
 in vec2 pos;
 
-#ifndef STRETCH_ANGLE
-in float stretch;
-#else
-
+#ifdef STRETCH_ANGLE
 in vec2 uv_angles;
 in float angle;
+
+#else
+in float ratio;
+uniform float totalAreaRatio;
+uniform float totalAreaRatioInv;
+
 #endif
 
 noperspective out vec4 finalColor;
@@ -69,6 +72,12 @@ float angle_normalized_v2v2(vec2 v1, vec2 v2)
   return (q) ? a : M_PI - a;
 }
 
+float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio)
+{
+  ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio;
+  return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
+}
+
 void main()
 {
   gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
@@ -80,6 +89,9 @@ void main()
   float stretch = 1.0 - abs(uv_angle - angle);
   stretch = stretch;
   stretch = 1.0 - stretch * stretch;
+#else
+  float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, -totalAreaRatioInv);
+
 #endif
 
   finalColor = vec4(weight_to_rgb(stretch), 1.0);