PageRenderTime 74ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/blender-2.63a/source/blender/editors/uvedit/uvedit_ops.c

#
C | 3696 lines | 2727 code | 688 blank | 281 comment | 585 complexity | 79353908284774c73bb53177d3804c82 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, BSD-3-Clause, LGPL-3.0, BSD-2-Clause, Apache-2.0, AGPL-1.0
  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. /** \file blender/editors/uvedit/uvedit_ops.c
  28. * \ingroup eduv
  29. */
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <math.h>
  33. #include <string.h>
  34. #include "MEM_guardedalloc.h"
  35. #include "DNA_object_types.h"
  36. #include "DNA_material_types.h"
  37. #include "DNA_mesh_types.h"
  38. #include "DNA_meshdata_types.h"
  39. #include "DNA_node_types.h"
  40. #include "DNA_image_types.h"
  41. #include "DNA_space_types.h"
  42. #include "DNA_scene_types.h"
  43. #include "BLI_math.h"
  44. #include "BLI_blenlib.h"
  45. #include "BLI_array.h"
  46. #include "BLI_utildefines.h"
  47. #include "BKE_context.h"
  48. #include "BKE_customdata.h"
  49. #include "BKE_depsgraph.h"
  50. #include "BKE_image.h"
  51. #include "BKE_library.h"
  52. #include "BKE_main.h"
  53. #include "BKE_material.h"
  54. #include "BKE_mesh.h"
  55. #include "BKE_node.h"
  56. #include "BKE_report.h"
  57. #include "BKE_scene.h"
  58. #include "BKE_tessmesh.h"
  59. #include "ED_image.h"
  60. #include "ED_mesh.h"
  61. #include "ED_node.h"
  62. #include "ED_uvedit.h"
  63. #include "ED_object.h"
  64. #include "ED_screen.h"
  65. #include "ED_transform.h"
  66. #include "RNA_access.h"
  67. #include "RNA_define.h"
  68. #include "WM_api.h"
  69. #include "WM_types.h"
  70. #include "UI_view2d.h"
  71. #include "uvedit_intern.h"
  72. static void select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int action);
  73. /************************* state testing ************************/
  74. int ED_uvedit_test(Object *obedit)
  75. {
  76. BMEditMesh *em;
  77. int ret;
  78. if (!obedit)
  79. return 0;
  80. if (obedit->type != OB_MESH)
  81. return 0;
  82. em = BMEdit_FromObject(obedit);
  83. ret = EDBM_mtexpoly_check(em);
  84. return ret;
  85. }
  86. static int ED_operator_uvedit_can_uv_sculpt(struct bContext *C)
  87. {
  88. SpaceImage *sima = CTX_wm_space_image(C);
  89. ToolSettings *toolsettings = CTX_data_tool_settings(C);
  90. Object *obedit = CTX_data_edit_object(C);
  91. return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
  92. }
  93. static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext * C)
  94. {
  95. Object *ob = CTX_data_active_object(C);
  96. if (ob && ob->type == OB_MESH) {
  97. Mesh *me = ob->data;
  98. if (CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL)
  99. return 1;
  100. }
  101. return 0;
  102. }
  103. /**************************** object active image *****************************/
  104. static int is_image_texture_node(bNode *node)
  105. {
  106. return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
  107. }
  108. int ED_object_get_active_image(Object *ob, int mat_nr, Image **ima, ImageUser **iuser, bNode **node_r)
  109. {
  110. Material *ma = give_current_material(ob, mat_nr);
  111. bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
  112. if (node && is_image_texture_node(node)) {
  113. if (ima) *ima = (Image *)node->id;
  114. if (iuser) *iuser = NULL;
  115. if (node_r) *node_r = node;
  116. return TRUE;
  117. }
  118. if (ima) *ima = NULL;
  119. if (iuser) *iuser = NULL;
  120. if (node_r) *node_r = node;
  121. return FALSE;
  122. }
  123. void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
  124. {
  125. Material *ma = give_current_material(ob, mat_nr);
  126. bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
  127. if (node && is_image_texture_node(node)) {
  128. node->id = &ima->id;
  129. ED_node_generic_update(bmain, ma->nodetree, node);
  130. }
  131. }
  132. /************************* assign image ************************/
  133. void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *ima, Image *previma)
  134. {
  135. BMEditMesh *em;
  136. BMFace *efa;
  137. BMIter iter;
  138. MTexPoly *tf;
  139. int update = 0;
  140. /* skip assigning these procedural images... */
  141. if (ima && (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE))
  142. return;
  143. /* verify we have a mesh we can work with */
  144. if (!obedit || (obedit->type != OB_MESH))
  145. return;
  146. em = BMEdit_FromObject(obedit);
  147. if (!em || !em->bm->totface) {
  148. return;
  149. }
  150. if (scene_use_new_shading_nodes(scene)) {
  151. /* new shading system, assign image in material */
  152. int sloppy = 1;
  153. BMFace *efa = BM_active_face_get(em->bm, sloppy);
  154. if (efa)
  155. ED_object_assign_active_image(bmain, obedit, efa->mat_nr + 1, ima);
  156. }
  157. else {
  158. /* old shading system, assign image to selected faces */
  159. /* ensure we have a uv map */
  160. if (!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) {
  161. BM_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY);
  162. BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV);
  163. update = 1;
  164. }
  165. /* now assign to all visible faces */
  166. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  167. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  168. if (uvedit_face_visible_test(scene, previma, efa, tf)) {
  169. if (ima) {
  170. tf->tpage = ima;
  171. if (ima->id.us == 0) id_us_plus(&ima->id);
  172. else id_lib_extern(&ima->id);
  173. }
  174. else {
  175. tf->tpage = NULL;
  176. }
  177. update = 1;
  178. }
  179. }
  180. /* and update depdency graph */
  181. if (update)
  182. DAG_id_tag_update(obedit->data, 0);
  183. }
  184. }
  185. /* dotile - 1, set the tile flag (from the space image)
  186. * 2, set the tile index for the faces. */
  187. static int uvedit_set_tile(Object *obedit, Image *ima, int curtile)
  188. {
  189. BMEditMesh *em;
  190. BMFace *efa;
  191. BMIter iter;
  192. MTexPoly *tf;
  193. /* verify if we have something to do */
  194. if (!ima || !ED_uvedit_test(obedit))
  195. return 0;
  196. if ((ima->tpageflag & IMA_TILES) == 0)
  197. return 0;
  198. /* skip assigning these procedural images... */
  199. if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE)
  200. return 0;
  201. em = BMEdit_FromObject(obedit);
  202. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  203. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  204. if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT))
  205. tf->tile = curtile; /* set tile index */
  206. }
  207. DAG_id_tag_update(obedit->data, 0);
  208. return 1;
  209. }
  210. /*********************** space conversion *********************/
  211. static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
  212. {
  213. int width, height;
  214. if (sima) {
  215. ED_space_image_size(sima, &width, &height);
  216. }
  217. else {
  218. width = 256;
  219. height = 256;
  220. }
  221. dist[0] = pixeldist / width;
  222. dist[1] = pixeldist / height;
  223. }
  224. /*************** visibility and selection utilities **************/
  225. int uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
  226. {
  227. ToolSettings *ts = scene->toolsettings;
  228. if (ts->uv_flag & UV_SYNC_SELECTION)
  229. return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
  230. else
  231. return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
  232. }
  233. int uvedit_face_visible_test(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf)
  234. {
  235. ToolSettings *ts = scene->toolsettings;
  236. if (ts->uv_flag & UV_SHOW_SAME_IMAGE)
  237. return (tf->tpage == ima) ? uvedit_face_visible_nolocal(scene, efa) : 0;
  238. else
  239. return uvedit_face_visible_nolocal(scene, efa);
  240. }
  241. int uvedit_face_select_test(Scene *scene, BMEditMesh *em, BMFace *efa)
  242. {
  243. ToolSettings *ts = scene->toolsettings;
  244. if (ts->uv_flag & UV_SYNC_SELECTION)
  245. return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
  246. else {
  247. BMLoop *l;
  248. MLoopUV *luv;
  249. BMIter liter;
  250. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  251. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  252. if (!(luv->flag & MLOOPUV_VERTSEL))
  253. return 0;
  254. }
  255. return 1;
  256. }
  257. }
  258. int uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const short do_history)
  259. {
  260. ToolSettings *ts = scene->toolsettings;
  261. if (ts->uv_flag & UV_SYNC_SELECTION) {
  262. BM_face_select_set(em->bm, efa, TRUE);
  263. if (do_history) {
  264. BM_select_history_store(em->bm, (BMElem *)efa);
  265. }
  266. }
  267. else {
  268. BMLoop *l;
  269. MLoopUV *luv;
  270. BMIter liter;
  271. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  272. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  273. luv->flag |= MLOOPUV_VERTSEL;
  274. }
  275. return 1;
  276. }
  277. return 0;
  278. }
  279. int uvedit_face_select_disable(Scene *scene, BMEditMesh *em, BMFace *efa)
  280. {
  281. ToolSettings *ts = scene->toolsettings;
  282. if (ts->uv_flag & UV_SYNC_SELECTION) {
  283. BM_face_select_set(em->bm, efa, FALSE);
  284. }
  285. else {
  286. BMLoop *l;
  287. MLoopUV *luv;
  288. BMIter liter;
  289. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  290. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  291. luv->flag &= ~MLOOPUV_VERTSEL;
  292. }
  293. return 1;
  294. }
  295. return 0;
  296. }
  297. int uvedit_edge_select_test(BMEditMesh *em, Scene *scene, BMLoop *l)
  298. {
  299. ToolSettings *ts = scene->toolsettings;
  300. if (ts->uv_flag & UV_SYNC_SELECTION) {
  301. if (ts->selectmode & SCE_SELECT_FACE) {
  302. return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
  303. }
  304. else if (ts->selectmode == SCE_SELECT_EDGE) {
  305. return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
  306. }
  307. else {
  308. return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
  309. BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
  310. }
  311. }
  312. else {
  313. MLoopUV *luv1, *luv2;
  314. luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  315. luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
  316. return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
  317. }
  318. }
  319. void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const short do_history)
  320. {
  321. ToolSettings *ts = scene->toolsettings;
  322. if (ts->uv_flag & UV_SYNC_SELECTION) {
  323. if (ts->selectmode & SCE_SELECT_FACE)
  324. BM_face_select_set(em->bm, l->f, TRUE);
  325. else if (ts->selectmode & SCE_SELECT_EDGE)
  326. BM_edge_select_set(em->bm, l->e, TRUE);
  327. else {
  328. BM_vert_select_set(em->bm, l->e->v1, TRUE);
  329. BM_vert_select_set(em->bm, l->e->v2, TRUE);
  330. }
  331. if (do_history) {
  332. BM_select_history_store(em->bm, (BMElem *)l->e);
  333. }
  334. }
  335. else {
  336. MLoopUV *luv1, *luv2;
  337. luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  338. luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
  339. luv1->flag |= MLOOPUV_VERTSEL;
  340. luv2->flag |= MLOOPUV_VERTSEL;
  341. }
  342. }
  343. void uvedit_edge_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l)
  344. {
  345. ToolSettings *ts = scene->toolsettings;
  346. if (ts->uv_flag & UV_SYNC_SELECTION) {
  347. if (ts->selectmode & SCE_SELECT_FACE)
  348. BM_face_select_set(em->bm, l->f, FALSE);
  349. else if (ts->selectmode & SCE_SELECT_EDGE)
  350. BM_edge_select_set(em->bm, l->e, FALSE);
  351. else {
  352. BM_vert_select_set(em->bm, l->e->v1, FALSE);
  353. BM_vert_select_set(em->bm, l->e->v2, FALSE);
  354. }
  355. }
  356. else {
  357. MLoopUV *luv1, *luv2;
  358. luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  359. luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
  360. luv1->flag &= ~MLOOPUV_VERTSEL;
  361. luv2->flag &= ~MLOOPUV_VERTSEL;
  362. }
  363. }
  364. int uvedit_uv_select_test(BMEditMesh *em, Scene *scene, BMLoop *l)
  365. {
  366. ToolSettings *ts = scene->toolsettings;
  367. if (ts->uv_flag & UV_SYNC_SELECTION) {
  368. if (ts->selectmode & SCE_SELECT_FACE)
  369. return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
  370. else
  371. return BM_elem_flag_test(l->v, BM_ELEM_SELECT);
  372. }
  373. else {
  374. MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  375. return luv->flag & MLOOPUV_VERTSEL;
  376. }
  377. }
  378. void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const short do_history)
  379. {
  380. ToolSettings *ts = scene->toolsettings;
  381. if (ts->uv_flag & UV_SYNC_SELECTION) {
  382. if (ts->selectmode & SCE_SELECT_FACE)
  383. BM_face_select_set(em->bm, l->f, TRUE);
  384. else
  385. BM_vert_select_set(em->bm, l->v, TRUE);
  386. if (do_history) {
  387. BM_select_history_remove(em->bm, (BMElem *)l->v);
  388. }
  389. }
  390. else {
  391. MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  392. luv->flag |= MLOOPUV_VERTSEL;
  393. }
  394. }
  395. void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l)
  396. {
  397. ToolSettings *ts = scene->toolsettings;
  398. if (ts->uv_flag & UV_SYNC_SELECTION) {
  399. if (ts->selectmode & SCE_SELECT_FACE)
  400. BM_face_select_set(em->bm, l->f, FALSE);
  401. else
  402. BM_vert_select_set(em->bm, l->v, FALSE);
  403. }
  404. else {
  405. MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  406. luv->flag &= ~MLOOPUV_VERTSEL;
  407. }
  408. }
  409. /*********************** live unwrap utilities ***********************/
  410. void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
  411. {
  412. if (sima && (sima->flag & SI_LIVE_UNWRAP)) {
  413. ED_uvedit_live_unwrap_begin(scene, obedit);
  414. ED_uvedit_live_unwrap_re_solve();
  415. ED_uvedit_live_unwrap_end(0);
  416. }
  417. }
  418. /*********************** geometric utilities ***********************/
  419. void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2])
  420. {
  421. BMLoop *l;
  422. MLoopUV *luv;
  423. BMIter liter;
  424. zero_v2(cent);
  425. BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
  426. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  427. add_v2_v2(cent, luv->uv);
  428. }
  429. mul_v2_fl(cent, 1.0f / (float)f->len);
  430. }
  431. void uv_center(float uv[][2], float cent[2], int quad)
  432. {
  433. if (quad) {
  434. cent[0] = (uv[0][0] + uv[1][0] + uv[2][0] + uv[3][0]) / 4.0f;
  435. cent[1] = (uv[0][1] + uv[1][1] + uv[2][1] + uv[3][1]) / 4.0f;
  436. }
  437. else {
  438. cent[0] = (uv[0][0] + uv[1][0] + uv[2][0]) / 3.0f;
  439. cent[1] = (uv[0][1] + uv[1][1] + uv[2][1]) / 3.0f;
  440. }
  441. }
  442. float uv_area(float uv[][2], int quad)
  443. {
  444. if (quad)
  445. return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]);
  446. else
  447. return area_tri_v2(uv[0], uv[1], uv[2]);
  448. }
  449. float poly_uv_area(float uv[][2], int len)
  450. {
  451. //BMESH_TODO: make this not suck
  452. //maybe use scanfill? I dunno.
  453. if (len >= 4)
  454. return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]);
  455. else
  456. return area_tri_v2(uv[0], uv[1], uv[2]);
  457. return 1.0;
  458. }
  459. void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
  460. {
  461. int i;
  462. for (i = 0; i < len; i++) {
  463. uv[i][0] = uv_orig[i][0] * aspx;
  464. uv[i][1] = uv_orig[i][1] * aspy;
  465. }
  466. }
  467. int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
  468. {
  469. BMEditMesh *em = BMEdit_FromObject(obedit);
  470. BMFace *efa;
  471. BMLoop *l;
  472. BMIter iter, liter;
  473. MTexPoly *tf;
  474. MLoopUV *luv;
  475. int sel;
  476. INIT_MINMAX2(min, max);
  477. sel = 0;
  478. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  479. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  480. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  481. continue;
  482. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  483. if (uvedit_uv_select_test(em, scene, l)) {
  484. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  485. DO_MINMAX2(luv->uv, min, max);
  486. sel = 1;
  487. }
  488. }
  489. }
  490. return sel;
  491. }
  492. static int ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[2])
  493. {
  494. BMEditMesh *em = BMEdit_FromObject(obedit);
  495. BMFace *efa;
  496. BMLoop *l;
  497. BMIter iter, liter;
  498. MTexPoly *tf;
  499. MLoopUV *luv;
  500. unsigned int sel = 0;
  501. zero_v2(co);
  502. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  503. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  504. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  505. continue;
  506. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  507. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  508. if (uvedit_uv_select_test(em, scene, l)) {
  509. add_v2_v2(co, luv->uv);
  510. sel++;
  511. }
  512. }
  513. }
  514. mul_v2_fl(co, 1.0f / (float)sel);
  515. return (sel != 0);
  516. }
  517. static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
  518. {
  519. int change = FALSE;
  520. if (mode == V3D_CENTER) { /* bounding box */
  521. float min[2], max[2];
  522. if (ED_uvedit_minmax(scene, ima, obedit, min, max)) {
  523. mid_v2_v2v2(cent, min, max);
  524. change = TRUE;
  525. }
  526. }
  527. else {
  528. if (ED_uvedit_median(scene, ima, obedit, cent)) {
  529. change = TRUE;
  530. }
  531. }
  532. return change;
  533. }
  534. /************************** find nearest ****************************/
  535. void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
  536. {
  537. MTexPoly *tf;
  538. BMFace *efa;
  539. BMLoop *l;
  540. BMIter iter, liter;
  541. MLoopUV *luv, *nextluv;
  542. float mindist, dist;
  543. int i;
  544. mindist = 1e10f;
  545. memset(hit, 0, sizeof(*hit));
  546. BM_mesh_elem_index_ensure(em->bm, BM_VERT);
  547. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  548. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  549. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  550. continue;
  551. i = 0;
  552. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  553. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  554. nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
  555. dist = dist_to_line_segment_v2(co, luv->uv, nextluv->uv);
  556. if (dist < mindist) {
  557. hit->tf = tf;
  558. hit->efa = efa;
  559. hit->l = l;
  560. hit->nextl = l->next;
  561. hit->luv = luv;
  562. hit->nextluv = nextluv;
  563. hit->lindex = i;
  564. hit->vert1 = BM_elem_index_get(hit->l->v);
  565. hit->vert2 = BM_elem_index_get(hit->l->next->v);
  566. mindist = dist;
  567. }
  568. i++;
  569. }
  570. }
  571. }
  572. static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
  573. {
  574. MTexPoly *tf;
  575. BMFace *efa;
  576. BMLoop *l;
  577. BMIter iter, liter;
  578. MLoopUV *luv;
  579. float mindist, dist, cent[2];
  580. mindist = 1e10f;
  581. memset(hit, 0, sizeof(*hit));
  582. /*this will fill in hit.vert1 and hit.vert2*/
  583. uv_find_nearest_edge(scene, ima, em, co, hit);
  584. hit->l = hit->nextl = NULL;
  585. hit->luv = hit->nextluv = NULL;
  586. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  587. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  588. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  589. continue;
  590. cent[0] = cent[1] = 0.0f;
  591. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  592. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  593. add_v2_v2(cent, luv->uv);
  594. }
  595. cent[0] /= efa->len;
  596. cent[1] /= efa->len;
  597. dist = fabs(co[0] - cent[0]) + fabs(co[1] - cent[1]);
  598. if (dist < mindist) {
  599. hit->tf = tf;
  600. hit->efa = efa;
  601. mindist = dist;
  602. }
  603. }
  604. }
  605. static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), int id,
  606. float co[2], float uv[2])
  607. {
  608. BMLoop *l;
  609. MLoopUV *luv;
  610. BMIter iter;
  611. float m[3], v1[3], v2[3], c1, c2, *uv1 = NULL, /* *uv2, */ /* UNUSED */ *uv3 = NULL;
  612. int id1, id2, i;
  613. id1 = (id + efa->len - 1) % efa->len;
  614. id2 = (id + efa->len + 1) % efa->len;
  615. m[0] = co[0] - uv[0];
  616. m[1] = co[1] - uv[1];
  617. i = 0;
  618. BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
  619. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  620. if (i == id1)
  621. uv1 = luv->uv;
  622. else if (i == id)
  623. ; /* uv2 = luv->uv; */ /* UNUSED */
  624. else if (i == id2)
  625. uv3 = luv->uv;
  626. i++;
  627. }
  628. sub_v3_v3v3(v1, uv1, uv);
  629. sub_v3_v3v3(v2, uv3, uv);
  630. /* m and v2 on same side of v-v1? */
  631. c1 = v1[0] * m[1] - v1[1] * m[0];
  632. c2 = v1[0] * v2[1] - v1[1] * v2[0];
  633. if (c1 * c2 < 0.0f)
  634. return 0;
  635. /* m and v1 on same side of v-v2? */
  636. c1 = v2[0] * m[1] - v2[1] * m[0];
  637. c2 = v2[0] * v1[1] - v2[1] * v1[0];
  638. return (c1 * c2 >= 0.0f);
  639. }
  640. void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
  641. float co[2], float penalty[2], NearestHit *hit)
  642. {
  643. BMFace *efa;
  644. BMLoop *l;
  645. BMIter iter, liter;
  646. MTexPoly *tf;
  647. MLoopUV *luv;
  648. float mindist, dist;
  649. int i;
  650. /*this will fill in hit.vert1 and hit.vert2*/
  651. uv_find_nearest_edge(scene, ima, em, co, hit);
  652. hit->l = hit->nextl = NULL;
  653. hit->luv = hit->nextluv = NULL;
  654. mindist = 1e10f;
  655. memset(hit, 0, sizeof(*hit));
  656. BM_mesh_elem_index_ensure(em->bm, BM_VERT);
  657. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  658. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  659. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  660. continue;
  661. i = 0;
  662. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  663. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  664. if (penalty && uvedit_uv_select_test(em, scene, l))
  665. dist = fabs(co[0] - luv->uv[0]) + penalty[0] + fabs(co[1] - luv->uv[1]) + penalty[1];
  666. else
  667. dist = fabs(co[0] - luv->uv[0]) + fabs(co[1] - luv->uv[1]);
  668. if (dist <= mindist) {
  669. if (dist == mindist)
  670. if (!nearest_uv_between(em, efa, efa->len, i, co, luv->uv)) {
  671. i++;
  672. continue;
  673. }
  674. mindist = dist;
  675. hit->l = l;
  676. hit->nextl = l->next;
  677. hit->luv = luv;
  678. hit->nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
  679. hit->tf = tf;
  680. hit->efa = efa;
  681. hit->lindex = i;
  682. hit->vert1 = BM_elem_index_get(hit->l->v);
  683. }
  684. i++;
  685. }
  686. }
  687. }
  688. int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
  689. {
  690. BMEditMesh *em = BMEdit_FromObject(obedit);
  691. BMFace *efa;
  692. BMLoop *l;
  693. BMIter iter, liter;
  694. MTexPoly *tf;
  695. MLoopUV *luv;
  696. float mindist, dist;
  697. int found = 0;
  698. mindist = 1e10f;
  699. uv[0] = co[0];
  700. uv[1] = co[1];
  701. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  702. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  703. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  704. continue;
  705. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  706. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  707. dist = fabs(co[0] - luv->uv[0]) + fabs(co[1] - luv->uv[1]);
  708. if (dist <= mindist) {
  709. mindist = dist;
  710. uv[0] = luv->uv[0];
  711. uv[1] = luv->uv[1];
  712. found = 1;
  713. }
  714. }
  715. }
  716. return found;
  717. }
  718. UvElement *ED_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
  719. {
  720. UvElement *element;
  721. element = map->vert[BM_elem_index_get(l->v)];
  722. for (; element; element = element->next)
  723. if (element->face == efa)
  724. return element;
  725. return NULL;
  726. }
  727. /*********************** loop select ***********************/
  728. static void select_edgeloop_uv_vertex_loop_flag(UvMapVert *first)
  729. {
  730. UvMapVert *iterv;
  731. int count = 0;
  732. for (iterv = first; iterv; iterv = iterv->next) {
  733. if (iterv->separate && iterv != first)
  734. break;
  735. count++;
  736. }
  737. if (count < 5)
  738. first->flag = 1;
  739. }
  740. static UvMapVert *select_edgeloop_uv_vertex_map_get(UvVertMap *vmap, BMFace *efa, int a)
  741. {
  742. UvMapVert *iterv, *first;
  743. BMLoop *l;
  744. l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, a);
  745. first = EDBM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
  746. for (iterv = first; iterv; iterv = iterv->next) {
  747. if (iterv->separate)
  748. first = iterv;
  749. if (iterv->f == BM_elem_index_get(efa))
  750. return first;
  751. }
  752. return NULL;
  753. }
  754. static int select_edgeloop_uv_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface)
  755. {
  756. UvMapVert *iterv1, *iterv2;
  757. BMFace *efa;
  758. int tot = 0;
  759. /* count number of faces this edge has */
  760. for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
  761. if (iterv1->separate && iterv1 != first1)
  762. break;
  763. for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
  764. if (iterv2->separate && iterv2 != first2)
  765. break;
  766. if (iterv1->f == iterv2->f) {
  767. /* if face already tagged, don't do this edge */
  768. efa = EDBM_face_at_index(em, iterv1->f);
  769. if (BM_elem_flag_test(efa, BM_ELEM_TAG))
  770. return 0;
  771. tot++;
  772. break;
  773. }
  774. }
  775. }
  776. if (*totface == 0) /* start edge */
  777. *totface = tot;
  778. else if (tot != *totface) /* check for same number of faces as start edge */
  779. return 0;
  780. /* tag the faces */
  781. for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
  782. if (iterv1->separate && iterv1 != first1)
  783. break;
  784. for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
  785. if (iterv2->separate && iterv2 != first2)
  786. break;
  787. if (iterv1->f == iterv2->f) {
  788. efa = EDBM_face_at_index(em, iterv1->f);
  789. BM_elem_flag_enable(efa, BM_ELEM_TAG);
  790. break;
  791. }
  792. }
  793. }
  794. return 1;
  795. }
  796. static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit,
  797. float limit[2], const short extend)
  798. {
  799. BMFace *efa;
  800. BMIter iter, liter;
  801. BMLoop *l;
  802. MTexPoly *tf;
  803. UvVertMap *vmap;
  804. UvMapVert *iterv1, *iterv2;
  805. int a, looking, nverts, starttotf, select;
  806. /* setup */
  807. EDBM_index_arrays_init(em, 0, 0, 1);
  808. vmap = EDBM_uv_vert_map_create(em, 0, 0, limit);
  809. BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
  810. if (!extend) {
  811. select_all_perform(scene, ima, em, SEL_DESELECT);
  812. }
  813. BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, FALSE);
  814. /* set flags for first face and verts */
  815. nverts = hit->efa->len;
  816. iterv1 = select_edgeloop_uv_vertex_map_get(vmap, hit->efa, hit->lindex);
  817. iterv2 = select_edgeloop_uv_vertex_map_get(vmap, hit->efa, (hit->lindex + 1) % nverts);
  818. select_edgeloop_uv_vertex_loop_flag(iterv1);
  819. select_edgeloop_uv_vertex_loop_flag(iterv2);
  820. starttotf = 0;
  821. select_edgeloop_uv_edge_tag_faces(em, iterv1, iterv2, &starttotf);
  822. /* sorry, first edge isn't even ok */
  823. if (iterv1->flag == 0 && iterv2->flag == 0) looking = 0;
  824. else looking = 1;
  825. /* iterate */
  826. while (looking) {
  827. looking = 0;
  828. /* find correct valence edges which are not tagged yet, but connect to tagged one */
  829. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  830. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  831. if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, ima, efa, tf)) {
  832. nverts = efa->len;
  833. for (a = 0; a < nverts; a++) {
  834. /* check face not hidden and not tagged */
  835. iterv1 = select_edgeloop_uv_vertex_map_get(vmap, efa, a);
  836. iterv2 = select_edgeloop_uv_vertex_map_get(vmap, efa, (a + 1) % nverts);
  837. if (!iterv1 || !iterv2)
  838. continue;
  839. /* check if vertex is tagged and has right valence */
  840. if (iterv1->flag || iterv2->flag) {
  841. if (select_edgeloop_uv_edge_tag_faces(em, iterv1, iterv2, &starttotf)) {
  842. looking = 1;
  843. BM_elem_flag_enable(efa, BM_ELEM_TAG);
  844. select_edgeloop_uv_vertex_loop_flag(iterv1);
  845. select_edgeloop_uv_vertex_loop_flag(iterv2);
  846. break;
  847. }
  848. }
  849. }
  850. }
  851. }
  852. }
  853. /* do the actual select/deselect */
  854. nverts = hit->efa->len;
  855. iterv1 = select_edgeloop_uv_vertex_map_get(vmap, hit->efa, hit->lindex);
  856. iterv2 = select_edgeloop_uv_vertex_map_get(vmap, hit->efa, (hit->lindex + 1) % nverts);
  857. iterv1->flag = 1;
  858. iterv2->flag = 1;
  859. if (extend) {
  860. if (uvedit_uv_select_test(em, scene, hit->l))
  861. select = 0;
  862. else
  863. select = 1;
  864. }
  865. else
  866. select = 1;
  867. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  868. a = 0;
  869. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  870. iterv1 = select_edgeloop_uv_vertex_map_get(vmap, efa, a);
  871. if (iterv1->flag) {
  872. if (select) uvedit_uv_select_enable(em, scene, l, FALSE);
  873. else uvedit_uv_select_disable(em, scene, l);
  874. }
  875. a++;
  876. }
  877. }
  878. /* cleanup */
  879. EDBM_uv_vert_map_free(vmap);
  880. EDBM_index_arrays_free(em);
  881. return (select) ? 1 : -1;
  882. }
  883. /*********************** linked select ***********************/
  884. static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, float limit[2], NearestHit *hit, int extend)
  885. {
  886. BMFace *efa;
  887. BMLoop *l;
  888. BMIter iter, liter;
  889. MTexPoly *tf;
  890. MLoopUV *luv;
  891. UvVertMap *vmap;
  892. UvMapVert *vlist, *iterv, *startv;
  893. int i, stacksize = 0, *stack;
  894. unsigned int a;
  895. char *flag;
  896. EDBM_index_arrays_init(em, 0, 0, 1); /* we can use this too */
  897. vmap = EDBM_uv_vert_map_create(em, 1, 1, limit);
  898. if (vmap == NULL)
  899. return;
  900. stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
  901. flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
  902. if (!hit) {
  903. BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
  904. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  905. if (uvedit_face_visible_test(scene, ima, efa, tf)) {
  906. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  907. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  908. if (luv->flag & MLOOPUV_VERTSEL) {
  909. stack[stacksize] = a;
  910. stacksize++;
  911. flag[a] = 1;
  912. break;
  913. }
  914. }
  915. }
  916. }
  917. }
  918. else {
  919. a = 0;
  920. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  921. if (efa == hit->efa) {
  922. stack[stacksize] = a;
  923. stacksize++;
  924. flag[a] = 1;
  925. break;
  926. }
  927. a++;
  928. }
  929. }
  930. while (stacksize > 0) {
  931. int j;
  932. stacksize--;
  933. a = stack[stacksize];
  934. j = 0;
  935. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  936. if (j == a)
  937. break;
  938. j++;
  939. }
  940. i = 0;
  941. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  942. /* make_uv_vert_map_EM sets verts tmp.l to the indices */
  943. vlist = EDBM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
  944. startv = vlist;
  945. for (iterv = vlist; iterv; iterv = iterv->next) {
  946. if (iterv->separate)
  947. startv = iterv;
  948. if (iterv->f == a)
  949. break;
  950. }
  951. for (iterv = startv; iterv; iterv = iterv->next) {
  952. if ((startv != iterv) && (iterv->separate))
  953. break;
  954. else if (!flag[iterv->f]) {
  955. flag[iterv->f] = 1;
  956. stack[stacksize] = iterv->f;
  957. stacksize++;
  958. }
  959. }
  960. i++;
  961. }
  962. }
  963. if (!extend) {
  964. a = 0;
  965. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  966. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  967. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  968. if (flag[a])
  969. luv->flag |= MLOOPUV_VERTSEL;
  970. else
  971. luv->flag &= ~MLOOPUV_VERTSEL;
  972. }
  973. a++;
  974. }
  975. }
  976. else {
  977. a = 0;
  978. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  979. if (!flag[a]) {
  980. a++;
  981. continue;
  982. }
  983. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  984. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  985. if (luv->flag & MLOOPUV_VERTSEL)
  986. break;
  987. }
  988. if (l)
  989. break;
  990. a++;
  991. }
  992. if (efa) {
  993. a = 0;
  994. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  995. if (!flag[a]) {
  996. a++;
  997. continue;
  998. }
  999. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1000. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1001. luv->flag &= ~MLOOPUV_VERTSEL;
  1002. }
  1003. a++;
  1004. }
  1005. }
  1006. else {
  1007. a = 0;
  1008. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1009. if (!flag[a]) {
  1010. a++;
  1011. continue;
  1012. }
  1013. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1014. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1015. luv->flag |= MLOOPUV_VERTSEL;
  1016. }
  1017. a++;
  1018. }
  1019. }
  1020. }
  1021. MEM_freeN(stack);
  1022. MEM_freeN(flag);
  1023. EDBM_uv_vert_map_free(vmap);
  1024. EDBM_index_arrays_free(em);
  1025. }
  1026. /* WATCH IT: this returns first selected UV,
  1027. * not ideal in many cases since there could be multiple */
  1028. static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVert *eve)
  1029. {
  1030. BMIter liter;
  1031. BMLoop *l;
  1032. BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
  1033. MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
  1034. if (!uvedit_face_visible_test(scene, ima, l->f, tf))
  1035. continue;
  1036. if (uvedit_uv_select_test(em, scene, l)) {
  1037. MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1038. return luv->uv;
  1039. }
  1040. }
  1041. return NULL;
  1042. }
  1043. /* ******************** align operator **************** */
  1044. static void weld_align_uv(bContext *C, int tool)
  1045. {
  1046. SpaceImage *sima;
  1047. Scene *scene;
  1048. Object *obedit;
  1049. Image *ima;
  1050. BMEditMesh *em;
  1051. BMIter iter, liter;
  1052. MTexPoly *tf;
  1053. MLoopUV *luv;
  1054. float cent[2], min[2], max[2];
  1055. scene = CTX_data_scene(C);
  1056. obedit = CTX_data_edit_object(C);
  1057. em = BMEdit_FromObject(obedit);
  1058. ima = CTX_data_edit_image(C);
  1059. sima = CTX_wm_space_image(C);
  1060. INIT_MINMAX2(min, max);
  1061. if (tool == 'a') {
  1062. BMFace *efa;
  1063. BMLoop *l;
  1064. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1065. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1066. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1067. continue;
  1068. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1069. if (uvedit_uv_select_test(em, scene, l)) {
  1070. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1071. DO_MINMAX2(luv->uv, min, max);
  1072. }
  1073. }
  1074. }
  1075. tool = (max[0] - min[0] >= max[1] - min[1]) ? 'y' : 'x';
  1076. }
  1077. uvedit_center(scene, ima, obedit, cent, 0);
  1078. if (tool == 'x' || tool == 'w') {
  1079. BMFace *efa;
  1080. BMLoop *l;
  1081. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1082. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1083. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1084. continue;
  1085. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1086. if (uvedit_uv_select_test(em, scene, l)) {
  1087. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1088. luv->uv[0] = cent[0];
  1089. }
  1090. }
  1091. }
  1092. }
  1093. if (tool == 'y' || tool == 'w') {
  1094. BMFace *efa;
  1095. BMLoop *l;
  1096. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1097. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1098. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1099. continue;
  1100. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1101. if (uvedit_uv_select_test(em, scene, l)) {
  1102. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1103. luv->uv[1] = cent[1];
  1104. }
  1105. }
  1106. }
  1107. }
  1108. if (tool == 's' || tool == 't' || tool == 'u') {
  1109. BMEdge *eed;
  1110. BMLoop *l;
  1111. BMVert *eve;
  1112. BMVert *eve_start;
  1113. BMIter iter, liter, eiter;
  1114. /* clear tag */
  1115. BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
  1116. BM_elem_flag_disable(eve, BM_ELEM_TAG);
  1117. }
  1118. /* tag verts with a selected UV */
  1119. BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
  1120. BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
  1121. tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
  1122. if (!uvedit_face_visible_test(scene, ima, l->f, tf))
  1123. continue;
  1124. if (uvedit_uv_select_test(em, scene, l)) {
  1125. BM_elem_flag_enable(eve, BM_ELEM_TAG);
  1126. break;
  1127. }
  1128. }
  1129. }
  1130. /* flush vertex tags to edges */
  1131. BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
  1132. BM_elem_flag_set(eed, BM_ELEM_TAG, (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
  1133. BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
  1134. }
  1135. /* find a vertex with only one tagged edge */
  1136. eve_start = NULL;
  1137. BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
  1138. int tot_eed_tag = 0;
  1139. BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
  1140. if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
  1141. tot_eed_tag++;
  1142. }
  1143. }
  1144. if (tot_eed_tag == 1) {
  1145. eve_start = eve;
  1146. break;
  1147. }
  1148. }
  1149. if (eve_start) {
  1150. BMVert **eve_line = NULL;
  1151. BMVert *eve_next = NULL;
  1152. BLI_array_declare(eve_line);
  1153. int i;
  1154. eve = eve_start;
  1155. /* walk over edges, building an array of verts in a line */
  1156. while (eve) {
  1157. BLI_array_append(eve_line, eve);
  1158. /* don't touch again */
  1159. BM_elem_flag_disable(eve, BM_ELEM_TAG);
  1160. eve_next = NULL;
  1161. /* find next eve */
  1162. BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
  1163. if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
  1164. BMVert *eve_other = BM_edge_other_vert(eed, eve);
  1165. if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
  1166. /* this is a tagged vert we didnt walk over yet, step onto it */
  1167. eve_next = eve_other;
  1168. break;
  1169. }
  1170. }
  1171. }
  1172. eve = eve_next;
  1173. }
  1174. /* now we have all verts, make into a line */
  1175. if (BLI_array_count(eve_line) > 2) {
  1176. /* we know the returns from these must be valid */
  1177. float *uv_start = uv_sel_co_from_eve(scene, ima, em, eve_line[0]);
  1178. float *uv_end = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_count(eve_line) - 1]);
  1179. /* For t & u modes */
  1180. float a = 0.0f;
  1181. if (tool == 't') {
  1182. if (uv_start[1] == uv_end[1])
  1183. tool = 's';
  1184. else
  1185. a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
  1186. }
  1187. else if (tool == 'u') {
  1188. if (uv_start[0] == uv_end[0])
  1189. tool = 's';
  1190. else
  1191. a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
  1192. }
  1193. /* go over all verts except for endpoints */
  1194. for (i = 0; i < BLI_array_count(eve_line); i++) {
  1195. BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
  1196. tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
  1197. if (!uvedit_face_visible_test(scene, ima, l->f, tf))
  1198. continue;
  1199. if (uvedit_uv_select_test(em, scene, l)) {
  1200. MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1201. /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
  1202. * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
  1203. * Maybe this should be a BLI func? Or is it already existing?
  1204. * Could use interp_v2_v2v2, but not sure it's worth it here...*/
  1205. if (tool == 't')
  1206. luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
  1207. else if (tool == 'u')
  1208. luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
  1209. else
  1210. closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
  1211. }
  1212. }
  1213. }
  1214. }
  1215. else {
  1216. /* error - not a line, needs 3+ points */
  1217. }
  1218. if (eve_line) {
  1219. MEM_freeN(eve_line);
  1220. }
  1221. }
  1222. else {
  1223. /* error - cant find an endpoint */
  1224. }
  1225. }
  1226. uvedit_live_unwrap_update(sima, scene, obedit);
  1227. DAG_id_tag_update(obedit->data, 0);
  1228. WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
  1229. }
  1230. static int align_exec(bContext *C, wmOperator *op)
  1231. {
  1232. weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
  1233. return OPERATOR_FINISHED;
  1234. }
  1235. static void UV_OT_align(wmOperatorType *ot)
  1236. {
  1237. static EnumPropertyItem axis_items[] = {
  1238. {'s', "ALIGN_S", 0, "Straighten", "Align UVs along the line defined by the endpoints"},
  1239. {'t', "ALIGN_T", 0, "Straighten X", "Align UVs along the line defined by the endpoints along the X axis"},
  1240. {'u', "ALIGN_U", 0, "Straighten Y", "Align UVs along the line defined by the endpoints along the Y axis"},
  1241. {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
  1242. {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
  1243. {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
  1244. {0, NULL, 0, NULL, NULL}};
  1245. /* identifiers */
  1246. ot->name = "Align";
  1247. ot->description = "Align selected UV vertices to an axis";
  1248. ot->idname = "UV_OT_align";
  1249. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  1250. /* api callbacks */
  1251. ot->exec = align_exec;
  1252. ot->poll = ED_operator_image_active; /* requires space image */;
  1253. /* properties */
  1254. RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
  1255. }
  1256. /* ******************** weld operator **************** */
  1257. static int weld_exec(bContext *C, wmOperator *UNUSED(op))
  1258. {
  1259. weld_align_uv(C, 'w');
  1260. return OPERATOR_FINISHED;
  1261. }
  1262. static void UV_OT_weld(wmOperatorType *ot)
  1263. {
  1264. /* identifiers */
  1265. ot->name = "Weld";
  1266. ot->description = "Weld selected UV vertices together";
  1267. ot->idname = "UV_OT_weld";
  1268. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  1269. /* api callbacks */
  1270. ot->exec = weld_exec;
  1271. ot->poll = ED_operator_uvedit;
  1272. }
  1273. /* ******************** (de)select all operator **************** */
  1274. static void select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int action)
  1275. {
  1276. ToolSettings *ts = scene->toolsettings;
  1277. BMFace *efa;
  1278. BMLoop *l;
  1279. BMIter iter, liter;
  1280. MTexPoly *tf;
  1281. MLoopUV *luv;
  1282. if (ts->uv_flag & UV_SYNC_SELECTION) {
  1283. switch (action) {
  1284. case SEL_TOGGLE:
  1285. EDBM_select_toggle_all(em);
  1286. break;
  1287. case SEL_SELECT:
  1288. EDBM_flag_enable_all(em, BM_ELEM_SELECT);
  1289. break;
  1290. case SEL_DESELECT:
  1291. EDBM_flag_disable_all(em, BM_ELEM_SELECT);
  1292. break;
  1293. case SEL_INVERT:
  1294. EDBM_select_swap(em);
  1295. EDBM_selectmode_flush(em);
  1296. break;
  1297. }
  1298. }
  1299. else {
  1300. if (action == SEL_TOGGLE) {
  1301. action = SEL_SELECT;
  1302. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1303. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1304. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1305. continue;
  1306. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1307. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1308. if (luv->flag & MLOOPUV_VERTSEL) {
  1309. action = SEL_DESELECT;
  1310. break;
  1311. }
  1312. }
  1313. }
  1314. }
  1315. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1316. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1317. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1318. continue;
  1319. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1320. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1321. switch (action) {
  1322. case SEL_SELECT:
  1323. luv->flag |= MLOOPUV_VERTSEL;
  1324. break;
  1325. case SEL_DESELECT:
  1326. luv->flag &= ~MLOOPUV_VERTSEL;
  1327. break;
  1328. case SEL_INVERT:
  1329. luv->flag ^= MLOOPUV_VERTSEL;
  1330. break;
  1331. }
  1332. }
  1333. }
  1334. }
  1335. }
  1336. static int select_all_exec(bContext *C, wmOperator *op)
  1337. {
  1338. Scene *scene = CTX_data_scene(C);
  1339. Object *obedit = CTX_data_edit_object(C);
  1340. Image *ima = CTX_data_edit_image(C);
  1341. BMEditMesh *em = BMEdit_FromObject(obedit);
  1342. int action = RNA_enum_get(op->ptr, "action");
  1343. select_all_perform(scene, ima, em, action);
  1344. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  1345. return OPERATOR_FINISHED;
  1346. }
  1347. static void UV_OT_select_all(wmOperatorType *ot)
  1348. {
  1349. /* identifiers */
  1350. ot->name = "(De)select All";
  1351. ot->description = "Change selection of all UV vertices";
  1352. ot->idname = "UV_OT_select_all";
  1353. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  1354. /* api callbacks */
  1355. ot->exec = select_all_exec;
  1356. ot->poll = ED_operator_uvedit;
  1357. WM_operator_properties_select_all(ot);
  1358. }
  1359. /* ******************** mouse select operator **************** */
  1360. static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen)
  1361. {
  1362. int i;
  1363. /* this function test if some vertex needs to selected
  1364. * in addition to the existing ones due to sticky select */
  1365. if (sticky == SI_STICKY_DISABLE)
  1366. return 0;
  1367. for (i = 0; i < hitlen; i++) {
  1368. if (hitv[i] == v) {
  1369. if (sticky == SI_STICKY_LOC) {
  1370. if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1])
  1371. return 1;
  1372. }
  1373. else if (sticky == SI_STICKY_VERTEX)
  1374. return 1;
  1375. }
  1376. }
  1377. return 0;
  1378. }
  1379. static int mouse_select(bContext *C, float co[2], int extend, int loop)
  1380. {
  1381. SpaceImage *sima = CTX_wm_space_image(C);
  1382. Scene *scene = CTX_data_scene(C);
  1383. ToolSettings *ts = CTX_data_tool_settings(C);
  1384. Object *obedit = CTX_data_edit_object(C);
  1385. Image *ima = CTX_data_edit_image(C);
  1386. BMEditMesh *em = BMEdit_FromObject(obedit);
  1387. BMFace *efa;
  1388. BMLoop *l;
  1389. BMIter iter, liter;
  1390. MTexPoly *tf;
  1391. MLoopUV *luv;
  1392. NearestHit hit;
  1393. int i, select = 1, selectmode, sticky, sync, *hitv = NULL;
  1394. BLI_array_declare(hitv);
  1395. int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
  1396. float limit[2], **hituv = NULL;
  1397. BLI_array_declare(hituv);
  1398. float penalty[2];
  1399. /* notice 'limit' is the same no matter the zoom level, since this is like
  1400. * remove doubles and could annoying if it joined points when zoomed out.
  1401. * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
  1402. * shift-selecting can consider an adjacent point close enough to add to
  1403. * the selection rather than de-selecting the closest. */
  1404. uvedit_pixel_to_float(sima, limit, 0.05f);
  1405. uvedit_pixel_to_float(sima, penalty, 5.0f / sima->zoom);
  1406. /* retrieve operation mode */
  1407. if (ts->uv_flag & UV_SYNC_SELECTION) {
  1408. sync = 1;
  1409. if (ts->selectmode & SCE_SELECT_FACE)
  1410. selectmode = UV_SELECT_FACE;
  1411. else if (ts->selectmode & SCE_SELECT_EDGE)
  1412. selectmode = UV_SELECT_EDGE;
  1413. else
  1414. selectmode = UV_SELECT_VERTEX;
  1415. sticky = SI_STICKY_DISABLE;
  1416. }
  1417. else {
  1418. sync = 0;
  1419. selectmode = ts->uv_selectmode;
  1420. sticky = (sima) ? sima->sticky : 1;
  1421. }
  1422. /* find nearest element */
  1423. if (loop) {
  1424. /* find edge */
  1425. uv_find_nearest_edge(scene, ima, em, co, &hit);
  1426. if (hit.efa == NULL) {
  1427. BLI_array_free(hitv);
  1428. BLI_array_free(hituv);
  1429. return OPERATOR_CANCELLED;
  1430. }
  1431. hitlen = 0;
  1432. }
  1433. else if (selectmode == UV_SELECT_VERTEX) {
  1434. /* find vertex */
  1435. uv_find_nearest_vert(scene, ima, em, co, penalty, &hit);
  1436. if (hit.efa == NULL) {
  1437. BLI_array_free(hitv);
  1438. BLI_array_free(hituv);
  1439. return OPERATOR_CANCELLED;
  1440. }
  1441. /* mark 1 vertex as being hit */
  1442. BLI_array_growitems(hitv, hit.efa->len);
  1443. BLI_array_growitems(hituv, hit.efa->len);
  1444. for (i = 0; i < hit.efa->len; i++) {
  1445. hitv[i] = 0xFFFFFFFF;
  1446. }
  1447. hitv[hit.lindex] = hit.vert1;
  1448. hituv[hit.lindex] = hit.luv->uv;
  1449. hitlen = hit.efa->len;
  1450. }
  1451. else if (selectmode == UV_SELECT_EDGE) {
  1452. /* find edge */
  1453. uv_find_nearest_edge(scene, ima, em, co, &hit);
  1454. if (hit.efa == NULL) {
  1455. BLI_array_free(hitv);
  1456. BLI_array_free(hituv);
  1457. return OPERATOR_CANCELLED;
  1458. }
  1459. /* mark 2 edge vertices as being hit */
  1460. BLI_array_growitems(hitv, hit.efa->len);
  1461. BLI_array_growitems(hituv, hit.efa->len);
  1462. fill_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
  1463. hitv[hit.lindex] = hit.vert1;
  1464. hitv[(hit.lindex + 1) % hit.efa->len] = hit.vert2;
  1465. hituv[hit.lindex] = hit.luv->uv;
  1466. hituv[(hit.lindex + 1) % hit.efa->len] = hit.nextluv->uv;
  1467. hitlen = hit.efa->len;
  1468. }
  1469. else if (selectmode == UV_SELECT_FACE) {
  1470. /* find face */
  1471. find_nearest_uv_face(scene, ima, em, co, &hit);
  1472. if (hit.efa == NULL) {
  1473. BLI_array_free(hitv);
  1474. BLI_array_free(hituv);
  1475. return OPERATOR_CANCELLED;
  1476. }
  1477. /* make active */
  1478. BM_active_face_set(em->bm, hit.efa);
  1479. /* mark all face vertices as being hit */
  1480. BLI_array_growitems(hitv, hit.efa->len);
  1481. BLI_array_growitems(hituv, hit.efa->len);
  1482. i = 0;
  1483. BM_ITER_ELEM (l, &liter, hit.efa, BM_LOOPS_OF_FACE) {
  1484. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1485. hituv[i] = luv->uv;
  1486. hitv[i] = BM_elem_index_get(l->v);
  1487. i++;
  1488. }
  1489. hitlen = hit.efa->len;
  1490. }
  1491. else if (selectmode == UV_SELECT_ISLAND) {
  1492. uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
  1493. if (hit.efa == NULL) {
  1494. BLI_array_free(hitv);
  1495. BLI_array_free(hituv);
  1496. return OPERATOR_CANCELLED;
  1497. }
  1498. hitlen = 0;
  1499. }
  1500. else {
  1501. hitlen = 0;
  1502. BLI_array_free(hitv);
  1503. BLI_array_free(hituv);
  1504. return OPERATOR_CANCELLED;
  1505. }
  1506. /* do selection */
  1507. if (loop) {
  1508. flush = select_edgeloop(scene, ima, em, &hit, limit, extend);
  1509. }
  1510. else if (selectmode == UV_SELECT_ISLAND) {
  1511. select_linked(scene, ima, em, limit, &hit, extend);
  1512. }
  1513. else if (extend) {
  1514. if (selectmode == UV_SELECT_VERTEX) {
  1515. /* (de)select uv vertex */
  1516. if (uvedit_uv_select_test(em, scene, hit.l)) {
  1517. uvedit_uv_select_disable(em, scene, hit.l);
  1518. select = 0;
  1519. }
  1520. else {
  1521. uvedit_uv_select_enable(em, scene, hit.l, TRUE);
  1522. select = 1;
  1523. }
  1524. flush = 1;
  1525. }
  1526. else if (selectmode == UV_SELECT_EDGE) {
  1527. /* (de)select edge */
  1528. if (uvedit_edge_select_test(em, scene, hit.l)) {
  1529. uvedit_edge_select_disable(em, scene, hit.l);
  1530. select = 0;
  1531. }
  1532. else {
  1533. uvedit_edge_select_enable(em, scene, hit.l, TRUE);
  1534. select = 1;
  1535. }
  1536. flush = 1;
  1537. }
  1538. else if (selectmode == UV_SELECT_FACE) {
  1539. /* (de)select face */
  1540. if (uvedit_face_select_test(scene, em, hit.efa)) {
  1541. uvedit_face_select_disable(scene, em, hit.efa);
  1542. select = 0;
  1543. }
  1544. else {
  1545. uvedit_face_select_enable(scene, em, hit.efa, TRUE);
  1546. select = 1;
  1547. }
  1548. flush = -1;
  1549. }
  1550. /* de-selecting an edge may deselect a face too - validate */
  1551. if (sync) {
  1552. if (select == FALSE) {
  1553. BM_select_history_validate(em->bm);
  1554. }
  1555. }
  1556. /* (de)select sticky uv nodes */
  1557. if (sticky != SI_STICKY_DISABLE) {
  1558. BM_mesh_elem_index_ensure(em->bm, BM_VERT);
  1559. /* deselect */
  1560. if (select == 0) {
  1561. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1562. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1563. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1564. continue;
  1565. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1566. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1567. if (sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
  1568. uvedit_uv_select_disable(em, scene, l);
  1569. }
  1570. }
  1571. flush = -1;
  1572. }
  1573. /* select */
  1574. else {
  1575. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1576. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1577. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1578. continue;
  1579. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1580. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1581. if (sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
  1582. uvedit_uv_select_enable(em, scene, l, FALSE);
  1583. }
  1584. }
  1585. flush = 1;
  1586. }
  1587. }
  1588. }
  1589. else {
  1590. /* deselect all */
  1591. select_all_perform(scene, ima, em, SEL_DESELECT);
  1592. if (selectmode == UV_SELECT_VERTEX) {
  1593. /* select vertex */
  1594. uvedit_uv_select_enable(em, scene, hit.l, TRUE);
  1595. flush = 1;
  1596. }
  1597. else if (selectmode == UV_SELECT_EDGE) {
  1598. /* select edge */
  1599. uvedit_edge_select_enable(em, scene, hit.l, TRUE);
  1600. flush = 1;
  1601. }
  1602. else if (selectmode == UV_SELECT_FACE) {
  1603. /* select face */
  1604. uvedit_face_select_enable(scene, em, hit.efa, TRUE);
  1605. }
  1606. /* select sticky uvs */
  1607. if (sticky != SI_STICKY_DISABLE) {
  1608. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1609. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1610. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1611. continue;
  1612. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1613. if (sticky == SI_STICKY_DISABLE) continue;
  1614. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1615. if (sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
  1616. uvedit_uv_select_enable(em, scene, l, FALSE);
  1617. flush = 1;
  1618. }
  1619. }
  1620. }
  1621. }
  1622. if (sync) {
  1623. /* flush for mesh selection */
  1624. /* before bmesh */
  1625. #if 0
  1626. if (ts->selectmode != SCE_SELECT_FACE) {
  1627. if (flush == 1) EDBM_select_flush(em);
  1628. else if (flush == -1) EDBM_deselect_flush(em);
  1629. }
  1630. #else
  1631. if (flush != 0) {
  1632. if (loop) {
  1633. /* push vertex -> edge selection */
  1634. if (select) {
  1635. EDBM_select_flush(em);
  1636. }
  1637. else {
  1638. EDBM_deselect_flush(em);
  1639. }
  1640. }
  1641. else {
  1642. EDBM_selectmode_flush(em);
  1643. }
  1644. }
  1645. #endif
  1646. }
  1647. DAG_id_tag_update(obedit->data, 0);
  1648. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  1649. BLI_array_free(hitv);
  1650. BLI_array_free(hituv);
  1651. return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
  1652. }
  1653. static int select_exec(bContext *C, wmOperator *op)
  1654. {
  1655. float co[2];
  1656. int extend, loop;
  1657. RNA_float_get_array(op->ptr, "location", co);
  1658. extend = RNA_boolean_get(op->ptr, "extend");
  1659. loop = 0;
  1660. return mouse_select(C, co, extend, loop);
  1661. }
  1662. static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
  1663. {
  1664. ARegion *ar = CTX_wm_region(C);
  1665. float co[2];
  1666. UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
  1667. RNA_float_set_array(op->ptr, "location", co);
  1668. return select_exec(C, op);
  1669. }
  1670. static void UV_OT_select(wmOperatorType *ot)
  1671. {
  1672. /* identifiers */
  1673. ot->name = "Select";
  1674. ot->description = "Select UV vertices";
  1675. ot->idname = "UV_OT_select";
  1676. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  1677. /* api callbacks */
  1678. ot->exec = select_exec;
  1679. ot->invoke = select_invoke;
  1680. ot->poll = ED_operator_image_active; /* requires space image */;
  1681. /* properties */
  1682. RNA_def_boolean(ot->srna, "extend", 0,
  1683. "Extend", "Extend selection rather than clearing the existing selection");
  1684. RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
  1685. "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
  1686. }
  1687. /* ******************** loop select operator **************** */
  1688. static int select_loop_exec(bContext *C, wmOperator *op)
  1689. {
  1690. float co[2];
  1691. int extend, loop;
  1692. RNA_float_get_array(op->ptr, "location", co);
  1693. extend = RNA_boolean_get(op->ptr, "extend");
  1694. loop = 1;
  1695. return mouse_select(C, co, extend, loop);
  1696. }
  1697. static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
  1698. {
  1699. ARegion *ar = CTX_wm_region(C);
  1700. float co[2];
  1701. UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
  1702. RNA_float_set_array(op->ptr, "location", co);
  1703. return select_loop_exec(C, op);
  1704. }
  1705. static void UV_OT_select_loop(wmOperatorType *ot)
  1706. {
  1707. /* identifiers */
  1708. ot->name = "Loop Select";
  1709. ot->description = "Select a loop of connected UV vertices";
  1710. ot->idname = "UV_OT_select_loop";
  1711. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  1712. /* api callbacks */
  1713. ot->exec = select_loop_exec;
  1714. ot->invoke = select_loop_invoke;
  1715. ot->poll = ED_operator_image_active; /* requires space image */;
  1716. /* properties */
  1717. RNA_def_boolean(ot->srna, "extend", 0,
  1718. "Extend", "Extend selection rather than clearing the existing selection");
  1719. RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
  1720. "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
  1721. }
  1722. /* ******************** linked select operator **************** */
  1723. static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, int pick)
  1724. {
  1725. SpaceImage *sima = CTX_wm_space_image(C);
  1726. Scene *scene = CTX_data_scene(C);
  1727. ToolSettings *ts = CTX_data_tool_settings(C);
  1728. Object *obedit = CTX_data_edit_object(C);
  1729. Image *ima = CTX_data_edit_image(C);
  1730. BMEditMesh *em = BMEdit_FromObject(obedit);
  1731. float limit[2];
  1732. int extend;
  1733. NearestHit hit, *hit_p = NULL;
  1734. if (ts->uv_flag & UV_SYNC_SELECTION) {
  1735. BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled");
  1736. return OPERATOR_CANCELLED;
  1737. }
  1738. extend = RNA_boolean_get(op->ptr, "extend");
  1739. uvedit_pixel_to_float(sima, limit, 0.05f);
  1740. if (pick) {
  1741. float co[2];
  1742. if (event) {
  1743. /* invoke */
  1744. ARegion *ar = CTX_wm_region(C);
  1745. UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
  1746. RNA_float_set_array(op->ptr, "location", co);
  1747. }
  1748. else {
  1749. /* exec */
  1750. RNA_float_get_array(op->ptr, "location", co);
  1751. }
  1752. uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
  1753. hit_p = &hit;
  1754. }
  1755. select_linked(scene, ima, em, limit, hit_p, extend);
  1756. DAG_id_tag_update(obedit->data, 0);
  1757. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  1758. return OPERATOR_FINISHED;
  1759. }
  1760. static int select_linked_exec(bContext *C, wmOperator *op)
  1761. {
  1762. return select_linked_internal(C, op, NULL, 0);
  1763. }
  1764. static void UV_OT_select_linked(wmOperatorType *ot)
  1765. {
  1766. /* identifiers */
  1767. ot->name = "Select Linked";
  1768. ot->description = "Select all UV vertices linked to the active UV map";
  1769. ot->idname = "UV_OT_select_linked";
  1770. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  1771. /* api callbacks */
  1772. ot->exec = select_linked_exec;
  1773. ot->poll = ED_operator_image_active; /* requires space image */
  1774. /* properties */
  1775. RNA_def_boolean(ot->srna, "extend", 0,
  1776. "Extend", "Extend selection rather than clearing the existing selection");
  1777. }
  1778. static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
  1779. {
  1780. return select_linked_internal(C, op, event, 1);
  1781. }
  1782. static int select_linked_pick_exec(bContext *C, wmOperator *op)
  1783. {
  1784. return select_linked_internal(C, op, NULL, 1);
  1785. }
  1786. static void UV_OT_select_linked_pick(wmOperatorType *ot)
  1787. {
  1788. /* identifiers */
  1789. ot->name = "Select Linked Pick";
  1790. ot->description = "Select all UV vertices linked under the mouse";
  1791. ot->idname = "UV_OT_select_linked_pick";
  1792. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  1793. /* api callbacks */
  1794. ot->invoke = select_linked_pick_invoke;
  1795. ot->exec = select_linked_pick_exec;
  1796. ot->poll = ED_operator_image_active; /* requires space image */;
  1797. /* properties */
  1798. RNA_def_boolean(ot->srna, "extend", 0,
  1799. "Extend", "Extend selection rather than clearing the existing selection");
  1800. RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
  1801. "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
  1802. }
  1803. /* ******************** unlink selection operator **************** */
  1804. static int unlink_selection_exec(bContext *C, wmOperator *op)
  1805. {
  1806. Scene *scene = CTX_data_scene(C);
  1807. ToolSettings *ts = CTX_data_tool_settings(C);
  1808. Object *obedit = CTX_data_edit_object(C);
  1809. Image *ima = CTX_data_edit_image(C);
  1810. BMEditMesh *em = BMEdit_FromObject(obedit);
  1811. BMFace *efa;
  1812. BMLoop *l;
  1813. BMIter iter, liter;
  1814. MTexPoly *tf;
  1815. MLoopUV *luv;
  1816. if (ts->uv_flag & UV_SYNC_SELECTION) {
  1817. BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled");
  1818. return OPERATOR_CANCELLED;
  1819. }
  1820. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1821. int desel = 0;
  1822. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  1823. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  1824. continue;
  1825. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1826. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1827. if (!(luv->flag & MLOOPUV_VERTSEL)) {
  1828. desel = 1;
  1829. break;
  1830. }
  1831. }
  1832. if (desel) {
  1833. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1834. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  1835. luv->flag &= ~MLOOPUV_VERTSEL;
  1836. }
  1837. }
  1838. }
  1839. DAG_id_tag_update(obedit->data, 0);
  1840. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  1841. return OPERATOR_FINISHED;
  1842. }
  1843. static void UV_OT_unlink_selected(wmOperatorType *ot)
  1844. {
  1845. /* identifiers */
  1846. ot->name = "Unlink Selection";
  1847. ot->description = "Unlink selected UV vertices from active UV map";
  1848. ot->idname = "UV_OT_unlink_selected";
  1849. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  1850. /* api callbacks */
  1851. ot->exec = unlink_selection_exec;
  1852. ot->poll = ED_operator_uvedit;
  1853. }
  1854. static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short select)
  1855. {
  1856. /* bmesh API handles flushing but not on de-select */
  1857. if (ts->uv_flag & UV_SYNC_SELECTION) {
  1858. if (ts->selectmode != SCE_SELECT_FACE) {
  1859. if (select == FALSE) {
  1860. EDBM_deselect_flush(em);
  1861. }
  1862. else {
  1863. EDBM_select_flush(em);
  1864. }
  1865. }
  1866. if (select == FALSE) {
  1867. BM_select_history_validate(em->bm);
  1868. }
  1869. }
  1870. }
  1871. /* ******************** border select operator **************** */
  1872. /* This function sets the selection on tagged faces, need because settings the
  1873. * selection a face is done in a number of places but it also needs to respect
  1874. * the sticky modes for the UV verts, so dealing with the sticky modes is best
  1875. * done in a separate function.
  1876. *
  1877. * De-selects faces that have been tagged on efa->tmp.l. */
  1878. static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
  1879. {
  1880. /* Selecting UV Faces with some modes requires us to change
  1881. * the selection in other faces (depending on the sticky mode).
  1882. *
  1883. * This only needs to be done when the Mesh is not used for
  1884. * selection (so for sticky modes, vertex or location based). */
  1885. ToolSettings *ts = CTX_data_tool_settings(C);
  1886. BMEditMesh *em = BMEdit_FromObject(obedit);
  1887. BMFace *efa;
  1888. BMLoop *l;
  1889. BMIter iter, liter;
  1890. /* MTexPoly *tf; */
  1891. if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
  1892. /* Tag all verts as untouched, then touch the ones that have a face center
  1893. * in the loop and select all MLoopUV's that use a touched vert. */
  1894. BMVert *eve;
  1895. BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
  1896. BM_elem_flag_disable(eve, BM_ELEM_TAG);
  1897. }
  1898. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1899. if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
  1900. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1901. BM_elem_flag_enable(l->v, BM_ELEM_TAG);
  1902. }
  1903. }
  1904. }
  1905. /* now select tagged verts */
  1906. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1907. /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
  1908. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1909. if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
  1910. if (select)
  1911. uvedit_uv_select_enable(em, scene, l, FALSE);
  1912. else
  1913. uvedit_uv_select_disable(em, scene, l);
  1914. }
  1915. }
  1916. }
  1917. }
  1918. else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
  1919. BMFace *efa_vlist;
  1920. /* MTexPoly *tf_vlist; */ /* UNUSED */
  1921. UvMapVert *start_vlist = NULL, *vlist_iter;
  1922. struct UvVertMap *vmap;
  1923. float limit[2];
  1924. unsigned int efa_index;
  1925. //BMVert *eve; /* removed vert counting for now */
  1926. //int a;
  1927. uvedit_pixel_to_float(sima, limit, 0.05);
  1928. EDBM_index_arrays_init(em, 0, 0, 1);
  1929. vmap = EDBM_uv_vert_map_create(em, 0, 0, limit);
  1930. /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
  1931. if (vmap == NULL) {
  1932. return;
  1933. }
  1934. efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
  1935. for (efa_index = 0; efa; efa = BM_iter_step(&iter), efa_index++) {
  1936. if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
  1937. /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
  1938. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  1939. if (select)
  1940. uvedit_uv_select_enable(em, scene, l, FALSE);
  1941. else
  1942. uvedit_uv_select_disable(em, scene, l);
  1943. vlist_iter = EDBM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
  1944. while (vlist_iter) {
  1945. if (vlist_iter->separate)
  1946. start_vlist = vlist_iter;
  1947. if (efa_index == vlist_iter->f)
  1948. break;
  1949. vlist_iter = vlist_iter->next;
  1950. }
  1951. vlist_iter = start_vlist;
  1952. while (vlist_iter) {
  1953. if (vlist_iter != start_vlist && vlist_iter->separate)
  1954. break;
  1955. if (efa_index != vlist_iter->f) {
  1956. efa_vlist = EDBM_face_at_index(em, vlist_iter->f);
  1957. /* tf_vlist = CustomData_bmesh_get(&em->bm->pdata, efa_vlist->head.data, CD_MTEXPOLY); */ /* UNUSED */
  1958. if (select)
  1959. uvedit_uv_select_enable(em, scene, BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex), FALSE);
  1960. else
  1961. uvedit_uv_select_disable(em, scene, BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex));
  1962. }
  1963. vlist_iter = vlist_iter->next;
  1964. }
  1965. }
  1966. }
  1967. }
  1968. EDBM_index_arrays_free(em);
  1969. EDBM_uv_vert_map_free(vmap);
  1970. }
  1971. else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
  1972. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  1973. if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
  1974. if (select)
  1975. uvedit_face_select_enable(scene, em, efa, FALSE);
  1976. else
  1977. uvedit_face_select_disable(scene, em, efa);
  1978. }
  1979. }
  1980. }
  1981. }
  1982. static int border_select_exec(bContext *C, wmOperator *op)
  1983. {
  1984. SpaceImage *sima = CTX_wm_space_image(C);
  1985. Scene *scene = CTX_data_scene(C);
  1986. ToolSettings *ts = CTX_data_tool_settings(C);
  1987. Object *obedit = CTX_data_edit_object(C);
  1988. Image *ima = CTX_data_edit_image(C);
  1989. ARegion *ar = CTX_wm_region(C);
  1990. BMEditMesh *em = BMEdit_FromObject(obedit);
  1991. BMFace *efa;
  1992. BMLoop *l;
  1993. BMIter iter, liter;
  1994. MTexPoly *tf;
  1995. MLoopUV *luv;
  1996. rcti rect;
  1997. rctf rectf;
  1998. int change, pinned, select, faces, extend;
  1999. /* get rectangle from operator */
  2000. rect.xmin = RNA_int_get(op->ptr, "xmin");
  2001. rect.ymin = RNA_int_get(op->ptr, "ymin");
  2002. rect.xmax = RNA_int_get(op->ptr, "xmax");
  2003. rect.ymax = RNA_int_get(op->ptr, "ymax");
  2004. UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
  2005. UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
  2006. /* figure out what to select/deselect */
  2007. select = (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
  2008. pinned = RNA_boolean_get(op->ptr, "pinned");
  2009. extend = RNA_boolean_get(op->ptr, "extend");
  2010. if (!extend)
  2011. select_all_perform(scene, ima, em, SEL_DESELECT);
  2012. if (ts->uv_flag & UV_SYNC_SELECTION)
  2013. faces = (ts->selectmode == SCE_SELECT_FACE);
  2014. else
  2015. faces = (ts->uv_selectmode == UV_SELECT_FACE);
  2016. /* do actual selection */
  2017. if (faces && !pinned) {
  2018. /* handle face selection mode */
  2019. float cent[2];
  2020. change = 0;
  2021. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2022. /* assume not touched */
  2023. BM_elem_flag_disable(efa, BM_ELEM_TAG);
  2024. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  2025. if (uvedit_face_visible_test(scene, ima, efa, tf)) {
  2026. poly_uv_center(em, efa, cent);
  2027. if (BLI_in_rctf(&rectf, cent[0], cent[1])) {
  2028. BM_elem_flag_enable(efa, BM_ELEM_TAG);
  2029. change = 1;
  2030. }
  2031. }
  2032. }
  2033. /* (de)selects all tagged faces and deals with sticky modes */
  2034. if (change)
  2035. uv_faces_do_sticky(C, sima, scene, obedit, select);
  2036. }
  2037. else {
  2038. /* other selection modes */
  2039. change = 1;
  2040. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2041. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  2042. if (!uvedit_face_visible_test(scene, ima, efa, tf))
  2043. continue;
  2044. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2045. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2046. if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) {
  2047. /* UV_SYNC_SELECTION - can't do pinned selection */
  2048. if (BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) {
  2049. if (select) uvedit_uv_select_enable(em, scene, l, FALSE);
  2050. else uvedit_uv_select_disable(em, scene, l);
  2051. }
  2052. }
  2053. else if (pinned) {
  2054. if ((luv->flag & MLOOPUV_PINNED) &&
  2055. BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) {
  2056. if (select) uvedit_uv_select_enable(em, scene, l, FALSE);
  2057. else uvedit_uv_select_disable(em, scene, l);
  2058. }
  2059. }
  2060. }
  2061. }
  2062. }
  2063. if (change) {
  2064. uv_select_sync_flush(ts, em, select);
  2065. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  2066. return OPERATOR_FINISHED;
  2067. }
  2068. return OPERATOR_CANCELLED;
  2069. }
  2070. static void UV_OT_select_border(wmOperatorType *ot)
  2071. {
  2072. /* identifiers */
  2073. ot->name = "Border Select";
  2074. ot->description = "Select UV vertices using border selection";
  2075. ot->idname = "UV_OT_select_border";
  2076. /* api callbacks */
  2077. ot->invoke = WM_border_select_invoke;
  2078. ot->exec = border_select_exec;
  2079. ot->modal = WM_border_select_modal;
  2080. ot->poll = ED_operator_image_active; /* requires space image */;
  2081. ot->cancel = WM_border_select_cancel;
  2082. /* flags */
  2083. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2084. /* properties */
  2085. RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
  2086. WM_operator_properties_gesture_border(ot, TRUE);
  2087. }
  2088. /* ******************** circle select operator **************** */
  2089. static int select_uv_inside_ellipse(BMEditMesh *em, SpaceImage *UNUSED(sima), Scene *scene, int select,
  2090. float *offset, float *ell, BMLoop *l, MLoopUV *luv)
  2091. {
  2092. /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
  2093. float x, y, r2, *uv;
  2094. uv = luv->uv;
  2095. x = (uv[0] - offset[0]) * ell[0];
  2096. y = (uv[1] - offset[1]) * ell[1];
  2097. r2 = x * x + y * y;
  2098. if (r2 < 1.0f) {
  2099. if (select) uvedit_uv_select_enable(em, scene, l, FALSE);
  2100. else uvedit_uv_select_disable(em, scene, l);
  2101. return TRUE;
  2102. }
  2103. else {
  2104. return FALSE;
  2105. }
  2106. }
  2107. static int circle_select_exec(bContext *C, wmOperator *op)
  2108. {
  2109. SpaceImage *sima = CTX_wm_space_image(C);
  2110. Scene *scene = CTX_data_scene(C);
  2111. Object *obedit = CTX_data_edit_object(C);
  2112. BMEditMesh *em = BMEdit_FromObject(obedit);
  2113. ARegion *ar = CTX_wm_region(C);
  2114. BMFace *efa;
  2115. BMLoop *l;
  2116. BMIter iter, liter;
  2117. MLoopUV *luv;
  2118. int x, y, radius, width, height, select;
  2119. float zoomx, zoomy, offset[2], ellipse[2];
  2120. int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
  2121. int change = FALSE;
  2122. /* get operator properties */
  2123. select = (gesture_mode == GESTURE_MODAL_SELECT);
  2124. x = RNA_int_get(op->ptr, "x");
  2125. y = RNA_int_get(op->ptr, "y");
  2126. radius = RNA_int_get(op->ptr, "radius");
  2127. /* compute ellipse size and location, not a circle since we deal
  2128. * with non square image. ellipse is normalized, r = 1.0. */
  2129. ED_space_image_size(sima, &width, &height);
  2130. ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
  2131. ellipse[0] = width * zoomx / radius;
  2132. ellipse[1] = height * zoomy / radius;
  2133. UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
  2134. /* do selection */
  2135. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2136. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2137. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2138. change |= select_uv_inside_ellipse(em, sima, scene, select, offset, ellipse, l, luv);
  2139. }
  2140. }
  2141. if (change) {
  2142. uv_select_sync_flush(scene->toolsettings, em, select);
  2143. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  2144. }
  2145. return OPERATOR_FINISHED;
  2146. }
  2147. static void UV_OT_circle_select(wmOperatorType *ot)
  2148. {
  2149. /* identifiers */
  2150. ot->name = "Circle Select";
  2151. ot->description = "Select UV vertices using circle selection";
  2152. ot->idname = "UV_OT_circle_select";
  2153. /* api callbacks */
  2154. ot->invoke = WM_gesture_circle_invoke;
  2155. ot->modal = WM_gesture_circle_modal;
  2156. ot->exec = circle_select_exec;
  2157. ot->poll = ED_operator_image_active; /* requires space image */;
  2158. ot->cancel = WM_gesture_circle_cancel;
  2159. /* flags */
  2160. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2161. /* properties */
  2162. RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
  2163. RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
  2164. RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
  2165. RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
  2166. }
  2167. /* ******************** snap cursor operator **************** */
  2168. static void snap_uv_to_pixel(float *uvco, float w, float h)
  2169. {
  2170. uvco[0] = ((float)((int)((uvco[0] * w) + 0.5f))) / w;
  2171. uvco[1] = ((float)((int)((uvco[1] * h) + 0.5f))) / h;
  2172. }
  2173. static void snap_cursor_to_pixels(SpaceImage *sima)
  2174. {
  2175. int width = 0, height = 0;
  2176. ED_space_image_size(sima, &width, &height);
  2177. snap_uv_to_pixel(sima->cursor, width, height);
  2178. }
  2179. static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
  2180. {
  2181. return uvedit_center(scene, ima, obedit, sima->cursor, sima->around);
  2182. }
  2183. static int snap_cursor_exec(bContext *C, wmOperator *op)
  2184. {
  2185. SpaceImage *sima = CTX_wm_space_image(C);
  2186. Scene *scene = CTX_data_scene(C);
  2187. Object *obedit = CTX_data_edit_object(C);
  2188. Image *ima = CTX_data_edit_image(C);
  2189. int change = 0;
  2190. switch (RNA_enum_get(op->ptr, "target")) {
  2191. case 0:
  2192. snap_cursor_to_pixels(sima);
  2193. change = 1;
  2194. break;
  2195. case 1:
  2196. change = snap_cursor_to_selection(scene, ima, obedit, sima);
  2197. break;
  2198. }
  2199. if (!change)
  2200. return OPERATOR_CANCELLED;
  2201. WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, sima);
  2202. return OPERATOR_FINISHED;
  2203. }
  2204. static void UV_OT_snap_cursor(wmOperatorType *ot)
  2205. {
  2206. static EnumPropertyItem target_items[] = {
  2207. {0, "PIXELS", 0, "Pixels", ""},
  2208. {1, "SELECTED", 0, "Selected", ""},
  2209. {0, NULL, 0, NULL, NULL}};
  2210. /* identifiers */
  2211. ot->name = "Snap Cursor";
  2212. ot->description = "Snap cursor to target type";
  2213. ot->idname = "UV_OT_snap_cursor";
  2214. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2215. /* api callbacks */
  2216. ot->exec = snap_cursor_exec;
  2217. ot->poll = ED_operator_image_active; /* requires space image */;
  2218. /* properties */
  2219. RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
  2220. }
  2221. /* ******************** snap selection operator **************** */
  2222. static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
  2223. {
  2224. BMEditMesh *em = BMEdit_FromObject(obedit);
  2225. BMFace *efa;
  2226. BMLoop *l;
  2227. BMIter iter, liter;
  2228. MTexPoly *tface;
  2229. MLoopUV *luv;
  2230. short change = 0;
  2231. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2232. tface = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  2233. if (!uvedit_face_visible_test(scene, ima, efa, tface))
  2234. continue;
  2235. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2236. if (uvedit_uv_select_test(em, scene, l)) {
  2237. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2238. copy_v2_v2(luv->uv, sima->cursor);
  2239. change = 1;
  2240. }
  2241. }
  2242. }
  2243. return change;
  2244. }
  2245. static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
  2246. {
  2247. BMEditMesh *em = BMEdit_FromObject(obedit);
  2248. BMesh *bm = em->bm;
  2249. BMFace *f;
  2250. BMLoop *l, *lsub;
  2251. BMIter iter, liter, lsubiter;
  2252. MTexPoly *tface;
  2253. MLoopUV *luv;
  2254. short change = FALSE;
  2255. /* index every vert that has a selected UV using it, but only once so as to
  2256. * get unique indices and to count how much to malloc */
  2257. BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
  2258. tface = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_MTEXPOLY);
  2259. if (uvedit_face_visible_test(scene, ima, f, tface)) {
  2260. BM_elem_flag_enable(f, BM_ELEM_TAG);
  2261. BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
  2262. BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(em, scene, l));
  2263. }
  2264. }
  2265. else {
  2266. BM_elem_flag_disable(f, BM_ELEM_TAG);
  2267. }
  2268. }
  2269. BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
  2270. if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* face: visible */
  2271. BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
  2272. if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* loop: selected*/
  2273. float uv[2] = {0.0f, 0.0f};
  2274. int uv_tot = 0;
  2275. BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) {
  2276. if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* face: visible */
  2277. !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* loop: unselected */
  2278. {
  2279. luv = CustomData_bmesh_get(&bm->ldata, lsub->head.data, CD_MLOOPUV);
  2280. add_v2_v2(uv, luv->uv);
  2281. uv_tot++;
  2282. }
  2283. }
  2284. if (uv_tot) {
  2285. luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
  2286. mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot);
  2287. change = TRUE;
  2288. }
  2289. }
  2290. }
  2291. }
  2292. }
  2293. return change;
  2294. }
  2295. static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
  2296. {
  2297. BMEditMesh *em = BMEdit_FromObject(obedit);
  2298. Image *ima = sima->image;
  2299. BMFace *efa;
  2300. BMLoop *l;
  2301. BMIter iter, liter;
  2302. MTexPoly *tface;
  2303. MLoopUV *luv;
  2304. int width = 0, height = 0;
  2305. float w, h;
  2306. short change = 0;
  2307. ED_space_image_size(sima, &width, &height);
  2308. w = (float)width;
  2309. h = (float)height;
  2310. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2311. tface = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  2312. if (!uvedit_face_visible_test(scene, ima, efa, tface))
  2313. continue;
  2314. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2315. if (uvedit_uv_select_test(em, scene, l)) {
  2316. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2317. snap_uv_to_pixel(luv->uv, w, h);
  2318. }
  2319. }
  2320. change = 1;
  2321. }
  2322. return change;
  2323. }
  2324. static int snap_selection_exec(bContext *C, wmOperator *op)
  2325. {
  2326. SpaceImage *sima = CTX_wm_space_image(C);
  2327. Scene *scene = CTX_data_scene(C);
  2328. Object *obedit = CTX_data_edit_object(C);
  2329. Image *ima = CTX_data_edit_image(C);
  2330. int change = 0;
  2331. switch (RNA_enum_get(op->ptr, "target")) {
  2332. case 0:
  2333. change = snap_uvs_to_pixels(sima, scene, obedit);
  2334. break;
  2335. case 1:
  2336. change = snap_uvs_to_cursor(scene, ima, obedit, sima);
  2337. break;
  2338. case 2:
  2339. change = snap_uvs_to_adjacent_unselected(scene, ima, obedit);
  2340. break;
  2341. }
  2342. if (!change)
  2343. return OPERATOR_CANCELLED;
  2344. uvedit_live_unwrap_update(sima, scene, obedit);
  2345. DAG_id_tag_update(obedit->data, 0);
  2346. WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
  2347. return OPERATOR_FINISHED;
  2348. }
  2349. static void UV_OT_snap_selected(wmOperatorType *ot)
  2350. {
  2351. static EnumPropertyItem target_items[] = {
  2352. {0, "PIXELS", 0, "Pixels", ""},
  2353. {1, "CURSOR", 0, "Cursor", ""},
  2354. {2, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
  2355. {0, NULL, 0, NULL, NULL}};
  2356. /* identifiers */
  2357. ot->name = "Snap Selection";
  2358. ot->description = "Snap selected UV vertices to target type";
  2359. ot->idname = "UV_OT_snap_selected";
  2360. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2361. /* api callbacks */
  2362. ot->exec = snap_selection_exec;
  2363. ot->poll = ED_operator_image_active; /* requires space image */;
  2364. /* properties */
  2365. RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
  2366. }
  2367. /* ******************** pin operator **************** */
  2368. static int pin_exec(bContext *C, wmOperator *op)
  2369. {
  2370. Scene *scene = CTX_data_scene(C);
  2371. Object *obedit = CTX_data_edit_object(C);
  2372. Image *ima = CTX_data_edit_image(C);
  2373. BMEditMesh *em = BMEdit_FromObject(obedit);
  2374. BMFace *efa;
  2375. BMLoop *l;
  2376. BMIter iter, liter;
  2377. MTexPoly *tface;
  2378. MLoopUV *luv;
  2379. int clear = RNA_boolean_get(op->ptr, "clear");
  2380. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2381. tface = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  2382. if (!uvedit_face_visible_test(scene, ima, efa, tface))
  2383. continue;
  2384. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2385. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2386. if (!clear) {
  2387. if (uvedit_uv_select_test(em, scene, l))
  2388. luv->flag |= MLOOPUV_PINNED;
  2389. }
  2390. else {
  2391. if (uvedit_uv_select_test(em, scene, l))
  2392. luv->flag &= ~MLOOPUV_PINNED;
  2393. }
  2394. }
  2395. }
  2396. WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
  2397. return OPERATOR_FINISHED;
  2398. }
  2399. static void UV_OT_pin(wmOperatorType *ot)
  2400. {
  2401. /* identifiers */
  2402. ot->name = "Pin";
  2403. ot->description = "Set/clear selected UV vertices as anchored between multiple unwrap operations";
  2404. ot->idname = "UV_OT_pin";
  2405. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2406. /* api callbacks */
  2407. ot->exec = pin_exec;
  2408. ot->poll = ED_operator_uvedit;
  2409. /* properties */
  2410. RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
  2411. }
  2412. /******************* select pinned operator ***************/
  2413. static int select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
  2414. {
  2415. Scene *scene = CTX_data_scene(C);
  2416. Object *obedit = CTX_data_edit_object(C);
  2417. Image *ima = CTX_data_edit_image(C);
  2418. BMEditMesh *em = BMEdit_FromObject(obedit);
  2419. BMFace *efa;
  2420. BMLoop *l;
  2421. BMIter iter, liter;
  2422. MTexPoly *tface;
  2423. MLoopUV *luv;
  2424. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2425. tface = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  2426. if (!uvedit_face_visible_test(scene, ima, efa, tface))
  2427. continue;
  2428. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2429. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2430. if (luv->flag & MLOOPUV_PINNED)
  2431. uvedit_uv_select_enable(em, scene, l, FALSE);
  2432. }
  2433. }
  2434. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  2435. return OPERATOR_FINISHED;
  2436. }
  2437. static void UV_OT_select_pinned(wmOperatorType *ot)
  2438. {
  2439. /* identifiers */
  2440. ot->name = "Selected Pinned";
  2441. ot->description = "Select all pinned UV vertices";
  2442. ot->idname = "UV_OT_select_pinned";
  2443. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2444. /* api callbacks */
  2445. ot->exec = select_pinned_exec;
  2446. ot->poll = ED_operator_uvedit;
  2447. }
  2448. /********************** hide operator *********************/
  2449. /* check if we are selected or unselected based on 'bool_test' arg,
  2450. * needed for select swap support */
  2451. #define UV_SEL_TEST(luv, bool_test) ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test)
  2452. /* is every UV vert selected or unselected depending on bool_test */
  2453. static int bm_face_is_all_uv_sel(BMesh *bm, BMFace *f, int bool_test)
  2454. {
  2455. BMLoop *l_iter;
  2456. BMLoop *l_first;
  2457. l_iter = l_first = BM_FACE_FIRST_LOOP(f);
  2458. do {
  2459. MLoopUV *luv = CustomData_bmesh_get(&bm->ldata, l_iter->head.data, CD_MLOOPUV);
  2460. if (!UV_SEL_TEST(luv, bool_test)) {
  2461. return FALSE;
  2462. }
  2463. } while ((l_iter = l_iter->next) != l_first);
  2464. return TRUE;
  2465. }
  2466. static int hide_exec(bContext *C, wmOperator *op)
  2467. {
  2468. SpaceImage *sima = CTX_wm_space_image(C);
  2469. ToolSettings *ts = CTX_data_tool_settings(C);
  2470. Object *obedit = CTX_data_edit_object(C);
  2471. Scene *scene = CTX_data_scene(C);
  2472. BMEditMesh *em = BMEdit_FromObject(obedit);
  2473. BMFace *efa;
  2474. BMLoop *l;
  2475. BMIter iter, liter;
  2476. MLoopUV *luv;
  2477. MTexPoly *tf;
  2478. int swap = RNA_boolean_get(op->ptr, "unselected");
  2479. Image *ima = sima ? sima->image : NULL;
  2480. int facemode = (ts->uv_selectmode == UV_SELECT_FACE);
  2481. if (ts->uv_flag & UV_SYNC_SELECTION) {
  2482. EDBM_mesh_hide(em, swap);
  2483. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  2484. return OPERATOR_FINISHED;
  2485. }
  2486. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2487. int hide = 0;
  2488. tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  2489. if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
  2490. continue;
  2491. }
  2492. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2493. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2494. if (UV_SEL_TEST(luv, !swap)) {
  2495. hide = 1;
  2496. break;
  2497. }
  2498. }
  2499. if (hide) {
  2500. /* note, a special case for edges could be used,
  2501. * for now edges act like verts and get flushed */
  2502. if (facemode) {
  2503. if (em->selectmode == SCE_SELECT_FACE) {
  2504. /* check that every UV is selected */
  2505. if (bm_face_is_all_uv_sel(em->bm, efa, TRUE) == !swap) {
  2506. BM_face_select_set(em->bm, efa, FALSE);
  2507. }
  2508. uvedit_face_select_disable(scene, em, efa);
  2509. }
  2510. else {
  2511. if (bm_face_is_all_uv_sel(em->bm, efa, TRUE) == !swap) {
  2512. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2513. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2514. if (UV_SEL_TEST(luv, !swap)) {
  2515. BM_vert_select_set(em->bm, l->v, FALSE);
  2516. }
  2517. }
  2518. }
  2519. if (!swap) uvedit_face_select_disable(scene, em, efa);
  2520. }
  2521. }
  2522. else if (em->selectmode == SCE_SELECT_FACE) {
  2523. /* check if a UV is de-selected */
  2524. if (bm_face_is_all_uv_sel(em->bm, efa, FALSE) != !swap) {
  2525. BM_face_select_set(em->bm, efa, FALSE);
  2526. uvedit_face_select_disable(scene, em, efa);
  2527. }
  2528. }
  2529. else {
  2530. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2531. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2532. if (UV_SEL_TEST(luv, !swap)) {
  2533. BM_vert_select_set(em->bm, l->v, FALSE);
  2534. if (!swap) luv->flag &= ~MLOOPUV_VERTSEL;
  2535. }
  2536. }
  2537. }
  2538. }
  2539. }
  2540. /* flush vertex selection changes */
  2541. if (em->selectmode != SCE_SELECT_FACE)
  2542. EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
  2543. BM_select_history_validate(em->bm);
  2544. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  2545. return OPERATOR_FINISHED;
  2546. }
  2547. #undef UV_SEL_TEST
  2548. static void UV_OT_hide(wmOperatorType *ot)
  2549. {
  2550. /* identifiers */
  2551. ot->name = "Hide Selected";
  2552. ot->description = "Hide (un)selected UV vertices";
  2553. ot->idname = "UV_OT_hide";
  2554. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2555. /* api callbacks */
  2556. ot->exec = hide_exec;
  2557. ot->poll = ED_operator_uvedit;
  2558. /* props */
  2559. RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
  2560. }
  2561. /****************** reveal operator ******************/
  2562. static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
  2563. {
  2564. SpaceImage *sima = CTX_wm_space_image(C);
  2565. ToolSettings *ts = CTX_data_tool_settings(C);
  2566. Object *obedit = CTX_data_edit_object(C);
  2567. /*Scene *scene = CTX_data_scene(C);*/ /*UNUSED*/
  2568. BMEditMesh *em = BMEdit_FromObject(obedit);
  2569. BMFace *efa;
  2570. BMLoop *l;
  2571. BMIter iter, liter;
  2572. MLoopUV *luv;
  2573. int facemode = (ts->uv_selectmode == UV_SELECT_FACE);
  2574. int stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
  2575. /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
  2576. * confuse our checks on selected verts. */
  2577. /* call the mesh function if we are in mesh sync sel */
  2578. if (ts->uv_flag & UV_SYNC_SELECTION) {
  2579. EDBM_mesh_reveal(em);
  2580. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  2581. return OPERATOR_FINISHED;
  2582. }
  2583. if (facemode) {
  2584. if (em->selectmode == SCE_SELECT_FACE) {
  2585. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2586. BM_elem_flag_disable(efa, BM_ELEM_TAG);
  2587. if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
  2588. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2589. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2590. luv->flag |= MLOOPUV_VERTSEL;
  2591. }
  2592. /* BM_face_select_set(em->bm, efa, TRUE); */
  2593. BM_elem_flag_enable(efa, BM_ELEM_TAG);
  2594. }
  2595. }
  2596. }
  2597. else {
  2598. /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
  2599. if (!stickymode) {
  2600. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2601. BM_elem_flag_disable(efa, BM_ELEM_TAG);
  2602. if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
  2603. int totsel = 0;
  2604. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2605. totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
  2606. }
  2607. if (!totsel) {
  2608. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2609. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2610. luv->flag |= MLOOPUV_VERTSEL;
  2611. }
  2612. /* BM_face_select_set(em->bm, efa, TRUE); */
  2613. BM_elem_flag_enable(efa, BM_ELEM_TAG);
  2614. }
  2615. }
  2616. }
  2617. }
  2618. else {
  2619. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2620. BM_elem_flag_disable(efa, BM_ELEM_TAG);
  2621. if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
  2622. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2623. if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
  2624. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2625. luv->flag |= MLOOPUV_VERTSEL;
  2626. }
  2627. }
  2628. /* BM_face_select_set(em->bm, efa, TRUE); */
  2629. BM_elem_flag_enable(efa, BM_ELEM_TAG);
  2630. }
  2631. }
  2632. }
  2633. }
  2634. }
  2635. else if (em->selectmode == SCE_SELECT_FACE) {
  2636. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2637. BM_elem_flag_disable(efa, BM_ELEM_TAG);
  2638. if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
  2639. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2640. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2641. luv->flag |= MLOOPUV_VERTSEL;
  2642. }
  2643. /* BM_face_select_set(em->bm, efa, TRUE); */
  2644. BM_elem_flag_enable(efa, BM_ELEM_TAG);
  2645. }
  2646. }
  2647. }
  2648. else {
  2649. BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
  2650. BM_elem_flag_disable(efa, BM_ELEM_TAG);
  2651. if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
  2652. BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
  2653. if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
  2654. luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  2655. luv->flag |= MLOOPUV_VERTSEL;
  2656. }
  2657. }
  2658. /* BM_face_select_set(em->bm, efa, TRUE); */
  2659. BM_elem_flag_enable(efa, BM_ELEM_TAG);
  2660. }
  2661. }
  2662. }
  2663. /* re-select tagged faces */
  2664. BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, TRUE, BM_ELEM_TAG);
  2665. WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
  2666. return OPERATOR_FINISHED;
  2667. }
  2668. static void UV_OT_reveal(wmOperatorType *ot)
  2669. {
  2670. /* identifiers */
  2671. ot->name = "Reveal Hidden";
  2672. ot->description = "Reveal all hidden UV vertices";
  2673. ot->idname = "UV_OT_reveal";
  2674. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2675. /* api callbacks */
  2676. ot->exec = reveal_exec;
  2677. ot->poll = ED_operator_uvedit;
  2678. }
  2679. /******************** set 3d cursor operator ********************/
  2680. static int set_2d_cursor_exec(bContext *C, wmOperator *op)
  2681. {
  2682. SpaceImage *sima = CTX_wm_space_image(C);
  2683. float location[2];
  2684. if (!sima)
  2685. return OPERATOR_CANCELLED;
  2686. RNA_float_get_array(op->ptr, "location", location);
  2687. sima->cursor[0] = location[0];
  2688. sima->cursor[1] = location[1];
  2689. WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
  2690. return OPERATOR_FINISHED;
  2691. }
  2692. static int set_2d_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
  2693. {
  2694. ARegion *ar = CTX_wm_region(C);
  2695. float location[2];
  2696. UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
  2697. RNA_float_set_array(op->ptr, "location", location);
  2698. return set_2d_cursor_exec(C, op);
  2699. }
  2700. static void UV_OT_cursor_set(wmOperatorType *ot)
  2701. {
  2702. /* identifiers */
  2703. ot->name = "Set 2D Cursor";
  2704. ot->description = "Set 2D cursor location";
  2705. ot->idname = "UV_OT_cursor_set";
  2706. /* api callbacks */
  2707. ot->exec = set_2d_cursor_exec;
  2708. ot->invoke = set_2d_cursor_invoke;
  2709. ot->poll = ED_operator_image_active; /* requires space image */;
  2710. /* flags */
  2711. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2712. /* properties */
  2713. RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in normalised (0.0-1.0) coordinates", -10.0f, 10.0f);
  2714. }
  2715. /********************** set tile operator **********************/
  2716. static int set_tile_exec(bContext *C, wmOperator *op)
  2717. {
  2718. Image *ima = CTX_data_edit_image(C);
  2719. int tile[2];
  2720. Object *obedit = CTX_data_edit_object(C);
  2721. RNA_int_get_array(op->ptr, "tile", tile);
  2722. if (uvedit_set_tile(obedit, ima, tile[0] + ima->xrep * tile[1])) {
  2723. WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
  2724. WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
  2725. return OPERATOR_FINISHED;
  2726. }
  2727. return OPERATOR_CANCELLED;
  2728. }
  2729. static int set_tile_invoke(bContext *C, wmOperator *op, wmEvent *event)
  2730. {
  2731. SpaceImage *sima = CTX_wm_space_image(C);
  2732. Image *ima = CTX_data_edit_image(C);
  2733. ARegion *ar = CTX_wm_region(C);
  2734. float fx, fy;
  2735. int tile[2];
  2736. if (!ima || !(ima->tpageflag & IMA_TILES))
  2737. return OPERATOR_CANCELLED;
  2738. UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
  2739. if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
  2740. fx = fx * ima->xrep;
  2741. fy = fy * ima->yrep;
  2742. tile[0] = fx;
  2743. tile[1] = fy;
  2744. sima->curtile = tile[1] * ima->xrep + tile[0];
  2745. RNA_int_set_array(op->ptr, "tile", tile);
  2746. }
  2747. return set_tile_exec(C, op);
  2748. }
  2749. static void UV_OT_tile_set(wmOperatorType *ot)
  2750. {
  2751. /* identifiers */
  2752. ot->name = "Set Tile";
  2753. ot->description = "Set UV image tile coordinates";
  2754. ot->idname = "UV_OT_tile_set";
  2755. /* api callbacks */
  2756. ot->exec = set_tile_exec;
  2757. ot->invoke = set_tile_invoke;
  2758. ot->poll = ED_operator_image_active; /* requires space image */;
  2759. /* flags */
  2760. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2761. /* properties */
  2762. RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate", 0, 10);
  2763. }
  2764. static int seams_from_islands_exec(bContext *C, wmOperator *op)
  2765. {
  2766. UvVertMap *vmap;
  2767. Object *ob = CTX_data_edit_object(C);
  2768. Mesh *me = (Mesh *)ob->data;
  2769. BMEditMesh *em;
  2770. BMEdge *editedge;
  2771. float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
  2772. char mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
  2773. char mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
  2774. BMesh *bm;
  2775. BMIter iter;
  2776. em = me->edit_btmesh;
  2777. bm = em->bm;
  2778. if (!EDBM_mtexpoly_check(em)) {
  2779. return OPERATOR_CANCELLED;
  2780. }
  2781. /* This code sets editvert->tmp.l to the index. This will be useful later on. */
  2782. EDBM_index_arrays_init(em, 0, 0, 1);
  2783. vmap = EDBM_uv_vert_map_create(em, 0, 0, limit);
  2784. BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
  2785. /* flags to determine if we uv is separated from first editface match */
  2786. char separated1 = 0, separated2;
  2787. /* set to denote edge must be flagged as seam */
  2788. char faces_separated = 0;
  2789. /* flag to keep track if uv1 is disconnected from first editface match */
  2790. char v1coincident = 1;
  2791. /* For use with v1coincident. v1coincident will change only if we've had commonFaces */
  2792. int commonFaces = 0;
  2793. BMFace *efa1, *efa2;
  2794. UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
  2795. /* mv2cache stores the first of the list of coincident uv's for later comparison
  2796. * mv2sep holds the last separator and is copied to mv2cache when a hit is first found */
  2797. UvMapVert *mv2cache = NULL, *mv2sep = NULL;
  2798. mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)];
  2799. if (mark_seams)
  2800. BM_elem_flag_disable(editedge, BM_ELEM_SEAM);
  2801. for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
  2802. if (mv1->separate && commonFaces)
  2803. v1coincident = 0;
  2804. separated2 = 0;
  2805. efa1 = EDBM_face_at_index(em, mv1->f);
  2806. mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)];
  2807. for (mv2 = mvinit2; mv2; mv2 = mv2->next) {
  2808. if (mv2->separate)
  2809. mv2sep = mv2;
  2810. efa2 = EDBM_face_at_index(em, mv2->f);
  2811. if (efa1 == efa2) {
  2812. /* if v1 is not coincident no point in comparing */
  2813. if (v1coincident) {
  2814. /* have we found previously anything? */
  2815. if (mv2cache) {
  2816. /* flag seam unless proved to be coincident with previous hit */
  2817. separated2 = 1;
  2818. for (mviter = mv2cache; mviter; mviter = mviter->next) {
  2819. if (mviter->separate && mviter != mv2cache)
  2820. break;
  2821. /* coincident with previous hit, do not flag seam */
  2822. if (mviter == mv2)
  2823. separated2 = 0;
  2824. }
  2825. }
  2826. /* First hit case, store the hit in the cache */
  2827. else {
  2828. mv2cache = mv2sep;
  2829. commonFaces = 1;
  2830. }
  2831. }
  2832. else
  2833. separated1 = 1;
  2834. if (separated1 || separated2) {
  2835. faces_separated = 1;
  2836. break;
  2837. }
  2838. }
  2839. }
  2840. }
  2841. if (faces_separated) {
  2842. if (mark_seams)
  2843. BM_elem_flag_enable(editedge, BM_ELEM_SEAM);
  2844. if (mark_sharp)
  2845. BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH);
  2846. }
  2847. }
  2848. me->drawflag |= ME_DRAWSEAMS;
  2849. EDBM_uv_vert_map_free(vmap);
  2850. EDBM_index_arrays_free(em);
  2851. DAG_id_tag_update(&me->id, 0);
  2852. WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
  2853. return OPERATOR_FINISHED;
  2854. }
  2855. static void UV_OT_seams_from_islands(wmOperatorType *ot)
  2856. {
  2857. /* identifiers */
  2858. ot->name = "Seams From Islands";
  2859. ot->description = "Set mesh seams according to island setup in the UV editor";
  2860. ot->idname = "UV_OT_seams_from_islands";
  2861. /* flags */
  2862. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2863. /* api callbacks */
  2864. ot->exec = seams_from_islands_exec;
  2865. ot->poll = ED_operator_uvedit;
  2866. RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams");
  2867. RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
  2868. }
  2869. static int mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
  2870. {
  2871. Object *ob = CTX_data_edit_object(C);
  2872. Scene *scene = CTX_data_scene(C);
  2873. Mesh *me = (Mesh *)ob->data;
  2874. BMEditMesh *em = me->edit_btmesh;
  2875. BMesh *bm = em->bm;
  2876. BMFace *efa;
  2877. BMLoop *loop;
  2878. BMIter iter, liter;
  2879. BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
  2880. BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
  2881. if (uvedit_edge_select_test(em, scene, loop)) {
  2882. BM_elem_flag_enable(loop->e, BM_ELEM_SEAM);
  2883. }
  2884. }
  2885. }
  2886. me->drawflag |= ME_DRAWSEAMS;
  2887. if (scene->toolsettings->edge_mode_live_unwrap)
  2888. ED_unwrap_lscm(scene, ob, FALSE);
  2889. DAG_id_tag_update(&me->id, 0);
  2890. WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
  2891. return OPERATOR_FINISHED;
  2892. }
  2893. static void UV_OT_mark_seam(wmOperatorType *ot)
  2894. {
  2895. /* identifiers */
  2896. ot->name = "Mark Seams";
  2897. ot->description = "Mark selected UV edges as seams";
  2898. ot->idname = "UV_OT_mark_seam";
  2899. /* flags */
  2900. ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  2901. /* api callbacks */
  2902. ot->exec = mark_seam_exec;
  2903. ot->poll = ED_operator_uvedit;
  2904. }
  2905. /* ************************** registration **********************************/
  2906. void ED_operatortypes_uvedit(void)
  2907. {
  2908. WM_operatortype_append(UV_OT_select_all);
  2909. WM_operatortype_append(UV_OT_select);
  2910. WM_operatortype_append(UV_OT_select_loop);
  2911. WM_operatortype_append(UV_OT_select_linked);
  2912. WM_operatortype_append(UV_OT_select_linked_pick);
  2913. WM_operatortype_append(UV_OT_unlink_selected);
  2914. WM_operatortype_append(UV_OT_select_pinned);
  2915. WM_operatortype_append(UV_OT_select_border);
  2916. WM_operatortype_append(UV_OT_circle_select);
  2917. WM_operatortype_append(UV_OT_snap_cursor);
  2918. WM_operatortype_append(UV_OT_snap_selected);
  2919. WM_operatortype_append(UV_OT_align);
  2920. WM_operatortype_append(UV_OT_stitch);
  2921. WM_operatortype_append(UV_OT_seams_from_islands);
  2922. WM_operatortype_append(UV_OT_mark_seam);
  2923. WM_operatortype_append(UV_OT_weld);
  2924. WM_operatortype_append(UV_OT_pin);
  2925. WM_operatortype_append(UV_OT_average_islands_scale);
  2926. WM_operatortype_append(UV_OT_cube_project);
  2927. WM_operatortype_append(UV_OT_cylinder_project);
  2928. WM_operatortype_append(UV_OT_from_view);
  2929. WM_operatortype_append(UV_OT_minimize_stretch);
  2930. WM_operatortype_append(UV_OT_pack_islands);
  2931. WM_operatortype_append(UV_OT_reset);
  2932. WM_operatortype_append(UV_OT_sphere_project);
  2933. WM_operatortype_append(UV_OT_unwrap);
  2934. WM_operatortype_append(UV_OT_reveal);
  2935. WM_operatortype_append(UV_OT_hide);
  2936. WM_operatortype_append(UV_OT_cursor_set);
  2937. WM_operatortype_append(UV_OT_tile_set);
  2938. }
  2939. void ED_keymap_uvedit(wmKeyConfig *keyconf)
  2940. {
  2941. wmKeyMap *keymap;
  2942. wmKeyMapItem *kmi;
  2943. keymap = WM_keymap_find(keyconf, "UV Editor", 0, 0);
  2944. keymap->poll = ED_operator_uvedit_can_uv_sculpt;
  2945. /* Uv sculpt toggle */
  2946. kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0);
  2947. RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_uv_sculpt");
  2948. /* Mark edge seam */
  2949. WM_keymap_add_item(keymap, "UV_OT_mark_seam", EKEY, KM_PRESS, KM_CTRL, 0);
  2950. /* pick selection */
  2951. RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0)->ptr, "extend", FALSE);
  2952. RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", TRUE);
  2953. RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_loop", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "extend", FALSE);
  2954. RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_loop", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "extend", TRUE);
  2955. /* border/circle selection */
  2956. kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, 0, 0);
  2957. RNA_boolean_set(kmi->ptr, "pinned", FALSE);
  2958. kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, KM_SHIFT, 0);
  2959. RNA_boolean_set(kmi->ptr, "pinned", TRUE);
  2960. WM_keymap_add_item(keymap, "UV_OT_circle_select", CKEY, KM_PRESS, 0, 0);
  2961. /* selection manipulation */
  2962. RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0)->ptr, "extend", FALSE);
  2963. RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0)->ptr, "extend", FALSE);
  2964. RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "extend", TRUE);
  2965. RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", TRUE);
  2966. WM_keymap_add_item(keymap, "UV_OT_unlink_selected", LKEY, KM_PRESS, KM_ALT, 0);
  2967. kmi = WM_keymap_add_item(keymap, "UV_OT_select_all", AKEY, KM_PRESS, 0, 0);
  2968. RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
  2969. kmi = WM_keymap_add_item(keymap, "UV_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
  2970. RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
  2971. WM_keymap_add_item(keymap, "UV_OT_select_pinned", PKEY, KM_PRESS, KM_SHIFT, 0);
  2972. WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, 0, 0);
  2973. /* uv operations */
  2974. WM_keymap_add_item(keymap, "UV_OT_stitch", VKEY, KM_PRESS, 0, 0);
  2975. kmi = WM_keymap_add_item(keymap, "UV_OT_pin", PKEY, KM_PRESS, 0, 0);
  2976. RNA_boolean_set(kmi->ptr, "clear", FALSE);
  2977. kmi = WM_keymap_add_item(keymap, "UV_OT_pin", PKEY, KM_PRESS, KM_ALT, 0);
  2978. RNA_boolean_set(kmi->ptr, "clear", TRUE);
  2979. /* unwrap */
  2980. WM_keymap_add_item(keymap, "UV_OT_unwrap", EKEY, KM_PRESS, 0, 0);
  2981. WM_keymap_add_item(keymap, "UV_OT_minimize_stretch", VKEY, KM_PRESS, KM_CTRL, 0);
  2982. WM_keymap_add_item(keymap, "UV_OT_pack_islands", PKEY, KM_PRESS, KM_CTRL, 0);
  2983. WM_keymap_add_item(keymap, "UV_OT_average_islands_scale", AKEY, KM_PRESS, KM_CTRL, 0);
  2984. /* hide */
  2985. kmi = WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, 0, 0);
  2986. RNA_boolean_set(kmi->ptr, "unselected", FALSE);
  2987. kmi = WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
  2988. RNA_boolean_set(kmi->ptr, "unselected", TRUE);
  2989. WM_keymap_add_item(keymap, "UV_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
  2990. /* cursor */
  2991. WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
  2992. WM_keymap_add_item(keymap, "UV_OT_tile_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
  2993. /* menus */
  2994. WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
  2995. WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0);
  2996. /* pivot */
  2997. kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
  2998. RNA_string_set(kmi->ptr, "data_path", "space_data.uv_editor.pivot_point");
  2999. RNA_string_set(kmi->ptr, "value", "CENTER");
  3000. kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, KM_CTRL, 0);
  3001. RNA_string_set(kmi->ptr, "data_path", "space_data.uv_editor.pivot_point");
  3002. RNA_string_set(kmi->ptr, "value", "MEDIAN");
  3003. kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
  3004. RNA_string_set(kmi->ptr, "data_path", "space_data.uv_editor.pivot_point");
  3005. RNA_string_set(kmi->ptr, "value", "CURSOR");
  3006. ED_object_generic_keymap(keyconf, keymap, 2);
  3007. transform_keymap_for_space(keyconf, keymap, SPACE_IMAGE);
  3008. }