LEFT | RIGHT |
(no file at all) | |
| 1 /* |
| 2 * ***** BEGIN GPL LICENSE BLOCK ***** |
| 3 * |
| 4 * This program is free software; you can redistribute it and/or |
| 5 * modify it under the terms of the GNU General Public License |
| 6 * as published by the Free Software Foundation; either version 2 |
| 7 * of the License, or (at your option) any later version. |
| 8 * |
| 9 * This program is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. |
| 13 * |
| 14 * You should have received a copy of the GNU General Public License |
| 15 * along with this program; if not, write to the Free Software Foundation, |
| 16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 * |
| 18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. |
| 19 * All rights reserved. |
| 20 * |
| 21 * The Original Code is: all of this file. |
| 22 * |
| 23 * Contributor(s): Antony Riakiotakis. |
| 24 * |
| 25 * ***** END GPL LICENSE BLOCK ***** |
| 26 */ |
| 27 |
| 28 /** \file blender/editors/uvedit/uvedit_stitch.c |
| 29 * \ingroup eduv |
| 30 */ |
| 31 |
| 32 |
| 33 #include <stdlib.h> |
| 34 #include <string.h> |
| 35 #include <math.h> |
| 36 |
| 37 #include "MEM_guardedalloc.h" |
| 38 |
| 39 #include "DNA_object_types.h" |
| 40 #include "DNA_meshdata_types.h" |
| 41 #include "DNA_scene_types.h" |
| 42 |
| 43 #include "BLI_editVert.h" |
| 44 #include "BLI_ghash.h" |
| 45 #include "BLI_math.h" |
| 46 #include "BLI_string.h" |
| 47 |
| 48 #include "BKE_context.h" |
| 49 #include "BKE_customdata.h" |
| 50 #include "BKE_depsgraph.h" |
| 51 #include "BKE_mesh.h" |
| 52 |
| 53 #include "ED_mesh.h" |
| 54 #include "ED_uvedit.h" |
| 55 #include "ED_screen.h" |
| 56 |
| 57 #include "RNA_access.h" |
| 58 #include "RNA_define.h" |
| 59 |
| 60 #include "WM_api.h" |
| 61 #include "WM_types.h" |
| 62 |
| 63 #include "UI_view2d.h" |
| 64 |
| 65 #include "uvedit_intern.h" |
| 66 |
| 67 /* ********************** smart stitch operator *********************** */ |
| 68 |
| 69 |
| 70 struct IslandStitchData; |
| 71 |
| 72 /* This is a straightforward implementation, count the uv's in the island that w
ill move and take the mean displacement/rotation and apply it to all |
| 73 * elements of the island except from the stitchable */ |
| 74 typedef struct IslandStitchData{ |
| 75 /* rotation can be used only for edges, for vertices there is no such no
tion */ |
| 76 float rotation; |
| 77 float translation[2]; |
| 78 /* Used for rotation, the island will rotate around this point */ |
| 79 float medianPoint[2]; |
| 80 int numOfElements; |
| 81 int numOfEdges; |
| 82 /* Flag to remember if island has been added for preview */ |
| 83 char addedForPreview; |
| 84 /* Flag an island to be considered for determining static island */ |
| 85 char stitchableCandidate; |
| 86 }IslandStitchData; |
| 87 |
| 88 /* just for averaging UVs */ |
| 89 typedef struct UVVertAverage { |
| 90 float uv[2]; |
| 91 unsigned short count; |
| 92 } UVVertAverage; |
| 93 |
| 94 typedef struct UvEdge { |
| 95 /* index to uv buffer */ |
| 96 unsigned int uv1; |
| 97 unsigned int uv2; |
| 98 /* general use flag (Used to check if edge is boundary here, and propaga
tes to adjacency elements) */ |
| 99 char flag; |
| 100 /* element that guarantees element->face has the face on element->tfinde
x and element->tfindex+1 is the second uv */ |
| 101 UvElement *element; |
| 102 }UvEdge; |
| 103 |
| 104 |
| 105 /* stitch state object */ |
| 106 typedef struct StitchState { |
| 107 /* use limit flag */ |
| 108 char use_limit; |
| 109 /* limit to operator, same as original operator */ |
| 110 float limit_dist; |
| 111 /* snap uv islands together during stitching */ |
| 112 char snap_islands; |
| 113 /* stich at midpoints or at islands */ |
| 114 char midpoints; |
| 115 /* editmesh, cached for use in modal handler */ |
| 116 EditMesh *em; |
| 117 /* element map for getting info about uv connectivity */ |
| 118 UvElementMap *element_map; |
| 119 /* edge container */ |
| 120 UvEdge *uvedges; |
| 121 /* container of first of a group of coincident uvs, these will be operat
ed upon */ |
| 122 UvElement **uvs; |
| 123 /* maps uvelements to their first coincident uv */ |
| 124 int *map; |
| 125 /* 2D normals per uv to calculate rotation for snapping */ |
| 126 float *normals; |
| 127 /* edge storage */ |
| 128 UvEdge *edges; |
| 129 |
| 130 /* count of separate uvs and edges */ |
| 131 int total_boundary_edges; |
| 132 int total_separate_uvs; |
| 133 /* hold selection related information */ |
| 134 UvElement **selection_stack; |
| 135 int selection_size; |
| 136 /* island that stays in place */ |
| 137 int static_island; |
| 138 /* store number of primitives per face so that we can allocate the activ
e island buffer later */ |
| 139 unsigned int *quads_per_island; |
| 140 unsigned int *tris_per_island; |
| 141 } StitchState; |
| 142 |
| 143 |
| 144 /* |
| 145 * defines for UvElement flags |
| 146 */ |
| 147 #define STITCH_SELECTED 1 |
| 148 #define STITCH_STITCHABLE 2 |
| 149 #define STITCH_PROCESSED 4 |
| 150 #define STITCH_BOUNDARY 8 |
| 151 #define STITCH_STITCHABLE_CANDIDATE 16 |
| 152 |
| 153 #define STITCH_NO_PREVIEW -1 |
| 154 |
| 155 /* previewer stuff (see uvedit_intern.h for more info) */ |
| 156 static StitchPreviewer *_stitch_preview; |
| 157 |
| 158 /* constructor */ |
| 159 static StitchPreviewer * stitch_preview_init(void) |
| 160 { |
| 161 _stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer
"); |
| 162 _stitch_preview->preview_quads = NULL; |
| 163 _stitch_preview->preview_tris = NULL; |
| 164 _stitch_preview->preview_stitchable = NULL; |
| 165 _stitch_preview->preview_unstitchable = NULL; |
| 166 |
| 167 _stitch_preview->num_quads = 0; |
| 168 _stitch_preview->num_tris = 0; |
| 169 _stitch_preview->num_stitchable = 0; |
| 170 _stitch_preview->num_unstitchable = 0; |
| 171 |
| 172 _stitch_preview->static_quads = NULL; |
| 173 _stitch_preview->static_tris = NULL; |
| 174 |
| 175 _stitch_preview->num_static_tris = 0; |
| 176 _stitch_preview->num_static_quads = 0; |
| 177 |
| 178 return _stitch_preview; |
| 179 } |
| 180 |
| 181 /* destructor...yeah this should be C++ :) */ |
| 182 static void stitch_preview_delete(void) |
| 183 { |
| 184 if(_stitch_preview) |
| 185 { |
| 186 if(_stitch_preview->preview_quads){ |
| 187 MEM_freeN(_stitch_preview->preview_quads); |
| 188 _stitch_preview->preview_quads = NULL; |
| 189 } |
| 190 if(_stitch_preview->preview_tris){ |
| 191 MEM_freeN(_stitch_preview->preview_tris); |
| 192 _stitch_preview->preview_tris = NULL; |
| 193 } |
| 194 if(_stitch_preview->preview_stitchable){ |
| 195 MEM_freeN(_stitch_preview->preview_stitchable); |
| 196 _stitch_preview->preview_stitchable = NULL; |
| 197 } |
| 198 if(_stitch_preview->preview_unstitchable){ |
| 199 MEM_freeN(_stitch_preview->preview_unstitchable); |
| 200 _stitch_preview->preview_unstitchable = NULL; |
| 201 } |
| 202 if(_stitch_preview->static_quads){ |
| 203 MEM_freeN(_stitch_preview->static_quads); |
| 204 _stitch_preview->static_quads = NULL; |
| 205 } |
| 206 if(_stitch_preview->static_tris){ |
| 207 MEM_freeN(_stitch_preview->static_tris); |
| 208 _stitch_preview->static_tris = NULL; |
| 209 } |
| 210 MEM_freeN(_stitch_preview); |
| 211 _stitch_preview = NULL; |
| 212 } |
| 213 } |
| 214 |
| 215 |
| 216 /* "getter method" */ |
| 217 StitchPreviewer *uv_get_stitch_previewer(void) |
| 218 { |
| 219 return _stitch_preview; |
| 220 } |
| 221 |
| 222 #define HEADER_LENGTH 256 |
| 223 |
| 224 /* This function updates the header of the UV editor when the stitch tool update
s its settings */ |
| 225 static void stitch_update_header(StitchState *stitch_state, bContext *C) |
| 226 { |
| 227 static char str[] = "(S)nap %s, (M)idpoints %s, (L)imit %.2f (Ctrl Wheel
adjust) %s, Switch (I)sland, shift select vertices"; |
| 228 |
| 229 char msg[HEADER_LENGTH]; |
| 230 ScrArea *sa= CTX_wm_area(C); |
| 231 |
| 232 if(sa) { |
| 233 BLI_snprintf(msg, HEADER_LENGTH, str, |
| 234 stitch_state->snap_islands? "On" : "Off", |
| 235 stitch_state->midpoints? "On": "Off", |
| 236 stitch_state->limit_dist, |
| 237 stitch_state->use_limit? "On" : "Off"); |
| 238 |
| 239 ED_area_headerprint(sa, msg); |
| 240 } |
| 241 } |
| 242 |
| 243 static int getNumOfIslandUvs(UvElementMap *elementMap, int island){ |
| 244 if(island == elementMap->totalIslands-1){ |
| 245 return elementMap->totalUVs - elementMap->islandIndices[island]; |
| 246 }else{ |
| 247 return elementMap->islandIndices[island+1] - elementMap->islandI
ndices[island]; |
| 248 } |
| 249 } |
| 250 |
| 251 static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2]){ |
| 252 float uv_rotation_result[2]; |
| 253 |
| 254 uv[0] -= medianPoint[0]; |
| 255 uv[1] -= medianPoint[1]; |
| 256 |
| 257 uv_rotation_result[0] = cos(rotation)*uv[0] - sin(rotation)*uv[1]; |
| 258 uv_rotation_result[1] = sin(rotation)*uv[0] + cos(rotation)*uv[1]; |
| 259 |
| 260 uv[0] = uv_rotation_result[0] + medianPoint[0]; |
| 261 uv[1] = uv_rotation_result[1] + medianPoint[1]; |
| 262 } |
| 263 |
| 264 |
| 265 /* calculate snapping for islands */ |
| 266 static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer
*preview, IslandStitchData *island_stitch_data, int final){ |
| 267 int i; |
| 268 EditFace *efa; |
| 269 MTFace *mt; |
| 270 UvElement *element; |
| 271 |
| 272 for(i = 0; i < state->element_map->totalIslands; i++){ |
| 273 if(island_stitch_data[i].addedForPreview){ |
| 274 int numOfIslandUVs = 0, j; |
| 275 |
| 276 /* check to avoid divide by 0 */ |
| 277 if(island_stitch_data[i].numOfEdges>0){ |
| 278 island_stitch_data[i].rotation /= island_stitch_
data[i].numOfEdges; |
| 279 island_stitch_data[i].medianPoint[0] /= island_s
titch_data[i].numOfElements; |
| 280 island_stitch_data[i].medianPoint[1] /= island_s
titch_data[i].numOfElements; |
| 281 } |
| 282 island_stitch_data[i].translation[0] /= island_stitch_da
ta[i].numOfElements; |
| 283 island_stitch_data[i].translation[1] /= island_stitch_da
ta[i].numOfElements; |
| 284 numOfIslandUVs = getNumOfIslandUvs(state->element_map, i
); |
| 285 element = &state->element_map->buf[state->element_map->i
slandIndices[i]]; |
| 286 for(j = 0; j < numOfIslandUVs; j++, element++){ |
| 287 /* stitchable uvs have already been processed, d
on't process */ |
| 288 if(!(element->flag & STITCH_PROCESSED)){ |
| 289 efa = element->face; |
| 290 mt = CustomData_em_get(&state->em->fdata
, efa->data, CD_MTFACE); |
| 291 if(final){ |
| 292 |
| 293 stitch_uv_rotate(island_stitch_d
ata[i].rotation, island_stitch_data[i].medianPoint, mt->uv[element->tfindex]); |
| 294 |
| 295 mt->uv[element->tfindex][0] += i
sland_stitch_data[i].translation[0]; |
| 296 mt->uv[element->tfindex][1] += i
sland_stitch_data[i].translation[1]; |
| 297 } |
| 298 else if(efa->tmp.l != STITCH_NO_PREVIEW)
{ |
| 299 if(efa->v4){ |
| 300 |
| 301 stitch_uv_rotate(island_
stitch_data[i].rotation, island_stitch_data[i].medianPoint, &preview->preview_qu
ads[efa->tmp.l + 2*element->tfindex]); |
| 302 |
| 303 preview->preview_quads[e
fa->tmp.l + 2*element->tfindex] += island_stitch_data[i].translation[0]; |
| 304 preview->preview_quads[e
fa->tmp.l + 2*element->tfindex + 1] += island_stitch_data[i].translation[1]; |
| 305 } |
| 306 else { |
| 307 |
| 308 stitch_uv_rotate(island_
stitch_data[i].rotation, island_stitch_data[i].medianPoint, &preview->preview_tr
is[efa->tmp.l + 2*element->tfindex]); |
| 309 |
| 310 preview->preview_tris[ef
a->tmp.l + 2*element->tfindex] += island_stitch_data[i].translation[0]; |
| 311 preview->preview_tris[ef
a->tmp.l + 2*element->tfindex + 1] += island_stitch_data[i].translation[1]; |
| 312 } |
| 313 } |
| 314 } |
| 315 /* cleanup */ |
| 316 element->flag &= STITCH_SELECTED; |
| 317 } |
| 318 } |
| 319 } |
| 320 } |
| 321 |
| 322 |
| 323 |
| 324 static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta
te, UVVertAverage *uv_average, unsigned int *uvfinal_map, IslandStitchData *isla
nd_stitch_data) |
| 325 { |
| 326 UvElement *element; |
| 327 EditFace *efa; |
| 328 MTFace *mt; |
| 329 int nverts; |
| 330 float uv1[2], uv2[2]; |
| 331 float edgecos, edgesin; |
| 332 int index1, index2; |
| 333 |
| 334 element = edge->element; |
| 335 efa = element->face; |
| 336 nverts = (efa->v4)? 4 : 3; |
| 337 mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); |
| 338 |
| 339 index1 = uvfinal_map[(*(&element->face->v1 + element->tfindex))->tmp.l]; |
| 340 index2 = uvfinal_map[(*(&element->face->v1 + (element->tfindex + 1)%nver
ts))->tmp.l]; |
| 341 |
| 342 /* the idea here is to take the directions of the edges and find the rot
ation between final and initial |
| 343 * direction. This, using inner and outer vector products, gives the angl
e. Directions are differences so... */ |
| 344 uv1[0] = mt->uv[(element->tfindex + 1)%nverts][0] - mt->uv[element->tfin
dex][0]; |
| 345 uv1[1] = mt->uv[(element->tfindex + 1)%nverts][1] - mt->uv[element->tfin
dex][1]; |
| 346 |
| 347 uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0]; |
| 348 uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1]; |
| 349 |
| 350 normalize_v2(uv1); |
| 351 normalize_v2(uv2); |
| 352 |
| 353 edgecos = uv1[0]*uv2[0] + uv1[1]*uv2[1]; |
| 354 edgesin = uv1[0]*uv2[1] - uv2[0]*uv1[1]; |
| 355 island_stitch_data[element->island].numOfEdges++; |
| 356 island_stitch_data[element->island].rotation += (edgesin > 0)? acos(MAX2
(-1.0, MIN2(1.0, edgecos))): -acos(MAX2(-1.0, MIN2(1.0, edgecos))); |
| 357 } |
| 358 |
| 359 static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat
e *state, IslandStitchData *island_stitch_data) |
| 360 { |
| 361 EditFace *efa; |
| 362 MTFace *mt; |
| 363 float normal1[2], normal2[2]; |
| 364 float edgecos, edgesin; |
| 365 int index; |
| 366 UvElement *element_iter; |
| 367 |
| 368 if((element->island == state->static_island) && !state->midpoints) |
| 369 return; |
| 370 |
| 371 efa = element->face; |
| 372 mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); |
| 373 |
| 374 index = (*(&element->face->v1 + element->tfindex))->tmp.l; |
| 375 |
| 376 element_iter = state->element_map->vert[index]; |
| 377 |
| 378 for(; element_iter; element_iter = element_iter->next){ |
| 379 if(element_iter->separate && (element_iter != element) && |
| 380 (element_iter->flag & STITCH_STITCHABLE)){ |
| 381 int index_tmp; |
| 382 /* easily possible*/ |
| 383 if(element_iter->island == element->island){ |
| 384 continue; |
| 385 } |
| 386 index_tmp = element_iter - state->element_map->buf; |
| 387 index_tmp = state->map[index_tmp]; |
| 388 } |
| 389 } |
| 390 edgecos = 0; |
| 391 edgesin = 0; |
| 392 |
| 393 island_stitch_data[element->island].rotation += (edgesin > 0)? acos(edge
cos): -acos(edgecos); |
| 394 island_stitch_data[element->island].medianPoint[0] += mt->uv[element->tf
index][0]; |
| 395 island_stitch_data[element->island].medianPoint[1] += mt->uv[element->tf
index][1];; |
| 396 } |
| 397 |
| 398 |
| 399 static void stitch_state_delete(StitchState *stitch_state) |
| 400 { |
| 401 if(stitch_state){ |
| 402 if(stitch_state->element_map){ |
| 403 EM_free_uv_element_map(stitch_state->element_map); |
| 404 } |
| 405 if(stitch_state->uvs){ |
| 406 MEM_freeN(stitch_state->uvs); |
| 407 } |
| 408 if(stitch_state->selection_stack){ |
| 409 MEM_freeN(stitch_state->selection_stack); |
| 410 } |
| 411 if(stitch_state->quads_per_island){ |
| 412 MEM_freeN(stitch_state->quads_per_island); |
| 413 } |
| 414 if(stitch_state->tris_per_island){ |
| 415 MEM_freeN(stitch_state->tris_per_island); |
| 416 } |
| 417 if(stitch_state->map){ |
| 418 MEM_freeN(stitch_state->map); |
| 419 } |
| 420 if(stitch_state->normals){ |
| 421 MEM_freeN(stitch_state->normals); |
| 422 } |
| 423 if(stitch_state->edges){ |
| 424 MEM_freeN(stitch_state->edges); |
| 425 } |
| 426 MEM_freeN(stitch_state); |
| 427 } |
| 428 } |
| 429 |
| 430 |
| 431 |
| 432 /* checks for remote uvs that may be stitched with a certain uv, flags them if s
titchable. */ |
| 433 static void determine_uv_stitchability(UvElement *element, StitchState *state, I
slandStitchData *island_stitch_data){ |
| 434 int vert_index; |
| 435 UvElement *element_iter; |
| 436 float limit= state->limit_dist; |
| 437 int do_limit = state->use_limit; |
| 438 |
| 439 vert_index = (*(&element->face->v1 + element->tfindex))->tmp.l; |
| 440 element_iter = state->element_map->vert[vert_index]; |
| 441 |
| 442 for(; element_iter; element_iter = element_iter->next){ |
| 443 if(element_iter->separate){ |
| 444 if(element_iter == element){ |
| 445 continue; |
| 446 } |
| 447 if(do_limit){ |
| 448 MTFace *mtface_orig = CustomData_em_get(&state->
em->fdata, element->face->data, CD_MTFACE); |
| 449 MTFace *mtface_iter = CustomData_em_get(&state->
em->fdata, element_iter->face->data, CD_MTFACE); |
| 450 |
| 451 if(fabs(mtface_orig->uv[element->tfindex][0] - m
tface_iter->uv[element_iter->tfindex][0]) < limit |
| 452 && fabs(mtface_orig->uv[element-
>tfindex][1] - mtface_iter->uv[element_iter->tfindex][1]) < limit){ |
| 453 island_stitch_data[element_iter->island]
.stitchableCandidate = 1; |
| 454 island_stitch_data[element->island].stit
chableCandidate = 1; |
| 455 element->flag |= STITCH_STITCHABLE_CANDI
DATE; |
| 456 } |
| 457 }else{ |
| 458 /* if no limit exists, then the mere existence o
f a separate uv means that the uv is stitchable */ |
| 459 island_stitch_data[element_iter->island].stitcha
bleCandidate = 1; |
| 460 island_stitch_data[element->island].stitchableCa
ndidate = 1; |
| 461 element->flag |= STITCH_STITCHABLE_CANDIDATE; |
| 462 } |
| 463 } |
| 464 } |
| 465 } |
| 466 |
| 467 |
| 468 |
| 469 /* set preview buffer position of UV face in editface->tmp.l */ |
| 470 static void stitch_set_face_preview_buffer_position(EditFace *efa, StitchPreview
er *preview) |
| 471 { |
| 472 if(efa->tmp.l == STITCH_NO_PREVIEW) |
| 473 { |
| 474 if(efa->v4) |
| 475 { |
| 476 efa->tmp.l = preview->num_quads*8; |
| 477 preview->num_quads++; |
| 478 } else { |
| 479 efa->tmp.l = preview->num_tris*6; |
| 480 preview->num_tris++; |
| 481 } |
| 482 } |
| 483 } |
| 484 |
| 485 |
| 486 /* setup face preview for all coincident uvs and their faces */ |
| 487 static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchSta
te *state, IslandStitchData *island_stitch_data){ |
| 488 StitchPreviewer *preview = uv_get_stitch_previewer(); |
| 489 |
| 490 /* static island does not change so returning immediately */ |
| 491 //if(state->snap_islands && !state->midpoints && state->static_island ==
element->island) |
| 492 // return; |
| 493 |
| 494 if(state->snap_islands){ |
| 495 island_stitch_data[element->island].addedForPreview = 1; |
| 496 } |
| 497 |
| 498 do{ |
| 499 stitch_set_face_preview_buffer_position(element->face, preview); |
| 500 element = element->next; |
| 501 }while(element && !element->separate); |
| 502 } |
| 503 |
| 504 |
| 505 /* checks if uvs are indeed stitchable and registers so that they can be shown i
n preview */ |
| 506 static void stitch_validate_stichability(UvElement *element, StitchState *state,
IslandStitchData *island_stitch_data){ |
| 507 UvElement *element_iter; |
| 508 StitchPreviewer *preview; |
| 509 |
| 510 preview = uv_get_stitch_previewer(); |
| 511 element_iter = state->element_map->vert[(*(&element->face->v1 + element-
>tfindex))->tmp.l]; |
| 512 |
| 513 for(; element_iter; element_iter = element_iter->next){ |
| 514 if(element_iter->separate){ |
| 515 if(element_iter == element) |
| 516 continue; |
| 517 if(state->use_limit){ |
| 518 MTFace *mtface_orig = CustomData_em_get(&state->
em->fdata, element->face->data, CD_MTFACE); |
| 519 MTFace *mtface_iter = CustomData_em_get(&state->
em->fdata, element_iter->face->data, CD_MTFACE); |
| 520 |
| 521 if(fabs(mtface_orig->uv[element->tfindex][0] - m
tface_iter->uv[element_iter->tfindex][0]) < state->limit_dist |
| 522 && fabs(mtface_orig->uv[element-
>tfindex][1] - mtface_iter->uv[element_iter->tfindex][1]) < state->limit_dist){ |
| 523 if(((element_iter->island == state->stat
ic_island) || (element->island == state->static_island)) && |
| 524 !((element_iter->island
== element->island) && state->snap_islands)){ |
| 525 element->flag |= STITCH_STITCHAB
LE; |
| 526 preview->num_stitchable++; |
| 527 stitch_setup_face_preview_for_uv
_group(element, state, island_stitch_data); |
| 528 return; |
| 529 } |
| 530 } |
| 531 }else{ |
| 532 if(((element_iter->island == state->static_islan
d) || (element->island == state->static_island)) && |
| 533 !((element_iter->island == eleme
nt->island) && state->snap_islands)){ |
| 534 element->flag |= STITCH_STITCHABLE; |
| 535 preview->num_stitchable++; |
| 536 stitch_setup_face_preview_for_uv_group(e
lement, state, island_stitch_data); |
| 537 return; |
| 538 } |
| 539 } |
| 540 } |
| 541 } |
| 542 |
| 543 /* this can happen if the uvs to be stitched are not on a stitchable isl
and */ |
| 544 if(!(element->flag & STITCH_STITCHABLE)){ |
| 545 preview->num_unstitchable++; |
| 546 } |
| 547 } |
| 548 |
| 549 /* main processing function. It calculates preview and final positions. */ |
| 550 static int stitch_process_data(StitchState *state, Scene *scene, int final) |
| 551 { |
| 552 int i; |
| 553 StitchPreviewer *preview = uv_get_stitch_previewer(); |
| 554 IslandStitchData *island_stitch_data = NULL; |
| 555 int previous_island = state->static_island; |
| 556 EditFace *efa; |
| 557 EditVert *ev; |
| 558 UVVertAverage *final_position; |
| 559 char stitch_midpoints = state->midpoints; |
| 560 /* use vertex normals for snapping rotation */ |
| 561 char use_vert_normals = 1; |
| 562 /* used to map uv indices to uvaverage indices for selection */ |
| 563 unsigned int *uvfinal_map; |
| 564 |
| 565 /* cleanup previous preview */ |
| 566 stitch_preview_delete(); |
| 567 preview = stitch_preview_init(); |
| 568 if(preview == NULL) |
| 569 return 0; |
| 570 /* each face holds its position in the preview buffer in tmp. -1 is unin
itialized */ |
| 571 for(efa = state->em->faces.first; efa; efa = efa->next){ |
| 572 efa->tmp.l = STITCH_NO_PREVIEW; |
| 573 } |
| 574 |
| 575 island_stitch_data = MEM_callocN(sizeof(*island_stitch_data)*state->elem
ent_map->totalIslands, "stitch_island_data"); |
| 576 if(!island_stitch_data){ |
| 577 return 0; |
| 578 } |
| 579 |
| 580 /* store Indices to editVerts. */ |
| 581 for(ev = state->em->verts.first, i = 0; ev; ev = ev->next, i++){ |
| 582 ev->tmp.l = i; |
| 583 } |
| 584 |
| 585 /***************************************** |
| 586 * First determine stitchability of uvs * |
| 587 *****************************************/ |
| 588 |
| 589 for(i = 0; i < state->selection_size; i++){ |
| 590 UvElement *element = state->selection_stack[i]; |
| 591 determine_uv_stitchability(element, state, island_stitch_data); |
| 592 } |
| 593 |
| 594 /* set static island to one that is added for preview */ |
| 595 state->static_island %= state->element_map->totalIslands; |
| 596 while(!(island_stitch_data[state->static_island].stitchableCandidate)){ |
| 597 state->static_island++; |
| 598 state->static_island %= state->element_map->totalIslands; |
| 599 /* this is entirely possible if for example limit stitching with
no stitchable verts or no selection */ |
| 600 if(state->static_island == previous_island) |
| 601 break; |
| 602 } |
| 603 |
| 604 for(i = 0; i < state->selection_size; i++){ |
| 605 UvElement *element = state->selection_stack[i]; |
| 606 if(element->flag & STITCH_STITCHABLE_CANDIDATE){ |
| 607 element->flag &= ~STITCH_STITCHABLE_CANDIDATE; |
| 608 stitch_validate_stichability(element, state, island_stit
ch_data); |
| 609 }else{ |
| 610 /* add to preview for unstitchable */ |
| 611 preview->num_unstitchable++; |
| 612 } |
| 613 } |
| 614 |
| 615 /***************************************** |
| 616 * Setup preview for stitchable islands * |
| 617 *****************************************/ |
| 618 if(state->snap_islands){ |
| 619 for(i = 0; i < state->element_map->totalIslands; i++){ |
| 620 if(island_stitch_data[i].addedForPreview){ |
| 621 int numOfIslandUVs = 0, j; |
| 622 UvElement *element; |
| 623 numOfIslandUVs = getNumOfIslandUvs(state->elemen
t_map, i); |
| 624 element = &state->element_map->buf[state->elemen
t_map->islandIndices[i]]; |
| 625 for(j = 0; j < numOfIslandUVs; j++, element++){ |
| 626 stitch_set_face_preview_buffer_position(
element->face, preview); |
| 627 } |
| 628 } |
| 629 } |
| 630 } |
| 631 |
| 632 /********************************************************************* |
| 633 * Setup the preview buffers and fill them with the appropriate data * |
| 634 *********************************************************************/ |
| 635 if(!final){ |
| 636 unsigned int tricount = 0, quadcount = 0; |
| 637 int stitchBufferIndex = 0, unstitchBufferIndex = 0; |
| 638 /* initialize the preview buffers */ |
| 639 preview->preview_quads = (float *)MEM_mallocN(preview->num_quads
*sizeof(float)*8, "quad_uv_stitch_prev"); |
| 640 preview->preview_tris = (float *)MEM_mallocN(preview->num_tris*s
izeof(float)*6, "tri_uv_stitch_prev"); |
| 641 |
| 642 preview->preview_stitchable = (float *)MEM_mallocN(preview->num_
stitchable*sizeof(float)*2, "stitch_preview_stichable_data"); |
| 643 preview->preview_unstitchable = (float *)MEM_mallocN(preview->nu
m_unstitchable*sizeof(float)*2, "stitch_preview_unstichable_data"); |
| 644 |
| 645 preview->static_quads = (float *)MEM_mallocN(state->quads_per_is
land[state->static_island]*sizeof(float)*8, "static_island_preview_quads"); |
| 646 preview->static_tris = (float *)MEM_mallocN(state->tris_per_isla
nd[state->static_island]*sizeof(float)*6, "static_island_preview_tris"); |
| 647 |
| 648 preview->num_static_quads = state->quads_per_island[state->stati
c_island]; |
| 649 preview->num_static_tris = state->tris_per_island[state->static_
island]; |
| 650 /* will cause cancel and freeing of all data structures so OK */ |
| 651 if(!preview->preview_quads || !preview->preview_tris || !preview
->preview_stitchable || !preview->preview_unstitchable){ |
| 652 return 0; |
| 653 } |
| 654 |
| 655 /* copy data from MTFaces to the preview display buffers */ |
| 656 for(efa = state->em->faces.first; efa; efa = efa->next){ |
| 657 MTFace *mt = CustomData_em_get(&state->em->fdata, efa->d
ata, CD_MTFACE); |
| 658 UvElement *element = ED_get_uv_element(state->element_ma
p, efa, 0); |
| 659 |
| 660 if(element){ |
| 661 if(efa->tmp.l != STITCH_NO_PREVIEW){ |
| 662 if(efa->v4) { |
| 663 memcpy(preview->preview_quads+ef
a->tmp.l, &mt->uv[0][0], 8*sizeof(float)); |
| 664 } else { |
| 665 memcpy(preview->preview_tris+efa
->tmp.l, &mt->uv[0][0], 6*sizeof(float)); |
| 666 } |
| 667 } |
| 668 |
| 669 if(element->island == state->static_island){ |
| 670 if(efa->v4) { |
| 671 memcpy(preview->static_quads + q
uadcount*8, &mt->uv[0][0], 8*sizeof(float)); |
| 672 quadcount++; |
| 673 } else { |
| 674 memcpy(preview->static_tris + tr
icount*6, &mt->uv[0][0], 6*sizeof(float)); |
| 675 tricount++; |
| 676 } |
| 677 } |
| 678 } |
| 679 } |
| 680 |
| 681 /* fill the appropriate preview buffers */ |
| 682 for(i = 0; i < state->total_separate_uvs; i++){ |
| 683 UvElement *element = (UvElement *)state->uvs[i]; |
| 684 if(element->flag & STITCH_STITCHABLE){ |
| 685 MTFace *mt; |
| 686 efa = element->face; |
| 687 mt = CustomData_em_get(&state->em->fdata, efa->d
ata, CD_MTFACE); |
| 688 |
| 689 preview->preview_stitchable[stitchBufferIndex*2]
= mt->uv[element->tfindex][0]; |
| 690 preview->preview_stitchable[stitchBufferIndex*2
+ 1] = mt->uv[element->tfindex][1]; |
| 691 stitchBufferIndex++; |
| 692 } |
| 693 else if(element->flag & STITCH_SELECTED){ |
| 694 MTFace *mt; |
| 695 efa = element->face; |
| 696 mt = CustomData_em_get(&state->em->fdata, efa->d
ata, CD_MTFACE); |
| 697 |
| 698 preview->preview_unstitchable[unstitchBufferInde
x*2] = mt->uv[element->tfindex][0]; |
| 699 preview->preview_unstitchable[unstitchBufferInde
x*2 + 1] = mt->uv[element->tfindex][1]; |
| 700 unstitchBufferIndex++; |
| 701 } |
| 702 } |
| 703 } |
| 704 |
| 705 /****************************************************** |
| 706 * Here we calculate the final coordinates of the uvs * |
| 707 ******************************************************/ |
| 708 |
| 709 final_position = MEM_callocN(state->selection_size*sizeof(*final_positio
n), "stitch_uv_average"); |
| 710 uvfinal_map = MEM_mallocN(state->em->totvert*sizeof(*uvfinal_map), "stit
ch_uv_final_map"); |
| 711 |
| 712 /* first pass, calculate final position for stitchable uvs of the static
island */ |
| 713 for(i = 0; i < state->selection_size; i++){ |
| 714 UvElement *element = state->selection_stack[i]; |
| 715 if(element->flag & STITCH_STITCHABLE){ |
| 716 UvElement *element_iter = state->element_map->vert[(*(&e
lement->face->v1 + element->tfindex))->tmp.l]; |
| 717 uvfinal_map[(*(&element->face->v1 + element->tfindex))->
tmp.l] = i; |
| 718 for(;element_iter; element_iter = element_iter->next){ |
| 719 if(element_iter->flag & STITCH_STITCHABLE){ |
| 720 MTFace *mt; |
| 721 efa = element_iter->face; |
| 722 mt = CustomData_em_get(&state->em->fdata
, efa->data, CD_MTFACE); |
| 723 if(stitch_midpoints){ |
| 724 final_position[i].uv[0] += mt->u
v[element_iter->tfindex][0]; |
| 725 final_position[i].uv[1] += mt->u
v[element_iter->tfindex][1]; |
| 726 final_position[i].count++; |
| 727 }else if(element_iter->island == state->
static_island){ |
| 728 final_position[i].uv[0] = mt->uv
[element_iter->tfindex][0]; |
| 729 final_position[i].uv[1] = mt->uv
[element_iter->tfindex][1]; |
| 730 } |
| 731 } |
| 732 } |
| 733 } |
| 734 if(stitch_midpoints){ |
| 735 final_position[i].uv[0] /= final_position[i].count; |
| 736 final_position[i].uv[1] /= final_position[i].count; |
| 737 } |
| 738 } |
| 739 |
| 740 /* second pass, calculate island rotation and translation before modifyi
ng any uvs */ |
| 741 if(state->snap_islands){ |
| 742 for(i = 0; i < state->selection_size; i++){ |
| 743 UvElement *element = state->selection_stack[i]; |
| 744 if(element->flag & STITCH_STITCHABLE){ |
| 745 MTFace *mt; |
| 746 efa = element->face; |
| 747 mt = CustomData_em_get(&state->em->fdata, efa->d
ata, CD_MTFACE); |
| 748 |
| 749 /* accumulate each islands' translation from sti
tchable elements. it is important to do here |
| 750 * because in final pass MTFaces get modified an
d result is zero. */ |
| 751 island_stitch_data[element->island].translation[
0] += final_position[i].uv[0] - mt->uv[element->tfindex][0]; |
| 752 island_stitch_data[element->island].translation[
1] += final_position[i].uv[1] - mt->uv[element->tfindex][1]; |
| 753 island_stitch_data[element->island].medianPoint[
0] += mt->uv[element->tfindex][0]; |
| 754 island_stitch_data[element->island].medianPoint[
1] += mt->uv[element->tfindex][1]; |
| 755 island_stitch_data[element->island].numOfElement
s++; |
| 756 } |
| 757 } |
| 758 |
| 759 /* only calculate rotation when an edge has been fully selected
*/ |
| 760 for(i = 0; i < state->total_boundary_edges; i++){ |
| 761 UvEdge *edge = state->edges+i; |
| 762 if((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
(state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)){ |
| 763 stitch_island_calculate_edge_rotation(edge, stat
e, final_position, uvfinal_map, island_stitch_data); |
| 764 use_vert_normals = 0; |
| 765 } |
| 766 } |
| 767 if(0){ |
| 768 for(i = 0; i < state->selection_size; i++){ |
| 769 UvElement *element = state->selection_stack[i]; |
| 770 if(element->flag & STITCH_STITCHABLE){ |
| 771 stitch_island_calculate_vert_rotation(el
ement, state, island_stitch_data); |
| 772 } |
| 773 } |
| 774 } |
| 775 } |
| 776 |
| 777 /* third pass, propagate changes to stitchable uvs */ |
| 778 for(i = 0; i < state->selection_size; i++){ |
| 779 UvElement *element = state->selection_stack[i]; |
| 780 if(element->flag & STITCH_STITCHABLE){ |
| 781 UvElement *element_iter = state->element_map->vert[(*(&e
lement->face->v1 + element->tfindex))->tmp.l]; |
| 782 for(;element_iter;){ |
| 783 /* determine if uv stitchable */ |
| 784 if(element_iter->separate && element_iter->flag
& STITCH_STITCHABLE){ |
| 785 MTFace *mt; |
| 786 efa = element_iter->face; |
| 787 mt = CustomData_em_get(&state->em->fdata
, efa->data, CD_MTFACE); |
| 788 |
| 789 /* propagate to coincident uvs */ |
| 790 do{ |
| 791 efa = element_iter->face; |
| 792 mt = CustomData_em_get(&state->e
m->fdata, efa->data, CD_MTFACE); |
| 793 |
| 794 element_iter->flag |= STITCH_PRO
CESSED; |
| 795 /* either flush to preview or to
the MTFace, if final */ |
| 796 if(final){ |
| 797 mt->uv[element_iter->tfi
ndex][0] = final_position[i].uv[0]; |
| 798 mt->uv[element_iter->tfi
ndex][1] = final_position[i].uv[1]; |
| 799 |
| 800 uvedit_uv_select(scene,
efa, mt, element_iter->tfindex); |
| 801 }else if(efa->tmp.l != STITCH_NO
_PREVIEW){ |
| 802 if(efa->v4){ |
| 803 *(preview->previ
ew_quads+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0]; |
| 804 *(preview->previ
ew_quads+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1]; |
| 805 }else{ |
| 806 *(preview->previ
ew_tris+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0]; |
| 807 *(preview->previ
ew_tris+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1]; |
| 808 } |
| 809 } |
| 810 |
| 811 /* end of calculations, keep onl
y the selection flag */ |
| 812 if( (!state->snap_islands) || ((
!stitch_midpoints) && (element_iter->island == state->static_island))) { |
| 813 element_iter->flag &= ST
ITCH_SELECTED; |
| 814 } |
| 815 |
| 816 element_iter = element_iter->nex
t; |
| 817 }while(element_iter && !element_iter->se
parate); |
| 818 |
| 819 continue; |
| 820 } |
| 821 element_iter = element_iter->next; |
| 822 } |
| 823 } |
| 824 } |
| 825 |
| 826 /* final pass, calculate Island translation/rotation if needed */ |
| 827 if(state->snap_islands){ |
| 828 stitch_calculate_island_snapping(state, preview, island_stitch_d
ata, final); |
| 829 } |
| 830 |
| 831 MEM_freeN(final_position); |
| 832 MEM_freeN(uvfinal_map); |
| 833 MEM_freeN(island_stitch_data); |
| 834 |
| 835 return 1; |
| 836 } |
| 837 |
| 838 /* Stitch hash initialisation functions */ |
| 839 static unsigned int uv_edge_hash(const void *key){ |
| 840 UvEdge *edge = (UvEdge *)key; |
| 841 return |
| 842 BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) + |
| 843 BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1)); |
| 844 } |
| 845 |
| 846 static int uv_edge_compare(const void *a, const void *b){ |
| 847 UvEdge *edge1 = (UvEdge *)a; |
| 848 UvEdge *edge2 = (UvEdge *)b; |
| 849 |
| 850 if((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)){ |
| 851 return 0; |
| 852 } |
| 853 return 1; |
| 854 } |
| 855 |
| 856 |
| 857 /* Select all common uvs */ |
| 858 static void stitch_select_uv(UvElement *element, StitchState *stitch_state, int
always_select) |
| 859 { |
| 860 /* This works due to setting of tmp in find nearest uv vert */ |
| 861 UvElement *element_iter; |
| 862 UvElement **selection_stack = stitch_state->selection_stack; |
| 863 |
| 864 element_iter = stitch_state->element_map->vert[(*(&element->face->v1 + e
lement->tfindex))->tmp.l]; |
| 865 /* first deselect all common uvs */ |
| 866 for(; element_iter; element_iter = element_iter->next){ |
| 867 if(element_iter->separate){ |
| 868 /* only separators go to selection */ |
| 869 if(element_iter->flag & STITCH_SELECTED){ |
| 870 int i; |
| 871 if(always_select) |
| 872 continue; |
| 873 |
| 874 element_iter->flag &= ~STITCH_SELECTED; |
| 875 for(i = 0; i < stitch_state->selection_size; i++
){ |
| 876 if(selection_stack[i] == element_iter){ |
| 877 (stitch_state->selection_size)--
; |
| 878 selection_stack[i] = selection_s
tack[stitch_state->selection_size]; |
| 879 break; |
| 880 } |
| 881 } |
| 882 }else{ |
| 883 element_iter->flag |= STITCH_SELECTED; |
| 884 selection_stack[(stitch_state->selection_size)++
] = element_iter; |
| 885 } |
| 886 } |
| 887 } |
| 888 } |
| 889 |
| 890 static void stitch_calculate_edge_normal(EditMesh *em, UvEdge *edge, float *norm
al){ |
| 891 UvElement *element = edge->element; |
| 892 EditFace *efa = element->face; |
| 893 MTFace *mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); |
| 894 int index; |
| 895 float tangent[2], internal[2]; |
| 896 |
| 897 if(efa->v4){ |
| 898 index = (element->tfindex + 2)%4; |
| 899 }else{ |
| 900 index = (element->tfindex + 2)%3; |
| 901 } |
| 902 |
| 903 sub_v2_v2v2(tangent, mt->uv[element->tfindex + 1], mt->uv[element->tfin
dex]); |
| 904 sub_v2_v2v2(internal, mt->uv[index], mt->uv[element->tfindex]); |
| 905 |
| 906 /* choose one of the normals */ |
| 907 normal[0] = tangent[1]; |
| 908 normal[1] = -tangent[0]; |
| 909 |
| 910 /* if normal points inside the face, invert */ |
| 911 if(dot_v2v2(normal, internal) > 0){ |
| 912 normal[0] = -tangent[1]; |
| 913 normal[1] = tangent[0]; |
| 914 } |
| 915 |
| 916 normalize_v2(normal); |
| 917 } |
| 918 |
| 919 static int stitch_init(bContext *C, wmOperator *op) |
| 920 { |
| 921 /* for fast edge lookup... */ |
| 922 GHash *edgeHash; |
| 923 /* ...and actual edge storage */ |
| 924 UvEdge *edges; |
| 925 int total_edges; |
| 926 /* maps uvelements to their first coincident uv */ |
| 927 int *map; |
| 928 int counter = 0, i; |
| 929 EditFace *efa; |
| 930 EditMesh *em; |
| 931 GHashIterator* ghi; |
| 932 UvEdge *all_edges; |
| 933 StitchState *state = MEM_mallocN(sizeof(StitchState), "stitch state"); |
| 934 Scene *scene = CTX_data_scene(C); |
| 935 ToolSettings *ts = scene->toolsettings; |
| 936 |
| 937 Object *obedit = CTX_data_edit_object(C); |
| 938 |
| 939 op->customdata = state; |
| 940 |
| 941 if(!state) |
| 942 return 0; |
| 943 |
| 944 /* initialize state */ |
| 945 state->use_limit = RNA_boolean_get(op->ptr, "use_limit"); |
| 946 state->limit_dist = RNA_float_get(op->ptr, "limit"); |
| 947 state->em = em = BKE_mesh_get_editmesh((Mesh*)obedit->data); |
| 948 state->snap_islands = RNA_boolean_get(op->ptr, "snap_islands"); |
| 949 state->static_island = RNA_int_get(op->ptr, "static_island"); |
| 950 state->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap"); |
| 951 /* in uv synch selection, all uv's are visible */ |
| 952 if(ts->uv_flag & UV_SYNC_SELECTION){ |
| 953 state->element_map = EM_make_uv_element_map(state->em, 0, 1); |
| 954 }else{ |
| 955 state->element_map = EM_make_uv_element_map(state->em, 1, 1); |
| 956 } |
| 957 if(!state->element_map){ |
| 958 stitch_state_delete(state); |
| 959 return 0; |
| 960 } |
| 961 |
| 962 /* Entirely possible if redoing last operator that static island is bigg
er than total number of islands. |
| 963 * This ensures we get no hang in the island checking code in stitch_pro
cess_data. */ |
| 964 state->static_island %= state->element_map->totalIslands; |
| 965 |
| 966 /* Count 'unique' uvs */ |
| 967 for(i = 0; i < state->element_map->totalUVs; i++){ |
| 968 if(state->element_map->buf[i].separate){ |
| 969 counter++; |
| 970 } |
| 971 } |
| 972 |
| 973 /* Allocate the unique uv buffers */ |
| 974 state->uvs = MEM_mallocN(sizeof(*state->uvs)*counter, "uv_stitch_unique_
uvs"); |
| 975 /* internal uvs need no normals but it is hard and slow to keep a map of |
| 976 * normals only for boundary uvs, so allocating for all uvs */ |
| 977 state->normals = MEM_callocN(sizeof(*state->normals)*counter*2, "uv_stit
ch_normals"); |
| 978 state->total_separate_uvs = counter; |
| 979 /* we can at most have totalUVs edges or uvs selected. Actually they are
less, considering we store only |
| 980 * unique uvs for processing but I am accounting for all bizarre cases,
especially for edges, this way */ |
| 981 state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack)*cou
nter, "uv_stitch_selection_stack"); |
| 982 state->map = map = MEM_mallocN(sizeof(*map)*state->element_map->totalUVs
, "uv_stitch_unique_map"); |
| 983 /* Allocate the edge stack */ |
| 984 edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_has
h"); |
| 985 all_edges = MEM_mallocN(sizeof(*all_edges)*state->element_map->totalUVs,
"stitch_all_edges"); |
| 986 |
| 987 if(!state->selection_stack || !state->uvs || !map || !edgeHash || !all_e
dges){ |
| 988 stitch_state_delete(state); |
| 989 return 0; |
| 990 } |
| 991 |
| 992 /* So that we can use this as index for the UvElements */ |
| 993 counter = -1; |
| 994 /* initialize the unique UVs and map */ |
| 995 for(i = 0; i < state->em->totvert; i++){ |
| 996 UvElement *element = state->element_map->vert[i]; |
| 997 for(; element; element = element->next){ |
| 998 if(element->separate){ |
| 999 counter++; |
| 1000 state->uvs[counter] = element; |
| 1001 } |
| 1002 /* pointer arithmetic to the rescue, as always :)*/ |
| 1003 map[element - state->element_map->buf] = counter; |
| 1004 } |
| 1005 } |
| 1006 |
| 1007 /* Now, on to generate our uv connectivity data */ |
| 1008 for(efa = state->em->faces.first, counter = 0; efa; efa = efa->next){ |
| 1009 if((ts->uv_flag & UV_SYNC_SELECTION) || (!efa->h && efa->f & SEL
ECT)){ |
| 1010 int nverts = efa->v4 ? 4 : 3; |
| 1011 |
| 1012 for(i = 0; i < nverts; i++){ |
| 1013 UvElement *element = ED_get_uv_element(state->el
ement_map, efa, i); |
| 1014 int offset1, itmp1 = element - state->element_ma
p->buf; |
| 1015 int offset2, itmp2 = ED_get_uv_element(state->el
ement_map, efa, (i+1)%nverts) - state->element_map->buf; |
| 1016 |
| 1017 offset1 = map[itmp1]; |
| 1018 offset2 = map[itmp2]; |
| 1019 |
| 1020 all_edges[counter].flag = 0; |
| 1021 all_edges[counter].element = element; |
| 1022 /* using an order policy, sort uvs according to
address space. This avoids |
| 1023 * Having two different UvEdges with the same uv
s on different positions */ |
| 1024 if(offset1 < offset2){ |
| 1025 all_edges[counter].uv1 = offset1; |
| 1026 all_edges[counter].uv2 = offset2; |
| 1027 } |
| 1028 else{ |
| 1029 all_edges[counter].uv1 = offset2; |
| 1030 all_edges[counter].uv2 = offset1; |
| 1031 } |
| 1032 /* Hack! Set the value of the key to its flag. N
ow we can set the flag when an edge exists twice :) */ |
| 1033 if(BLI_ghash_haskey(edgeHash, &all_edges[counter
])){ |
| 1034 char *flag = BLI_ghash_lookup(edgeHash,
&all_edges[counter]); |
| 1035 *flag = 0; |
| 1036 } |
| 1037 else{ |
| 1038 /* Hack mentioned */ |
| 1039 BLI_ghash_insert(edgeHash, &all_edges[co
unter], &(all_edges[counter].flag)); |
| 1040 all_edges[counter].flag = STITCH_BOUNDAR
Y; |
| 1041 } |
| 1042 counter++; |
| 1043 } |
| 1044 } |
| 1045 } |
| 1046 |
| 1047 |
| 1048 ghi = BLI_ghashIterator_new(edgeHash); |
| 1049 total_edges = 0; |
| 1050 /* fill the edges with data */ |
| 1051 for(i = 0; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)){ |
| 1052 UvEdge *edge = ((UvEdge *)BLI_ghashIterator_getKey(ghi)); |
| 1053 if(edge->flag & STITCH_BOUNDARY){ |
| 1054 total_edges++; |
| 1055 } |
| 1056 } |
| 1057 state->edges = edges = MEM_mallocN(sizeof(*edges)*total_edges, "stitch_e
dges"); |
| 1058 if(!ghi || !edges){ |
| 1059 MEM_freeN(all_edges); |
| 1060 stitch_state_delete(state); |
| 1061 return 0; |
| 1062 } |
| 1063 |
| 1064 state->total_boundary_edges = total_edges; |
| 1065 |
| 1066 /* fill the edges with data */ |
| 1067 for(i = 0, BLI_ghashIterator_init(ghi, edgeHash); !BLI_ghashIterator_isD
one(ghi); BLI_ghashIterator_step(ghi)){ |
| 1068 UvEdge *edge = ((UvEdge *)BLI_ghashIterator_getKey(ghi)); |
| 1069 if(edge->flag & STITCH_BOUNDARY){ |
| 1070 edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi)); |
| 1071 } |
| 1072 } |
| 1073 |
| 1074 /* cleanup temporary stuff */ |
| 1075 BLI_ghashIterator_free(ghi); |
| 1076 MEM_freeN(all_edges); |
| 1077 |
| 1078 /* refill hash with new pointers to cleanup duplicates */ |
| 1079 BLI_ghash_free(edgeHash, NULL, NULL); |
| 1080 |
| 1081 /***** calculate 2D normals for boundary uvs *****/ |
| 1082 |
| 1083 /* we use boundary edges to calculate 2D normals. |
| 1084 * to disambiguate the direction of the normal, we also need |
| 1085 * a point "inside" the island, that can be provided by |
| 1086 * the opposite uv for a quad, or the next uv for a triangle. */ |
| 1087 |
| 1088 for(i = 0; i < total_edges; i++){ |
| 1089 float normal[2]; |
| 1090 stitch_calculate_edge_normal(em, edges + i, normal); |
| 1091 |
| 1092 add_v2_v2(state->normals + edges[i].uv1*2, normal); |
| 1093 add_v2_v2(state->normals + edges[i].uv2*2, normal); |
| 1094 |
| 1095 normalize_v2(state->normals + edges[i].uv1*2); |
| 1096 normalize_v2(state->normals + edges[i].uv2*2); |
| 1097 } |
| 1098 |
| 1099 |
| 1100 /***** fill selection stack *******/ |
| 1101 |
| 1102 state->selection_size = 0; |
| 1103 |
| 1104 /* Load old selection if redoing operator with different settings */ |
| 1105 if(RNA_property_is_set(op->ptr, "selection")){ |
| 1106 int faceIndex, elementIndex; |
| 1107 UvElement *element; |
| 1108 |
| 1109 EM_init_index_arrays(em, 0, 0, 1); |
| 1110 |
| 1111 |
| 1112 RNA_BEGIN(op->ptr, itemptr, "selection") { |
| 1113 faceIndex = RNA_int_get(&itemptr, "face_index"); |
| 1114 elementIndex = RNA_int_get(&itemptr, "element_in
dex"); |
| 1115 efa = EM_get_face_for_index(faceIndex); |
| 1116 element = ED_get_uv_element(state->element_map,
efa, elementIndex); |
| 1117 stitch_select_uv(element, state, 1); |
| 1118 } |
| 1119 RNA_END; |
| 1120 |
| 1121 EM_free_index_arrays(); |
| 1122 /* Clear the selection */ |
| 1123 RNA_collection_clear(op->ptr, "selection"); |
| 1124 |
| 1125 } else { |
| 1126 for(efa = state->em->faces.first ; efa; efa = efa->next){ |
| 1127 int numOfVerts; |
| 1128 MTFace *mt; |
| 1129 mt = CustomData_em_get(&state->em->fdata, efa->data, CD_
MTFACE); |
| 1130 numOfVerts = efa->v4 ? 4 : 3; |
| 1131 |
| 1132 for(i = 0; i < numOfVerts; i++){ |
| 1133 if(uvedit_uv_selected(scene, efa, mt, i)){ |
| 1134 UvElement *element = ED_get_uv_element(s
tate->element_map, efa, i); |
| 1135 stitch_select_uv(element, state, 1); |
| 1136 } |
| 1137 } |
| 1138 } |
| 1139 } |
| 1140 |
| 1141 /***** initialise static island preview data *****/ |
| 1142 |
| 1143 state->quads_per_island = MEM_mallocN(sizeof(*state->quads_per_island)*s
tate->element_map->totalIslands, |
| 1144 "stitch island quads"); |
| 1145 state->tris_per_island = MEM_mallocN(sizeof(*state->tris_per_island)*sta
te->element_map->totalIslands, |
| 1146 "stitch island tris"); |
| 1147 for(i = 0; i < state->element_map->totalIslands; i++){ |
| 1148 state->quads_per_island[i] = 0; |
| 1149 state->tris_per_island[i] = 0; |
| 1150 } |
| 1151 |
| 1152 for(efa = state->em->faces.first; efa; efa = efa->next){ |
| 1153 UvElement *element = ED_get_uv_element(state->element_map, efa,
0); |
| 1154 |
| 1155 if(element){ |
| 1156 if(efa->v4){ |
| 1157 state->quads_per_island[element->island]++; |
| 1158 } |
| 1159 else { |
| 1160 state->tris_per_island[element->island]++; |
| 1161 } |
| 1162 } |
| 1163 } |
| 1164 |
| 1165 if(!stitch_process_data(state, scene, 0)){ |
| 1166 stitch_state_delete(state); |
| 1167 return 0; |
| 1168 } |
| 1169 |
| 1170 stitch_update_header(state, C); |
| 1171 return 1; |
| 1172 } |
| 1173 |
| 1174 static int stitch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) |
| 1175 { |
| 1176 Object *obedit = CTX_data_edit_object(C); |
| 1177 if(!stitch_init(C, op)) |
| 1178 return OPERATOR_CANCELLED; |
| 1179 |
| 1180 WM_event_add_modal_handler(C, op); |
| 1181 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); |
| 1182 return OPERATOR_RUNNING_MODAL; |
| 1183 } |
| 1184 |
| 1185 static void stitch_exit(bContext *C, wmOperator *op, int finished) |
| 1186 { |
| 1187 StitchState *stitch_state; |
| 1188 Scene *scene; |
| 1189 SpaceImage *sima; |
| 1190 ScrArea *sa= CTX_wm_area(C); |
| 1191 Object *obedit; |
| 1192 |
| 1193 scene= CTX_data_scene(C); |
| 1194 obedit= CTX_data_edit_object(C); |
| 1195 sima= CTX_wm_space_image(C); |
| 1196 |
| 1197 stitch_state = (StitchState *)op->customdata; |
| 1198 |
| 1199 if(finished){ |
| 1200 EditFace *efa; |
| 1201 int i; |
| 1202 |
| 1203 RNA_float_set(op->ptr, "limit", stitch_state->limit_dist); |
| 1204 RNA_boolean_set(op->ptr, "use_limit", stitch_state->use_limit); |
| 1205 RNA_boolean_set(op->ptr, "snap_islands", stitch_state->snap_isla
nds); |
| 1206 RNA_int_set(op->ptr, "static_island", stitch_state->static_islan
d); |
| 1207 RNA_boolean_set(op->ptr, "midpoint_snap", stitch_state->midpoint
s); |
| 1208 |
| 1209 for(i = 0, efa = stitch_state->em->faces.first; efa; efa = efa->
next, i++){ |
| 1210 efa->tmp.l = i; |
| 1211 } |
| 1212 |
| 1213 /* Store selection for re-execution of stitch */ |
| 1214 for(i = 0; i < stitch_state->selection_size; i++){ |
| 1215 PointerRNA itemptr; |
| 1216 UvElement *element = stitch_state->selection_stack[i]; |
| 1217 |
| 1218 RNA_collection_add(op->ptr, "selection", &itemptr); |
| 1219 |
| 1220 RNA_int_set(&itemptr, "face_index", element->face->tmp.l
); |
| 1221 RNA_int_set(&itemptr, "element_index", element->tfindex)
; |
| 1222 } |
| 1223 |
| 1224 |
| 1225 uvedit_live_unwrap_update(sima, scene, obedit); |
| 1226 } |
| 1227 |
| 1228 if(sa) |
| 1229 ED_area_headerprint(sa, NULL); |
| 1230 |
| 1231 DAG_id_tag_update(obedit->data, 0); |
| 1232 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); |
| 1233 BKE_mesh_end_editmesh(obedit->data, stitch_state->em); |
| 1234 |
| 1235 stitch_state_delete(stitch_state); |
| 1236 op->customdata = NULL; |
| 1237 |
| 1238 stitch_preview_delete(); |
| 1239 } |
| 1240 |
| 1241 |
| 1242 static int stitch_cancel(bContext *C, wmOperator *op) |
| 1243 { |
| 1244 stitch_exit(C, op, 0); |
| 1245 return OPERATOR_CANCELLED; |
| 1246 } |
| 1247 |
| 1248 |
| 1249 static int stitch_exec(bContext *C, wmOperator *op) |
| 1250 { |
| 1251 Scene *scene = CTX_data_scene(C); |
| 1252 |
| 1253 if(!stitch_init(C, op)) |
| 1254 return OPERATOR_CANCELLED; |
| 1255 if(stitch_process_data((StitchState *)op->customdata, scene, 1)){ |
| 1256 stitch_exit(C, op, 1); |
| 1257 return OPERATOR_FINISHED; |
| 1258 }else { |
| 1259 return stitch_cancel(C, op); |
| 1260 } |
| 1261 } |
| 1262 |
| 1263 |
| 1264 static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event) |
| 1265 { |
| 1266 StitchState *stitch_state; |
| 1267 Scene *scene = CTX_data_scene(C); |
| 1268 |
| 1269 stitch_state = (StitchState *)op->customdata; |
| 1270 |
| 1271 switch(event->type){ |
| 1272 case MIDDLEMOUSE: |
| 1273 return OPERATOR_PASS_THROUGH; |
| 1274 |
| 1275 /* Cancel */ |
| 1276 case ESCKEY: |
| 1277 return stitch_cancel(C, op); |
| 1278 |
| 1279 |
| 1280 case LEFTMOUSE: |
| 1281 case PADENTER: |
| 1282 case RETKEY: |
| 1283 if(stitch_process_data(stitch_state, scene, 1)){ |
| 1284 stitch_exit(C, op, 1); |
| 1285 return OPERATOR_FINISHED; |
| 1286 } |
| 1287 else { |
| 1288 return stitch_cancel(C, op); |
| 1289 } |
| 1290 |
| 1291 /* Increase limit */ |
| 1292 case PADPLUSKEY: |
| 1293 case WHEELUPMOUSE: |
| 1294 if(event->ctrl){ |
| 1295 stitch_state->limit_dist += 0.01; |
| 1296 if(!stitch_process_data(stitch_state, scene, 0))
{ |
| 1297 return stitch_cancel(C, op); |
| 1298 } |
| 1299 break; |
| 1300 } |
| 1301 else{ |
| 1302 return OPERATOR_PASS_THROUGH; |
| 1303 } |
| 1304 /* Decrease limit */ |
| 1305 case PADMINUS: |
| 1306 case WHEELDOWNMOUSE: |
| 1307 if(event->ctrl){ |
| 1308 stitch_state->limit_dist -= 0.01; |
| 1309 stitch_state->limit_dist = MAX2(0.01, stitch_sta
te->limit_dist); |
| 1310 if(!stitch_process_data(stitch_state, scene, 0))
{ |
| 1311 return stitch_cancel(C, op); |
| 1312 } |
| 1313 break; |
| 1314 }else{ |
| 1315 return OPERATOR_PASS_THROUGH; |
| 1316 } |
| 1317 |
| 1318 /* Use Limit (Default off)*/ |
| 1319 case LKEY: |
| 1320 if(event->val == KM_PRESS){ |
| 1321 stitch_state->use_limit = !stitch_state->use_lim
it; |
| 1322 if(!stitch_process_data(stitch_state, scene, 0))
{ |
| 1323 return stitch_cancel(C, op); |
| 1324 } |
| 1325 break; |
| 1326 } |
| 1327 return OPERATOR_RUNNING_MODAL; |
| 1328 |
| 1329 case IKEY: |
| 1330 if(event->val == KM_PRESS){ |
| 1331 stitch_state->static_island++; |
| 1332 stitch_state->static_island %= stitch_state->ele
ment_map->totalIslands; |
| 1333 |
| 1334 if(!stitch_process_data(stitch_state, scene, 0))
{ |
| 1335 return stitch_cancel(C, op); |
| 1336 } |
| 1337 break; |
| 1338 } |
| 1339 return OPERATOR_RUNNING_MODAL; |
| 1340 |
| 1341 case MKEY: |
| 1342 if(event->val == KM_PRESS){ |
| 1343 stitch_state->midpoints = !stitch_state->midpoin
ts; |
| 1344 if(!stitch_process_data(stitch_state, scene, 0))
{ |
| 1345 return stitch_cancel(C, op); |
| 1346 } |
| 1347 } |
| 1348 break; |
| 1349 |
| 1350 /* Select geometry*/ |
| 1351 case RIGHTMOUSE: |
| 1352 if(!event->shift){ |
| 1353 return stitch_cancel(C, op); |
| 1354 } |
| 1355 if(event->val == KM_RELEASE){ |
| 1356 /* add uv under mouse to processed uv's */ |
| 1357 float co[2]; |
| 1358 NearestHit hit; |
| 1359 ARegion *ar= CTX_wm_region(C); |
| 1360 Image *ima= CTX_data_edit_image(C); |
| 1361 |
| 1362 UI_view2d_region_to_view(&ar->v2d, event->mval[0
], event->mval[1], &co[0], &co[1]); |
| 1363 ED_find_nearest_uv_vert(scene, ima, stitch_state
->em, co, NULL, &hit); |
| 1364 |
| 1365 if(hit.efa) |
| 1366 { |
| 1367 /* Add vertex to selection, deselect all
common uv's of vert other |
| 1368 * than selected and update the preview.
This behavior was decided so that |
| 1369 * you can do stuff like deselect the op
posite stitchable vertex and the initial still gets deselected */ |
| 1370 |
| 1371 /* This works due to setting of
tmp in find nearest uv vert */ |
| 1372 UvElement *element = ED_get_uv_e
lement(stitch_state->element_map, hit.efa, hit.uv); |
| 1373 stitch_select_uv(element, stitch
_state, 0); |
| 1374 |
| 1375 } |
| 1376 if(!stitch_process_data(stitch_state, scene, 0))
{ |
| 1377 return stitch_cancel(C, op); |
| 1378 } |
| 1379 break; |
| 1380 } |
| 1381 return OPERATOR_RUNNING_MODAL; |
| 1382 |
| 1383 /* snap islands on/off */ |
| 1384 case SKEY: |
| 1385 if(event->val == KM_PRESS){ |
| 1386 stitch_state->snap_islands = !stitch_state->snap
_islands; |
| 1387 if(!stitch_process_data(stitch_state, scene, 0))
{ |
| 1388 return stitch_cancel(C, op); |
| 1389 } |
| 1390 break; |
| 1391 } else |
| 1392 return OPERATOR_RUNNING_MODAL; |
| 1393 |
| 1394 default: |
| 1395 return OPERATOR_RUNNING_MODAL; |
| 1396 } |
| 1397 |
| 1398 /* if updated settings, renew feedback message */ |
| 1399 stitch_update_header(stitch_state, C); |
| 1400 ED_region_tag_redraw(CTX_wm_region(C)); |
| 1401 return OPERATOR_RUNNING_MODAL; |
| 1402 } |
| 1403 |
| 1404 void UV_OT_stitch(wmOperatorType *ot) |
| 1405 { |
| 1406 PropertyRNA *prop; |
| 1407 |
| 1408 /* identifiers */ |
| 1409 ot->name = "Stitch"; |
| 1410 ot->description = "Stitch selected UV vertices by proximity"; |
| 1411 ot->idname = "UV_OT_stitch"; |
| 1412 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; |
| 1413 ········ |
| 1414 /* api callbacks */ |
| 1415 ot->invoke = stitch_invoke; |
| 1416 ot->modal = stitch_modal; |
| 1417 ot->exec = stitch_exec; |
| 1418 ot->cancel = stitch_cancel; |
| 1419 ot->poll= ED_operator_uvedit; |
| 1420 |
| 1421 /* properties */ |
| 1422 RNA_def_boolean(ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs withi
n a specified limit distance"); |
| 1423 RNA_def_boolean(ot->srna, "snap_islands", 1, "Snap Islands", "Snap islan
ds together. On edge stitch mode, rotates the islands too"); |
| 1424 |
| 1425 RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit d
istance in normalized coordinates", 0.0, FLT_MAX); |
| 1426 RNA_def_int(ot->srna, "static_island", 0, 0, INT_MAX, "Static Island",
"Island that stays in place when stitching islands", 0, INT_MAX); |
| 1427 RNA_def_boolean(ot->srna, "midpoint_snap", 0, "Snap At Midpoint", "Uv's
are stitched at midpoint instead of at static island"); |
| 1428 prop = RNA_def_collection_runtime(ot->srna, "selection", &RNA_SelectedUv
Element, "Selection", ""); |
| 1429 /* Selection should not be editable or viewed in toolbar */ |
| 1430 RNA_def_property_flag(prop, PROP_HIDDEN); |
| 1431 } |
| 1432 |
| 1433 |
LEFT | RIGHT |