Fix T81247: Constrain selected UVs to correct UDIM

With Constrain to Image Bounds selected, UVs will be constrained to the
correct/closest UDIM if the image is tiled.
UVs will be constrained to the 0-1 UV space if the image is not tiled.
This will override the present behavior of always constraining selected
UVs to the 0-1 UV space (UDIM 1001).

Reviewed By: campbellbarton

Ref D11202
This commit is contained in:
Siddhartha Jejurkar 2021-05-13 00:08:16 +10:00 committed by Campbell Barton
parent 79b7c46eec
commit c1f7f18a8e
3 changed files with 76 additions and 19 deletions

View File

@ -325,6 +325,7 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
const float uv[2],
float r_uv[2],
float r_ofs[2]);
int BKE_image_find_nearest_tile(const struct Image *image, const float co[2]);
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *r_width, int *r_height);
void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float r_size[2]);

View File

@ -735,6 +735,37 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
return tile_number;
}
/**
* Return the tile_number for the closest UDIM tile.
*/
int BKE_image_find_nearest_tile(const Image *image, const float co[2])
{
const float co_floor[2] = {floorf(co[0]), floorf(co[1])};
/* Distance to the closest UDIM tile. */
float dist_best_sq = FLT_MAX;
int tile_number_best = -1;
LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
const int tile_index = tile->tile_number - 1001;
/* Coordinates of the current tile. */
const float tile_index_co[2] = {tile_index % 10, tile_index / 10};
if (equals_v2v2(co_floor, tile_index_co)) {
return tile->tile_number;
}
/* Distance between co[2] and UDIM tile. */
const float dist_sq = len_squared_v2v2(tile_index_co, co);
if (dist_sq < dist_best_sq) {
dist_best_sq = dist_sq;
tile_number_best = tile->tile_number;
}
}
return tile_number_best;
}
static void image_init_color_management(Image *ima)
{
ImBuf *ibuf;

View File

@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@ -505,9 +506,27 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
bool clipx = true, clipy = true;
float min[2], max[2];
min[0] = min[1] = 0.0f;
max[0] = t->aspect[0];
max[1] = t->aspect[1];
/* 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) {
@ -520,42 +539,48 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
}
if (resize) {
if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) {
vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
if (min[0] < base_offset[0] && t->center_global[0] > base_offset[0] &&
t->center_global[0] < base_offset[0] + (t->aspect[0] * 0.5f)) {
vec[0] *= (t->center_global[0] - base_offset[0]) / (t->center_global[0] - min[0]);
}
else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) {
vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
else if (max[0] > (base_offset[0] + t->aspect[0]) &&
t->center_global[0] < (base_offset[0] + t->aspect[0])) {
vec[0] *= (t->center_global[0] - (base_offset[0] + t->aspect[0])) /
(t->center_global[0] - max[0]);
}
else {
clipx = 0;
}
if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) {
vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
if (min[1] < base_offset[1] && t->center_global[1] > base_offset[1] &&
t->center_global[1] < base_offset[1] + (t->aspect[1] * 0.5f)) {
vec[1] *= (t->center_global[1] - base_offset[1]) / (t->center_global[1] - min[1]);
}
else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) {
vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
else if (max[1] > (base_offset[1] + t->aspect[1]) &&
t->center_global[1] < (base_offset[1] + t->aspect[1])) {
vec[1] *= (t->center_global[1] - (base_offset[1] + t->aspect[1])) /
(t->center_global[1] - max[1]);
}
else {
clipy = 0;
}
}
else {
if (min[0] < 0.0f) {
vec[0] -= min[0];
if (min[0] < base_offset[0]) {
vec[0] += base_offset[0] - min[0];
}
else if (max[0] > t->aspect[0]) {
vec[0] -= max[0] - t->aspect[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] < 0.0f) {
vec[1] -= min[1];
if (min[1] < base_offset[1]) {
vec[1] += base_offset[1] - min[1];
}
else if (max[1] > t->aspect[1]) {
vec[1] -= max[1] - t->aspect[1];
else if (max[1] > base_offset[1] + t->aspect[1]) {
vec[1] -= max[1] - base_offset[1] - t->aspect[1];
}
else {
clipy = 0;