|
Blender
V2.59
|
00001 /* 00002 * $Id: uvedit_unwrap_ops.c 37670 2011-06-20 17:28:25Z blendix $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): none yet. 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <string.h> 00036 #include <stdlib.h> 00037 #include <math.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "DNA_camera_types.h" 00042 #include "DNA_meshdata_types.h" 00043 #include "DNA_object_types.h" 00044 #include "DNA_scene_types.h" 00045 00046 #include "BLI_math.h" 00047 #include "BLI_edgehash.h" 00048 #include "BLI_editVert.h" 00049 #include "BLI_uvproject.h" 00050 #include "BLI_utildefines.h" 00051 00052 #include "BKE_context.h" 00053 #include "BKE_customdata.h" 00054 #include "BKE_depsgraph.h" 00055 #include "BKE_image.h" 00056 #include "BKE_mesh.h" 00057 00058 #include "PIL_time.h" 00059 00060 #include "ED_image.h" 00061 #include "ED_mesh.h" 00062 #include "ED_screen.h" 00063 #include "ED_uvedit.h" 00064 #include "ED_view3d.h" 00065 00066 #include "RNA_access.h" 00067 #include "RNA_define.h" 00068 00069 00070 #include "WM_api.h" 00071 #include "WM_types.h" 00072 00073 #include "uvedit_intern.h" 00074 #include "uvedit_parametrizer.h" 00075 00076 static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) 00077 { 00078 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00079 EditFace *efa; 00080 MTFace *tf; 00081 Image *ima; 00082 bScreen *sc; 00083 ScrArea *sa; 00084 SpaceLink *slink; 00085 SpaceImage *sima; 00086 00087 if(ED_uvedit_test(obedit)) { 00088 BKE_mesh_end_editmesh(obedit->data, em); 00089 return 1; 00090 } 00091 00092 if(em && em->faces.first) 00093 EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL); 00094 00095 if(!ED_uvedit_test(obedit)) { 00096 BKE_mesh_end_editmesh(obedit->data, em); 00097 return 0; 00098 } 00099 00100 ima= CTX_data_edit_image(C); 00101 00102 if(!ima) { 00103 /* no image in context in the 3d view, we find first image window .. */ 00104 sc= CTX_wm_screen(C); 00105 00106 for(sa=sc->areabase.first; sa; sa=sa->next) { 00107 slink= sa->spacedata.first; 00108 if(slink->spacetype == SPACE_IMAGE) { 00109 sima= (SpaceImage*)slink; 00110 00111 ima= sima->image; 00112 if(ima) { 00113 if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE) 00114 ima= NULL; 00115 else 00116 break; 00117 } 00118 } 00119 } 00120 } 00121 00122 if(ima) 00123 ED_uvedit_assign_image(scene, obedit, ima, NULL); 00124 00125 /* select new UV's */ 00126 for(efa=em->faces.first; efa; efa=efa->next) { 00127 tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00128 uvedit_face_select(scene, efa, tf); 00129 } 00130 00131 BKE_mesh_end_editmesh(obedit->data, em); 00132 return 1; 00133 } 00134 00135 /****************** Parametrizer Conversion ***************/ 00136 00137 static int uvedit_have_selection(Scene *scene, EditMesh *em, short implicit) 00138 { 00139 EditFace *efa; 00140 MTFace *tf; 00141 00142 /* verify if we have any selected uv's before unwrapping, 00143 so we can cancel the operator early */ 00144 for(efa= em->faces.first; efa; efa= efa->next) { 00145 if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { 00146 if(efa->h) 00147 continue; 00148 } 00149 else if((efa->h) || ((efa->f & SELECT)==0)) 00150 continue; 00151 00152 tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00153 00154 if(!tf) 00155 return 1; /* default selected if doesn't exists */ 00156 00157 if(implicit && 00158 !( uvedit_uv_selected(scene, efa, tf, 0) || 00159 uvedit_uv_selected(scene, efa, tf, 1) || 00160 uvedit_uv_selected(scene, efa, tf, 2) || 00161 (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) ) 00162 ) { 00163 continue; 00164 } 00165 00166 return 1; 00167 } 00168 00169 return 0; 00170 } 00171 00172 static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit, short fill, short sel, short correct_aspect) 00173 { 00174 ParamHandle *handle; 00175 EditFace *efa; 00176 EditEdge *eed; 00177 EditVert *ev; 00178 MTFace *tf; 00179 int a; 00180 00181 handle = param_construct_begin(); 00182 00183 if(correct_aspect) { 00184 efa = EM_get_actFace(em, 1); 00185 00186 if(efa) { 00187 float aspx, aspy; 00188 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00189 00190 ED_image_uv_aspect(tf->tpage, &aspx, &aspy); 00191 00192 if(aspx!=aspy) 00193 param_aspect_ratio(handle, aspx, aspy); 00194 } 00195 } 00196 00197 /* we need the vert indices */ 00198 for(ev= em->verts.first, a=0; ev; ev= ev->next, a++) 00199 ev->tmp.l = a; 00200 00201 for(efa= em->faces.first; efa; efa= efa->next) { 00202 ParamKey key, vkeys[4]; 00203 ParamBool pin[4], select[4]; 00204 float *co[4]; 00205 float *uv[4]; 00206 int nverts; 00207 00208 if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { 00209 if(efa->h) 00210 continue; 00211 } 00212 else if((efa->h) || (sel && (efa->f & SELECT)==0)) 00213 continue; 00214 00215 tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00216 00217 if(implicit && 00218 !( uvedit_uv_selected(scene, efa, tf, 0) || 00219 uvedit_uv_selected(scene, efa, tf, 1) || 00220 uvedit_uv_selected(scene, efa, tf, 2) || 00221 (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) ) 00222 ) { 00223 continue; 00224 } 00225 00226 key = (ParamKey)efa; 00227 vkeys[0] = (ParamKey)efa->v1->tmp.l; 00228 vkeys[1] = (ParamKey)efa->v2->tmp.l; 00229 vkeys[2] = (ParamKey)efa->v3->tmp.l; 00230 00231 co[0] = efa->v1->co; 00232 co[1] = efa->v2->co; 00233 co[2] = efa->v3->co; 00234 00235 uv[0] = tf->uv[0]; 00236 uv[1] = tf->uv[1]; 00237 uv[2] = tf->uv[2]; 00238 00239 pin[0] = ((tf->unwrap & TF_PIN1) != 0); 00240 pin[1] = ((tf->unwrap & TF_PIN2) != 0); 00241 pin[2] = ((tf->unwrap & TF_PIN3) != 0); 00242 00243 select[0] = ((uvedit_uv_selected(scene, efa, tf, 0)) != 0); 00244 select[1] = ((uvedit_uv_selected(scene, efa, tf, 1)) != 0); 00245 select[2] = ((uvedit_uv_selected(scene, efa, tf, 2)) != 0); 00246 00247 if(efa->v4) { 00248 vkeys[3] = (ParamKey)efa->v4->tmp.l; 00249 co[3] = efa->v4->co; 00250 uv[3] = tf->uv[3]; 00251 pin[3] = ((tf->unwrap & TF_PIN4) != 0); 00252 select[3] = (uvedit_uv_selected(scene, efa, tf, 3) != 0); 00253 nverts = 4; 00254 } 00255 else 00256 nverts = 3; 00257 00258 param_face_add(handle, key, nverts, vkeys, co, uv, pin, select); 00259 } 00260 00261 if(!implicit) { 00262 for(eed= em->edges.first; eed; eed= eed->next) { 00263 if(eed->seam) { 00264 ParamKey vkeys[2]; 00265 vkeys[0] = (ParamKey)eed->v1->tmp.l; 00266 vkeys[1] = (ParamKey)eed->v2->tmp.l; 00267 param_edge_set_seam(handle, vkeys); 00268 } 00269 } 00270 } 00271 00272 param_construct_end(handle, fill, implicit); 00273 00274 return handle; 00275 } 00276 00277 /* ******************** Minimize Stretch operator **************** */ 00278 00279 typedef struct MinStretch { 00280 Scene *scene; 00281 Object *obedit; 00282 EditMesh *em; 00283 ParamHandle *handle; 00284 float blend; 00285 double lasttime; 00286 int i, iterations; 00287 wmTimer *timer; 00288 } MinStretch; 00289 00290 static int minimize_stretch_init(bContext *C, wmOperator *op) 00291 { 00292 Scene *scene= CTX_data_scene(C); 00293 Object *obedit= CTX_data_edit_object(C); 00294 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00295 MinStretch *ms; 00296 int fill_holes= RNA_boolean_get(op->ptr, "fill_holes"); 00297 short implicit= 1; 00298 00299 if(!uvedit_have_selection(scene, em, implicit)) { 00300 BKE_mesh_end_editmesh(obedit->data, em); 00301 return 0; 00302 } 00303 00304 ms= MEM_callocN(sizeof(MinStretch), "MinStretch"); 00305 ms->scene= scene; 00306 ms->obedit= obedit; 00307 ms->em= em; 00308 ms->blend= RNA_float_get(op->ptr, "blend"); 00309 ms->iterations= RNA_int_get(op->ptr, "iterations"); 00310 ms->i= 0; 00311 ms->handle= construct_param_handle(scene, em, implicit, fill_holes, 1, 1); 00312 ms->lasttime= PIL_check_seconds_timer(); 00313 00314 param_stretch_begin(ms->handle); 00315 if(ms->blend != 0.0f) 00316 param_stretch_blend(ms->handle, ms->blend); 00317 00318 op->customdata= ms; 00319 00320 return 1; 00321 } 00322 00323 static void minimize_stretch_iteration(bContext *C, wmOperator *op, int interactive) 00324 { 00325 MinStretch *ms= op->customdata; 00326 ScrArea *sa= CTX_wm_area(C); 00327 00328 param_stretch_blend(ms->handle, ms->blend); 00329 param_stretch_iter(ms->handle); 00330 00331 ms->i++; 00332 RNA_int_set(op->ptr, "iterations", ms->i); 00333 00334 if(interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) { 00335 char str[100]; 00336 00337 param_flush(ms->handle); 00338 00339 if(sa) { 00340 sprintf(str, "Minimize Stretch. Blend %.2f.", ms->blend); 00341 ED_area_headerprint(sa, str); 00342 } 00343 00344 ms->lasttime = PIL_check_seconds_timer(); 00345 00346 DAG_id_tag_update(ms->obedit->data, 0); 00347 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ms->obedit->data); 00348 } 00349 } 00350 00351 static void minimize_stretch_exit(bContext *C, wmOperator *op, int cancel) 00352 { 00353 MinStretch *ms= op->customdata; 00354 ScrArea *sa= CTX_wm_area(C); 00355 00356 if(sa) 00357 ED_area_headerprint(sa, NULL); 00358 if(ms->timer) 00359 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer); 00360 00361 if(cancel) 00362 param_flush_restore(ms->handle); 00363 else 00364 param_flush(ms->handle); 00365 00366 param_stretch_end(ms->handle); 00367 param_delete(ms->handle); 00368 00369 DAG_id_tag_update(ms->obedit->data, 0); 00370 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ms->obedit->data); 00371 00372 MEM_freeN(ms); 00373 op->customdata= NULL; 00374 } 00375 00376 static int minimize_stretch_exec(bContext *C, wmOperator *op) 00377 { 00378 int i, iterations; 00379 00380 if(!minimize_stretch_init(C, op)) 00381 return OPERATOR_CANCELLED; 00382 00383 iterations= RNA_int_get(op->ptr, "iterations"); 00384 for(i=0; i<iterations; i++) 00385 minimize_stretch_iteration(C, op, 0); 00386 minimize_stretch_exit(C, op, 0); 00387 00388 return OPERATOR_FINISHED; 00389 } 00390 00391 static int minimize_stretch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00392 { 00393 MinStretch *ms; 00394 00395 if(!minimize_stretch_init(C, op)) 00396 return OPERATOR_CANCELLED; 00397 00398 minimize_stretch_iteration(C, op, 1); 00399 00400 ms= op->customdata; 00401 WM_event_add_modal_handler(C, op); 00402 ms->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); 00403 00404 return OPERATOR_RUNNING_MODAL; 00405 } 00406 00407 static int minimize_stretch_modal(bContext *C, wmOperator *op, wmEvent *event) 00408 { 00409 MinStretch *ms= op->customdata; 00410 00411 switch(event->type) { 00412 case ESCKEY: 00413 case RIGHTMOUSE: 00414 minimize_stretch_exit(C, op, 1); 00415 return OPERATOR_CANCELLED; 00416 case RETKEY: 00417 case PADENTER: 00418 case LEFTMOUSE: 00419 minimize_stretch_exit(C, op, 0); 00420 return OPERATOR_FINISHED; 00421 case PADPLUSKEY: 00422 case WHEELUPMOUSE: 00423 if(ms->blend < 0.95f) { 00424 ms->blend += 0.1f; 00425 ms->lasttime= 0.0f; 00426 RNA_float_set(op->ptr, "blend", ms->blend); 00427 minimize_stretch_iteration(C, op, 1); 00428 } 00429 break; 00430 case PADMINUS: 00431 case WHEELDOWNMOUSE: 00432 if(ms->blend > 0.05f) { 00433 ms->blend -= 0.1f; 00434 ms->lasttime= 0.0f; 00435 RNA_float_set(op->ptr, "blend", ms->blend); 00436 minimize_stretch_iteration(C, op, 1); 00437 } 00438 break; 00439 case TIMER: 00440 if(ms->timer == event->customdata) { 00441 double start= PIL_check_seconds_timer(); 00442 00443 do { 00444 minimize_stretch_iteration(C, op, 1); 00445 } while(PIL_check_seconds_timer() - start < 0.01); 00446 } 00447 break; 00448 } 00449 00450 if(ms->iterations && ms->i >= ms->iterations) { 00451 minimize_stretch_exit(C, op, 0); 00452 return OPERATOR_FINISHED; 00453 } 00454 00455 return OPERATOR_RUNNING_MODAL; 00456 } 00457 00458 static int minimize_stretch_cancel(bContext *C, wmOperator *op) 00459 { 00460 minimize_stretch_exit(C, op, 1); 00461 00462 return OPERATOR_CANCELLED; 00463 } 00464 00465 void UV_OT_minimize_stretch(wmOperatorType *ot) 00466 { 00467 /* identifiers */ 00468 ot->name= "Minimize Stretch"; 00469 ot->idname= "UV_OT_minimize_stretch"; 00470 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00471 ot->description="Reduce UV stretching by relaxing angles"; 00472 00473 /* api callbacks */ 00474 ot->exec= minimize_stretch_exec; 00475 ot->invoke= minimize_stretch_invoke; 00476 ot->modal= minimize_stretch_modal; 00477 ot->cancel= minimize_stretch_cancel; 00478 ot->poll= ED_operator_uvedit; 00479 00480 /* properties */ 00481 RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry."); 00482 RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original.", 0.0f, 1.0f); 00483 RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively.", 0, 100); 00484 } 00485 00486 /* ******************** Pack Islands operator **************** */ 00487 00488 static int pack_islands_exec(bContext *C, wmOperator *op) 00489 { 00490 Scene *scene= CTX_data_scene(C); 00491 Object *obedit= CTX_data_edit_object(C); 00492 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00493 ParamHandle *handle; 00494 short implicit= 1; 00495 00496 if(!uvedit_have_selection(scene, em, implicit)) { 00497 BKE_mesh_end_editmesh(obedit->data, em); 00498 return OPERATOR_CANCELLED; 00499 } 00500 00501 if(RNA_property_is_set(op->ptr, "margin")) { 00502 scene->toolsettings->uvcalc_margin= RNA_float_get(op->ptr, "margin"); 00503 } 00504 else { 00505 RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin); 00506 } 00507 00508 handle = construct_param_handle(scene, em, implicit, 0, 1, 1); 00509 param_pack(handle, scene->toolsettings->uvcalc_margin); 00510 param_flush(handle); 00511 param_delete(handle); 00512 00513 DAG_id_tag_update(obedit->data, 0); 00514 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00515 00516 BKE_mesh_end_editmesh(obedit->data, em); 00517 return OPERATOR_FINISHED; 00518 } 00519 00520 void UV_OT_pack_islands(wmOperatorType *ot) 00521 { 00522 /* identifiers */ 00523 ot->name= "Pack Islands"; 00524 ot->idname= "UV_OT_pack_islands"; 00525 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00526 00527 /* api callbacks */ 00528 ot->exec= pack_islands_exec; 00529 ot->poll= ED_operator_uvedit; 00530 00531 /* properties */ 00532 RNA_def_float_factor(ot->srna, "margin", 0.0f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); 00533 } 00534 00535 /* ******************** Average Islands Scale operator **************** */ 00536 00537 static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) 00538 { 00539 Scene *scene= CTX_data_scene(C); 00540 Object *obedit= CTX_data_edit_object(C); 00541 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00542 ParamHandle *handle; 00543 short implicit= 1; 00544 00545 if(!uvedit_have_selection(scene, em, implicit)) { 00546 BKE_mesh_end_editmesh(obedit->data, em); 00547 return OPERATOR_CANCELLED; 00548 } 00549 00550 handle= construct_param_handle(scene, em, implicit, 0, 1, 1); 00551 param_average(handle); 00552 param_flush(handle); 00553 param_delete(handle); 00554 00555 DAG_id_tag_update(obedit->data, 0); 00556 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00557 00558 BKE_mesh_end_editmesh(obedit->data, em); 00559 return OPERATOR_FINISHED; 00560 } 00561 00562 void UV_OT_average_islands_scale(wmOperatorType *ot) 00563 { 00564 /* identifiers */ 00565 ot->name= "Average Islands Scale"; 00566 ot->idname= "UV_OT_average_islands_scale"; 00567 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00568 00569 /* api callbacks */ 00570 ot->exec= average_islands_scale_exec; 00571 ot->poll= ED_operator_uvedit; 00572 } 00573 00574 /**************** Live Unwrap *****************/ 00575 00576 static ParamHandle *liveHandle = NULL; 00577 00578 void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) 00579 { 00580 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00581 short abf = scene->toolsettings->unwrapper == 0; 00582 short fillholes = scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES; 00583 00584 if(!ED_uvedit_test(obedit)) { 00585 BKE_mesh_end_editmesh(obedit->data, em); 00586 return; 00587 } 00588 00589 liveHandle = construct_param_handle(scene, em, 0, fillholes, 1, 1); 00590 00591 param_lscm_begin(liveHandle, PARAM_TRUE, abf); 00592 BKE_mesh_end_editmesh(obedit->data, em); 00593 } 00594 00595 void ED_uvedit_live_unwrap_re_solve(void) 00596 { 00597 if(liveHandle) { 00598 param_lscm_solve(liveHandle); 00599 param_flush(liveHandle); 00600 } 00601 } 00602 00603 void ED_uvedit_live_unwrap_end(short cancel) 00604 { 00605 if(liveHandle) { 00606 param_lscm_end(liveHandle); 00607 if(cancel) 00608 param_flush_restore(liveHandle); 00609 param_delete(liveHandle); 00610 liveHandle = NULL; 00611 } 00612 } 00613 00614 /*************** UV Map Common Transforms *****************/ 00615 00616 #define VIEW_ON_EQUATOR 0 00617 #define VIEW_ON_POLES 1 00618 #define ALIGN_TO_OBJECT 2 00619 00620 #define POLAR_ZX 0 00621 #define POLAR_ZY 1 00622 00623 static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Object *ob, EditMesh *em) 00624 { 00625 EditFace *efa; 00626 float min[3], max[3], *cursx; 00627 int around= (v3d)? v3d->around: V3D_CENTER; 00628 00629 /* only operates on the edit object - this is all that's needed now */ 00630 00631 switch(around) { 00632 case V3D_CENTER: /* bounding box center */ 00633 min[0]= min[1]= min[2]= 1e20f; 00634 max[0]= max[1]= max[2]= -1e20f; 00635 00636 for(efa= em->faces.first; efa; efa= efa->next) { 00637 if(efa->f & SELECT) { 00638 DO_MINMAX(efa->v1->co, min, max); 00639 DO_MINMAX(efa->v2->co, min, max); 00640 DO_MINMAX(efa->v3->co, min, max); 00641 if(efa->v4) DO_MINMAX(efa->v4->co, min, max); 00642 } 00643 } 00644 mid_v3_v3v3(result, min, max); 00645 break; 00646 00647 case V3D_CURSOR: /*cursor center*/ 00648 cursx= give_cursor(scene, v3d); 00649 /* shift to objects world */ 00650 result[0]= cursx[0]-ob->obmat[3][0]; 00651 result[1]= cursx[1]-ob->obmat[3][1]; 00652 result[2]= cursx[2]-ob->obmat[3][2]; 00653 break; 00654 00655 case V3D_LOCAL: /*object center*/ 00656 case V3D_CENTROID: /* multiple objects centers, only one object here*/ 00657 default: 00658 result[0]= result[1]= result[2]= 0.0; 00659 break; 00660 } 00661 } 00662 00663 static void uv_map_rotation_matrix(float result[][4], RegionView3D *rv3d, Object *ob, float upangledeg, float sideangledeg, float radius) 00664 { 00665 float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4]; 00666 float sideangle= 0.0f, upangle= 0.0f; 00667 int k; 00668 00669 /* get rotation of the current view matrix */ 00670 if(rv3d) 00671 copy_m4_m4(viewmatrix, rv3d->viewmat); 00672 else 00673 unit_m4(viewmatrix); 00674 00675 /* but shifting */ 00676 for(k=0; k<4; k++) 00677 viewmatrix[3][k] =0.0f; 00678 00679 /* get rotation of the current object matrix */ 00680 copy_m4_m4(rotobj,ob->obmat); 00681 00682 /* but shifting */ 00683 for(k=0; k<4; k++) 00684 rotobj[3][k] =0.0f; 00685 00686 zero_m4(rotup); 00687 zero_m4(rotside); 00688 00689 /* compensate front/side.. against opengl x,y,z world definition */ 00690 /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */ 00691 /* i wanted to keep the reason here, so we're rotating*/ 00692 sideangle= (float)M_PI*(sideangledeg + 180.0f)/180.0f; 00693 rotside[0][0]= (float)cos(sideangle); 00694 rotside[0][1]= -(float)sin(sideangle); 00695 rotside[1][0]= (float)sin(sideangle); 00696 rotside[1][1]= (float)cos(sideangle); 00697 rotside[2][2]= 1.0f; 00698 00699 upangle= (float)M_PI*upangledeg/180.0f; 00700 rotup[1][1]= (float)cos(upangle)/radius; 00701 rotup[1][2]= -(float)sin(upangle)/radius; 00702 rotup[2][1]= (float)sin(upangle)/radius; 00703 rotup[2][2]= (float)cos(upangle)/radius; 00704 rotup[0][0]= (float)1.0f/radius; 00705 00706 /* calculate transforms*/ 00707 mul_serie_m4(result, rotup, rotside, viewmatrix, rotobj, NULL, NULL, NULL, NULL); 00708 } 00709 00710 static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4]) 00711 { 00712 /* context checks are messy here, making it work in both 3d view and uv editor */ 00713 Scene *scene= CTX_data_scene(C); 00714 Object *obedit= CTX_data_edit_object(C); 00715 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00716 View3D *v3d= CTX_wm_view3d(C); 00717 RegionView3D *rv3d= CTX_wm_region_view3d(C); 00718 /* common operator properties */ 00719 int align= RNA_enum_get(op->ptr, "align"); 00720 int direction= RNA_enum_get(op->ptr, "direction"); 00721 float radius= RNA_struct_find_property(op->ptr, "radius")? RNA_float_get(op->ptr, "radius"): 1.0f; 00722 float upangledeg, sideangledeg; 00723 00724 uv_map_transform_center(scene, v3d, center, obedit, em); 00725 00726 if(direction == VIEW_ON_EQUATOR) { 00727 upangledeg= 90.0f; 00728 sideangledeg= 0.0f; 00729 } 00730 else { 00731 upangledeg= 0.0f; 00732 if(align == POLAR_ZY) sideangledeg= 0.0f; 00733 else sideangledeg= 90.0f; 00734 } 00735 00736 /* be compatible to the "old" sphere/cylinder mode */ 00737 if(direction == ALIGN_TO_OBJECT) 00738 unit_m4(rotmat); 00739 else 00740 uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius); 00741 00742 BKE_mesh_end_editmesh(obedit->data, em); 00743 } 00744 00745 static void uv_transform_properties(wmOperatorType *ot, int radius) 00746 { 00747 static EnumPropertyItem direction_items[]= { 00748 {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"}, 00749 {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"}, 00750 {ALIGN_TO_OBJECT, "ALIGN_TO_OBJECT", 0, "Align to Object", "Align according to object transform"}, 00751 {0, NULL, 0, NULL, NULL} 00752 }; 00753 static EnumPropertyItem align_items[]= { 00754 {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"}, 00755 {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"}, 00756 {0, NULL, 0, NULL, NULL} 00757 }; 00758 00759 RNA_def_enum(ot->srna, "direction", direction_items, VIEW_ON_EQUATOR, "Direction", "Direction of the sphere or cylinder."); 00760 RNA_def_enum(ot->srna, "align", align_items, VIEW_ON_EQUATOR, "Align", "How to determine rotation around the pole."); 00761 if(radius) 00762 RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "Radius of the sphere or cylinder.", 0.0001f, 100.0f); 00763 } 00764 00765 static void correct_uv_aspect(EditMesh *em) 00766 { 00767 EditFace *efa= EM_get_actFace(em, 1); 00768 MTFace *tf; 00769 float scale, aspx= 1.0f, aspy=1.0f; 00770 00771 if(efa) { 00772 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00773 ED_image_uv_aspect(tf->tpage, &aspx, &aspy); 00774 } 00775 00776 if(aspx == aspy) 00777 return; 00778 00779 if(aspx > aspy) { 00780 scale= aspy/aspx; 00781 00782 for(efa= em->faces.first; efa; efa= efa->next) { 00783 if(efa->f & SELECT) { 00784 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00785 00786 tf->uv[0][0]= ((tf->uv[0][0]-0.5f)*scale)+0.5f; 00787 tf->uv[1][0]= ((tf->uv[1][0]-0.5f)*scale)+0.5f; 00788 tf->uv[2][0]= ((tf->uv[2][0]-0.5f)*scale)+0.5f; 00789 if(efa->v4) 00790 tf->uv[3][0]= ((tf->uv[3][0]-0.5f)*scale)+0.5f; 00791 } 00792 } 00793 } 00794 else { 00795 scale= aspx/aspy; 00796 00797 for(efa= em->faces.first; efa; efa= efa->next) { 00798 if(efa->f & SELECT) { 00799 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00800 00801 tf->uv[0][1]= ((tf->uv[0][1]-0.5f)*scale)+0.5f; 00802 tf->uv[1][1]= ((tf->uv[1][1]-0.5f)*scale)+0.5f; 00803 tf->uv[2][1]= ((tf->uv[2][1]-0.5f)*scale)+0.5f; 00804 if(efa->v4) 00805 tf->uv[3][1]= ((tf->uv[3][1]-0.5f)*scale)+0.5f; 00806 } 00807 } 00808 } 00809 } 00810 00811 /******************** Map Clip & Correct ******************/ 00812 00813 static void uv_map_clip_correct_properties(wmOperatorType *ot) 00814 { 00815 RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", "Map UV's taking image aspect ratio into account."); 00816 RNA_def_boolean(ot->srna, "clip_to_bounds", 0, "Clip to Bounds", "Clip UV coordinates to bounds after unwrapping."); 00817 RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds", "Scale UV coordinates to bounds after unwrapping."); 00818 } 00819 00820 static void uv_map_clip_correct(EditMesh *em, wmOperator *op) 00821 { 00822 EditFace *efa; 00823 MTFace *tf; 00824 float dx, dy, min[2], max[2]; 00825 int b, nverts; 00826 int correct_aspect= RNA_boolean_get(op->ptr, "correct_aspect"); 00827 int clip_to_bounds= RNA_boolean_get(op->ptr, "clip_to_bounds"); 00828 int scale_to_bounds= RNA_boolean_get(op->ptr, "scale_to_bounds"); 00829 00830 /* correct for image aspect ratio */ 00831 if(correct_aspect) 00832 correct_uv_aspect(em); 00833 00834 if(scale_to_bounds) { 00835 INIT_MINMAX2(min, max); 00836 00837 for(efa= em->faces.first; efa; efa= efa->next) { 00838 if(efa->f & SELECT) { 00839 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00840 00841 DO_MINMAX2(tf->uv[0], min, max); 00842 DO_MINMAX2(tf->uv[1], min, max); 00843 DO_MINMAX2(tf->uv[2], min, max); 00844 00845 if(efa->v4) 00846 DO_MINMAX2(tf->uv[3], min, max); 00847 } 00848 } 00849 00850 /* rescale UV to be in 1/1 */ 00851 dx= (max[0]-min[0]); 00852 dy= (max[1]-min[1]); 00853 00854 if(dx > 0.0f) 00855 dx= 1.0f/dx; 00856 if(dy > 0.0f) 00857 dy= 1.0f/dy; 00858 00859 for(efa= em->faces.first; efa; efa= efa->next) { 00860 if(efa->f & SELECT) { 00861 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00862 00863 nverts= (efa->v4)? 4: 3; 00864 00865 for(b=0; b<nverts; b++) { 00866 tf->uv[b][0]= (tf->uv[b][0]-min[0])*dx; 00867 tf->uv[b][1]= (tf->uv[b][1]-min[1])*dy; 00868 } 00869 } 00870 } 00871 } 00872 else if(clip_to_bounds) { 00873 /* clipping and wrapping */ 00874 for(efa= em->faces.first; efa; efa= efa->next) { 00875 if(efa->f & SELECT) { 00876 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00877 00878 nverts= (efa->v4)? 4: 3; 00879 00880 for(b=0; b<nverts; b++) { 00881 CLAMP(tf->uv[b][0], 0.0f, 1.0f); 00882 CLAMP(tf->uv[b][1], 0.0f, 1.0f); 00883 } 00884 } 00885 } 00886 } 00887 } 00888 00889 /* ******************** Unwrap operator **************** */ 00890 00891 /* assumes UV layer is checked, doesn't run update funcs */ 00892 void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) 00893 { 00894 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00895 ParamHandle *handle; 00896 00897 const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES; 00898 const short correct_aspect= !(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT); 00899 short implicit= 0; 00900 00901 handle= construct_param_handle(scene, em, implicit, fill_holes, sel, correct_aspect); 00902 00903 param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0); 00904 param_lscm_solve(handle); 00905 param_lscm_end(handle); 00906 00907 param_pack(handle, scene->toolsettings->uvcalc_margin); 00908 00909 param_flush(handle); 00910 00911 param_delete(handle); 00912 00913 BKE_mesh_end_editmesh(obedit->data, em); 00914 } 00915 00916 static int unwrap_exec(bContext *C, wmOperator *op) 00917 { 00918 Scene *scene= CTX_data_scene(C); 00919 Object *obedit= CTX_data_edit_object(C); 00920 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00921 int method = RNA_enum_get(op->ptr, "method"); 00922 int fill_holes = RNA_boolean_get(op->ptr, "fill_holes"); 00923 int correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); 00924 short implicit= 0; 00925 00926 if(!uvedit_have_selection(scene, em, implicit)) { 00927 BKE_mesh_end_editmesh(obedit->data, em); 00928 return 0; 00929 } 00930 00931 BKE_mesh_end_editmesh(obedit->data, em); 00932 00933 /* add uvs if they don't exist yet */ 00934 if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { 00935 return OPERATOR_CANCELLED; 00936 } 00937 00938 /* remember last method for live unwrap */ 00939 scene->toolsettings->unwrapper = method; 00940 00941 if(fill_holes) scene->toolsettings->uvcalc_flag |= UVCALC_FILLHOLES; 00942 else scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES; 00943 00944 if(correct_aspect) scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT; 00945 else scene->toolsettings->uvcalc_flag |= UVCALC_NO_ASPECT_CORRECT; 00946 00947 /* execute unwrap */ 00948 ED_unwrap_lscm(scene, obedit, TRUE); 00949 00950 DAG_id_tag_update(obedit->data, 0); 00951 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00952 00953 return OPERATOR_FINISHED; 00954 } 00955 00956 void UV_OT_unwrap(wmOperatorType *ot) 00957 { 00958 static EnumPropertyItem method_items[] = { 00959 {0, "ANGLE_BASED", 0, "Angle Based", ""}, 00960 {1, "CONFORMAL", 0, "Conformal", ""}, 00961 {0, NULL, 0, NULL, NULL}}; 00962 00963 /* identifiers */ 00964 ot->name= "Unwrap"; 00965 ot->description= "Unwrap the mesh of the object being edited"; 00966 ot->idname= "UV_OT_unwrap"; 00967 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00968 00969 /* api callbacks */ 00970 ot->exec= unwrap_exec; 00971 ot->poll= ED_operator_uvmap; 00972 00973 /* properties */ 00974 RNA_def_enum(ot->srna, "method", method_items, 0, "Method", "Unwrapping method. Angle Based usually gives better results than Conformal, while being somewhat slower."); 00975 RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry."); 00976 RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", "Map UV's taking image aspect ratio into account."); 00977 } 00978 00979 /**************** Project From View operator **************/ 00980 static int uv_from_view_exec(bContext *C, wmOperator *op) 00981 { 00982 Scene *scene= CTX_data_scene(C); 00983 Object *obedit= CTX_data_edit_object(C); 00984 Camera *camera= NULL; 00985 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 00986 ARegion *ar= CTX_wm_region(C); 00987 View3D *v3d= CTX_wm_view3d(C); 00988 RegionView3D *rv3d= ar->regiondata; 00989 EditFace *efa; 00990 MTFace *tf; 00991 float rotmat[4][4]; 00992 00993 /* add uvs if they don't exist yet */ 00994 if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { 00995 BKE_mesh_end_editmesh(obedit->data, em); 00996 return OPERATOR_CANCELLED; 00997 } 00998 00999 /* establish the camera object, so we can default to view mapping if anything is wrong with it */ 01000 if ((rv3d->persp==RV3D_CAMOB) && (v3d->camera) && (v3d->camera->type==OB_CAMERA)) { 01001 camera= v3d->camera->data; 01002 } 01003 01004 if(RNA_boolean_get(op->ptr, "orthographic")) { 01005 uv_map_rotation_matrix(rotmat, ar->regiondata, obedit, 90.0f, 0.0f, 1.0f); 01006 01007 for(efa= em->faces.first; efa; efa= efa->next) { 01008 if(efa->f & SELECT) { 01009 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 01010 01011 project_from_view_ortho(tf->uv[0], efa->v1->co, rotmat); 01012 project_from_view_ortho(tf->uv[1], efa->v2->co, rotmat); 01013 project_from_view_ortho(tf->uv[2], efa->v3->co, rotmat); 01014 if(efa->v4) 01015 project_from_view_ortho(tf->uv[3], efa->v4->co, rotmat); 01016 } 01017 } 01018 } 01019 else if (camera) { 01020 struct UvCameraInfo *uci= project_camera_info(v3d->camera, obedit->obmat, scene->r.xsch, scene->r.ysch); 01021 01022 if(uci) { 01023 for(efa= em->faces.first; efa; efa= efa->next) { 01024 if(efa->f & SELECT) { 01025 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 01026 01027 project_from_camera(tf->uv[0], efa->v1->co, uci); 01028 project_from_camera(tf->uv[1], efa->v2->co, uci); 01029 project_from_camera(tf->uv[2], efa->v3->co, uci); 01030 if(efa->v4) 01031 project_from_camera(tf->uv[3], efa->v4->co, uci); 01032 } 01033 } 01034 01035 MEM_freeN(uci); 01036 } 01037 } 01038 else { 01039 copy_m4_m4(rotmat, obedit->obmat); 01040 01041 for(efa= em->faces.first; efa; efa= efa->next) { 01042 if(efa->f & SELECT) { 01043 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 01044 01045 project_from_view(tf->uv[0], efa->v1->co, rv3d->persmat, rotmat, ar->winx, ar->winy); 01046 project_from_view(tf->uv[1], efa->v2->co, rv3d->persmat, rotmat, ar->winx, ar->winy); 01047 project_from_view(tf->uv[2], efa->v3->co, rv3d->persmat, rotmat, ar->winx, ar->winy); 01048 if(efa->v4) 01049 project_from_view(tf->uv[3], efa->v4->co, rv3d->persmat, rotmat, ar->winx, ar->winy); 01050 } 01051 } 01052 } 01053 01054 uv_map_clip_correct(em, op); 01055 01056 DAG_id_tag_update(obedit->data, 0); 01057 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01058 01059 BKE_mesh_end_editmesh(obedit->data, em); 01060 return OPERATOR_FINISHED; 01061 } 01062 01063 static int uv_from_view_poll(bContext *C) 01064 { 01065 RegionView3D *rv3d= CTX_wm_region_view3d(C); 01066 01067 if(!ED_operator_uvmap(C)) 01068 return 0; 01069 01070 return (rv3d != NULL); 01071 } 01072 01073 void UV_OT_from_view(wmOperatorType *ot) 01074 { 01075 /* identifiers */ 01076 ot->name= "Project From View"; 01077 ot->idname= "UV_OT_project_from_view"; 01078 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01079 01080 /* api callbacks */ 01081 ot->exec= uv_from_view_exec; 01082 ot->poll= uv_from_view_poll; 01083 01084 /* properties */ 01085 RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection."); 01086 uv_map_clip_correct_properties(ot); 01087 } 01088 01089 /********************** Reset operator ********************/ 01090 01091 static int reset_exec(bContext *C, wmOperator *UNUSED(op)) 01092 { 01093 Scene *scene= CTX_data_scene(C); 01094 Object *obedit= CTX_data_edit_object(C); 01095 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 01096 EditFace *efa; 01097 MTFace *tf; 01098 01099 /* add uvs if they don't exist yet */ 01100 if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { 01101 BKE_mesh_end_editmesh(obedit->data, em); 01102 return OPERATOR_CANCELLED; 01103 } 01104 01105 for(efa= em->faces.first; efa; efa= efa->next) { 01106 if(efa->f & SELECT) { 01107 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 01108 01109 tf->uv[0][0]= 0.0f; 01110 tf->uv[0][1]= 0.0f; 01111 01112 tf->uv[1][0]= 1.0f; 01113 tf->uv[1][1]= 0.0f; 01114 01115 tf->uv[2][0]= 1.0f; 01116 tf->uv[2][1]= 1.0f; 01117 01118 tf->uv[3][0]= 0.0f; 01119 tf->uv[3][1]= 1.0f; 01120 } 01121 } 01122 01123 DAG_id_tag_update(obedit->data, 0); 01124 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01125 01126 BKE_mesh_end_editmesh(obedit->data, em); 01127 return OPERATOR_FINISHED; 01128 } 01129 01130 void UV_OT_reset(wmOperatorType *ot) 01131 { 01132 /* identifiers */ 01133 ot->name= "Reset"; 01134 ot->idname= "UV_OT_reset"; 01135 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01136 01137 /* api callbacks */ 01138 ot->exec= reset_exec; 01139 ot->poll= ED_operator_uvmap; 01140 } 01141 01142 /****************** Sphere Project operator ***************/ 01143 01144 static void uv_sphere_project(float target[2], float source[3], float center[3], float rotmat[4][4]) 01145 { 01146 float pv[3]; 01147 01148 sub_v3_v3v3(pv, source, center); 01149 mul_m4_v3(rotmat, pv); 01150 01151 map_to_sphere( &target[0], &target[1],pv[0], pv[1], pv[2]); 01152 01153 /* split line is always zero */ 01154 if(target[0] >= 1.0f) 01155 target[0] -= 1.0f; 01156 } 01157 01158 static void uv_map_mirror(EditFace *efa, MTFace *tf) 01159 { 01160 float dx; 01161 int nverts, i, mi; 01162 01163 nverts= (efa->v4)? 4: 3; 01164 01165 mi = 0; 01166 for(i=1; i<nverts; i++) 01167 if(tf->uv[i][0] > tf->uv[mi][0]) 01168 mi = i; 01169 01170 for(i=0; i<nverts; i++) { 01171 if(i != mi) { 01172 dx = tf->uv[mi][0] - tf->uv[i][0]; 01173 if(dx > 0.5f) tf->uv[i][0] += 1.0f; 01174 } 01175 } 01176 } 01177 01178 static int sphere_project_exec(bContext *C, wmOperator *op) 01179 { 01180 Scene *scene= CTX_data_scene(C); 01181 Object *obedit= CTX_data_edit_object(C); 01182 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 01183 EditFace *efa; 01184 MTFace *tf; 01185 float center[3], rotmat[4][4]; 01186 01187 /* add uvs if they don't exist yet */ 01188 if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { 01189 BKE_mesh_end_editmesh(obedit->data, em); 01190 return OPERATOR_CANCELLED; 01191 } 01192 01193 uv_map_transform(C, op, center, rotmat); 01194 01195 for(efa= em->faces.first; efa; efa= efa->next) { 01196 if(efa->f & SELECT) { 01197 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 01198 01199 uv_sphere_project(tf->uv[0], efa->v1->co, center, rotmat); 01200 uv_sphere_project(tf->uv[1], efa->v2->co, center, rotmat); 01201 uv_sphere_project(tf->uv[2], efa->v3->co, center, rotmat); 01202 if(efa->v4) 01203 uv_sphere_project(tf->uv[3], efa->v4->co, center, rotmat); 01204 01205 uv_map_mirror(efa, tf); 01206 } 01207 } 01208 01209 uv_map_clip_correct(em, op); 01210 01211 DAG_id_tag_update(obedit->data, 0); 01212 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01213 01214 BKE_mesh_end_editmesh(obedit->data, em); 01215 return OPERATOR_FINISHED; 01216 } 01217 01218 void UV_OT_sphere_project(wmOperatorType *ot) 01219 { 01220 /* identifiers */ 01221 ot->name= "Sphere Projection"; 01222 ot->idname= "UV_OT_sphere_project"; 01223 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01224 01225 /* api callbacks */ 01226 ot->exec= sphere_project_exec; 01227 ot->poll= ED_operator_uvmap; 01228 01229 /* properties */ 01230 uv_transform_properties(ot, 0); 01231 uv_map_clip_correct_properties(ot); 01232 } 01233 01234 /***************** Cylinder Project operator **************/ 01235 01236 static void uv_cylinder_project(float target[2], float source[3], float center[3], float rotmat[4][4]) 01237 { 01238 float pv[3]; 01239 01240 sub_v3_v3v3(pv, source, center); 01241 mul_m4_v3(rotmat, pv); 01242 01243 map_to_tube( &target[0], &target[1],pv[0], pv[1], pv[2]); 01244 01245 /* split line is always zero */ 01246 if(target[0] >= 1.0f) 01247 target[0] -= 1.0f; 01248 } 01249 01250 static int cylinder_project_exec(bContext *C, wmOperator *op) 01251 { 01252 Scene *scene= CTX_data_scene(C); 01253 Object *obedit= CTX_data_edit_object(C); 01254 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 01255 EditFace *efa; 01256 MTFace *tf; 01257 float center[3], rotmat[4][4]; 01258 01259 /* add uvs if they don't exist yet */ 01260 if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { 01261 BKE_mesh_end_editmesh(obedit->data, em); 01262 return OPERATOR_CANCELLED; 01263 } 01264 01265 uv_map_transform(C, op, center, rotmat); 01266 01267 for(efa= em->faces.first; efa; efa= efa->next) { 01268 if(efa->f & SELECT) { 01269 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 01270 01271 uv_cylinder_project(tf->uv[0], efa->v1->co, center, rotmat); 01272 uv_cylinder_project(tf->uv[1], efa->v2->co, center, rotmat); 01273 uv_cylinder_project(tf->uv[2], efa->v3->co, center, rotmat); 01274 if(efa->v4) 01275 uv_cylinder_project(tf->uv[3], efa->v4->co, center, rotmat); 01276 01277 uv_map_mirror(efa, tf); 01278 } 01279 } 01280 01281 uv_map_clip_correct(em, op); 01282 01283 DAG_id_tag_update(obedit->data, 0); 01284 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01285 01286 BKE_mesh_end_editmesh(obedit->data, em); 01287 return OPERATOR_FINISHED; 01288 } 01289 01290 void UV_OT_cylinder_project(wmOperatorType *ot) 01291 { 01292 /* identifiers */ 01293 ot->name= "Cylinder Projection"; 01294 ot->idname= "UV_OT_cylinder_project"; 01295 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01296 01297 /* api callbacks */ 01298 ot->exec= cylinder_project_exec; 01299 ot->poll= ED_operator_uvmap; 01300 01301 /* properties */ 01302 uv_transform_properties(ot, 1); 01303 uv_map_clip_correct_properties(ot); 01304 } 01305 01306 /******************* Cube Project operator ****************/ 01307 01308 static int cube_project_exec(bContext *C, wmOperator *op) 01309 { 01310 Scene *scene= CTX_data_scene(C); 01311 Object *obedit= CTX_data_edit_object(C); 01312 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); 01313 EditFace *efa; 01314 MTFace *tf; 01315 float no[3], cube_size, *loc, dx, dy; 01316 int cox, coy; 01317 01318 /* add uvs if they don't exist yet */ 01319 if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { 01320 BKE_mesh_end_editmesh(obedit->data, em); 01321 return OPERATOR_CANCELLED; 01322 } 01323 01324 loc= obedit->obmat[3]; 01325 cube_size= RNA_float_get(op->ptr, "cube_size"); 01326 01327 /* choose x,y,z axis for projection depending on the largest normal 01328 * component, but clusters all together around the center of map. */ 01329 01330 for(efa= em->faces.first; efa; efa= efa->next) { 01331 if(efa->f & SELECT) { 01332 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 01333 normal_tri_v3( no,efa->v1->co, efa->v2->co, efa->v3->co); 01334 01335 no[0]= fabs(no[0]); 01336 no[1]= fabs(no[1]); 01337 no[2]= fabs(no[2]); 01338 01339 cox=0; coy= 1; 01340 if(no[2]>=no[0] && no[2]>=no[1]); 01341 else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2; 01342 else { cox= 1; coy= 2; } 01343 01344 tf->uv[0][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v1->co[cox]); 01345 tf->uv[0][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v1->co[coy]); 01346 dx = floor(tf->uv[0][0]); 01347 dy = floor(tf->uv[0][1]); 01348 tf->uv[0][0] -= dx; 01349 tf->uv[0][1] -= dy; 01350 tf->uv[1][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v2->co[cox]); 01351 tf->uv[1][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v2->co[coy]); 01352 tf->uv[1][0] -= dx; 01353 tf->uv[1][1] -= dy; 01354 tf->uv[2][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v3->co[cox]); 01355 tf->uv[2][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v3->co[coy]); 01356 tf->uv[2][0] -= dx; 01357 tf->uv[2][1] -= dy; 01358 01359 if(efa->v4) { 01360 tf->uv[3][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v4->co[cox]); 01361 tf->uv[3][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v4->co[coy]); 01362 tf->uv[3][0] -= dx; 01363 tf->uv[3][1] -= dy; 01364 } 01365 } 01366 } 01367 01368 uv_map_clip_correct(em, op); 01369 01370 DAG_id_tag_update(obedit->data, 0); 01371 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01372 01373 BKE_mesh_end_editmesh(obedit->data, em); 01374 return OPERATOR_FINISHED; 01375 } 01376 01377 void UV_OT_cube_project(wmOperatorType *ot) 01378 { 01379 /* identifiers */ 01380 ot->name= "Cube Projection"; 01381 ot->idname= "UV_OT_cube_project"; 01382 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01383 01384 /* api callbacks */ 01385 ot->exec= cube_project_exec; 01386 ot->poll= ED_operator_uvmap; 01387 01388 /* properties */ 01389 RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size", "Size of the cube to project on.", 0.001f, 100.0f); 01390 uv_map_clip_correct_properties(ot); 01391 }