diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/sculpt_paint/sculpt_uv.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_uv.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_uv.c | 1512 |
1 files changed, 768 insertions, 744 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index dde09bb0f45..39ada703b9b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -22,7 +22,6 @@ * \ingroup edsculpt */ - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -64,126 +63,123 @@ #include "UI_view2d.h" -#define MARK_BOUNDARY 1 +#define MARK_BOUNDARY 1 typedef struct UvAdjacencyElement { - /* pointer to original uvelement */ - UvElement *element; - /* uv pointer for convenience. Caution, this points to the original UVs! */ - float *uv; - /* general use flag (Used to check if Element is boundary here) */ - char flag; + /* pointer to original uvelement */ + UvElement *element; + /* uv pointer for convenience. Caution, this points to the original UVs! */ + float *uv; + /* general use flag (Used to check if Element is boundary here) */ + char flag; } UvAdjacencyElement; typedef struct UvEdge { - unsigned int uv1; - unsigned int uv2; - /* general use flag - * (Used to check if edge is boundary here, and propagates to adjacency elements) */ - char flag; + unsigned int uv1; + unsigned int uv2; + /* general use flag + * (Used to check if edge is boundary here, and propagates to adjacency elements) */ + char flag; } UvEdge; typedef struct UVInitialStrokeElement { - /* index to unique uv */ - int uv; + /* index to unique uv */ + int uv; - /* strength of brush on initial position */ - float strength; + /* strength of brush on initial position */ + float strength; - /* initial uv position */ - float initial_uv[2]; + /* initial uv position */ + float initial_uv[2]; } UVInitialStrokeElement; typedef struct UVInitialStroke { - /* Initial Selection,for grab brushes for instance */ - UVInitialStrokeElement *initialSelection; + /* Initial Selection,for grab brushes for instance */ + UVInitialStrokeElement *initialSelection; - /* total initially selected UVs*/ - int totalInitialSelected; + /* total initially selected UVs*/ + int totalInitialSelected; - /* initial mouse coordinates */ - float init_coord[2]; + /* initial mouse coordinates */ + float init_coord[2]; } UVInitialStroke; - /* custom data for uv smoothing brush */ typedef struct UvSculptData { - /* Contains the first of each set of coincident uvs. - * These will be used to perform smoothing on and propagate the changes - * to their coincident uvs */ - UvAdjacencyElement *uv; + /* Contains the first of each set of coincident uvs. + * These will be used to perform smoothing on and propagate the changes + * to their coincident uvs */ + UvAdjacencyElement *uv; - /* ...Is what it says */ - int totalUniqueUvs; + /* ...Is what it says */ + int totalUniqueUvs; - /* Edges used for adjacency info, used with laplacian smoothing */ - UvEdge *uvedges; + /* Edges used for adjacency info, used with laplacian smoothing */ + UvEdge *uvedges; - /* need I say more? */ - int totalUvEdges; + /* need I say more? */ + int totalUvEdges; - /* data for initial stroke, used by tools like grab */ - UVInitialStroke *initial_stroke; + /* data for initial stroke, used by tools like grab */ + UVInitialStroke *initial_stroke; - /* timer to be used for airbrush-type brush */ - wmTimer *timer; + /* timer to be used for airbrush-type brush */ + wmTimer *timer; - /* to determine quickly adjacent uvs */ - UvElementMap *elementMap; + /* to determine quickly adjacent uvs */ + UvElementMap *elementMap; - /* uvsmooth Paint for fast reference */ - Paint *uvsculpt; + /* uvsmooth Paint for fast reference */ + Paint *uvsculpt; - /* tool to use. duplicating here to change if modifier keys are pressed */ - char tool; + /* tool to use. duplicating here to change if modifier keys are pressed */ + char tool; - /* store invert flag here */ - char invert; + /* store invert flag here */ + char invert; } UvSculptData; - static Brush *uv_sculpt_brush(bContext *C) { - Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; + Scene *scene = CTX_data_scene(C); + ToolSettings *settings = scene->toolsettings; - if (!settings->uvsculpt) - return NULL; - return BKE_paint_brush(&settings->uvsculpt->paint); + if (!settings->uvsculpt) + return NULL; + return BKE_paint_brush(&settings->uvsculpt->paint); } - static bool uv_sculpt_brush_poll_do(bContext *C, const bool check_region) { - BMEditMesh *em; - int ret; - Object *obedit = CTX_data_edit_object(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *toolsettings = scene->toolsettings; - - if (!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH || - !sima || ED_space_image_show_render(sima) || (sima->mode == SI_MODE_PAINT)) - { - return 0; - } - - em = BKE_editmesh_from_object(obedit); - ret = EDBM_uv_check(em); - - if (ret) { - ARegion *ar = CTX_wm_region(C); - if ((!toolsettings->use_uv_sculpt) || (check_region && ar && (ar->regiontype != RGN_TYPE_WINDOW))) { - ret = 0; - } - } - - return ret; + BMEditMesh *em; + int ret; + Object *obedit = CTX_data_edit_object(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *toolsettings = scene->toolsettings; + + if (!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH || !sima || + ED_space_image_show_render(sima) || (sima->mode == SI_MODE_PAINT)) { + return 0; + } + + em = BKE_editmesh_from_object(obedit); + ret = EDBM_uv_check(em); + + if (ret) { + ARegion *ar = CTX_wm_region(C); + if ((!toolsettings->use_uv_sculpt) || + (check_region && ar && (ar->regiontype != RGN_TYPE_WINDOW))) { + ret = 0; + } + } + + return ret; } static bool uv_sculpt_brush_poll(bContext *C) { - return uv_sculpt_brush_poll_do(C, true); + return uv_sculpt_brush_poll_do(C, true); } static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(customdata)) @@ -191,74 +187,70 @@ static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(cu #define PX_SIZE_FADE_MAX 12.0f #define PX_SIZE_FADE_MIN 4.0f - Scene *scene = CTX_data_scene(C); - //Brush *brush = image_paint_brush(C); - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *brush = BKE_paint_brush(paint); - - if (paint && brush && paint->flags & PAINT_SHOW_BRUSH) { - const float size = (float)BKE_brush_size_get(scene, brush); - float alpha = 0.5f; - - /* fade out the brush (cheap trick to work around brush interfering with sampling [#])*/ - if (size < PX_SIZE_FADE_MIN) { - return; - } - else if (size < PX_SIZE_FADE_MAX) { - alpha *= (size - PX_SIZE_FADE_MIN) / (PX_SIZE_FADE_MAX - PX_SIZE_FADE_MIN); - } - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor3fvAlpha(brush->add_col, alpha); - - GPU_line_smooth(true); - GPU_blend(true); - imm_draw_circle_wire_2d(pos, (float)x, (float)y, size, 40); - GPU_blend(false); - GPU_line_smooth(false); - - immUnbindProgram(); - } + Scene *scene = CTX_data_scene(C); + //Brush *brush = image_paint_brush(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = BKE_paint_brush(paint); + + if (paint && brush && paint->flags & PAINT_SHOW_BRUSH) { + const float size = (float)BKE_brush_size_get(scene, brush); + float alpha = 0.5f; + + /* fade out the brush (cheap trick to work around brush interfering with sampling [#])*/ + if (size < PX_SIZE_FADE_MIN) { + return; + } + else if (size < PX_SIZE_FADE_MAX) { + alpha *= (size - PX_SIZE_FADE_MIN) / (PX_SIZE_FADE_MAX - PX_SIZE_FADE_MIN); + } + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fvAlpha(brush->add_col, alpha); + + GPU_line_smooth(true); + GPU_blend(true); + imm_draw_circle_wire_2d(pos, (float)x, (float)y, size, 40); + GPU_blend(false); + GPU_line_smooth(false); + + immUnbindProgram(); + } #undef PX_SIZE_FADE_MAX #undef PX_SIZE_FADE_MIN } - void ED_space_image_uv_sculpt_update(Main *bmain, wmWindowManager *wm, Scene *scene) { - ToolSettings *settings = scene->toolsettings; - if (settings->use_uv_sculpt) { - if (settings->uvsculpt == NULL) { - settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB; - settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS; - settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN; - } - BKE_paint_ensure(settings, (Paint **)&settings->uvsculpt); - BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT_UV, PAINT_CURSOR_SCULPT); - - settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate( - wm, - SPACE_IMAGE, RGN_TYPE_WINDOW, - uv_sculpt_brush_poll, - brush_drawcursor_uvsculpt, NULL); - } - else { - if (settings->uvsculpt) { - WM_paint_cursor_end(wm, settings->uvsculpt->paint.paint_cursor); - settings->uvsculpt->paint.paint_cursor = NULL; - } - } + ToolSettings *settings = scene->toolsettings; + if (settings->use_uv_sculpt) { + if (settings->uvsculpt == NULL) { + settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB; + settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS; + settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN; + } + BKE_paint_ensure(settings, (Paint **)&settings->uvsculpt); + BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT_UV, PAINT_CURSOR_SCULPT); + + settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate( + wm, SPACE_IMAGE, RGN_TYPE_WINDOW, uv_sculpt_brush_poll, brush_drawcursor_uvsculpt, NULL); + } + else { + if (settings->uvsculpt) { + WM_paint_cursor_end(wm, settings->uvsculpt->paint.paint_cursor); + settings->uvsculpt->paint.paint_cursor = NULL; + } + } } bool uv_sculpt_poll(bContext *C) { - return uv_sculpt_brush_poll_do(C, true); + return uv_sculpt_brush_poll_do(C, true); } bool uv_sculpt_keymap_poll(bContext *C) { - return uv_sculpt_brush_poll_do(C, false); + return uv_sculpt_brush_poll_do(C, false); } /*********** Improved Laplacian Relaxation Operator ************************/ @@ -267,660 +259,692 @@ bool uv_sculpt_keymap_poll(bContext *C) ***************************************************************************/ typedef struct Temp_UvData { - float sum_co[2], p[2], b[2], sum_b[2]; - int ncounter; + float sum_co[2], p[2], b[2], sum_b[2]; + int ncounter; } Temp_UVData; - - -static void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], - float alpha, float radius, float aspectRatio) +static void HC_relaxation_iteration_uv(BMEditMesh *em, + UvSculptData *sculptdata, + float mouse_coord[2], + float alpha, + float radius, + float aspectRatio) { - Temp_UVData *tmp_uvdata; - float diff[2]; - int i; - float radius_root = sqrtf(radius); - Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); - - tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data"); - - /* counting neighbors */ - for (i = 0; i < sculptdata->totalUvEdges; i++) { - UvEdge *tmpedge = sculptdata->uvedges + i; - tmp_uvdata[tmpedge->uv1].ncounter++; - tmp_uvdata[tmpedge->uv2].ncounter++; - - add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv); - add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv); - } - - for (i = 0; i < sculptdata->totalUniqueUvs; i++) { - copy_v2_v2(diff, tmp_uvdata[i].sum_co); - mul_v2_fl(diff, 1.f / tmp_uvdata[i].ncounter); - copy_v2_v2(tmp_uvdata[i].p, diff); - - tmp_uvdata[i].b[0] = diff[0] - sculptdata->uv[i].uv[0]; - tmp_uvdata[i].b[1] = diff[1] - sculptdata->uv[i].uv[1]; - } - - for (i = 0; i < sculptdata->totalUvEdges; i++) { - UvEdge *tmpedge = sculptdata->uvedges + i; - add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_b, tmp_uvdata[tmpedge->uv2].b); - add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_b, tmp_uvdata[tmpedge->uv1].b); - } - - for (i = 0; i < sculptdata->totalUniqueUvs; i++) { - float dist; - /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start - * If ever uv brushes get their own mode we should check for toolsettings option too */ - if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) { - continue; - } - - sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord); - diff[1] /= aspectRatio; - if ((dist = dot_v2v2(diff, diff)) <= radius) { - UvElement *element; - float strength; - strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); - - sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + strength * (tmp_uvdata[i].p[0] - 0.5f * (tmp_uvdata[i].b[0] + tmp_uvdata[i].sum_b[0] / tmp_uvdata[i].ncounter)); - sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * (tmp_uvdata[i].p[1] - 0.5f * (tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter)); - - for (element = sculptdata->uv[i].element; element; element = element->next) { - MLoopUV *luv; - BMLoop *l; - - if (element->separate && element != sculptdata->uv[i].element) - break; - - l = element->l; - luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(luv->uv, sculptdata->uv[i].uv); - } - } - } - - MEM_freeN(tmp_uvdata); - - return; + Temp_UVData *tmp_uvdata; + float diff[2]; + int i; + float radius_root = sqrtf(radius); + Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); + + tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), + "Temporal data"); + + /* counting neighbors */ + for (i = 0; i < sculptdata->totalUvEdges; i++) { + UvEdge *tmpedge = sculptdata->uvedges + i; + tmp_uvdata[tmpedge->uv1].ncounter++; + tmp_uvdata[tmpedge->uv2].ncounter++; + + add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv); + add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv); + } + + for (i = 0; i < sculptdata->totalUniqueUvs; i++) { + copy_v2_v2(diff, tmp_uvdata[i].sum_co); + mul_v2_fl(diff, 1.f / tmp_uvdata[i].ncounter); + copy_v2_v2(tmp_uvdata[i].p, diff); + + tmp_uvdata[i].b[0] = diff[0] - sculptdata->uv[i].uv[0]; + tmp_uvdata[i].b[1] = diff[1] - sculptdata->uv[i].uv[1]; + } + + for (i = 0; i < sculptdata->totalUvEdges; i++) { + UvEdge *tmpedge = sculptdata->uvedges + i; + add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_b, tmp_uvdata[tmpedge->uv2].b); + add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_b, tmp_uvdata[tmpedge->uv1].b); + } + + for (i = 0; i < sculptdata->totalUniqueUvs; i++) { + float dist; + /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start + * If ever uv brushes get their own mode we should check for toolsettings option too */ + if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) { + continue; + } + + sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord); + diff[1] /= aspectRatio; + if ((dist = dot_v2v2(diff, diff)) <= radius) { + UvElement *element; + float strength; + strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); + + sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + + strength * + (tmp_uvdata[i].p[0] - + 0.5f * (tmp_uvdata[i].b[0] + + tmp_uvdata[i].sum_b[0] / tmp_uvdata[i].ncounter)); + sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + + strength * + (tmp_uvdata[i].p[1] - + 0.5f * (tmp_uvdata[i].b[1] + + tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter)); + + for (element = sculptdata->uv[i].element; element; element = element->next) { + MLoopUV *luv; + BMLoop *l; + + if (element->separate && element != sculptdata->uv[i].element) + break; + + l = element->l; + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, sculptdata->uv[i].uv); + } + } + } + + MEM_freeN(tmp_uvdata); + + return; } -static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio) +static void laplacian_relaxation_iteration_uv(BMEditMesh *em, + UvSculptData *sculptdata, + float mouse_coord[2], + float alpha, + float radius, + float aspectRatio) { - Temp_UVData *tmp_uvdata; - float diff[2]; - int i; - float radius_root = sqrtf(radius); - Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); - - tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data"); - - /* counting neighbors */ - for (i = 0; i < sculptdata->totalUvEdges; i++) { - UvEdge *tmpedge = sculptdata->uvedges + i; - tmp_uvdata[tmpedge->uv1].ncounter++; - tmp_uvdata[tmpedge->uv2].ncounter++; - - add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv); - add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv); - } - - /* Original Lacplacian algorithm included removal of normal component of translation. here it is not - * needed since we translate along the UV plane always.*/ - for (i = 0; i < sculptdata->totalUniqueUvs; i++) { - copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co); - mul_v2_fl(tmp_uvdata[i].p, 1.f / tmp_uvdata[i].ncounter); - } - - for (i = 0; i < sculptdata->totalUniqueUvs; i++) { - float dist; - /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start - * If ever uv brushes get their own mode we should check for toolsettings option too */ - if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) { - continue; - } - - sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord); - diff[1] /= aspectRatio; - if ((dist = dot_v2v2(diff, diff)) <= radius) { - UvElement *element; - float strength; - strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); - - sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + strength * tmp_uvdata[i].p[0]; - sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * tmp_uvdata[i].p[1]; - - for (element = sculptdata->uv[i].element; element; element = element->next) { - MLoopUV *luv; - BMLoop *l; - - if (element->separate && element != sculptdata->uv[i].element) - break; - - l = element->l; - luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(luv->uv, sculptdata->uv[i].uv); - } - } - } - - MEM_freeN(tmp_uvdata); - - return; + Temp_UVData *tmp_uvdata; + float diff[2]; + int i; + float radius_root = sqrtf(radius); + Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); + + tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), + "Temporal data"); + + /* counting neighbors */ + for (i = 0; i < sculptdata->totalUvEdges; i++) { + UvEdge *tmpedge = sculptdata->uvedges + i; + tmp_uvdata[tmpedge->uv1].ncounter++; + tmp_uvdata[tmpedge->uv2].ncounter++; + + add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv); + add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv); + } + + /* Original Lacplacian algorithm included removal of normal component of translation. here it is not + * needed since we translate along the UV plane always.*/ + for (i = 0; i < sculptdata->totalUniqueUvs; i++) { + copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co); + mul_v2_fl(tmp_uvdata[i].p, 1.f / tmp_uvdata[i].ncounter); + } + + for (i = 0; i < sculptdata->totalUniqueUvs; i++) { + float dist; + /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start + * If ever uv brushes get their own mode we should check for toolsettings option too */ + if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) { + continue; + } + + sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord); + diff[1] /= aspectRatio; + if ((dist = dot_v2v2(diff, diff)) <= radius) { + UvElement *element; + float strength; + strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); + + sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + + strength * tmp_uvdata[i].p[0]; + sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + + strength * tmp_uvdata[i].p[1]; + + for (element = sculptdata->uv[i].element; element; element = element->next) { + MLoopUV *luv; + BMLoop *l; + + if (element->separate && element != sculptdata->uv[i].element) + break; + + l = element->l; + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, sculptdata->uv[i].uv); + } + } + } + + MEM_freeN(tmp_uvdata); + + return; } - -static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *event, Object *obedit) +static void uv_sculpt_stroke_apply(bContext *C, + wmOperator *op, + const wmEvent *event, + Object *obedit) { - float co[2], radius, radius_root; - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - unsigned int tool; - UvSculptData *sculptdata = (UvSculptData *)op->customdata; - SpaceImage *sima; - int invert; - int width, height; - float aspectRatio; - float alpha, zoomx, zoomy; - Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); - ToolSettings *toolsettings = CTX_data_tool_settings(C); - tool = sculptdata->tool; - invert = sculptdata->invert ? -1 : 1; - alpha = BKE_brush_alpha_get(scene, brush); - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - - sima = CTX_wm_space_image(C); - ED_space_image_get_size(sima, &width, &height); - ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); - - radius = BKE_brush_size_get(scene, brush) / (width * zoomx); - aspectRatio = width / (float)height; - - /* We will compare squares to save some computation */ - radius = radius * radius; - radius_root = sqrtf(radius); - - /* - * Pinch Tool - */ - if (tool == UV_SCULPT_TOOL_PINCH) { - int i; - alpha *= invert; - for (i = 0; i < sculptdata->totalUniqueUvs; i++) { - float dist, diff[2]; - /* This is supposed to happen only if "Lock Borders" is on, since we have initialization on stroke start - * If ever uv brushes get their own mode we should check for toolsettings option too */ - if (sculptdata->uv[i].flag & MARK_BOUNDARY) { - continue; - } - - sub_v2_v2v2(diff, sculptdata->uv[i].uv, co); - diff[1] /= aspectRatio; - if ((dist = dot_v2v2(diff, diff)) <= radius) { - UvElement *element; - float strength; - strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); - normalize_v2(diff); - - sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f; - sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f; - - for (element = sculptdata->uv[i].element; element; element = element->next) { - MLoopUV *luv; - BMLoop *l; - - if (element->separate && element != sculptdata->uv[i].element) - break; - - l = element->l; - luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(luv->uv, sculptdata->uv[i].uv); - } - } - } - } - - /* - * Smooth Tool - */ - else if (tool == UV_SCULPT_TOOL_RELAX) { - unsigned int method = toolsettings->uv_relax_method; - if (method == UV_SCULPT_TOOL_RELAX_HC) { - HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio); - } - else { - laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio); - } - } - - /* - * Grab Tool - */ - else if (tool == UV_SCULPT_TOOL_GRAB) { - int i; - float diff[2]; - sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord); - - for (i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++) { - UvElement *element; - int uvindex = sculptdata->initial_stroke->initialSelection[i].uv; - float strength = sculptdata->initial_stroke->initialSelection[i].strength; - sculptdata->uv[uvindex].uv[0] = sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength * diff[0]; - sculptdata->uv[uvindex].uv[1] = sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1]; - - for (element = sculptdata->uv[uvindex].element; element; element = element->next) { - MLoopUV *luv; - BMLoop *l; - - if (element->separate && element != sculptdata->uv[uvindex].element) - break; - - l = element->l; - luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv); - } - } - } + float co[2], radius, radius_root; + Scene *scene = CTX_data_scene(C); + ARegion *ar = CTX_wm_region(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + unsigned int tool; + UvSculptData *sculptdata = (UvSculptData *)op->customdata; + SpaceImage *sima; + int invert; + int width, height; + float aspectRatio; + float alpha, zoomx, zoomy; + Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); + ToolSettings *toolsettings = CTX_data_tool_settings(C); + tool = sculptdata->tool; + invert = sculptdata->invert ? -1 : 1; + alpha = BKE_brush_alpha_get(scene, brush); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + + sima = CTX_wm_space_image(C); + ED_space_image_get_size(sima, &width, &height); + ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); + + radius = BKE_brush_size_get(scene, brush) / (width * zoomx); + aspectRatio = width / (float)height; + + /* We will compare squares to save some computation */ + radius = radius * radius; + radius_root = sqrtf(radius); + + /* + * Pinch Tool + */ + if (tool == UV_SCULPT_TOOL_PINCH) { + int i; + alpha *= invert; + for (i = 0; i < sculptdata->totalUniqueUvs; i++) { + float dist, diff[2]; + /* This is supposed to happen only if "Lock Borders" is on, since we have initialization on stroke start + * If ever uv brushes get their own mode we should check for toolsettings option too */ + if (sculptdata->uv[i].flag & MARK_BOUNDARY) { + continue; + } + + sub_v2_v2v2(diff, sculptdata->uv[i].uv, co); + diff[1] /= aspectRatio; + if ((dist = dot_v2v2(diff, diff)) <= radius) { + UvElement *element; + float strength; + strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); + normalize_v2(diff); + + sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f; + sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f; + + for (element = sculptdata->uv[i].element; element; element = element->next) { + MLoopUV *luv; + BMLoop *l; + + if (element->separate && element != sculptdata->uv[i].element) + break; + + l = element->l; + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, sculptdata->uv[i].uv); + } + } + } + } + + /* + * Smooth Tool + */ + else if (tool == UV_SCULPT_TOOL_RELAX) { + unsigned int method = toolsettings->uv_relax_method; + if (method == UV_SCULPT_TOOL_RELAX_HC) { + HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio); + } + else { + laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio); + } + } + + /* + * Grab Tool + */ + else if (tool == UV_SCULPT_TOOL_GRAB) { + int i; + float diff[2]; + sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord); + + for (i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++) { + UvElement *element; + int uvindex = sculptdata->initial_stroke->initialSelection[i].uv; + float strength = sculptdata->initial_stroke->initialSelection[i].strength; + sculptdata->uv[uvindex].uv[0] = + sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength * diff[0]; + sculptdata->uv[uvindex].uv[1] = + sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1]; + + for (element = sculptdata->uv[uvindex].element; element; element = element->next) { + MLoopUV *luv; + BMLoop *l; + + if (element->separate && element != sculptdata->uv[uvindex].element) + break; + + l = element->l; + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv); + } + } + } } - static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op) { - UvSculptData *data = op->customdata; - if (data->timer) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer); - } - if (data->elementMap) { - BM_uv_element_map_free(data->elementMap); - } - if (data->uv) { - MEM_freeN(data->uv); - } - if (data->uvedges) { - MEM_freeN(data->uvedges); - } - if (data->initial_stroke) { - if (data->initial_stroke->initialSelection) { - MEM_freeN(data->initial_stroke->initialSelection); - } - MEM_freeN(data->initial_stroke); - } - - MEM_freeN(data); - op->customdata = NULL; + UvSculptData *data = op->customdata; + if (data->timer) { + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer); + } + if (data->elementMap) { + BM_uv_element_map_free(data->elementMap); + } + if (data->uv) { + MEM_freeN(data->uv); + } + if (data->uvedges) { + MEM_freeN(data->uvedges); + } + if (data->initial_stroke) { + if (data->initial_stroke->initialSelection) { + MEM_freeN(data->initial_stroke->initialSelection); + } + MEM_freeN(data->initial_stroke); + } + + MEM_freeN(data); + op->customdata = NULL; } -static int uv_element_offset_from_face_get(UvElementMap *map, BMFace *efa, BMLoop *l, int island_index, const bool doIslands) +static int uv_element_offset_from_face_get( + UvElementMap *map, BMFace *efa, BMLoop *l, int island_index, const bool doIslands) { - UvElement *element = BM_uv_element_get(map, efa, l); - if (!element || (doIslands && element->island != island_index)) { - return -1; - } - return element - map->buf; + UvElement *element = BM_uv_element_get(map, efa, l); + if (!element || (doIslands && element->island != island_index)) { + return -1; + } + return element - map->buf; } - static unsigned int uv_edge_hash(const void *key) { - const UvEdge *edge = key; - return (BLI_ghashutil_uinthash(edge->uv2) + - BLI_ghashutil_uinthash(edge->uv1)); + const UvEdge *edge = key; + return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1)); } static bool uv_edge_compare(const void *a, const void *b) { - const UvEdge *edge1 = a; - const UvEdge *edge2 = b; + const UvEdge *edge1 = a; + const UvEdge *edge2 = b; - if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { - return 0; - } - return 1; + if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { + return 0; + } + return 1; } - static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event) { - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - ToolSettings *ts = scene->toolsettings; - UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data"); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - op->customdata = data; - - curvemapping_initialize(ts->uvsculpt->paint.brush->curve); - - if (data) { - int counter = 0, i; - ARegion *ar = CTX_wm_region(C); - float co[2]; - BMFace *efa; - MLoopUV *luv; - BMLoop *l; - BMIter iter, liter; - - UvEdge *edges; - GHash *edgeHash; - GHashIterator gh_iter; - - bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS); - int island_index = 0; - /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/ - int *uniqueUv; - data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ? UV_SCULPT_TOOL_RELAX : ts->uv_sculpt_tool; - data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT) ? 1 : 0; - - data->uvsculpt = &ts->uvsculpt->paint; - - if (do_island_optimization) { - /* We will need island information */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - data->elementMap = BM_uv_element_map_create(bm, false, true, true); - } - else { - data->elementMap = BM_uv_element_map_create(bm, true, true, true); - } - } - else { - if (ts->uv_flag & UV_SYNC_SELECTION) { - data->elementMap = BM_uv_element_map_create(bm, false, true, false); - } - else { - data->elementMap = BM_uv_element_map_create(bm, true, true, false); - } - } - - if (!data->elementMap) { - uv_sculpt_stroke_exit(C, op); - return NULL; - } - - /* Mouse coordinates, useful for some functions like grab and sculpt all islands */ - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - - /* we need to find the active island here */ - if (do_island_optimization) { - UvElement *element; - UvNearestHit hit = UV_NEAREST_HIT_INIT; - Image *ima = CTX_data_edit_image(C); - uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit); - - element = BM_uv_element_get(data->elementMap, hit.efa, hit.l); - island_index = element->island; - } - - - /* Count 'unique' uvs */ - for (i = 0; i < data->elementMap->totalUVs; i++) { - if (data->elementMap->buf[i].separate && - (!do_island_optimization || data->elementMap->buf[i].island == island_index)) - { - counter++; - } - } - - /* Allocate the unique uv buffers */ - data->uv = MEM_mallocN(sizeof(*data->uv) * counter, "uv_brush_unique_uvs"); - uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->totalUVs, "uv_brush_unique_uv_map"); - edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash"); - /* we have at most totalUVs edges */ - edges = MEM_mallocN(sizeof(*edges) * data->elementMap->totalUVs, "uv_brush_all_edges"); - if (!data->uv || !uniqueUv || !edgeHash || !edges) { - if (edges) { - MEM_freeN(edges); - } - if (uniqueUv) { - MEM_freeN(uniqueUv); - } - if (edgeHash) { - BLI_ghash_free(edgeHash, NULL, NULL); - } - uv_sculpt_stroke_exit(C, op); - return NULL; - } - - data->totalUniqueUvs = counter; - /* So that we can use this as index for the UvElements */ - counter = -1; - /* initialize the unique UVs */ - for (i = 0; i < bm->totvert; i++) { - UvElement *element = data->elementMap->vert[i]; - for (; element; element = element->next) { - if (element->separate) { - if (do_island_optimization && (element->island != island_index)) { - /* skip this uv if not on the active island */ - for (; element->next && !(element->next->separate); element = element->next) - ; - continue; - } - - l = element->l; - luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - - counter++; - data->uv[counter].element = element; - data->uv[counter].flag = 0; - data->uv[counter].uv = luv->uv; - } - /* pointer arithmetic to the rescue, as always :)*/ - uniqueUv[element - data->elementMap->buf] = counter; - } - } - - - /* Now, on to generate our uv connectivity data */ - counter = 0; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - int offset1, itmp1 = uv_element_offset_from_face_get(data->elementMap, efa, l, island_index, do_island_optimization); - int offset2, itmp2 = uv_element_offset_from_face_get(data->elementMap, efa, l->next, island_index, do_island_optimization); - char *flag; - - /* Skip edge if not found(unlikely) or not on valid island */ - if (itmp1 == -1 || itmp2 == -1) - continue; - - offset1 = uniqueUv[itmp1]; - offset2 = uniqueUv[itmp2]; - - edges[counter].flag = 0; - /* using an order policy, sort uvs according to address space. This avoids - * Having two different UvEdges with the same uvs on different positions */ - if (offset1 < offset2) { - edges[counter].uv1 = offset1; - edges[counter].uv2 = offset2; - } - else { - edges[counter].uv1 = offset2; - edges[counter].uv2 = offset1; - } - /* Hack! Set the value of the key to its flag. - * Now we can set the flag when an edge exists twice :) */ - flag = BLI_ghash_lookup(edgeHash, &edges[counter]); - if (flag) { - *flag = 1; - } - else { - /* Hack mentioned */ - BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag); - } - counter++; - } - } - - MEM_freeN(uniqueUv); - - /* Allocate connectivity data, we allocate edges once */ - data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash), "uv_brush_edge_connectivity_data"); - if (!data->uvedges) { - BLI_ghash_free(edgeHash, NULL, NULL); - MEM_freeN(edges); - uv_sculpt_stroke_exit(C, op); - return NULL; - } - - /* fill the edges with data */ - i = 0; - GHASH_ITER (gh_iter, edgeHash) { - data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); - } - data->totalUvEdges = BLI_ghash_len(edgeHash); - - /* cleanup temporary stuff */ - BLI_ghash_free(edgeHash, NULL, NULL); - MEM_freeN(edges); - - /* transfer boundary edge property to uvs */ - if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) { - for (i = 0; i < data->totalUvEdges; i++) { - if (!data->uvedges[i].flag) { - data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY; - data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY; - } - } - } - - /* Allocate initial selection for grab tool */ - if (data->tool == UV_SCULPT_TOOL_GRAB) { - float radius, radius_root; - UvSculptData *sculptdata = (UvSculptData *)op->customdata; - SpaceImage *sima; - int width, height; - float aspectRatio; - float alpha, zoomx, zoomy; - Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); - - alpha = BKE_brush_alpha_get(scene, brush); - - radius = BKE_brush_size_get(scene, brush); - sima = CTX_wm_space_image(C); - ED_space_image_get_size(sima, &width, &height); - ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); - - aspectRatio = width / (float)height; - radius /= (width * zoomx); - radius = radius * radius; - radius_root = sqrtf(radius); - - /* Allocate selection stack */ - data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke), "uv_sculpt_initial_stroke"); - if (!data->initial_stroke) { - uv_sculpt_stroke_exit(C, op); - } - data->initial_stroke->initialSelection = MEM_mallocN(sizeof(*data->initial_stroke->initialSelection) * data->totalUniqueUvs, "uv_sculpt_initial_selection"); - if (!data->initial_stroke->initialSelection) { - uv_sculpt_stroke_exit(C, op); - } - - copy_v2_v2(data->initial_stroke->init_coord, co); - - counter = 0; - - for (i = 0; i < data->totalUniqueUvs; i++) { - float dist, diff[2]; - if (data->uv[i].flag & MARK_BOUNDARY) { - continue; - } - - sub_v2_v2v2(diff, data->uv[i].uv, co); - diff[1] /= aspectRatio; - if ((dist = dot_v2v2(diff, diff)) <= radius) { - float strength; - strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); - - data->initial_stroke->initialSelection[counter].uv = i; - data->initial_stroke->initialSelection[counter].strength = strength; - copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv); - counter++; - } - } - - data->initial_stroke->totalInitialSelected = counter; - } - } - - return op->customdata; + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + ToolSettings *ts = scene->toolsettings; + UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data"); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + op->customdata = data; + + curvemapping_initialize(ts->uvsculpt->paint.brush->curve); + + if (data) { + int counter = 0, i; + ARegion *ar = CTX_wm_region(C); + float co[2]; + BMFace *efa; + MLoopUV *luv; + BMLoop *l; + BMIter iter, liter; + + UvEdge *edges; + GHash *edgeHash; + GHashIterator gh_iter; + + bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS); + int island_index = 0; + /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/ + int *uniqueUv; + data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ? UV_SCULPT_TOOL_RELAX : + ts->uv_sculpt_tool; + data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT) ? 1 : 0; + + data->uvsculpt = &ts->uvsculpt->paint; + + if (do_island_optimization) { + /* We will need island information */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + data->elementMap = BM_uv_element_map_create(bm, false, true, true); + } + else { + data->elementMap = BM_uv_element_map_create(bm, true, true, true); + } + } + else { + if (ts->uv_flag & UV_SYNC_SELECTION) { + data->elementMap = BM_uv_element_map_create(bm, false, true, false); + } + else { + data->elementMap = BM_uv_element_map_create(bm, true, true, false); + } + } + + if (!data->elementMap) { + uv_sculpt_stroke_exit(C, op); + return NULL; + } + + /* Mouse coordinates, useful for some functions like grab and sculpt all islands */ + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + + /* we need to find the active island here */ + if (do_island_optimization) { + UvElement *element; + UvNearestHit hit = UV_NEAREST_HIT_INIT; + Image *ima = CTX_data_edit_image(C); + uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit); + + element = BM_uv_element_get(data->elementMap, hit.efa, hit.l); + island_index = element->island; + } + + /* Count 'unique' uvs */ + for (i = 0; i < data->elementMap->totalUVs; i++) { + if (data->elementMap->buf[i].separate && + (!do_island_optimization || data->elementMap->buf[i].island == island_index)) { + counter++; + } + } + + /* Allocate the unique uv buffers */ + data->uv = MEM_mallocN(sizeof(*data->uv) * counter, "uv_brush_unique_uvs"); + uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->totalUVs, + "uv_brush_unique_uv_map"); + edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash"); + /* we have at most totalUVs edges */ + edges = MEM_mallocN(sizeof(*edges) * data->elementMap->totalUVs, "uv_brush_all_edges"); + if (!data->uv || !uniqueUv || !edgeHash || !edges) { + if (edges) { + MEM_freeN(edges); + } + if (uniqueUv) { + MEM_freeN(uniqueUv); + } + if (edgeHash) { + BLI_ghash_free(edgeHash, NULL, NULL); + } + uv_sculpt_stroke_exit(C, op); + return NULL; + } + + data->totalUniqueUvs = counter; + /* So that we can use this as index for the UvElements */ + counter = -1; + /* initialize the unique UVs */ + for (i = 0; i < bm->totvert; i++) { + UvElement *element = data->elementMap->vert[i]; + for (; element; element = element->next) { + if (element->separate) { + if (do_island_optimization && (element->island != island_index)) { + /* skip this uv if not on the active island */ + for (; element->next && !(element->next->separate); element = element->next) + ; + continue; + } + + l = element->l; + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + counter++; + data->uv[counter].element = element; + data->uv[counter].flag = 0; + data->uv[counter].uv = luv->uv; + } + /* pointer arithmetic to the rescue, as always :)*/ + uniqueUv[element - data->elementMap->buf] = counter; + } + } + + /* Now, on to generate our uv connectivity data */ + counter = 0; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + int offset1, itmp1 = uv_element_offset_from_face_get( + data->elementMap, efa, l, island_index, do_island_optimization); + int offset2, itmp2 = uv_element_offset_from_face_get( + data->elementMap, efa, l->next, island_index, do_island_optimization); + char *flag; + + /* Skip edge if not found(unlikely) or not on valid island */ + if (itmp1 == -1 || itmp2 == -1) + continue; + + offset1 = uniqueUv[itmp1]; + offset2 = uniqueUv[itmp2]; + + edges[counter].flag = 0; + /* using an order policy, sort uvs according to address space. This avoids + * Having two different UvEdges with the same uvs on different positions */ + if (offset1 < offset2) { + edges[counter].uv1 = offset1; + edges[counter].uv2 = offset2; + } + else { + edges[counter].uv1 = offset2; + edges[counter].uv2 = offset1; + } + /* Hack! Set the value of the key to its flag. + * Now we can set the flag when an edge exists twice :) */ + flag = BLI_ghash_lookup(edgeHash, &edges[counter]); + if (flag) { + *flag = 1; + } + else { + /* Hack mentioned */ + BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag); + } + counter++; + } + } + + MEM_freeN(uniqueUv); + + /* Allocate connectivity data, we allocate edges once */ + data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash), + "uv_brush_edge_connectivity_data"); + if (!data->uvedges) { + BLI_ghash_free(edgeHash, NULL, NULL); + MEM_freeN(edges); + uv_sculpt_stroke_exit(C, op); + return NULL; + } + + /* fill the edges with data */ + i = 0; + GHASH_ITER (gh_iter, edgeHash) { + data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); + } + data->totalUvEdges = BLI_ghash_len(edgeHash); + + /* cleanup temporary stuff */ + BLI_ghash_free(edgeHash, NULL, NULL); + MEM_freeN(edges); + + /* transfer boundary edge property to uvs */ + if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) { + for (i = 0; i < data->totalUvEdges; i++) { + if (!data->uvedges[i].flag) { + data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY; + data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY; + } + } + } + + /* Allocate initial selection for grab tool */ + if (data->tool == UV_SCULPT_TOOL_GRAB) { + float radius, radius_root; + UvSculptData *sculptdata = (UvSculptData *)op->customdata; + SpaceImage *sima; + int width, height; + float aspectRatio; + float alpha, zoomx, zoomy; + Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); + + alpha = BKE_brush_alpha_get(scene, brush); + + radius = BKE_brush_size_get(scene, brush); + sima = CTX_wm_space_image(C); + ED_space_image_get_size(sima, &width, &height); + ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); + + aspectRatio = width / (float)height; + radius /= (width * zoomx); + radius = radius * radius; + radius_root = sqrtf(radius); + + /* Allocate selection stack */ + data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke), + "uv_sculpt_initial_stroke"); + if (!data->initial_stroke) { + uv_sculpt_stroke_exit(C, op); + } + data->initial_stroke->initialSelection = MEM_mallocN( + sizeof(*data->initial_stroke->initialSelection) * data->totalUniqueUvs, + "uv_sculpt_initial_selection"); + if (!data->initial_stroke->initialSelection) { + uv_sculpt_stroke_exit(C, op); + } + + copy_v2_v2(data->initial_stroke->init_coord, co); + + counter = 0; + + for (i = 0; i < data->totalUniqueUvs; i++) { + float dist, diff[2]; + if (data->uv[i].flag & MARK_BOUNDARY) { + continue; + } + + sub_v2_v2v2(diff, data->uv[i].uv, co); + diff[1] /= aspectRatio; + if ((dist = dot_v2v2(diff, diff)) <= radius) { + float strength; + strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); + + data->initial_stroke->initialSelection[counter].uv = i; + data->initial_stroke->initialSelection[counter].strength = strength; + copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv); + counter++; + } + } + + data->initial_stroke->totalInitialSelected = counter; + } + } + + return op->customdata; } static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - UvSculptData *data; - Object *obedit = CTX_data_edit_object(C); + UvSculptData *data; + Object *obedit = CTX_data_edit_object(C); - if (!(data = uv_sculpt_stroke_init(C, op, event))) { - return OPERATOR_CANCELLED; - } + if (!(data = uv_sculpt_stroke_init(C, op, event))) { + return OPERATOR_CANCELLED; + } - uv_sculpt_stroke_apply(C, op, event, obedit); + uv_sculpt_stroke_apply(C, op, event, obedit); - data->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.001f); + data->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.001f); - if (!data->timer) { - uv_sculpt_stroke_exit(C, op); - return OPERATOR_CANCELLED; - } - WM_event_add_modal_handler(C, op); + if (!data->timer) { + uv_sculpt_stroke_exit(C, op); + return OPERATOR_CANCELLED; + } + WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } - static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) { - UvSculptData *data = (UvSculptData *)op->customdata; - Object *obedit = CTX_data_edit_object(C); - - switch (event->type) { - case LEFTMOUSE: - case MIDDLEMOUSE: - case RIGHTMOUSE: - uv_sculpt_stroke_exit(C, op); - return OPERATOR_FINISHED; - - case MOUSEMOVE: - case INBETWEEN_MOUSEMOVE: - uv_sculpt_stroke_apply(C, op, event, obedit); - break; - case TIMER: - if (event->customdata == data->timer) - uv_sculpt_stroke_apply(C, op, event, obedit); - break; - default: - return OPERATOR_RUNNING_MODAL; - } - - ED_region_tag_redraw(CTX_wm_region(C)); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); - return OPERATOR_RUNNING_MODAL; + UvSculptData *data = (UvSculptData *)op->customdata; + Object *obedit = CTX_data_edit_object(C); + + switch (event->type) { + case LEFTMOUSE: + case MIDDLEMOUSE: + case RIGHTMOUSE: + uv_sculpt_stroke_exit(C, op); + return OPERATOR_FINISHED; + + case MOUSEMOVE: + case INBETWEEN_MOUSEMOVE: + uv_sculpt_stroke_apply(C, op, event, obedit); + break; + case TIMER: + if (event->customdata == data->timer) + uv_sculpt_stroke_apply(C, op, event, obedit); + break; + default: + return OPERATOR_RUNNING_MODAL; + } + + ED_region_tag_redraw(CTX_wm_region(C)); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + return OPERATOR_RUNNING_MODAL; } void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot) { - static const EnumPropertyItem stroke_mode_items[] = { - {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"}, - {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"}, - {BRUSH_STROKE_SMOOTH, "RELAX", 0, "Relax", "Switch brush to relax mode for duration of stroke"}, - {0}, - }; - - /* identifiers */ - ot->name = "Sculpt UVs"; - ot->description = "Sculpt UVs using a brush"; - ot->idname = "SCULPT_OT_uv_sculpt_stroke"; - - /* api callbacks */ - ot->invoke = uv_sculpt_stroke_invoke; - ot->modal = uv_sculpt_stroke_modal; - ot->poll = uv_sculpt_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Mode", "Stroke Mode"); + static const EnumPropertyItem stroke_mode_items[] = { + {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"}, + {BRUSH_STROKE_INVERT, + "INVERT", + 0, + "Invert", + "Invert action of brush for duration of stroke"}, + {BRUSH_STROKE_SMOOTH, + "RELAX", + 0, + "Relax", + "Switch brush to relax mode for duration of stroke"}, + {0}, + }; + + /* identifiers */ + ot->name = "Sculpt UVs"; + ot->description = "Sculpt UVs using a brush"; + ot->idname = "SCULPT_OT_uv_sculpt_stroke"; + + /* api callbacks */ + ot->invoke = uv_sculpt_stroke_invoke; + ot->modal = uv_sculpt_stroke_modal; + ot->poll = uv_sculpt_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Mode", "Stroke Mode"); } |