diff options
4 files changed, 154 insertions, 129 deletions
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index a23689166c4..bab700560fe 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -479,132 +479,6 @@ TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTr /** \name UV Coordinates * \{ */ -/** - * Find the correction for the scaling factor when "Constrain to Bounds" is active. - * \param numerator: How far the UV boundary (unit square) is from the origin of the scale. - * \param denominator: How far the AABB is from the origin of the scale. - * \param scale: Scale parameter to update. - */ -static void constrain_scale_to_boundary(const float numerator, - const float denominator, - float *scale) -{ - if (denominator == 0.0f) { - /* The origin of the scale is on the edge of the boundary. */ - if (numerator < 0.0f) { - /* Negative scale will wrap around and put us outside the boundary. */ - *scale = 0.0f; /* Hold at the boundary instead. */ - } - return; /* Nothing else we can do without more info. */ - } - - const float correction = numerator / denominator; - if (correction < 0.0f || !isfinite(correction)) { - /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */ - return; - } - - if (denominator < 0.0f) { - /* Scale origin is outside boundary, only make scale bigger. */ - if (*scale < correction) { - *scale = correction; - } - return; - } - - /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */ - if (*scale > correction) { - *scale = correction; - } -} - -bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) -{ - bool clipx = true, clipy = true; - float min[2], max[2]; - - /* Check if the current image in UV editor is a tiled image or not. */ - const SpaceImage *sima = t->area->spacedata.first; - const Image *image = sima->image; - const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); - /* Stores the coordinates of the closest UDIM tile. - * Also acts as an offset to the tile from the origin of UV space. */ - float base_offset[2] = {0.0f, 0.0f}; - - /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ - if (is_tiled_image) { - int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global); - if (nearest_tile_index != -1) { - nearest_tile_index -= 1001; - /* Getting coordinates of nearest tile from the tile index. */ - base_offset[0] = nearest_tile_index % 10; - base_offset[1] = nearest_tile_index / 10; - } - } - - min[0] = min[1] = FLT_MAX; - max[0] = max[1] = FLT_MIN; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - - TransData *td; - int a; - - for (a = 0, td = tc->data; a < tc->data_len; a++, td++) { - minmax_v2v2_v2(min, max, td->loc); - } - } - - if (resize) { - /* Assume no change is required. */ - float scalex = 1.0f; - float scaley = 1.0f; - - /* Update U against the left border. */ - constrain_scale_to_boundary( - t->center_global[0] - base_offset[0], t->center_global[0] - min[0], &scalex); - /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */ - constrain_scale_to_boundary(base_offset[0] + t->aspect[0] - t->center_global[0], - max[0] - t->center_global[0], - &scalex); - - /* Do the same for the V co-ordinate, which is called `y`. */ - constrain_scale_to_boundary( - t->center_global[1] - base_offset[1], t->center_global[1] - min[1], &scaley); - constrain_scale_to_boundary(base_offset[1] + t->aspect[1] - t->center_global[1], - max[1] - t->center_global[1], - &scaley); - - clipx = (scalex != 1.0f); - clipy = (scaley != 1.0f); - vec[0] *= scalex; - vec[1] *= scaley; - } - else { - if (min[0] < base_offset[0]) { - vec[0] += base_offset[0] - min[0]; - } - else if (max[0] > base_offset[0] + t->aspect[0]) { - vec[0] -= max[0] - base_offset[0] - t->aspect[0]; - } - else { - clipx = 0; - } - - if (min[1] < base_offset[1]) { - vec[1] += base_offset[1] - min[1]; - } - else if (max[1] > base_offset[1] + t->aspect[1]) { - vec[1] -= max[1] - base_offset[1] - t->aspect[1]; - } - else { - clipy = 0; - } - } - - return (clipx || clipy); -} - void clipUVData(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 037fbe26c77..f25a3db3f75 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -34,7 +34,6 @@ int special_transform_moving(TransInfo *t); void special_aftertrans_update(struct bContext *C, TransInfo *t); void sort_trans_data_dist(TransInfo *t); void createTransData(struct bContext *C, TransInfo *t); -bool clipUVTransform(TransInfo *t, float vec[2], bool resize); void clipUVData(TransInfo *t); void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, float y_fac); /** diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index 31d40486afc..bc45ec07eab 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -11,6 +11,7 @@ #include "BLI_task.h" #include "BKE_context.h" +#include "BKE_image.h" #include "BKE_unit.h" #include "ED_screen.h" @@ -84,6 +85,102 @@ static void ApplySnapResize(TransInfo *t, float vec[3]) } } +/** + * Find the correction for the scaling factor when "Constrain to Bounds" is active. + * \param numerator: How far the UV boundary (unit square) is from the origin of the scale. + * \param denominator: How far the AABB is from the origin of the scale. + * \param scale: Scale parameter to update. + */ +static void constrain_scale_to_boundary(const float numerator, + const float denominator, + float *scale) +{ + if (denominator == 0.0f) { + /* The origin of the scale is on the edge of the boundary. */ + if (numerator < 0.0f) { + /* Negative scale will wrap around and put us outside the boundary. */ + *scale = 0.0f; /* Hold at the boundary instead. */ + } + return; /* Nothing else we can do without more info. */ + } + + const float correction = numerator / denominator; + if (correction < 0.0f || !isfinite(correction)) { + /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */ + return; + } + + if (denominator < 0.0f) { + /* Scale origin is outside boundary, only make scale bigger. */ + if (*scale < correction) { + *scale = correction; + } + return; + } + + /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */ + if (*scale > correction) { + *scale = correction; + } +} + +static bool clip_uv_transform_resize(TransInfo *t, float vec[2]) +{ + /* Assume no change is required. */ + float scalex = 1.0f; + float scaley = 1.0f; + + /* Check if the current image in UV editor is a tiled image or not. */ + const SpaceImage *sima = t->area->spacedata.first; + const Image *image = sima->image; + const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); + + /* Stores the coordinates of the closest UDIM tile. + * Also acts as an offset to the tile from the origin of UV space. */ + float base_offset[2] = {0.0f, 0.0f}; + + /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ + if (is_tiled_image) { + int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global); + if (nearest_tile_index != -1) { + nearest_tile_index -= 1001; + /* Getting coordinates of nearest tile from the tile index. */ + base_offset[0] = nearest_tile_index % 10; + base_offset[1] = nearest_tile_index / 10; + } + } + + float min[2], max[2]; + min[0] = min[1] = FLT_MAX; + max[0] = max[1] = -FLT_MAX; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + + TransData *td; + int a; + for (a = 0, td = tc->data; a < tc->data_len; a++, td++) { + minmax_v2v2_v2(min, max, td->loc); + } + } + + /* Update U against the left border. */ + constrain_scale_to_boundary( + t->center_global[0] - base_offset[0], t->center_global[0] - min[0], &scalex); + /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */ + constrain_scale_to_boundary( + base_offset[0] + t->aspect[0] - t->center_global[0], max[0] - t->center_global[0], &scalex); + + /* Do the same for the V co-ordinate, which is called `y`. */ + constrain_scale_to_boundary( + t->center_global[1] - base_offset[1], t->center_global[1] - min[1], &scaley); + constrain_scale_to_boundary( + base_offset[1] + t->aspect[1] - t->center_global[1], max[1] - t->center_global[1], &scaley); + + vec[0] *= scalex; + vec[1] *= scaley; + return (scalex != 1.0f) || (scaley != 1.0f); +} + static void applyResize(TransInfo *t, const int UNUSED(mval[2])) { float mat[3][3]; @@ -157,7 +254,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2])) } /* Evil hack - redo resize if clipping needed. */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) { + if (t->flag & T_CLIP_UV && clip_uv_transform_resize(t, t->values_final)) { size_to_mat3(mat, t->values_final); if (t->con.mode & CON_APPLY) { diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 65690f9069d..67bdeb3fed0 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -16,6 +16,7 @@ #include "BLI_task.h" #include "BKE_context.h" +#include "BKE_image.h" #include "BKE_report.h" #include "BKE_unit.h" @@ -434,6 +435,60 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) custom_data->prev.rotate_mode = rotate_mode; } +static bool clip_uv_transform_translation(TransInfo *t, float vec[2]) +{ + /* Check if the current image in UV editor is a tiled image or not. */ + const SpaceImage *sima = t->area->spacedata.first; + const Image *image = sima->image; + const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); + + /* Stores the coordinates of the closest UDIM tile. + * Also acts as an offset to the tile from the origin of UV space. */ + float base_offset[2] = {0.0f, 0.0f}; + + /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ + if (is_tiled_image) { + int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global); + if (nearest_tile_index != -1) { + nearest_tile_index -= 1001; + /* Getting coordinates of nearest tile from the tile index. */ + base_offset[0] = nearest_tile_index % 10; + base_offset[1] = nearest_tile_index / 10; + } + } + + float min[2], max[2]; + min[0] = min[1] = FLT_MAX; + max[0] = max[1] = -FLT_MAX; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + for (TransData *td = tc->data; td < tc->data + tc->data_len; td++) { + minmax_v2v2_v2(min, max, td->loc); + } + } + + bool result = false; + if (min[0] < base_offset[0]) { + vec[0] += base_offset[0] - min[0]; + result = true; + } + else if (max[0] > base_offset[0] + t->aspect[0]) { + vec[0] -= max[0] - base_offset[0] - t->aspect[0]; + result = true; + } + + if (min[1] < base_offset[1]) { + vec[1] += base_offset[1] - min[1]; + result = true; + } + else if (max[1] > base_offset[1] + t->aspect[1]) { + vec[1] -= max[1] - base_offset[1] - t->aspect[1]; + result = true; + } + + return result; +} + static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) { char str[UI_MAX_DRAW_STR]; @@ -498,7 +553,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) applyTranslationValue(t, global_dir); /* evil hack - redo translation if clipping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) { + if (t->flag & T_CLIP_UV && clip_uv_transform_translation(t, global_dir)) { applyTranslationValue(t, global_dir); /* In proportional edit it can happen that */ |