65#define MARK_BOUNDARY 1
156 uv[0] =
clamp_f(uv[0], u, u + 1.0f);
167 CLAMP(strength, 0.0f, 1.0f);
183 const int cd_loop_uv_offset,
184 const float mouse_coord[2],
186 const float radius_sq,
187 const float aspectRatio)
191 const float radius =
sqrtf(radius_sq);
211 tmp_uvdata[i].
b[0] =
diff[0] - sculptdata->
uv[i].
uv[0];
212 tmp_uvdata[i].
b[1] =
diff[1] - sculptdata->
uv[i].
uv[1];
227 diff[1] /= aspectRatio;
229 if (dist <= radius_sq) {
234 sculptdata->
uv[i].
uv[0] = (1.0f - strength) * sculptdata->
uv[i].
uv[0] +
236 (tmp_uvdata[i].
p[0] -
237 0.5f * (tmp_uvdata[i].
b[0] +
239 sculptdata->
uv[i].
uv[1] = (1.0f - strength) * sculptdata->
uv[i].
uv[1] +
241 (tmp_uvdata[i].
p[1] -
242 0.5f * (tmp_uvdata[i].
b[1] +
247 for (element = sculptdata->
uv[i].
element;
element; element = element->next) {
248 if (element->separate && element != sculptdata->
uv[i].
element) {
268 const int cd_loop_uv_offset,
269 const float mouse_coord[2],
271 const float radius_sq,
272 const float aspectRatio)
276 const float radius =
sqrtf(radius_sq);
286 if (code1 || (code1 == code2)) {
290 if (code2 || (code1 == code2)) {
299 copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
300 mul_v2_fl(tmp_uvdata[i].p, 1.0f / tmp_uvdata[i].ncounter);
309 diff[1] /= aspectRatio;
311 if (dist <= radius_sq) {
316 sculptdata->
uv[i].
uv[0] = (1.0f - strength) * sculptdata->
uv[i].
uv[0] +
317 strength * tmp_uvdata[i].
p[0];
318 sculptdata->
uv[i].
uv[1] = (1.0f - strength) * sculptdata->
uv[i].
uv[1] +
319 strength * tmp_uvdata[i].
p[1];
323 for (element = sculptdata->
uv[i].
element;
element; element = element->next) {
324 if (element->separate && element != sculptdata->
uv[i].
element) {
341 const float luv_next[2],
342 const float luv_prev[2],
350 if (code1 || (code1 == code2)) {
351 int index_next = ele_next - storage;
352 delta_buf[index_next][0] -= delta[0] * weight;
353 delta_buf[index_next][1] -= delta[1] * weight;
354 delta_buf[index_next][2] +=
fabsf(weight);
356 if (code2 || (code1 == code2)) {
357 int index_prev = ele_prev - storage;
358 delta_buf[index_prev][0] += delta[0] * weight;
359 delta_buf[index_prev][1] += delta[1] * weight;
360 delta_buf[index_prev][2] +=
fabsf(weight);
364static float tri_weight_v3(
int method,
const float *v1,
const float *
v2,
const float *v3)
379 const int cd_loop_uv_offset,
380 const float mouse_coord[2],
382 const float radius_sq,
383 const float aspect_ratio,
388 sculptdata, cd_loop_uv_offset, mouse_coord, alpha, radius_sq, aspect_ratio);
393 sculptdata, cd_loop_uv_offset, mouse_coord, alpha, radius_sq, aspect_ratio);
403 for (
int j = 0; j < total_uvs; j++) {
408 const float *v_curr_co = ele_curr->
l->
v->
co;
409 const float *v_prev_co = ele_prev->
l->
v->
co;
410 const float *v_next_co = ele_next->
l->
v->
co;
421 const float weight_curr =
tri_weight_v3(method, v_curr_co, v_prev_co, v_next_co);
422 add_weighted_edge(delta_buf, storage, head_next, head_prev, *luv_next, *luv_prev, weight_curr);
425 const float weight_prev =
tri_weight_v3(method, v_prev_co, v_curr_co, v_next_co);
426 add_weighted_edge(delta_buf, storage, head_next, head_curr, *luv_next, *luv_curr, weight_prev);
434 const float weight_next =
tri_weight_v3(method, v_next_co, v_curr_co, v_prev_co);
435 add_weighted_edge(delta_buf, storage, head_prev, head_curr, *luv_prev, *luv_curr, weight_next);
447 diff[1] /= aspect_ratio;
449 if (dist_sq > radius_sq) {
454 const float *delta_sum = delta_buf[adj_el->
element - storage];
459 adj_el->
uv[0] = (*luv)[0] + strength *
safe_divide(delta_sum[0], delta_sum[2]);
460 adj_el->
uv[1] = (*luv)[1] + strength *
safe_divide(delta_sum[1], delta_sum[2]);
502 const float radius = sculptdata->
uvsculpt->
size / (width * zoomx);
503 float aspectRatio = width /
float(height);
506 const float radius_sq = radius * radius;
521 diff[1] /= aspectRatio;
523 if (dist <= radius_sq) {
529 sculptdata->
uv[i].
uv[0] -= strength *
diff[0] * 0.001f;
530 sculptdata->
uv[i].
uv[1] -= strength *
diff[1] * 0.001f;
534 for (element = sculptdata->
uv[i].
element;
element; element = element->next) {
535 if (element->separate && element != sculptdata->
uv[i].
element) {
564 sculptdata->
uv[uvindex].
uv[0] =
566 sculptdata->
uv[uvindex].
uv[1] =
571 for (element = sculptdata->
uv[uvindex].
element;
element; element = element->next) {
572 if (element->separate && element != sculptdata->
uv[uvindex].
element) {
598 data->elementMap =
nullptr;
601 if (data->initial_stroke) {
613 const bool do_islands)
616 if (!element || (do_islands && element->island != island_index)) {
619 return element - map->storage;
633 if ((edge1->
uv1 == edge2->
uv1) && (edge1->
uv2 == edge2->
uv2)) {
643 element = element->next;
644 if (!element || element->separate) {
677 int island_index = 0;
694 const bool use_winding =
false;
695 const bool use_seams =
true;
697 bm, scene,
false, use_winding, use_seams, do_island_optimization);
699 if (!data->elementMap) {
708 if (do_island_optimization) {
714 island_index = element->island;
719 int unique_uvs = data->elementMap->total_unique_uvs;
720 if (do_island_optimization) {
721 unique_uvs = data->elementMap->island_total_unique_uvs[island_index];
725 data->uv = MEM_cnew_array<UvAdjacencyElement>(unique_uvs, __func__);
727 int *uniqueUv =
static_cast<int *
>(
728 MEM_mallocN(
sizeof(*uniqueUv) * data->elementMap->total_uvs, __func__));
731 UvEdge *edges = MEM_cnew_array<UvEdge>(data->elementMap->total_uvs, __func__);
732 if (!data->uv || !uniqueUv || !edgeHash || !edges) {
742 data->totalUniqueUvs = unique_uvs;
749 UvElement *element = data->elementMap->vertex[i];
750 for (;
element; element = element->next) {
751 if (element->separate) {
752 if (do_island_optimization && (element->island != island_index)) {
754 for (; element->next && !(element->next->separate); element = element->next) {
763 data->uv[counter].element =
element;
764 data->uv[counter].uv = *luv;
767 data->uv[counter].is_locked =
true;
772 uniqueUv[element - data->elementMap->storage] = counter;
782 data->elementMap,
l, island_index, do_island_optimization);
784 data->elementMap,
l->
next, island_index, do_island_optimization);
787 if (itmp1 == -1 || itmp2 == -1) {
791 int offset1 = uniqueUv[itmp1];
792 int offset2 = uniqueUv[itmp2];
796 if (offset1 < offset2) {
797 edges[counter].uv1 = offset1;
798 edges[counter].uv2 = offset2;
801 edges[counter].uv1 = offset2;
802 edges[counter].uv2 = offset1;
807 edges[counter].is_interior =
true;
819 data->uvedges = MEM_cnew_array<UvEdge>(
BLI_ghash_len(edgeHash), __func__);
820 if (!data->uvedges) {
841 for (
int i = 0; i < data->totalUvEdges; i++) {
842 if (!data->uvedges[i].is_interior) {
843 data->uv[data->uvedges[i].uv1].is_boundary =
true;
844 data->uv[data->uvedges[i].uv2].is_boundary =
true;
846 data->uv[data->uvedges[i].uv1].is_locked =
true;
847 data->uv[data->uvedges[i].uv2].is_locked =
true;
860 float alpha = data->uvsculpt->strength;
861 float radius = data->uvsculpt->size;
867 float aspectRatio = width /
float(height);
868 radius /= (width * zoomx);
869 const float radius_sq = radius * radius;
873 MEM_mallocN(
sizeof(*data->initial_stroke), __func__));
874 if (!data->initial_stroke) {
878 sizeof(*data->initial_stroke->initialSelection) * data->totalUniqueUvs, __func__));
879 if (!data->initial_stroke->initialSelection) {
883 copy_v2_v2(data->initial_stroke->init_coord, co);
886 for (
int i = 0; i < data->totalUniqueUvs; i++) {
887 if (data->uv[i].is_locked) {
893 diff[1] /= aspectRatio;
895 if (dist <= radius_sq) {
899 data->initial_stroke->initialSelection[counter].uv = i;
900 data->initial_stroke->initialSelection[counter].strength = strength;
901 copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv);
906 data->initial_stroke->totalInitialSelected = counter;
943 switch (event->
type) {
974 ot->
srna,
"use_invert",
false,
"Invert",
"Invert action for the duration of the stroke");
982 ot->
idname =
"SCULPT_OT_uv_sculpt_grab";
997 ot->
idname =
"SCULPT_OT_uv_sculpt_relax";
1012 "Use Laplacian method for relaxation"},
1018 "Use Geometry (cotangent) relaxation, making UVs follow the underlying 3D geometry"},
1019 {0,
nullptr, 0,
nullptr,
nullptr},
1027 "Algorithm used for UV relaxation");
1034 ot->
idname =
"SCULPT_OT_uv_sculpt_pinch";
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
SpaceImage * CTX_wm_space_image(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
int BKE_image_find_nearest_tile_with_offset(const Image *image, const float co[2], float r_uv_offset[2]) ATTR_NONNULL(2
#define BLI_assert_unreachable()
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
unsigned int BLI_ghashutil_uinthash(unsigned int key)
#define GHASH_ITER(gh_iter_, ghash_)
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
void BLI_ghash_insert(GHash *gh, void *key, void *val)
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float safe_divide(float a, float b)
float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3])
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float n[2])
void DEG_id_tag_update(ID *id, unsigned int flags)
Object is a sort of wrapper for general info.
void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
void ED_space_image_get_zoom(SpaceImage *sima, const ARegion *region, float *r_zoomx, float *r_zoomy)
UvElement * BM_uv_element_get(const UvElementMap *element_map, const BMLoop *l)
void BM_uv_element_map_free(UvElementMap *element_map)
UvElementMap * BM_uv_element_map_create(BMesh *bm, const Scene *scene, bool uv_selected, bool use_winding, bool use_seams, bool do_islands)
UvElement ** BM_uv_element_map_ensure_head_table(UvElementMap *element_map)
bool ED_operator_uvedit_space_image(bContext *C)
void ED_region_tag_redraw(ARegion *region)
void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit, struct wmWindow *win_modal)
void ED_uvedit_live_unwrap_re_solve()
void ED_uvedit_live_unwrap_end(bool cancel)
Read Guarded memory(de)allocation.
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#define BM_ELEM_CD_GET_BOOL(ele, offset)
#define BM_ELEM_CD_GET_FLOAT2_P(ele, offset)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
ATTR_WARN_UNUSED_RESULT BMesh * bm
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
BMUVOffsets BM_uv_map_get_offsets(const BMesh *bm)
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
void *(* MEM_mallocN)(size_t len, const char *str)
void *(* MEM_callocN)(size_t len, const char *str)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void SCULPT_OT_uv_sculpt_relax(wmOperatorType *ot)
static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void laplacian_relaxation_iteration_uv(UvSculptData *sculptdata, const int cd_loop_uv_offset, const float mouse_coord[2], const float alpha, const float radius_sq, const float aspectRatio)
static void register_common_props(wmOperatorType *ot)
@ UV_SCULPT_BRUSH_TYPE_RELAX_HC
@ UV_SCULPT_BRUSH_TYPE_RELAX_COTAN
@ UV_SCULPT_BRUSH_TYPE_RELAX_LAPLACIAN
static UvSculptData * uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event)
static void relaxation_iteration_uv(UvSculptData *sculptdata, const int cd_loop_uv_offset, const float mouse_coord[2], const float alpha, const float radius_sq, const float aspect_ratio, const int method)
static void add_weighted_edge(float(*delta_buf)[3], const UvElement *storage, const UvElement *ele_next, const UvElement *ele_prev, const float luv_next[2], const float luv_prev[2], const float weight)
static bool uv_edge_compare(const void *a, const void *b)
static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@ UV_SCULPT_BRUSH_TYPE_GRAB
@ UV_SCULPT_BRUSH_TYPE_PINCH
@ UV_SCULPT_BRUSH_TYPE_RELAX
static float tri_weight_v3(int method, const float *v1, const float *v2, const float *v3)
static void apply_sculpt_data_constraints(UvSculptData *sculptdata, float uv[2])
static int uv_element_offset_from_face_get(UvElementMap *map, BMLoop *l, int island_index, const bool do_islands)
static void HC_relaxation_iteration_uv(UvSculptData *sculptdata, const int cd_loop_uv_offset, const float mouse_coord[2], const float alpha, const float radius_sq, const float aspectRatio)
static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *event, Object *obedit)
static uint uv_edge_hash(const void *key)
void SCULPT_OT_uv_sculpt_pinch(wmOperatorType *ot)
static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
static void set_element_flag(UvElement *element, const int flag)
void SCULPT_OT_uv_sculpt_grab(wmOperatorType *ot)
static float calc_strength(const UvSculptData *sculptdata, float p, const float len)
UVInitialStrokeElement * initialSelection
UVInitialStroke * initial_stroke
UvElementMap * elementMap
struct CurveMapping * strength_curve
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
struct wmOperatorType * type
bool uv_find_nearest_vert(Scene *scene, Object *obedit, const float co[2], float penalty_dist, UvNearestHit *hit)
UvNearestHit uv_nearest_hit_init_max(const View2D *v2d)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const int event_type, const double time_step)