Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt_uv.c
| Show First 20 Lines • Show All 213 Lines • ▼ Show 20 Lines | if (dist <= radius) { | ||||
| strength * | strength * | ||||
| (tmp_uvdata[i].p[1] - | (tmp_uvdata[i].p[1] - | ||||
| 0.5f * (tmp_uvdata[i].b[1] + | 0.5f * (tmp_uvdata[i].b[1] + | ||||
| tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter)); | tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter)); | ||||
| apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); | apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); | ||||
| for (element = sculptdata->uv[i].element; element; element = element->next) { | for (element = sculptdata->uv[i].element; element; element = element->next) { | ||||
| MLoopUV *luv; | float(*luv)[2]; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| if (element->separate && element != sculptdata->uv[i].element) { | if (element->separate && element != sculptdata->uv[i].element) { | ||||
| break; | break; | ||||
| } | } | ||||
| l = element->l; | l = element->l; | ||||
| luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); | luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_PROP_FLOAT2); | ||||
| copy_v2_v2(luv->uv, sculptdata->uv[i].uv); | copy_v2_v2(*luv, sculptdata->uv[i].uv); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(tmp_uvdata); | MEM_SAFE_FREE(tmp_uvdata); | ||||
| } | } | ||||
| /* Legacy version which only does laplacian relaxation. | /* Legacy version which only does laplacian relaxation. | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (dist <= radius) { | ||||
| sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + | sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + | ||||
| strength * tmp_uvdata[i].p[0]; | strength * tmp_uvdata[i].p[0]; | ||||
| sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + | sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + | ||||
| strength * tmp_uvdata[i].p[1]; | strength * tmp_uvdata[i].p[1]; | ||||
| apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); | apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); | ||||
| for (element = sculptdata->uv[i].element; element; element = element->next) { | for (element = sculptdata->uv[i].element; element; element = element->next) { | ||||
| MLoopUV *luv; | float(*luv)[2]; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| if (element->separate && element != sculptdata->uv[i].element) { | if (element->separate && element != sculptdata->uv[i].element) { | ||||
| break; | break; | ||||
| } | } | ||||
| l = element->l; | l = element->l; | ||||
| luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); | luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_PROP_FLOAT2); | ||||
| copy_v2_v2(luv->uv, sculptdata->uv[i].uv); | copy_v2_v2(*luv, sculptdata->uv[i].uv); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(tmp_uvdata); | MEM_SAFE_FREE(tmp_uvdata); | ||||
| } | } | ||||
| static void add_weighted_edge(float (*delta_buf)[3], | static void add_weighted_edge(float (*delta_buf)[3], | ||||
| const UvElement *storage, | const UvElement *storage, | ||||
| const UvElement *ele_next, | const UvElement *ele_next, | ||||
| const UvElement *ele_prev, | const UvElement *ele_prev, | ||||
| const MLoopUV *luv_next, | const float luv_next[2], | ||||
| const MLoopUV *luv_prev, | const float luv_prev[2], | ||||
| const float weight) | const float weight) | ||||
| { | { | ||||
| float delta[2]; | float delta[2]; | ||||
| sub_v2_v2v2(delta, luv_next->uv, luv_prev->uv); | sub_v2_v2v2(delta, luv_next, luv_prev); | ||||
| bool code1 = (ele_prev->flag & MARK_BOUNDARY); | bool code1 = (ele_prev->flag & MARK_BOUNDARY); | ||||
| bool code2 = (ele_next->flag & MARK_BOUNDARY); | bool code2 = (ele_next->flag & MARK_BOUNDARY); | ||||
| if (code1 || (code1 == code2)) { | if (code1 || (code1 == code2)) { | ||||
| int index_next = ele_next - storage; | int index_next = ele_next - storage; | ||||
| delta_buf[index_next][0] -= delta[0] * weight; | delta_buf[index_next][0] -= delta[0] * weight; | ||||
| delta_buf[index_next][1] -= delta[1] * weight; | delta_buf[index_next][1] -= delta[1] * weight; | ||||
| delta_buf[index_next][2] += fabsf(weight); | delta_buf[index_next][2] += fabsf(weight); | ||||
| Show All 35 Lines | static void relaxation_iteration_uv(BMEditMesh *em, | ||||
| if (method == UV_SCULPT_TOOL_RELAX_LAPLACIAN) { | if (method == UV_SCULPT_TOOL_RELAX_LAPLACIAN) { | ||||
| laplacian_relaxation_iteration_uv( | laplacian_relaxation_iteration_uv( | ||||
| em, sculptdata, mouse_coord, alpha, radius_squared, aspect_ratio); | em, sculptdata, mouse_coord, alpha, radius_squared, aspect_ratio); | ||||
| return; | return; | ||||
| } | } | ||||
| struct UvElement **head_table = BM_uv_element_map_ensure_head_table(sculptdata->elementMap); | struct UvElement **head_table = BM_uv_element_map_ensure_head_table(sculptdata->elementMap); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BLI_assert(cd_loop_uv_offset >= 0); | BLI_assert(cd_loop_uv_offset >= 0); | ||||
| const int total_uvs = sculptdata->elementMap->total_uvs; | const int total_uvs = sculptdata->elementMap->total_uvs; | ||||
| float(*delta_buf)[3] = (float(*)[3])MEM_callocN(total_uvs * sizeof(float[3]), __func__); | float(*delta_buf)[3] = (float(*)[3])MEM_callocN(total_uvs * sizeof(float[3]), __func__); | ||||
| const UvElement *storage = sculptdata->elementMap->storage; | const UvElement *storage = sculptdata->elementMap->storage; | ||||
| for (int j = 0; j < total_uvs; j++) { | for (int j = 0; j < total_uvs; j++) { | ||||
| const UvElement *ele_curr = storage + j; | const UvElement *ele_curr = storage + j; | ||||
| const BMFace *efa = ele_curr->l->f; | const BMFace *efa = ele_curr->l->f; | ||||
| const UvElement *ele_next = BM_uv_element_get(sculptdata->elementMap, efa, ele_curr->l->next); | const UvElement *ele_next = BM_uv_element_get(sculptdata->elementMap, efa, ele_curr->l->next); | ||||
| const UvElement *ele_prev = BM_uv_element_get(sculptdata->elementMap, efa, ele_curr->l->prev); | const UvElement *ele_prev = BM_uv_element_get(sculptdata->elementMap, efa, ele_curr->l->prev); | ||||
| const float *v_curr_co = ele_curr->l->v->co; | const float *v_curr_co = ele_curr->l->v->co; | ||||
| const float *v_prev_co = ele_prev->l->v->co; | const float *v_prev_co = ele_prev->l->v->co; | ||||
| const float *v_next_co = ele_next->l->v->co; | const float *v_next_co = ele_next->l->v->co; | ||||
| const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(ele_curr->l, cd_loop_uv_offset); | const float(*luv_curr)[2] = BM_ELEM_CD_GET_FLOAT2_P(ele_curr->l, cd_loop_uv_offset); | ||||
| const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(ele_next->l, cd_loop_uv_offset); | const float(*luv_next)[2] = BM_ELEM_CD_GET_FLOAT2_P(ele_next->l, cd_loop_uv_offset); | ||||
| const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(ele_prev->l, cd_loop_uv_offset); | const float(*luv_prev)[2] = BM_ELEM_CD_GET_FLOAT2_P(ele_prev->l, cd_loop_uv_offset); | ||||
| const UvElement *head_curr = head_table[ele_curr - sculptdata->elementMap->storage]; | const UvElement *head_curr = head_table[ele_curr - sculptdata->elementMap->storage]; | ||||
| const UvElement *head_next = head_table[ele_next - sculptdata->elementMap->storage]; | const UvElement *head_next = head_table[ele_next - sculptdata->elementMap->storage]; | ||||
| const UvElement *head_prev = head_table[ele_prev - sculptdata->elementMap->storage]; | const UvElement *head_prev = head_table[ele_prev - sculptdata->elementMap->storage]; | ||||
| /* If the mesh is triangulated with no boundaries, only one edge is required. */ | /* If the mesh is triangulated with no boundaries, only one edge is required. */ | ||||
| const float weight_curr = tri_weight_v3(method, v_curr_co, v_prev_co, v_next_co); | const float weight_curr = tri_weight_v3(method, v_curr_co, v_prev_co, v_next_co); | ||||
| add_weighted_edge(delta_buf, storage, head_next, head_prev, luv_next, luv_prev, weight_curr); | add_weighted_edge(delta_buf, storage, head_next, head_prev, *luv_next, *luv_prev, weight_curr); | ||||
| /* Triangulated with a boundary? We need the incoming edges to solve the boundary. */ | /* Triangulated with a boundary? We need the incoming edges to solve the boundary. */ | ||||
| const float weight_prev = tri_weight_v3(method, v_prev_co, v_curr_co, v_next_co); | const float weight_prev = tri_weight_v3(method, v_prev_co, v_curr_co, v_next_co); | ||||
| add_weighted_edge(delta_buf, storage, head_next, head_curr, luv_next, luv_curr, weight_prev); | add_weighted_edge(delta_buf, storage, head_next, head_curr, *luv_next, *luv_curr, weight_prev); | ||||
| if (method == UV_SCULPT_TOOL_RELAX_LAPLACIAN) { | if (method == UV_SCULPT_TOOL_RELAX_LAPLACIAN) { | ||||
| /* Laplacian method has zero weights on virtual edges. */ | /* Laplacian method has zero weights on virtual edges. */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Meshes with quads (or other n-gons) need "virtual" edges too. */ | /* Meshes with quads (or other n-gons) need "virtual" edges too. */ | ||||
| const float weight_next = tri_weight_v3(method, v_next_co, v_curr_co, v_prev_co); | const float weight_next = tri_weight_v3(method, v_next_co, v_curr_co, v_prev_co); | ||||
| add_weighted_edge(delta_buf, storage, head_prev, head_curr, luv_prev, luv_curr, weight_next); | add_weighted_edge(delta_buf, storage, head_prev, head_curr, *luv_prev, *luv_curr, weight_next); | ||||
| } | } | ||||
| Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); | Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); | ||||
| for (int i = 0; i < sculptdata->totalUniqueUvs; i++) { | for (int i = 0; i < sculptdata->totalUniqueUvs; i++) { | ||||
| UvAdjacencyElement *adj_el = &sculptdata->uv[i]; | UvAdjacencyElement *adj_el = &sculptdata->uv[i]; | ||||
| if (adj_el->is_locked) { | if (adj_el->is_locked) { | ||||
| continue; /* Locked UVs can't move. */ | continue; /* Locked UVs can't move. */ | ||||
| } | } | ||||
| /* Is UV within brush's influence? */ | /* Is UV within brush's influence? */ | ||||
| float diff[2]; | float diff[2]; | ||||
| sub_v2_v2v2(diff, adj_el->uv, mouse_coord); | sub_v2_v2v2(diff, adj_el->uv, mouse_coord); | ||||
| diff[1] /= aspect_ratio; | diff[1] /= aspect_ratio; | ||||
| const float dist_squared = len_squared_v2(diff); | const float dist_squared = len_squared_v2(diff); | ||||
| if (dist_squared > radius_squared) { | if (dist_squared > radius_squared) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const float strength = alpha * BKE_brush_curve_strength_clamped( | const float strength = alpha * BKE_brush_curve_strength_clamped( | ||||
| brush, sqrtf(dist_squared), sqrtf(radius_squared)); | brush, sqrtf(dist_squared), sqrtf(radius_squared)); | ||||
| const float *delta_sum = delta_buf[adj_el->element - storage]; | const float *delta_sum = delta_buf[adj_el->element - storage]; | ||||
| { | { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(adj_el->element->l, cd_loop_uv_offset); | const float(*luv)[2] = BM_ELEM_CD_GET_FLOAT2_P(adj_el->element->l, cd_loop_uv_offset); | ||||
| BLI_assert(adj_el->uv == luv->uv); /* Only true for head. */ | BLI_assert(adj_el->uv == (float *)luv); /* Only true for head. */ | ||||
| adj_el->uv[0] = luv->uv[0] + strength * safe_divide(delta_sum[0], delta_sum[2]); | adj_el->uv[0] = (*luv)[0] + strength * safe_divide(delta_sum[0], delta_sum[2]); | ||||
| adj_el->uv[1] = luv->uv[1] + strength * safe_divide(delta_sum[1], delta_sum[2]); | adj_el->uv[1] = (*luv)[1] + strength * safe_divide(delta_sum[1], delta_sum[2]); | ||||
| apply_sculpt_data_constraints(sculptdata, adj_el->uv); | apply_sculpt_data_constraints(sculptdata, adj_el->uv); | ||||
| } | } | ||||
| /* Copy UV co-ordinates to all UvElements. */ | /* Copy UV co-ordinates to all UvElements. */ | ||||
| UvElement *tail = adj_el->element; | UvElement *tail = adj_el->element; | ||||
| while (tail) { | while (tail) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(tail->l, cd_loop_uv_offset); | float(*luv)[2] = BM_ELEM_CD_GET_FLOAT2_P(tail->l, cd_loop_uv_offset); | ||||
| copy_v2_v2(luv->uv, adj_el->uv); | copy_v2_v2(*luv, adj_el->uv); | ||||
| tail = tail->next; | tail = tail->next; | ||||
| if (tail && tail->separate) { | if (tail && tail->separate) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(delta_buf); | MEM_SAFE_FREE(delta_buf); | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | for (i = 0; i < sculptdata->totalUniqueUvs; i++) { | ||||
| normalize_v2(diff); | normalize_v2(diff); | ||||
| sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f; | sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f; | ||||
| sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f; | sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f; | ||||
| apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); | apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); | ||||
| for (element = sculptdata->uv[i].element; element; element = element->next) { | for (element = sculptdata->uv[i].element; element; element = element->next) { | ||||
| MLoopUV *luv; | float(*luv)[2]; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| if (element->separate && element != sculptdata->uv[i].element) { | if (element->separate && element != sculptdata->uv[i].element) { | ||||
| break; | break; | ||||
| } | } | ||||
| l = element->l; | l = element->l; | ||||
| luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); | luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_PROP_FLOAT2); | ||||
| copy_v2_v2(luv->uv, sculptdata->uv[i].uv); | copy_v2_v2(*luv, sculptdata->uv[i].uv); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * Relax Tool | * Relax Tool | ||||
| */ | */ | ||||
| Show All 17 Lines | for (i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++) { | ||||
| sculptdata->uv[uvindex].uv[0] = | sculptdata->uv[uvindex].uv[0] = | ||||
| sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength * diff[0]; | sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength * diff[0]; | ||||
| sculptdata->uv[uvindex].uv[1] = | sculptdata->uv[uvindex].uv[1] = | ||||
| sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1]; | sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1]; | ||||
| apply_sculpt_data_constraints(sculptdata, sculptdata->uv[uvindex].uv); | apply_sculpt_data_constraints(sculptdata, sculptdata->uv[uvindex].uv); | ||||
| for (element = sculptdata->uv[uvindex].element; element; element = element->next) { | for (element = sculptdata->uv[uvindex].element; element; element = element->next) { | ||||
| MLoopUV *luv; | float(*luv)[2]; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| if (element->separate && element != sculptdata->uv[uvindex].element) { | if (element->separate && element != sculptdata->uv[uvindex].element) { | ||||
| break; | break; | ||||
| } | } | ||||
| l = element->l; | l = element->l; | ||||
| luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); | luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_PROP_FLOAT2); | ||||
| copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv); | copy_v2_v2(*luv, sculptdata->uv[uvindex].uv); | ||||
| } | } | ||||
| } | } | ||||
| if (sima->flag & SI_LIVE_UNWRAP) { | if (sima->flag & SI_LIVE_UNWRAP) { | ||||
| ED_uvedit_live_unwrap_re_solve(); | ED_uvedit_live_unwrap_re_solve(); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| op->customdata = data; | op->customdata = data; | ||||
| BKE_curvemapping_init(ts->uvsculpt->paint.brush->curve); | BKE_curvemapping_init(ts->uvsculpt->paint.brush->curve); | ||||
| if (data) { | if (data) { | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| float co[2]; | float co[2]; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| MLoopUV *luv; | float(*luv)[2]; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| UvEdge *edges; | UvEdge *edges; | ||||
| GHash *edgeHash; | GHash *edgeHash; | ||||
| GHashIterator gh_iter; | GHashIterator gh_iter; | ||||
| bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS); | bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS); | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | if (!data->uv || !uniqueUv || !edgeHash || !edges) { | ||||
| } | } | ||||
| uv_sculpt_stroke_exit(C, op); | uv_sculpt_stroke_exit(C, op); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| data->totalUniqueUvs = unique_uvs; | data->totalUniqueUvs = unique_uvs; | ||||
| /* Index for the UvElements. */ | /* Index for the UvElements. */ | ||||
| int counter = -1; | int counter = -1; | ||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| /* initialize the unique UVs */ | /* initialize the unique UVs */ | ||||
| for (int i = 0; i < bm->totvert; i++) { | for (int i = 0; i < bm->totvert; i++) { | ||||
| UvElement *element = data->elementMap->vertex[i]; | UvElement *element = data->elementMap->vertex[i]; | ||||
| for (; element; element = element->next) { | for (; element; element = element->next) { | ||||
| if (element->separate) { | if (element->separate) { | ||||
| if (do_island_optimization && (element->island != island_index)) { | if (do_island_optimization && (element->island != island_index)) { | ||||
| /* skip this uv if not on the active island */ | /* skip this uv if not on the active island */ | ||||
| for (; element->next && !(element->next->separate); element = element->next) { | for (; element->next && !(element->next->separate); element = element->next) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| continue; | continue; | ||||
| } | } | ||||
| l = element->l; | luv = BM_ELEM_CD_GET_FLOAT2_P(element->l, offsets.uv); | ||||
| luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); | |||||
| counter++; | counter++; | ||||
| data->uv[counter].element = element; | data->uv[counter].element = element; | ||||
| data->uv[counter].uv = luv->uv; | data->uv[counter].uv = *luv; | ||||
| if (data->tool != UV_SCULPT_TOOL_GRAB) { | if (data->tool != UV_SCULPT_TOOL_GRAB) { | ||||
| if (luv->flag & MLOOPUV_PINNED) { | if (BM_ELEM_CD_GET_BOOL(element->l, offsets.pin)) { | ||||
| data->uv[counter].is_locked = true; | data->uv[counter].is_locked = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Pointer arithmetic to the rescue, as always :). */ | /* Pointer arithmetic to the rescue, as always :). */ | ||||
| uniqueUv[element - data->elementMap->storage] = counter; | uniqueUv[element - data->elementMap->storage] = counter; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 253 Lines • Show Last 20 Lines | |||||