Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2009-02-09 23:58:31 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2009-02-09 23:58:31 +0300
commit283926aa2d0c6366d92a4f38e994e843b73659f6 (patch)
tree2bd35e5609efa63882ab81eab9e8009a691c5acb /source/blender/editors/uvedit
parentc02bc1ce5379356b5c17034457a59aebf6e41725 (diff)
2.5: UV Editor module porting pretty much finished now, only missing
still is mirror transform. This commits adds the remaining operators: * UV mapping operators (U key menu): cube, sphere, cylinder, etc. * Hide/Show operators. And solves most XXX's, including: * Fix bad includes and calls into space image. * Aspect ratio correction. * Create UVs if they don't exist yet on unwrap. * Assign image to UVs. * Drawing proportional edit circle.
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c51
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h10
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c322
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c963
5 files changed, 1188 insertions, 162 deletions
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 5bffe6b1124..9686d4d6094 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -38,7 +38,6 @@
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
-#include "BKE_global.h" // XXX make edge and face drawing flags local
#include "BKE_object.h"
#include "BKE_utildefines.h"
@@ -48,54 +47,21 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "ED_image.h"
#include "ED_mesh.h"
#include "UI_resources.h"
-#include "../space_image/image_intern.h"
#include "uvedit_intern.h"
-/* XXX make this draw extra for transform operator */
-#if 0
-static void draw_image_transform(ImBuf *ibuf, float xuser_asp, float yuser_asp)
-{
-#if 0
- if(G.moving) {
- float aspx, aspy, center[3];
-
- BIF_drawConstraint();
-
- if(ibuf==0 || ibuf->rect==0 || ibuf->x==0 || ibuf->y==0) {
- aspx= aspy= 1.0;
- }
- else {
- aspx= (256.0/ibuf->x) * xuser_asp;
- aspy= (256.0/ibuf->y) * yuser_asp;
- }
- BIF_getPropCenter(center);
-
- /* scale and translate the circle into place and draw it */
- glPushMatrix();
- glScalef(aspx, aspy, 1.0);
- glTranslatef((1/aspx)*center[0] - center[0],
- (1/aspy)*center[1] - center[1], 0.0);
-
- BIF_drawPropCircle();
-
- glPopMatrix();
- }
-#endif
-}
-#endif
-
static void drawcursor_sima(SpaceImage *sima, ARegion *ar)
{
View2D *v2d= &ar->v2d;
float zoomx, zoomy, w, h;
int width, height;
- get_space_image_size(sima, &width, &height);
- get_space_image_zoom(sima, ar, &zoomx, &zoomy);
+ ED_space_image_size(sima, &width, &height);
+ ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
w= zoomx*width/256.0f;
h= zoomy*height/256.0f;
@@ -191,9 +157,7 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
Image *ima= sima->image;
float aspx, aspy, col[4], tf_uv[4][2];
- aspx= 1.0f;
- aspy= 1.0f;
- //XXX transform_aspect_ratio_tf_uv(&aspx, &aspy);
+ ED_space_image_uv_aspect(sima, &aspx, &aspy);
switch(sima->dt_uvstretch) {
case SI_UVDT_STRETCH_AREA:
@@ -823,8 +787,8 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi
{
int show_uvedit, show_uvshadow;
- show_uvedit= get_space_image_show_uvedit(sima, obedit);
- show_uvshadow= get_space_image_show_uvshadow(sima, obedit);
+ show_uvedit= ED_space_image_show_uvedit(sima, obedit);
+ show_uvshadow= ED_space_image_show_uvshadow(sima, obedit);
if(show_uvedit || show_uvshadow) {
/* this is basically the same object_handle_update as in the 3d view,
@@ -840,9 +804,6 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi
if(show_uvedit)
drawcursor_sima(sima, ar);
-
- // XXX becomes operator draw extra:
- // draw_image_transform(ibuf, xuser_asp, yuser_asp);
}
}
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index a66c9ea2fb8..cca357c8685 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -66,10 +66,16 @@ float uv_area(float uv[][2], int quad);
void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy);
/* operators */
+void UV_OT_average_islands_scale(struct wmOperatorType *ot);
+void UV_OT_cube_project(struct wmOperatorType *ot);
+void UV_OT_cylinder_project(struct wmOperatorType *ot);
+void UV_OT_from_view(struct wmOperatorType *ot);
+void UV_OT_mapping_menu(struct wmOperatorType *ot);
+void UV_OT_minimize_stretch(struct wmOperatorType *ot);
void UV_OT_pack_islands(struct wmOperatorType *ot);
+void UV_OT_reset(struct wmOperatorType *ot);
+void UV_OT_sphere_project(struct wmOperatorType *ot);
void UV_OT_unwrap(struct wmOperatorType *ot);
-void UV_OT_minimize_stretch(struct wmOperatorType *ot);
-void UV_OT_average_islands_scale(struct wmOperatorType *ot);
#endif /* ED_UVEDIT_INTERN_H */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 86f5c782ca3..4c27151acef 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -56,6 +56,7 @@
#include "BIF_transform.h"
+#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -69,7 +70,6 @@
#include "UI_view2d.h"
#include "uvedit_intern.h"
-#include "../space_image/image_intern.h"
/************************* state testing ************************/
@@ -99,7 +99,7 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
return;
em= ((Mesh*)obedit->data)->edit_mesh;
- if(!em || !em->faces.first);
+ if(!em || !em->faces.first)
return;
/* ensure we have a uv layer */
@@ -133,15 +133,13 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
}
/* and update depdency graph */
- if(update) {
+ if(update)
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
- /* XXX ensure undo, notifiers? */
- }
}
/* dotile - 1, set the tile flag (from the space image)
* 2, set the tile index for the faces. */
-void ED_uvedit_set_tile(Scene *scene, Object *obedit, Image *ima, int curtile, int dotile)
+void ED_uvedit_set_tile(bContext *C, Scene *scene, Object *obedit, Image *ima, int curtile, int dotile)
{
EditMesh *em;
EditFace *efa;
@@ -174,7 +172,7 @@ void ED_uvedit_set_tile(Scene *scene, Object *obedit, Image *ima, int curtile, i
}
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
- // XXX WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
}
/*********************** space conversion *********************/
@@ -183,7 +181,7 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
{
int width, height;
- get_space_image_size(sima, &width, &height);
+ ED_space_image_size(sima, &width, &height);
dist[0]= pixeldist/width;
dist[1]= pixeldist/height;
@@ -2183,8 +2181,8 @@ int circle_select_exec(bContext *C, wmOperator *op)
/* compute ellipse size and location, not a circle since we deal
* with non square image. ellipse is normalized, r = 1.0. */
- get_space_image_size(sima, &width, &height);
- get_space_image_zoom(sima, ar, &zoomx, &zoomy);
+ ED_space_image_size(sima, &width, &height);
+ ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
ellipse[0]= width*zoomx/radius;
ellipse[1]= height*zoomy/radius;
@@ -2243,7 +2241,7 @@ static void snap_cursor_to_pixels(SpaceImage *sima, View2D *v2d)
{
int width= 0, height= 0;
- get_space_image_size(sima, &width, &height);
+ ED_space_image_size(sima, &width, &height);
snap_uv_to_pixel(v2d->cursor, width, height);
}
@@ -2460,7 +2458,7 @@ static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
float w, h;
short change = 0;
- get_space_image_size(sima, &width, &height);
+ ED_space_image_size(sima, &width, &height);
w = (float)width;
h = (float)height;
@@ -2515,7 +2513,7 @@ void UV_OT_snap_selection(wmOperatorType *ot)
static EnumPropertyItem target_items[] = {
{0, "PIXELS", "Pixels", ""},
{1, "CURSOR", "Cursor", ""},
- {2, "ADJACENT_UNSELECTED", "Adjacent Unselected", ""},
+ {2, "ADJACENT_DESELECTED", "Adjacent Deselected", ""},
{0, NULL, NULL, NULL}};
/* identifiers */
@@ -2584,7 +2582,7 @@ void UV_OT_pin(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it.");
}
-/* ******************** select pinned operator **************** */
+/******************* select pinned operator ***************/
static int select_pinned_exec(bContext *C, wmOperator *op)
{
@@ -2625,6 +2623,280 @@ void UV_OT_select_pinned(wmOperatorType *ot)
ot->poll= ED_operator_uvedit;
}
+/********************** hide operator *********************/
+
+static int hide_exec(bContext *C, wmOperator *op)
+{
+ SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ EditFace *efa;
+ MTFace *tf;
+ int swap= (strcmp(op->idname, "UV_OT_hide_deselected") == 0);
+
+ if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+ EM_hide_mesh(em, swap);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+ return OPERATOR_FINISHED;
+ }
+
+ if(swap) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if(sima->flag & SI_SELACTFACE) {
+ /* Pretend face mode */
+ if(( (efa->v4==NULL &&
+ ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) ||
+ ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) == 0) {
+
+ if(em->selectmode == SCE_SELECT_FACE) {
+ efa->f &= ~SELECT;
+ /* must re-select after */
+ efa->e1->f &= ~SELECT;
+ efa->e2->f &= ~SELECT;
+ efa->e3->f &= ~SELECT;
+ if(efa->e4) efa->e4->f &= ~SELECT;
+ }
+ else
+ EM_select_face(efa, 0);
+ }
+ tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ else if(em->selectmode == SCE_SELECT_FACE) {
+ if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) {
+ if(!efa->v4)
+ EM_select_face(efa, 0);
+ else if(!(tf->flag & TF_SEL4))
+ EM_select_face(efa, 0);
+ tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ }
+ else {
+ /* EM_deselect_flush will deselect the face */
+ if((tf->flag & TF_SEL1)==0) efa->v1->f &= ~SELECT;
+ if((tf->flag & TF_SEL2)==0) efa->v2->f &= ~SELECT;
+ if((tf->flag & TF_SEL3)==0) efa->v3->f &= ~SELECT;
+ if((efa->v4) && (tf->flag & TF_SEL4)==0) efa->v4->f &= ~SELECT;
+
+ tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ }
+ }
+ }
+ else {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ if(sima->flag & SI_SELACTFACE) {
+ if( (efa->v4==NULL &&
+ ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) ||
+ ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) {
+
+ if(em->selectmode == SCE_SELECT_FACE) {
+ efa->f &= ~SELECT;
+ /* must re-select after */
+ efa->e1->f &= ~SELECT;
+ efa->e2->f &= ~SELECT;
+ efa->e3->f &= ~SELECT;
+ if(efa->e4) efa->e4->f &= ~SELECT;
+ }
+ else
+ EM_select_face(efa, 0);
+ }
+
+ tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ else if(em->selectmode == SCE_SELECT_FACE) {
+ if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
+ EM_select_face(efa, 0);
+ else if(efa->v4 && tf->flag & TF_SEL4)
+ EM_select_face(efa, 0);
+
+ tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ else {
+ /* EM_deselect_flush will deselect the face */
+ if(tf->flag & TF_SEL1) efa->v1->f &= ~SELECT;
+ if(tf->flag & TF_SEL2) efa->v2->f &= ~SELECT;
+ if(tf->flag & TF_SEL3) efa->v3->f &= ~SELECT;
+ if((efa->v4) && tf->flag & TF_SEL4) efa->v4->f &= ~SELECT;
+
+ tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ }
+ }
+ }
+
+ /*deselects too many but ok for now*/
+ if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX))
+ EM_deselect_flush(em);
+
+ if(em->selectmode==SCE_SELECT_FACE) {
+ /* de-selected all edges from faces that were de-selected.
+ * now make sure all faces that are selected also have selected edges */
+ for(efa= em->faces.first; efa; efa= efa->next)
+ if(efa->f & SELECT)
+ EM_select_face(efa, 1);
+ }
+
+ EM_validate_selections(em);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_hide_selected(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Hide Selected";
+ ot->idname= "UV_OT_hide_selected";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= hide_exec;
+ ot->poll= ED_operator_uvedit;
+}
+
+void UV_OT_hide_deselected(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Hide Deselected";
+ ot->idname= "UV_OT_hide_deselected";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= hide_exec;
+ ot->poll= ED_operator_uvedit;
+}
+
+/****************** show hidden operator ******************/
+
+static int show_hidden_exec(bContext *C, wmOperator *op)
+{
+ SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ EditFace *efa;
+ MTFace *tf;
+
+ /* call the mesh function if we are in mesh sync sel */
+ if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+ EM_reveal_mesh(em);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+ return OPERATOR_FINISHED;
+ }
+
+ if(sima->flag & SI_SELACTFACE) {
+ if(em->selectmode == SCE_SELECT_FACE) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(!(efa->h) && !(efa->f & SELECT)) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ EM_select_face(efa, 1);
+ tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
+ }
+ }
+ }
+ else {
+ /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
+ if(sima->sticky == SI_STICKY_DISABLE) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(!(efa->h) && !(efa->f & SELECT)) {
+ /* All verts must be unselected for the face to be selected in the UV view */
+ if((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==0 || (efa->v4->f&SELECT)==0)) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
+ /* Cant use EM_select_face here because it unselects the verts
+ * and we cant tell if the face was totally unselected or not */
+ /*EM_select_face(efa, 1);
+ *
+ * See Loop with EM_select_face() below... */
+ efa->f |= SELECT;
+ }
+ }
+ }
+ }
+ else {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(!(efa->h) && !(efa->f & SELECT)) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ if((efa->v1->f & SELECT)==0) {tf->flag |= TF_SEL1;}
+ if((efa->v2->f & SELECT)==0) {tf->flag |= TF_SEL2;}
+ if((efa->v3->f & SELECT)==0) {tf->flag |= TF_SEL3;}
+ if((efa->v4 && (efa->v4->f & SELECT)==0)) {tf->flag |= TF_SEL4;}
+
+ efa->f |= SELECT;
+ }
+ }
+ }
+
+ /* Select all edges and verts now */
+ for(efa= em->faces.first; efa; efa= efa->next)
+ /* we only selected the face flags, and didnt changes edges or verts, fix this now */
+ if(!(efa->h) && (efa->f & SELECT))
+ EM_select_face(efa, 1);
+
+ EM_select_flush(em);
+ }
+ }
+ else if(em->selectmode == SCE_SELECT_FACE) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(!(efa->h) && !(efa->f & SELECT)) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ efa->f |= SELECT;
+ tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
+ }
+ }
+
+ /* Select all edges and verts now */
+ for(efa= em->faces.first; efa; efa= efa->next)
+ /* we only selected the face flags, and didnt changes edges or verts, fix this now */
+ if(!(efa->h) && (efa->f & SELECT))
+ EM_select_face(efa, 1);
+ }
+ else {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(!(efa->h) && !(efa->f & SELECT)) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ if((efa->v1->f & SELECT)==0) {tf->flag |= TF_SEL1;}
+ if((efa->v2->f & SELECT)==0) {tf->flag |= TF_SEL2;}
+ if((efa->v3->f & SELECT)==0) {tf->flag |= TF_SEL3;}
+ if((efa->v4 && (efa->v4->f & SELECT)==0)) {tf->flag |= TF_SEL4;}
+
+ efa->f |= SELECT;
+ }
+ }
+
+ /* Select all edges and verts now */
+ for(efa= em->faces.first; efa; efa= efa->next)
+ /* we only selected the face flags, and didnt changes edges or verts, fix this now */
+ if(!(efa->h) && (efa->f & SELECT))
+ EM_select_face(efa, 1);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_show_hidden(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Show Hidden";
+ ot->idname= "UV_OT_show_hidden";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= show_hidden_exec;
+ ot->poll= ED_operator_uvedit;
+}
+
/* ************************** registration **********************************/
void ED_operatortypes_uvedit(void)
@@ -2648,10 +2920,20 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_weld);
WM_operatortype_append(UV_OT_pin);
- WM_operatortype_append(UV_OT_unwrap);
- WM_operatortype_append(UV_OT_minimize_stretch);
WM_operatortype_append(UV_OT_average_islands_scale);
+ WM_operatortype_append(UV_OT_cube_project);
+ WM_operatortype_append(UV_OT_cylinder_project);
+ WM_operatortype_append(UV_OT_from_view);
+ WM_operatortype_append(UV_OT_mapping_menu);
+ WM_operatortype_append(UV_OT_minimize_stretch);
WM_operatortype_append(UV_OT_pack_islands);
+ WM_operatortype_append(UV_OT_reset);
+ WM_operatortype_append(UV_OT_sphere_project);
+ WM_operatortype_append(UV_OT_unwrap);
+
+ WM_operatortype_append(UV_OT_show_hidden);
+ WM_operatortype_append(UV_OT_hide_selected);
+ WM_operatortype_append(UV_OT_hide_deselected);
}
void ED_keymap_uvedit(wmWindowManager *wm)
@@ -2662,8 +2944,7 @@ void ED_keymap_uvedit(wmWindowManager *wm)
WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
- // XXX not working?
- RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, KM_ALT)->ptr, "extend", 1);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_ALT, 0)->ptr, "extend", 1);
/* border/circle selection */
WM_keymap_add_item(keymap, "UV_OT_border_select", BKEY, KM_PRESS, 0, 0);
@@ -2688,6 +2969,11 @@ void ED_keymap_uvedit(wmWindowManager *wm)
WM_keymap_add_item(keymap, "UV_OT_pack_islands", PKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "UV_OT_average_islands_scale", AKEY, KM_PRESS, KM_CTRL, 0);
+ /* hide */
+ WM_keymap_add_item(keymap, "UV_OT_hide_selected", HKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "UV_OT_hide_deselected", HKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "UV_OT_show_hidden", HKEY, KM_PRESS, KM_ALT, 0);
+
transform_keymap_for_space(wm, keymap, SPACE_IMAGE);
}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 635a7903d6f..0fcd0062044 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -3828,7 +3828,7 @@ static void p_smooth(PChart *chart)
if (hedges) MEM_freeN(hedges);
if (vedges) MEM_freeN(vedges);
- // XXX error("Not enough memory for area smoothing grid.");
+ // printf("Not enough memory for area smoothing grid.");
return;
}
@@ -3978,7 +3978,7 @@ static void p_smooth(PChart *chart)
if (triangles) MEM_freeN(triangles);
if (tri) MEM_freeN(tri);
- // XXX error("Not enough memory for area smoothing grid.");
+ // printf("Not enough memory for area smoothing grid.");
return;
}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index c7e0dfd7bc7..ccad3acfd56 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -53,46 +53,54 @@
#include "PIL_time.h"
+#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_uvedit.h"
+#include "ED_view3d.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "UI_interface.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "uvedit_intern.h"
#include "uvedit_parametrizer.h"
-static void ED_uvedit_create_uvs(EditMesh *em)
+static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
{
-#if 0
- if (em && em->faces.first)
- EM_add_data_layer(&em->fdata, CD_MTFACE);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ EditFace *efa;
+ MTFace *tf;
+
+ if(ED_uvedit_test(obedit))
+ return 1;
+
+ if(em && em->faces.first)
+ EM_add_data_layer(em, &em->fdata, CD_MTFACE);
- if (!ED_uvedit_test(obedit))
- return;
+ if(!ED_uvedit_test(obedit))
+ return 0;
- if (G.sima && G.sima->image) /* this is a bit of a kludge, but assume they want the image on their mesh when UVs are added */
- image_changed(G.sima, G.sima->image);
+ // XXX this image is not in context in 3d view .. only
+ // way to get would be to find the first image window?
+ ED_uvedit_assign_image(scene, obedit, CTX_data_edit_image(C), NULL);
/* select new UV's */
- if ((G.sima==0 || G.sima->flag & SI_SYNC_UVSEL)==0) {
- EditFace *efa;
- MTFace *tf;
- for(efa=em->faces.first; efa; efa=efa->next) {
- tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- simaFaceSel_Set(efa, tf);
- }
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ uvedit_face_select(scene, efa, tf);
}
-#endif
+
+ return 1;
}
/****************** Parametrizer Conversion ***************/
-ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit, short fill, short sel)
+ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit, short fill, short sel, short correct_aspect)
{
ParamHandle *handle;
EditFace *efa;
@@ -103,37 +111,37 @@ ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit,
handle = param_construct_begin();
- if((scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT)==0) {
+ if(correct_aspect) {
efa = EM_get_actFace(em, 1);
- if (efa) {
- float aspx = 1.0f, aspy= 1.0f;
- // XXX MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- // XXX image_final_aspect(tf->tpage, &aspx, &aspy);
- // XXX get_space_image_aspect(sima, &aspx, &aspy);
+ if(efa) {
+ MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ float aspx, aspy;
+
+ ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
- if (aspx!=aspy)
+ if(aspx!=aspy)
param_aspect_ratio(handle, aspx, aspy);
}
}
/* we need the vert indicies */
- for (ev= em->verts.first, a=0; ev; ev= ev->next, a++)
+ for(ev= em->verts.first, a=0; ev; ev= ev->next, a++)
ev->tmp.l = a;
- for (efa= em->faces.first; efa; efa= efa->next) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
ParamKey key, vkeys[4];
ParamBool pin[4], select[4];
float *co[4];
float *uv[4];
int nverts;
- if ((efa->h) || (sel && (efa->f & SELECT)==0))
+ if((efa->h) || (sel && (efa->f & SELECT)==0))
continue;
tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (implicit &&
+ if(implicit &&
!( uvedit_uv_selected(scene, efa, tf, 0) ||
uvedit_uv_selected(scene, efa, tf, 1) ||
uvedit_uv_selected(scene, efa, tf, 2) ||
@@ -163,7 +171,7 @@ ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit,
select[1] = ((uvedit_uv_selected(scene, efa, tf, 1)) != 0);
select[2] = ((uvedit_uv_selected(scene, efa, tf, 2)) != 0);
- if (efa->v4) {
+ if(efa->v4) {
vkeys[3] = (ParamKey)efa->v4->tmp.l;
co[3] = efa->v4->co;
uv[3] = tf->uv[3];
@@ -177,8 +185,8 @@ ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit,
param_face_add(handle, key, nverts, vkeys, co, uv, pin, select);
}
- if (!implicit) {
- for (eed= em->edges.first; eed; eed= eed->next) {
+ if(!implicit) {
+ for(eed= em->edges.first; eed; eed= eed->next) {
if(eed->seam) {
ParamKey vkeys[2];
vkeys[0] = (ParamKey)eed->v1->tmp.l;
@@ -193,61 +201,7 @@ ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit,
return handle;
}
-/* ******************** unwrap operator **************** */
-
-static int unwrap_exec(bContext *C, wmOperator *op)
-{
- Scene *scene= CTX_data_scene(C);
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
- ParamHandle *handle;
- int method = RNA_enum_get(op->ptr, "method");
- int fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
-
- /* add uvs if they don't exist yet */
- if(!ED_uvedit_test(obedit))
- ED_uvedit_create_uvs(em);
-
- handle= construct_param_handle(scene, em, 0, fill_holes, 0);
-
- param_lscm_begin(handle, PARAM_FALSE, method == 0);
- param_lscm_solve(handle);
- param_lscm_end(handle);
-
- param_pack(handle);
-
- param_flush(handle);
-
- param_delete(handle);
-
- DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void UV_OT_unwrap(wmOperatorType *ot)
-{
- static EnumPropertyItem method_items[] = {
- {0, "ANGLE_BASED", "Angle Based", ""},
- {1, "CONFORMAL", "Conformal", ""},
- {0, NULL, NULL, NULL}};
-
- /* identifiers */
- ot->name= "Unwrap";
- ot->idname= "UV_OT_unwrap";
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec= unwrap_exec;
- ot->poll= ED_operator_uvmap;
-
- /* properties */
- RNA_def_enum(ot->srna, "method", method_items, 0, "Method", "Unwrapping method. Angle Based usually gives better results than Conformal, while being somewhat slower.");
- RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry.");
-}
-
-/* ******************** minimize stretch operator **************** */
+/* ******************** Minimize Stretch operator **************** */
typedef struct MinStretch {
Scene *scene;
@@ -274,7 +228,7 @@ static void minimize_stretch_init(bContext *C, wmOperator *op)
ms->em= em;
ms->blend= RNA_float_get(op->ptr, "blend");
ms->iterations= RNA_int_get(op->ptr, "iterations");
- ms->handle= construct_param_handle(scene, em, 1, fill_holes, 1);
+ ms->handle= construct_param_handle(scene, em, 1, fill_holes, 1, 1);
ms->lasttime= PIL_check_seconds_timer();
param_stretch_begin(ms->handle);
@@ -440,7 +394,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively.", 0, 100);
}
-/* ******************** pack islands operator **************** */
+/* ******************** Pack Islands operator **************** */
static int pack_islands_exec(bContext *C, wmOperator *op)
{
@@ -449,7 +403,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
ParamHandle *handle;
- handle = construct_param_handle(scene, em, 1, 0, 1);
+ handle = construct_param_handle(scene, em, 1, 0, 1, 1);
param_pack(handle);
param_flush(handle);
param_delete(handle);
@@ -472,7 +426,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
ot->poll= ED_operator_uvedit;
}
-/* ******************** average islands scale operator **************** */
+/* ******************** Average Islands Scale operator **************** */
static int average_islands_scale_exec(bContext *C, wmOperator *op)
{
@@ -481,7 +435,7 @@ static int average_islands_scale_exec(bContext *C, wmOperator *op)
EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
ParamHandle *handle;
- handle= construct_param_handle(scene, em, 1, 0, 1);
+ handle= construct_param_handle(scene, em, 1, 0, 1, 1);
param_average(handle);
param_flush(handle);
param_delete(handle);
@@ -516,14 +470,14 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
if(!ED_uvedit_test(obedit)) return;
- liveHandle = construct_param_handle(scene, em, 0, fillholes, 1);
+ liveHandle = construct_param_handle(scene, em, 0, fillholes, 1, 1);
param_lscm_begin(liveHandle, PARAM_TRUE, abf);
}
void ED_uvedit_live_unwrap_re_solve(void)
{
- if (liveHandle) {
+ if(liveHandle) {
param_lscm_solve(liveHandle);
param_flush(liveHandle);
}
@@ -531,12 +485,831 @@ void ED_uvedit_live_unwrap_re_solve(void)
void ED_uvedit_live_unwrap_end(short cancel)
{
- if (liveHandle) {
+ if(liveHandle) {
param_lscm_end(liveHandle);
- if (cancel)
+ if(cancel)
param_flush_restore(liveHandle);
param_delete(liveHandle);
liveHandle = NULL;
}
}
+/*************** UV Map Common Transforms *****************/
+
+#define VIEW_ON_EQUATOR 0
+#define VIEW_ON_POLES 1
+#define ALIGN_TO_OBJECT 2
+
+#define POLAR_ZX 0
+#define POLAR_ZY 1
+
+static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Object *ob, EditMesh *em)
+{
+ EditFace *efa;
+ float min[3], max[3], *cursx;
+ int around= (v3d)? v3d->around: V3D_CENTER;
+
+ /* only operates on the edit object - this is all that's needed now */
+
+ switch(around) {
+ case V3D_CENTER: /* bounding box center */
+ min[0]= min[1]= min[2]= 1e20f;
+ max[0]= max[1]= max[2]= -1e20f;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ DO_MINMAX(efa->v1->co, min, max);
+ DO_MINMAX(efa->v2->co, min, max);
+ DO_MINMAX(efa->v3->co, min, max);
+ if(efa->v4) DO_MINMAX(efa->v4->co, min, max);
+ }
+ }
+ VecMidf(result, min, max);
+ break;
+
+ case V3D_CURSOR: /*cursor center*/
+ cursx= give_cursor(scene, v3d);
+ /* shift to objects world */
+ result[0]= cursx[0]-ob->obmat[3][0];
+ result[1]= cursx[1]-ob->obmat[3][1];
+ result[2]= cursx[2]-ob->obmat[3][2];
+ break;
+
+ case V3D_LOCAL: /*object center*/
+ case V3D_CENTROID: /* multiple objects centers, only one object here*/
+ default:
+ result[0]= result[1]= result[2]= 0.0;
+ break;
+ }
+}
+
+static void uv_map_rotation_matrix(float result[][4], RegionView3D *rv3d, Object *ob, float upangledeg, float sideangledeg, float radius)
+{
+ float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
+ float sideangle= 0.0f, upangle= 0.0f;
+ int k;
+
+ /* get rotation of the current view matrix */
+ if(rv3d)
+ Mat4CpyMat4(viewmatrix, rv3d->viewmat);
+ else
+ Mat4One(viewmatrix);
+
+ /* but shifting */
+ for(k=0; k<4; k++)
+ viewmatrix[3][k] =0.0f;
+
+ /* get rotation of the current object matrix */
+ Mat4CpyMat4(rotobj,ob->obmat);
+
+ /* but shifting */
+ for(k=0; k<4; k++)
+ rotobj[3][k] =0.0f;
+
+ Mat4Clr(*rotup);
+ Mat4Clr(*rotside);
+
+ /* compensate front/side.. against opengl x,y,z world definition */
+ /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
+ /* i wanted to keep the reason here, so we're rotating*/
+ sideangle= (float)M_PI*(sideangledeg + 180.0f)/180.0f;
+ rotside[0][0]= (float)cos(sideangle);
+ rotside[0][1]= -(float)sin(sideangle);
+ rotside[1][0]= (float)sin(sideangle);
+ rotside[1][1]= (float)cos(sideangle);
+ rotside[2][2]= 1.0f;
+
+ upangle= (float)M_PI*upangledeg/180.0f;
+ rotup[1][1]= (float)cos(upangle)/radius;
+ rotup[1][2]= -(float)sin(upangle)/radius;
+ rotup[2][1]= (float)sin(upangle)/radius;
+ rotup[2][2]= (float)cos(upangle)/radius;
+ rotup[0][0]= (float)1.0f/radius;
+
+ /* calculate transforms*/
+ Mat4MulSerie(result, rotup, rotside, viewmatrix, rotobj, NULL, NULL, NULL, NULL);
+}
+
+static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4])
+{
+ /* context checks are messy here, making it work in both 3d view and uv editor */
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ SpaceLink *sl= CTX_wm_space_data(C);
+ View3D *v3d= (sl->spacetype == SPACE_VIEW3D)? (View3D*)sl: NULL;
+ ARegion *ar= CTX_wm_region(C);
+ RegionView3D *rv3d= (v3d && ar->regiontype == RGN_TYPE_WINDOW)? ar->regiondata: NULL;
+ /* common operator properties */
+ int align= RNA_enum_get(op->ptr, "align");
+ int direction= RNA_enum_get(op->ptr, "direction");
+ float radius= RNA_struct_find_property(op->ptr, "radius")? RNA_float_get(op->ptr, "radius"): 1.0f;
+ float upangledeg, sideangledeg;
+
+ uv_map_transform_center(scene, v3d, center, obedit, em);
+
+ if(direction == VIEW_ON_EQUATOR) {
+ upangledeg= 90.0f;
+ sideangledeg= 0.0f;
+ }
+ else {
+ upangledeg= 0.0f;
+ if(align == POLAR_ZY) sideangledeg= 0.0f;
+ else sideangledeg= 90.0f;
+ }
+
+ /* be compatible to the "old" sphere/cylinder mode */
+ if(direction == ALIGN_TO_OBJECT)
+ Mat4One(rotmat);
+ else
+ uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
+}
+
+static void uv_transform_properties(wmOperatorType *ot, int radius)
+{
+ static EnumPropertyItem direction_items[]= {
+ {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", "View on Equator", "3D view is on the equator."},
+ {VIEW_ON_POLES, "VIEW_ON_POLES", "View on Poles", "3D view is on the poles."},
+ {ALIGN_TO_OBJECT, "ALIGN_TO_OBJECT", "Align to Object", "Align according to object transform."},
+ {0, NULL, NULL, NULL}
+ };
+ static EnumPropertyItem align_items[]= {
+ {POLAR_ZX, "POLAR_ZX", "Polar ZX", "Polar 0 is X."},
+ {POLAR_ZY, "POLAR_ZY", "Polar ZY", "Polar 0 is Y."},
+ {0, NULL, NULL, NULL}
+ };
+
+ RNA_def_enum(ot->srna, "direction", direction_items, VIEW_ON_EQUATOR, "Direction", "Direction of the sphere or cylinder.");
+ RNA_def_enum(ot->srna, "align", align_items, VIEW_ON_EQUATOR, "Align", "How to determine rotation around the pole.");
+ if(radius)
+ RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "Radius of the sphere or cylinder.", 0.0001f, 100.0f);
+}
+
+static void correct_uv_aspect(EditMesh *em)
+{
+ EditFace *efa= EM_get_actFace(em, 1);
+ MTFace *tf;
+ float scale, aspx= 1.0f, aspy=1.0f;
+
+ if(efa) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
+ }
+
+ if(aspx == aspy)
+ return;
+
+ if(aspx > aspy) {
+ scale= aspy/aspx;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ tf->uv[0][0]= ((tf->uv[0][0]-0.5)*scale)+0.5;
+ tf->uv[1][0]= ((tf->uv[1][0]-0.5)*scale)+0.5;
+ tf->uv[2][0]= ((tf->uv[2][0]-0.5)*scale)+0.5;
+ if(efa->v4)
+ tf->uv[3][0]= ((tf->uv[3][0]-0.5)*scale)+0.5;
+ }
+ }
+ }
+ else {
+ scale= aspx/aspy;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ tf->uv[0][1]= ((tf->uv[0][1]-0.5)*scale)+0.5;
+ tf->uv[1][1]= ((tf->uv[1][1]-0.5)*scale)+0.5;
+ tf->uv[2][1]= ((tf->uv[2][1]-0.5)*scale)+0.5;
+ if(efa->v4)
+ tf->uv[3][1]= ((tf->uv[3][1]-0.5)*scale)+0.5;
+ }
+ }
+ }
+}
+
+/******************** Map Clip & Correct ******************/
+
+static void uv_map_clip_correct_properties(wmOperatorType *ot)
+{
+ RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", "Map UV's taking image aspect ratio into account.");
+ RNA_def_boolean(ot->srna, "clip_to_bounds", 0, "Clip to Bounds", "Clip UV coordinates to bounds after unwrapping.");
+ RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds", "Scale UV coordinates to bounds after unwrapping.");
+}
+
+static void uv_map_clip_correct(EditMesh *em, wmOperator *op)
+{
+ EditFace *efa;
+ MTFace *tf;
+ float dx, dy, min[2], max[2];
+ int b, nverts;
+ int correct_aspect= RNA_boolean_get(op->ptr, "correct_aspect");
+ int clip_to_bounds= RNA_boolean_get(op->ptr, "clip_to_bounds");
+ int scale_to_bounds= RNA_boolean_get(op->ptr, "scale_to_bounds");
+
+ /* correct for image aspect ratio */
+ if(correct_aspect)
+ correct_uv_aspect(em);
+
+ if(scale_to_bounds) {
+ INIT_MINMAX2(min, max);
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ DO_MINMAX2(tf->uv[0], min, max);
+ DO_MINMAX2(tf->uv[1], min, max);
+ DO_MINMAX2(tf->uv[2], min, max);
+
+ if(efa->v4)
+ DO_MINMAX2(tf->uv[3], min, max);
+ }
+ }
+
+ /* rescale UV to be in 1/1 */
+ dx= (max[0]-min[0]);
+ dy= (max[1]-min[1]);
+
+ if(dx > 0.0f)
+ dx= 1.0f/dx;
+ if(dy > 0.0f)
+ dy= 1.0f/dy;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ nverts= (efa->v4)? 4: 3;
+
+ for(b=0; b<nverts; b++) {
+ tf->uv[b][0]= (tf->uv[b][0]-min[0])*dx;
+ tf->uv[b][1]= (tf->uv[b][1]-min[1])*dy;
+ }
+ }
+ }
+ }
+ else if(clip_to_bounds) {
+ /* clipping and wrapping */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ nverts= (efa->v4)? 4: 3;
+
+ for(b=0; b<nverts; b++) {
+ CLAMP(tf->uv[b][0], 0.0, 1.0);
+ CLAMP(tf->uv[b][1], 0.0, 1.0);
+ }
+ }
+ }
+ }
+}
+
+/* ******************** Unwrap operator **************** */
+
+static int unwrap_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ ParamHandle *handle;
+ int method = RNA_enum_get(op->ptr, "method");
+ int fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
+ int correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
+
+ /* add uvs if they don't exist yet */
+ if(!ED_uvedit_ensure_uvs(C, scene, obedit))
+ return OPERATOR_CANCELLED;
+
+ handle= construct_param_handle(scene, em, 0, fill_holes, 0, correct_aspect);
+
+ param_lscm_begin(handle, PARAM_FALSE, method == 0);
+ param_lscm_solve(handle);
+ param_lscm_end(handle);
+
+ param_pack(handle);
+
+ param_flush(handle);
+
+ param_delete(handle);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_unwrap(wmOperatorType *ot)
+{
+ static EnumPropertyItem method_items[] = {
+ {0, "ANGLE_BASED", "Angle Based", ""},
+ {1, "CONFORMAL", "Conformal", ""},
+ {0, NULL, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Unwrap";
+ ot->idname= "UV_OT_unwrap";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= unwrap_exec;
+ ot->poll= ED_operator_uvmap;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "method", method_items, 0, "Method", "Unwrapping method. Angle Based usually gives better results than Conformal, while being somewhat slower.");
+ RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry.");
+ RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", "Map UV's taking image aspect ratio into account.");
+}
+
+/**************** Project From View operator **************/
+
+static void uv_from_view_bounds(float target[2], float source[3], float rotmat[4][4])
+{
+ float pv[3];
+
+ Mat4MulVecfl(rotmat, pv);
+
+ /* ortho projection */
+ target[0] = -pv[0];
+ target[1] = pv[2];
+}
+
+static void uv_from_view(ARegion *ar, float target[2], float source[3], float rotmat[4][4])
+{
+ RegionView3D *rv3d= ar->regiondata;
+ float pv[3], pv4[4], dx, dy, x= 0.0, y= 0.0;
+
+ Mat4MulVecfl(rotmat, pv);
+
+ dx= ar->winx;
+ dy= ar->winy;
+
+ VecCopyf(pv4, source);
+ pv4[3]= 1.0;
+
+ /* rotmat is the object matrix in this case */
+ Mat4MulVec4fl(rotmat, pv4);
+
+ /* almost project_short */
+ Mat4MulVec4fl(rv3d->persmat, pv4);
+ if(fabs(pv4[3]) > 0.00001) { /* avoid division by zero */
+ target[0] = dx/2.0 + (dx/2.0)*pv4[0]/pv4[3];
+ target[1] = dy/2.0 + (dy/2.0)*pv4[1]/pv4[3];
+ }
+ else {
+ /* scaling is lost but give a valid result */
+ target[0] = dx/2.0 + (dx/2.0)*pv4[0];
+ target[1] = dy/2.0 + (dy/2.0)*pv4[1];
+ }
+
+ /* v3d->persmat seems to do this funky scaling */
+ if(dx > dy) {
+ y= (dx-dy)/2.0;
+ dy = dx;
+ }
+ else {
+ x= (dy-dx)/2.0;
+ dx = dy;
+ }
+
+ target[0]= (x + target[0])/dx;
+ target[1]= (y + target[1])/dy;
+}
+
+static int from_view_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ ARegion *ar= CTX_wm_region(C);
+ EditFace *efa;
+ MTFace *tf;
+ float rotmat[4][4];
+
+ /* add uvs if they don't exist yet */
+ if(!ED_uvedit_ensure_uvs(C, scene, obedit))
+ return OPERATOR_CANCELLED;
+
+ if(RNA_boolean_get(op->ptr, "orthographic")) {
+ uv_map_rotation_matrix(rotmat, ar->regiondata, obedit, 90.0f, 0.0f, 1.0f);
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ uv_from_view_bounds(tf->uv[0], efa->v1->co, rotmat);
+ uv_from_view_bounds(tf->uv[1], efa->v2->co, rotmat);
+ uv_from_view_bounds(tf->uv[2], efa->v3->co, rotmat);
+ if(efa->v4)
+ uv_from_view_bounds(tf->uv[3], efa->v4->co, rotmat);
+ }
+ }
+ }
+ else {
+ Mat4CpyMat4(rotmat, obedit->obmat);
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ uv_from_view(ar, tf->uv[0], efa->v1->co, rotmat);
+ uv_from_view(ar, tf->uv[1], efa->v2->co, rotmat);
+ uv_from_view(ar, tf->uv[2], efa->v3->co, rotmat);
+ if(efa->v4)
+ uv_from_view(ar, tf->uv[3], efa->v4->co, rotmat);
+ }
+ }
+ }
+
+ uv_map_clip_correct(em, op);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+static int from_view_poll(bContext *C)
+{
+ SpaceLink *sl= CTX_wm_space_data(C);
+ ARegion *ar= CTX_wm_region(C);
+
+ if(!ED_operator_uvmap(C))
+ return 0;
+
+ return (sl->spacetype == SPACE_VIEW3D && ar->regiontype == RGN_TYPE_WINDOW);
+}
+
+void UV_OT_from_view(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Project From View";
+ ot->idname= "UV_OT_project_from_view";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= from_view_exec;
+ ot->poll= from_view_poll;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection.");
+ uv_map_clip_correct_properties(ot);
+}
+
+/********************** Reset operator ********************/
+
+static int reset_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ EditFace *efa;
+ MTFace *tf;
+
+ /* add uvs if they don't exist yet */
+ if(!ED_uvedit_ensure_uvs(C, scene, obedit))
+ return OPERATOR_CANCELLED;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ tf->uv[0][0]= 0.0f;
+ tf->uv[0][1]= 0.0f;
+
+ tf->uv[1][0]= 1.0f;
+ tf->uv[1][1]= 0.0f;
+
+ tf->uv[2][0]= 1.0f;
+ tf->uv[2][1]= 1.0f;
+
+ tf->uv[3][0]= 0.0f;
+ tf->uv[3][1]= 1.0f;
+ }
+ }
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_reset(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Reset";
+ ot->idname= "UV_OT_reset";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= reset_exec;
+ ot->poll= ED_operator_uvmap;
+}
+
+/****************** Sphere Project operator ***************/
+
+static void uv_sphere_project(float target[2], float source[3], float center[3], float rotmat[4][4])
+{
+ float pv[3];
+
+ VecSubf(pv, source, center);
+ Mat4MulVecfl(rotmat, pv);
+
+ spheremap(pv[0], pv[1], pv[2], &target[0], &target[1]);
+
+ /* split line is always zero */
+ if(target[0] >= 1.0f)
+ target[0] -= 1.0f;
+}
+
+static void uv_map_mirror(EditFace *efa, MTFace *tf)
+{
+ float dx;
+ int nverts, i, mi;
+
+ nverts= (efa->v4)? 4: 3;
+
+ mi = 0;
+ for(i=1; i<nverts; i++)
+ if(tf->uv[i][0] > tf->uv[mi][0])
+ mi = i;
+
+ for(i=0; i<nverts; i++) {
+ if(i != mi) {
+ dx = tf->uv[mi][0] - tf->uv[i][0];
+ if(dx > 0.5) tf->uv[i][0] += 1.0;
+ }
+ }
+}
+
+static int sphere_project_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ EditFace *efa;
+ MTFace *tf;
+ float center[3], rotmat[4][4];
+
+ /* add uvs if they don't exist yet */
+ if(!ED_uvedit_ensure_uvs(C, scene, obedit))
+ return OPERATOR_CANCELLED;
+
+ uv_map_transform(C, op, center, rotmat);
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ uv_sphere_project(tf->uv[0], efa->v1->co, center, rotmat);
+ uv_sphere_project(tf->uv[1], efa->v2->co, center, rotmat);
+ uv_sphere_project(tf->uv[2], efa->v3->co, center, rotmat);
+ if(efa->v4)
+ uv_sphere_project(tf->uv[3], efa->v4->co, center, rotmat);
+
+ uv_map_mirror(efa, tf);
+ }
+ }
+
+ uv_map_clip_correct(em, op);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_sphere_project(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Sphere Projection";
+ ot->idname= "UV_OT_sphere_project";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= sphere_project_exec;
+ ot->poll= ED_operator_uvmap;
+
+ /* properties */
+ uv_transform_properties(ot, 0);
+ uv_map_clip_correct_properties(ot);
+}
+
+/***************** Cylinder Project operator **************/
+
+static void uv_cylinder_project(float target[2], float source[3], float center[3], float rotmat[4][4])
+{
+ float pv[3];
+
+ VecSubf(pv, source, center);
+ Mat4MulVecfl(rotmat, pv);
+
+ tubemap(pv[0], pv[1], pv[2], &target[0], &target[1]);
+
+ /* split line is always zero */
+ if(target[0] >= 1.0f)
+ target[0] -= 1.0f;
+}
+
+static int cylinder_project_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ EditFace *efa;
+ MTFace *tf;
+ float center[3], rotmat[4][4];
+
+ /* add uvs if they don't exist yet */
+ if(!ED_uvedit_ensure_uvs(C, scene, obedit))
+ return OPERATOR_CANCELLED;
+
+ uv_map_transform(C, op, center, rotmat);
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ uv_cylinder_project(tf->uv[0], efa->v1->co, center, rotmat);
+ uv_cylinder_project(tf->uv[1], efa->v2->co, center, rotmat);
+ uv_cylinder_project(tf->uv[2], efa->v3->co, center, rotmat);
+ if(efa->v4)
+ uv_cylinder_project(tf->uv[3], efa->v4->co, center, rotmat);
+
+ uv_map_mirror(efa, tf);
+ }
+ }
+
+ uv_map_clip_correct(em, op);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_cylinder_project(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Cylinder Projection";
+ ot->idname= "UV_OT_cylinder_project";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= cylinder_project_exec;
+ ot->poll= ED_operator_uvmap;
+
+ /* properties */
+ uv_transform_properties(ot, 1);
+ uv_map_clip_correct_properties(ot);
+}
+
+/******************* Cube Project operator ****************/
+
+static int cube_project_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+ EditFace *efa;
+ MTFace *tf;
+ float no[3], cube_size, *loc, dx, dy;
+ int cox, coy;
+
+ /* add uvs if they don't exist yet */
+ if(!ED_uvedit_ensure_uvs(C, scene, obedit))
+ return OPERATOR_CANCELLED;
+
+ loc= obedit->obmat[3];
+ cube_size= RNA_float_get(op->ptr, "cube_size");
+
+ /* choose x,y,z axis for projection depending on the largest normal
+ * component, but clusters all together around the center of map. */
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, no);
+
+ no[0]= fabs(no[0]);
+ no[1]= fabs(no[1]);
+ no[2]= fabs(no[2]);
+
+ cox=0; coy= 1;
+ if(no[2]>=no[0] && no[2]>=no[1]);
+ else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2;
+ else { cox= 1; coy= 2; }
+
+ tf->uv[0][0]= 0.5+0.5*cube_size*(loc[cox] + efa->v1->co[cox]);
+ tf->uv[0][1]= 0.5+0.5*cube_size*(loc[coy] + efa->v1->co[coy]);
+ dx = floor(tf->uv[0][0]);
+ dy = floor(tf->uv[0][1]);
+ tf->uv[0][0] -= dx;
+ tf->uv[0][1] -= dy;
+ tf->uv[1][0]= 0.5+0.5*cube_size*(loc[cox] + efa->v2->co[cox]);
+ tf->uv[1][1]= 0.5+0.5*cube_size*(loc[coy] + efa->v2->co[coy]);
+ tf->uv[1][0] -= dx;
+ tf->uv[1][1] -= dy;
+ tf->uv[2][0]= 0.5+0.5*cube_size*(loc[cox] + efa->v3->co[cox]);
+ tf->uv[2][1]= 0.5+0.5*cube_size*(loc[coy] + efa->v3->co[coy]);
+ tf->uv[2][0] -= dx;
+ tf->uv[2][1] -= dy;
+
+ if(efa->v4) {
+ tf->uv[3][0]= 0.5+0.5*cube_size*(loc[cox] + efa->v4->co[cox]);
+ tf->uv[3][1]= 0.5+0.5*cube_size*(loc[coy] + efa->v4->co[coy]);
+ tf->uv[3][0] -= dx;
+ tf->uv[3][1] -= dy;
+ }
+ }
+ }
+
+ uv_map_clip_correct(em, op);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_cube_project(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Cube Projection";
+ ot->idname= "UV_OT_cube_project";
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec= cube_project_exec;
+ ot->poll= ED_operator_uvmap;
+
+ /* properties */
+ 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);
+ uv_map_clip_correct_properties(ot);
+}
+
+/******************* Mapping Menu operator ****************/
+
+static int mapping_menu_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ uiMenuItem *head;
+
+ head= uiPupMenuBegin("UV Mapping", 0);
+ uiMenuItemO(head, 0, "UV_OT_unwrap");
+ uiMenuSeparator(head);
+ uiMenuItemO(head, 0, "UV_OT_cube_project");
+ uiMenuItemO(head, 0, "UV_OT_cylinder_project");
+ uiMenuItemO(head, 0, "UV_OT_sphere_project");
+ uiMenuItemO(head, 0, "UV_OT_project_from_view");
+ uiMenuSeparator(head);
+ uiMenuItemO(head, 0, "UV_OT_reset");
+ uiPupMenuEnd(C, head);
+
+ /* XXX python */
+#ifndef DISABLE_PYTHON
+#if 0
+ /* note that we account for the 10 previous entries with i+10: */
+ for(pym = BPyMenuTable[PYMENU_UVCALCULATION]; pym; pym = pym->next, i++) {
+
+ if(!has_pymenu) {
+ strcat(uvmenu, "|%l");
+ has_pymenu = 1;
+ }
+
+ strcat(uvmenu, "|");
+ strcat(uvmenu, pym->name);
+ strcat(uvmenu, " %x");
+ sprintf(menu_number, "%d", i+10);
+ strcat(uvmenu, menu_number);
+ }
+#endif
+#endif
+
+#ifndef DISABLE_PYTHON
+#if 0
+ mode= pupmenu(uvmenu);
+ if(mode >= 10) {
+ BPY_menu_do_python(PYMENU_UVCALCULATION, mode - 10);
+ return;
+ }
+#endif
+#endif
+
+ return OPERATOR_CANCELLED;
+}
+
+void UV_OT_mapping_menu(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mapping Menu";
+ ot->idname= "UV_OT_mapping_menu";
+
+ /* api callbacks */
+ ot->invoke= mapping_menu_invoke;
+ ot->poll= ED_operator_uvmap;
+}
+