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