Uv Tools branch GSOC 2011
========================= Documentation: http://wiki.blender.org/index.php/User:Psy-Fi/UV_Tools Major features include: *16 bit image support in viewport *Subsurf aware unwrapping *Smart Stitch(snap/rotate islands, preview, middlepoint/endpoint stitching) *Seams from islands tool (marks seams and sharp, depending on settings) *Uv Sculpting(Grab/Pinch/Rotate) All tools are complete apart from stitching that is considered stable but with an extra edge mode under development(will be in soc-2011-onion-uv-tools).
This commit is contained in:
parent
fcc54520d1
commit
a8081c1d2b
|
@ -70,6 +70,7 @@ KM_HIERARCHY = [
|
|||
('Image', 'IMAGE_EDITOR', 'WINDOW', [
|
||||
('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image
|
||||
('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
|
||||
('UV Sculpt', 'EMPTY', 'WINDOW', []),
|
||||
('Image Generic', 'IMAGE_EDITOR', 'WINDOW', [])
|
||||
]),
|
||||
|
||||
|
|
|
@ -52,7 +52,8 @@ class IMAGE_MT_view(Menu):
|
|||
layout.prop(sima, "use_realtime_update")
|
||||
if show_uvedit:
|
||||
layout.prop(toolsettings, "show_uv_local_view")
|
||||
layout.prop(uv, "show_other_objects")
|
||||
|
||||
layout.prop(uv, "show_other_objects")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -146,9 +147,11 @@ class IMAGE_MT_image(Menu):
|
|||
if ima.source in {'FILE', 'GENERATED'} and ima.type != 'OPEN_EXR_MULTILAYER':
|
||||
layout.operator("image.pack", text="Pack As PNG").as_png = True
|
||||
|
||||
layout.separator()
|
||||
if not context.tool_settings.use_uv_sculpt:
|
||||
layout.separator()
|
||||
layout.prop(sima, "use_image_paint")
|
||||
|
||||
layout.prop(sima, "use_image_paint")
|
||||
layout.separator()
|
||||
|
||||
|
||||
class IMAGE_MT_image_invert(Menu):
|
||||
|
@ -256,6 +259,10 @@ class IMAGE_MT_uvs(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.prop(toolsettings, "use_uv_sculpt")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.prop(uv, "use_live_unwrap")
|
||||
layout.operator("uv.unwrap")
|
||||
layout.operator("uv.pin", text="Unpin").clear = True
|
||||
|
@ -267,6 +274,8 @@ class IMAGE_MT_uvs(Menu):
|
|||
layout.operator("uv.average_islands_scale")
|
||||
layout.operator("uv.minimize_stretch")
|
||||
layout.operator("uv.stitch")
|
||||
layout.operator("uv.mark_seam")
|
||||
layout.operator("uv.seams_from_islands")
|
||||
layout.operator("mesh.faces_mirror_uv")
|
||||
|
||||
layout.separator()
|
||||
|
@ -753,5 +762,80 @@ class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
|
|||
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
|
||||
|
||||
class IMAGE_UV_sculpt_curve(bpy.types.Panel):
|
||||
bl_space_type = 'IMAGE_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
bl_label = "UV Sculpt Curve"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
sima = context.space_data
|
||||
toolsettings = context.tool_settings.image_paint
|
||||
return sima.show_uvedit and context.tool_settings.use_uv_sculpt and not (sima.show_paint and toolsettings.brush)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
toolsettings = context.tool_settings.uv_sculpt
|
||||
brush = toolsettings.brush
|
||||
|
||||
layout.template_curve_mapping(brush, "curve")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("brush.curve_preset", icon="SMOOTHCURVE", text="").shape = 'SMOOTH'
|
||||
row.operator("brush.curve_preset", icon="SPHERECURVE", text="").shape = 'ROUND'
|
||||
row.operator("brush.curve_preset", icon="ROOTCURVE", text="").shape = 'ROOT'
|
||||
row.operator("brush.curve_preset", icon="SHARPCURVE", text="").shape = 'SHARP'
|
||||
row.operator("brush.curve_preset", icon="LINCURVE", text="").shape = 'LINE'
|
||||
row.operator("brush.curve_preset", icon="NOCURVE", text="").shape = 'MAX'
|
||||
|
||||
|
||||
class IMAGE_UV_sculpt(bpy.types.Panel):
|
||||
bl_space_type = 'IMAGE_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
bl_label = "UV Sculpt"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
sima = context.space_data
|
||||
toolsettings = context.tool_settings.image_paint
|
||||
return sima.show_uvedit and context.tool_settings.use_uv_sculpt and not (sima.show_paint and toolsettings.brush)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
toolsettings = context.tool_settings.uv_sculpt
|
||||
brush = toolsettings.brush
|
||||
|
||||
if brush:
|
||||
col = layout.column()
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(brush, "size", slider=True)
|
||||
row.prop(brush, "use_pressure_size", toggle=True, text="")
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(brush, "strength", slider=True)
|
||||
row.prop(brush, "use_pressure_strength", toggle=True, text="")
|
||||
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
|
||||
col.prop(context.tool_settings, "uv_sculpt_lock_borders");
|
||||
col.prop(context.tool_settings, "uv_sculpt_all_islands");
|
||||
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
|
||||
col.prop(context.tool_settings, "uv_sculpt_tool");
|
||||
|
||||
if context.tool_settings.uv_sculpt_tool == 'RELAX':
|
||||
col.prop(context.tool_settings, "uv_relax_method");
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
bpy.utils.register_module(__name__)
|
||||
|
|
|
@ -425,6 +425,7 @@ class USERPREF_PT_system(Panel):
|
|||
col.label(text="OpenGL:")
|
||||
col.prop(system, "gl_clip_alpha", slider=True)
|
||||
col.prop(system, "use_mipmaps")
|
||||
col.prop(system, "use_16bit_textures")
|
||||
col.label(text="Anisotropic Filtering")
|
||||
col.prop(system, "anisotropic_filter", text="")
|
||||
col.prop(system, "use_vertex_buffer_objects")
|
||||
|
|
|
@ -52,7 +52,10 @@ struct CustomData;
|
|||
struct DerivedMesh;
|
||||
struct Scene;
|
||||
struct MLoopUV;
|
||||
|
||||
struct UvVertMap;
|
||||
struct UvMapVert;
|
||||
struct UvElementMap;
|
||||
struct UvElement;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -126,6 +129,39 @@ typedef struct UvMapVert {
|
|||
unsigned char tfindex, separate, flag;
|
||||
} UvMapVert;
|
||||
|
||||
typedef struct UvElementMap {
|
||||
/* address UvElements by their vertex */
|
||||
struct UvElement **vert;
|
||||
/* UvElement Store */
|
||||
struct UvElement *buf;
|
||||
/* Total number of UVs in the layer. Useful to know */
|
||||
int totalUVs;
|
||||
/* Number of Islands in the mesh */
|
||||
int totalIslands;
|
||||
/* Stores the starting index in buf where each island begins */
|
||||
int *islandIndices;
|
||||
} UvElementMap;
|
||||
|
||||
typedef struct UvElement {
|
||||
/* Next UvElement corresponding to same vertex */
|
||||
struct UvElement *next;
|
||||
/* Face the element belongs to */
|
||||
struct EditFace *face;
|
||||
/* Index in the editFace of the uv */
|
||||
unsigned char tfindex;
|
||||
/* Whether this element is the first of coincident elements */
|
||||
unsigned char separate;
|
||||
/* general use flag */
|
||||
unsigned char flag;
|
||||
/* If generating element map with island sorting, this stores the island index */
|
||||
unsigned short island;
|
||||
} UvElement;
|
||||
|
||||
/* invalid island index is max short. If any one has the patience
|
||||
* to make that many islands, he can bite me :p */
|
||||
#define INVALID_ISLAND 0xFFFF
|
||||
|
||||
|
||||
UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit);
|
||||
UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v);
|
||||
void free_uv_vert_map(UvVertMap *vmap);
|
||||
|
|
|
@ -66,6 +66,11 @@ Paint *paint_get_active(Scene *sce)
|
|||
return &ts->wpaint->paint;
|
||||
case OB_MODE_TEXTURE_PAINT:
|
||||
return &ts->imapaint.paint;
|
||||
case OB_MODE_EDIT:
|
||||
if(ts->use_uv_sculpt)
|
||||
return &ts->uvsculpt->paint;
|
||||
else
|
||||
return &ts->imapaint.paint;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -297,6 +297,10 @@ void free_scene(Scene *sce)
|
|||
free_paint(&sce->toolsettings->sculpt->paint);
|
||||
MEM_freeN(sce->toolsettings->sculpt);
|
||||
}
|
||||
if(sce->toolsettings->uvsculpt) {
|
||||
free_paint(&sce->toolsettings->uvsculpt->paint);
|
||||
MEM_freeN(sce->toolsettings->uvsculpt);
|
||||
}
|
||||
free_paint(&sce->toolsettings->imapaint.paint);
|
||||
|
||||
MEM_freeN(sce->toolsettings);
|
||||
|
|
|
@ -116,9 +116,10 @@ MINLINE void star_m3_v3(float rmat[3][3],float a[3]);
|
|||
|
||||
/*********************************** Length **********************************/
|
||||
|
||||
MINLINE float len_squared_v2(const float v[2]);
|
||||
MINLINE float len_v2(const float a[2]);
|
||||
MINLINE float len_v2v2(const float a[2], const float b[2]);
|
||||
MINLINE float len_squared_v2v2(const float a[3], const float b[3]);
|
||||
MINLINE float len_squared_v2v2(const float a[2], const float b[2]);
|
||||
MINLINE float len_v3(const float a[3]);
|
||||
MINLINE float len_v3v3(const float a[3], const float b[3]);
|
||||
MINLINE float len_squared_v3v3(const float a[3], const float b[3]);
|
||||
|
|
|
@ -429,6 +429,11 @@ MINLINE void star_m3_v3(float rmat[][3], float a[3])
|
|||
|
||||
/*********************************** Length **********************************/
|
||||
|
||||
MINLINE float len_squared_v2(const float v[2])
|
||||
{
|
||||
return v[0]*v[0] + v[1]*v[1];
|
||||
}
|
||||
|
||||
MINLINE float len_v2(const float v[2])
|
||||
{
|
||||
return (float)sqrtf(v[0]*v[0] + v[1]*v[1]);
|
||||
|
@ -448,7 +453,7 @@ MINLINE float len_v3(const float a[3])
|
|||
return sqrtf(dot_v3v3(a, a));
|
||||
}
|
||||
|
||||
MINLINE float len_squared_v2v2(const float a[3], const float b[3])
|
||||
MINLINE float len_squared_v2v2(const float a[2], const float b[2])
|
||||
{
|
||||
float d[2];
|
||||
|
||||
|
|
|
@ -4715,7 +4715,7 @@ static void lib_link_scene(FileData *fd, Main *main)
|
|||
link_paint(fd, sce, &sce->toolsettings->vpaint->paint);
|
||||
link_paint(fd, sce, &sce->toolsettings->wpaint->paint);
|
||||
link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
|
||||
|
||||
link_paint(fd, sce, &sce->toolsettings->uvsculpt->paint);
|
||||
sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
|
||||
|
||||
for(base= sce->base.first; base; base= next) {
|
||||
|
@ -4845,6 +4845,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
|
|||
direct_link_paint(fd, (Paint**)&sce->toolsettings->sculpt);
|
||||
direct_link_paint(fd, (Paint**)&sce->toolsettings->vpaint);
|
||||
direct_link_paint(fd, (Paint**)&sce->toolsettings->wpaint);
|
||||
direct_link_paint(fd, (Paint**)&sce->toolsettings->uvsculpt);
|
||||
|
||||
sce->toolsettings->imapaint.paintcursor= NULL;
|
||||
sce->toolsettings->particle.paintcursor= NULL;
|
||||
|
|
|
@ -1963,6 +1963,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
|
|||
if(tos->sculpt) {
|
||||
writestruct(wd, DATA, "Sculpt", 1, tos->sculpt);
|
||||
}
|
||||
if(tos->uvsculpt) {
|
||||
writestruct(wd, DATA, "UvSculpt", 1, tos->uvsculpt);
|
||||
}
|
||||
|
||||
// write_paint(wd, &tos->imapaint.paint);
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ void ED_space_image_zoom(struct SpaceImage *sima, struct ARegion *ar, float *zoo
|
|||
void ED_space_image_uv_aspect(struct SpaceImage *sima, float *aspx, float *aspy);
|
||||
|
||||
void ED_space_image_paint_update(struct wmWindowManager *wm, struct ToolSettings *settings);
|
||||
void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct ToolSettings *settings);
|
||||
|
||||
void ED_image_size(struct Image *ima, int *width, int *height);
|
||||
void ED_image_aspect(struct Image *ima, float *aspx, float *aspy);
|
||||
|
|
|
@ -155,6 +155,9 @@ struct UvVertMap *EM_make_uv_vert_map(struct EditMesh *em, int selected, int do_
|
|||
struct UvMapVert *EM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v);
|
||||
void EM_free_uv_vert_map(struct UvVertMap *vmap);
|
||||
|
||||
struct UvElementMap *EM_make_uv_element_map(struct EditMesh *em, int selected, int doIslands);
|
||||
void EM_free_uv_element_map(struct UvElementMap *vmap);
|
||||
|
||||
void EM_add_data_layer(struct EditMesh *em, struct CustomData *data, int type, const char *name);
|
||||
void EM_free_data_layer(struct EditMesh *em, struct CustomData *data, int type);
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ void ED_uvedit_live_unwrap_end(short cancel);
|
|||
void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
|
||||
|
||||
/* uvedit_draw.c */
|
||||
void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit);
|
||||
void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact);
|
||||
|
||||
/* uvedit_buttons.c */
|
||||
void ED_uvedit_buttons_register(struct ARegionType *art);
|
||||
|
|
|
@ -279,10 +279,10 @@ void ED_view3d_draw_offscreen(struct Scene *scene, struct View3D *v3d, struct AR
|
|||
int winx, int winy, float viewmat[][4], float winmat[][4]);
|
||||
|
||||
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag, char err_out[256]);
|
||||
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype, char err_out[256]);
|
||||
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype, char err_out[256]);
|
||||
|
||||
|
||||
Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
|
||||
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
|
||||
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, short do_clip);
|
||||
int ED_view3d_lock(struct RegionView3D *rv3d);
|
||||
|
||||
|
|
|
@ -255,7 +255,15 @@ enum {
|
|||
TH_PATH_BEFORE,
|
||||
TH_PATH_AFTER,
|
||||
TH_CAMERA_PATH,
|
||||
TH_LOCK_MARKER
|
||||
TH_LOCK_MARKER,
|
||||
|
||||
TH_STITCH_PREVIEW_FACE,
|
||||
TH_STITCH_PREVIEW_EDGE,
|
||||
TH_STITCH_PREVIEW_VERT,
|
||||
TH_STITCH_PREVIEW_STITCHABLE,
|
||||
TH_STITCH_PREVIEW_UNSTITCHABLE,
|
||||
TH_STITCH_PREVIEW_ACTIVE
|
||||
|
||||
};
|
||||
/* XXX WARNING: previous is saved in file, so do not change order! */
|
||||
|
||||
|
|
|
@ -410,6 +410,28 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
|
|||
cp= ts->preview_back;
|
||||
break;
|
||||
|
||||
case TH_STITCH_PREVIEW_FACE:
|
||||
cp = ts->preview_stitch_face;
|
||||
break;
|
||||
|
||||
case TH_STITCH_PREVIEW_EDGE:
|
||||
cp = ts->preview_stitch_edge;
|
||||
break;
|
||||
|
||||
case TH_STITCH_PREVIEW_VERT:
|
||||
cp = ts->preview_stitch_vert;
|
||||
break;
|
||||
|
||||
case TH_STITCH_PREVIEW_STITCHABLE:
|
||||
cp = ts->preview_stitch_stitchable;
|
||||
break;
|
||||
|
||||
case TH_STITCH_PREVIEW_UNSTITCHABLE:
|
||||
cp = ts->preview_stitch_unstitchable;
|
||||
break;
|
||||
case TH_STITCH_PREVIEW_ACTIVE:
|
||||
cp = ts->preview_stitch_active;
|
||||
break;
|
||||
case TH_MARKER_OUTLINE:
|
||||
cp= ts->marker_outline; break;
|
||||
case TH_MARKER:
|
||||
|
@ -746,6 +768,11 @@ void ui_theme_init_default(void)
|
|||
SETCOL(btheme->tima.face_select, 255, 133, 0, 60);
|
||||
SETCOL(btheme->tima.editmesh_active, 255, 255, 255, 128);
|
||||
SETCOLF(btheme->tima.preview_back, 0.45, 0.45, 0.45, 1.0);
|
||||
SETCOLF(btheme->tima.preview_stitch_face, 0.5, 0.5, 0.0, 0.2);
|
||||
SETCOLF(btheme->tima.preview_stitch_edge, 1.0, 0.0, 1.0, 0.2);
|
||||
SETCOLF(btheme->tima.preview_stitch_vert, 0.0, 0.0, 1.0, 0.2);
|
||||
SETCOLF(btheme->tima.preview_stitch_stitchable, 0.0, 1.0, 0.0, 1.0);
|
||||
SETCOLF(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0);
|
||||
|
||||
/* space text */
|
||||
btheme->text= btheme->tv3d;
|
||||
|
@ -1679,6 +1706,19 @@ void init_userdef_do_versions(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (bmain->versionfile < 262){
|
||||
bTheme *btheme;
|
||||
for(btheme= U.themes.first; btheme; btheme= btheme->next) {
|
||||
SETCOLF(btheme->tima.preview_stitch_face, 0.071, 0.259, 0.694, 0.150);
|
||||
SETCOLF(btheme->tima.preview_stitch_edge, 1.0, 0.522, 0.0, 0.7);
|
||||
SETCOLF(btheme->tima.preview_stitch_vert, 1.0, 0.522, 0.0, 0.5);
|
||||
SETCOLF(btheme->tima.preview_stitch_stitchable, 0.0, 1.0, 0.0, 1.0);
|
||||
SETCOLF(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0);
|
||||
SETCOLF(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140);
|
||||
}
|
||||
U.use_16bit_textures = 0;
|
||||
}
|
||||
|
||||
/* GL Texture Garbage Collection (variable abused above!) */
|
||||
if (U.textimeout == 0) {
|
||||
U.texcollectrate = 60;
|
||||
|
|
|
@ -2322,7 +2322,7 @@ UvVertMap *EM_make_uv_vert_map(EditMesh *em, int selected, int do_face_idx_array
|
|||
for(a=0, ev=em->verts.first; ev; a++, ev= ev->next) {
|
||||
UvMapVert *newvlist= NULL, *vlist=vmap->vert[a];
|
||||
UvMapVert *iterv, *v, *lastv, *next;
|
||||
float *uv, *uv2, uvdiff[2];
|
||||
float *uv, *uv2;
|
||||
|
||||
while(vlist) {
|
||||
v= vlist;
|
||||
|
@ -2332,8 +2332,8 @@ UvVertMap *EM_make_uv_vert_map(EditMesh *em, int selected, int do_face_idx_array
|
|||
|
||||
efa = EM_get_face_for_index(v->f);
|
||||
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
uv = tf->uv[v->tfindex];
|
||||
|
||||
uv = tf->uv[v->tfindex];
|
||||
|
||||
lastv= NULL;
|
||||
iterv= vlist;
|
||||
|
||||
|
@ -2342,8 +2342,6 @@ UvVertMap *EM_make_uv_vert_map(EditMesh *em, int selected, int do_face_idx_array
|
|||
efa = EM_get_face_for_index(iterv->f);
|
||||
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
uv2 = tf->uv[iterv->tfindex];
|
||||
|
||||
sub_v2_v2v2(uvdiff, uv2, uv);
|
||||
|
||||
if(fabsf(uv[0]-uv2[0]) < limit[0] && fabsf(uv[1]-uv2[1]) < limit[1]) {
|
||||
if(lastv) lastv->next= next;
|
||||
|
@ -2353,22 +2351,224 @@ UvVertMap *EM_make_uv_vert_map(EditMesh *em, int selected, int do_face_idx_array
|
|||
}
|
||||
else
|
||||
lastv=iterv;
|
||||
|
||||
iterv= next;
|
||||
}
|
||||
newvlist->separate = 1;
|
||||
}
|
||||
vmap->vert[a]= newvlist;
|
||||
}
|
||||
|
||||
|
||||
if (do_face_idx_array)
|
||||
EM_free_index_arrays();
|
||||
|
||||
return vmap;
|
||||
}
|
||||
|
||||
/* A specialized vert map used by stitch operator */
|
||||
UvElementMap *EM_make_uv_element_map(EditMesh *em, int selected, int do_islands)
|
||||
{
|
||||
EditVert *ev;
|
||||
EditFace *efa;
|
||||
|
||||
/* vars from original func */
|
||||
UvElementMap *vmap;
|
||||
UvElement *buf;
|
||||
UvElement *islandbuf;
|
||||
MTFace *tf;
|
||||
unsigned int a;
|
||||
int i,j, totuv, nverts, nislands = 0, islandbufsize = 0;
|
||||
unsigned int *map;
|
||||
/* for uv island creation */
|
||||
EditFace **stack;
|
||||
int stacksize = 0;
|
||||
|
||||
/* we need the vert */
|
||||
for(ev = em->verts.first, i = 0; ev; ev = ev->next, i++)
|
||||
ev->tmp.l = i;
|
||||
|
||||
totuv = 0;
|
||||
|
||||
for(efa = em->faces.first; efa; efa = efa->next)
|
||||
if(!selected || ((!efa->h) && (efa->f & SELECT)))
|
||||
totuv += (efa->v4)? 4: 3;
|
||||
|
||||
if(totuv == 0)
|
||||
return NULL;
|
||||
|
||||
vmap = (UvElementMap *)MEM_callocN(sizeof(*vmap), "UvVertElementMap");
|
||||
if(!vmap)
|
||||
return NULL;
|
||||
|
||||
vmap->vert = (UvElement**)MEM_callocN(sizeof(*vmap->vert)*em->totvert, "UvElementVerts");
|
||||
buf = vmap->buf = (UvElement*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvElement");
|
||||
|
||||
if(!vmap->vert || !vmap->buf) {
|
||||
EM_free_uv_element_map(vmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vmap->totalUVs = totuv;
|
||||
|
||||
for(efa = em->faces.first; efa; a++, efa = efa->next) {
|
||||
if(!selected || ((!efa->h) && (efa->f & SELECT))) {
|
||||
nverts = (efa->v4)? 4: 3;
|
||||
|
||||
for(i = 0; i<nverts; i++) {
|
||||
buf->tfindex = i;
|
||||
buf->face = efa;
|
||||
buf->separate = 0;
|
||||
buf->island = INVALID_ISLAND;
|
||||
|
||||
buf->next = vmap->vert[(*(&efa->v1 + i))->tmp.l];
|
||||
vmap->vert[(*(&efa->v1 + i))->tmp.l] = buf;
|
||||
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
efa->tmp.l = INVALID_ISLAND;
|
||||
}
|
||||
|
||||
/* sort individual uvs for each vert */
|
||||
for(a = 0, ev = em->verts.first; ev; a++, ev = ev->next) {
|
||||
UvElement *newvlist = NULL, *vlist = vmap->vert[a];
|
||||
UvElement *iterv, *v, *lastv, *next;
|
||||
float *uv, *uv2;
|
||||
|
||||
while(vlist) {
|
||||
v= vlist;
|
||||
vlist= vlist->next;
|
||||
v->next= newvlist;
|
||||
newvlist= v;
|
||||
|
||||
efa = v->face;
|
||||
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
uv = tf->uv[v->tfindex];
|
||||
|
||||
lastv= NULL;
|
||||
iterv= vlist;
|
||||
|
||||
while(iterv) {
|
||||
next= iterv->next;
|
||||
efa = iterv->face;
|
||||
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
uv2 = tf->uv[iterv->tfindex];
|
||||
|
||||
if(fabsf(uv[0]-uv2[0]) < STD_UV_CONNECT_LIMIT && fabsf(uv[1]-uv2[1]) < STD_UV_CONNECT_LIMIT) {
|
||||
if(lastv) lastv->next = next;
|
||||
else vlist = next;
|
||||
iterv->next = newvlist;
|
||||
newvlist = iterv;
|
||||
}
|
||||
else
|
||||
lastv = iterv;
|
||||
|
||||
iterv = next;
|
||||
}
|
||||
|
||||
newvlist->separate = 1;
|
||||
}
|
||||
|
||||
vmap->vert[a]= newvlist;
|
||||
vmap->vert[a] = newvlist;
|
||||
}
|
||||
|
||||
if (do_face_idx_array)
|
||||
EM_free_index_arrays();
|
||||
|
||||
|
||||
if(do_islands) {
|
||||
/* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */
|
||||
|
||||
/* map holds the map from current vmap->buf to the new, sorted map*/
|
||||
map = MEM_mallocN(sizeof(*map)*totuv, "uvelement_remap");
|
||||
stack = MEM_mallocN(sizeof(*stack)*em->totface, "uv_island_face_stack");
|
||||
islandbuf = MEM_callocN(sizeof(*islandbuf)*totuv, "uvelement_island_buffer");
|
||||
|
||||
for(i = 0; i < totuv; i++) {
|
||||
if(vmap->buf[i].island == INVALID_ISLAND) {
|
||||
vmap->buf[i].island = nislands;
|
||||
stack[0] = vmap->buf[i].face;
|
||||
stack[0]->tmp.l = nislands;
|
||||
stacksize=1;
|
||||
|
||||
while(stacksize > 0) {
|
||||
efa = stack[--stacksize];
|
||||
nverts = efa->v4? 4 : 3;
|
||||
|
||||
for(j = 0; j < nverts; j++) {
|
||||
UvElement *element, *initelement = vmap->vert[(*(&efa->v1 + j))->tmp.l];
|
||||
|
||||
for(element = initelement; element; element = element->next) {
|
||||
if(element->separate)
|
||||
initelement = element;
|
||||
|
||||
if(element->face == efa) {
|
||||
/* found the uv corresponding to our face and vertex. Now fill it to the buffer */
|
||||
element->island = nislands;
|
||||
map[element - vmap->buf] = islandbufsize;
|
||||
islandbuf[islandbufsize].tfindex = element->tfindex;
|
||||
islandbuf[islandbufsize].face = element->face;
|
||||
islandbuf[islandbufsize].separate = element->separate;
|
||||
islandbuf[islandbufsize].island = nislands;
|
||||
islandbufsize++;
|
||||
|
||||
for(element = initelement; element; element = element->next) {
|
||||
if(element->separate && element != initelement)
|
||||
break;
|
||||
|
||||
if(element->face->tmp.l == INVALID_ISLAND) {
|
||||
stack[stacksize++] = element->face;
|
||||
element->face->tmp.l = nislands;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nislands++;
|
||||
}
|
||||
}
|
||||
|
||||
/* remap */
|
||||
for(i = 0; i < em->totvert; i++) {
|
||||
/* important since we may do selection only. Some of these may be NULL */
|
||||
if(vmap->vert[i])
|
||||
vmap->vert[i] = &islandbuf[map[vmap->vert[i] - vmap->buf]];
|
||||
}
|
||||
|
||||
vmap->islandIndices = MEM_callocN(sizeof(*vmap->islandIndices)*nislands,"UvVertMap2_island_indices");
|
||||
if(!vmap->islandIndices) {
|
||||
MEM_freeN(islandbuf);
|
||||
MEM_freeN(stack);
|
||||
MEM_freeN(map);
|
||||
EM_free_uv_element_map(vmap);
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for(i = 0; i < totuv; i++) {
|
||||
UvElement *element = vmap->buf[i].next;
|
||||
if(element == NULL)
|
||||
islandbuf[map[i]].next = NULL;
|
||||
else
|
||||
islandbuf[map[i]].next = &islandbuf[map[element - vmap->buf]];
|
||||
|
||||
if(islandbuf[i].island != j) {
|
||||
j++;
|
||||
vmap->islandIndices[j] = i;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(vmap->buf);
|
||||
|
||||
vmap->buf = islandbuf;
|
||||
vmap->totalIslands = nislands;
|
||||
MEM_freeN(stack);
|
||||
MEM_freeN(map);
|
||||
}
|
||||
|
||||
return vmap;
|
||||
}
|
||||
|
||||
|
||||
UvMapVert *EM_get_uv_map_vert(UvVertMap *vmap, unsigned int v)
|
||||
{
|
||||
return vmap->vert[v];
|
||||
|
@ -2383,6 +2583,16 @@ void EM_free_uv_vert_map(UvVertMap *vmap)
|
|||
}
|
||||
}
|
||||
|
||||
void EM_free_uv_element_map(UvElementMap *vmap)
|
||||
{
|
||||
if (vmap) {
|
||||
if (vmap->vert) MEM_freeN(vmap->vert);
|
||||
if (vmap->buf) MEM_freeN(vmap->buf);
|
||||
if (vmap->islandIndices) MEM_freeN(vmap->islandIndices);
|
||||
MEM_freeN(vmap);
|
||||
}
|
||||
}
|
||||
|
||||
/* poll call for mesh operators requiring a view3d context */
|
||||
int EM_view3d_poll(bContext *C)
|
||||
{
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
#include "ED_object.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_util.h"
|
||||
|
||||
#include "ED_image.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
|
@ -513,11 +513,15 @@ void ED_object_enter_editmode(bContext *C, int flag)
|
|||
|
||||
static int editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
ToolSettings *toolsettings = CTX_data_tool_settings(C);
|
||||
|
||||
if(!CTX_data_edit_object(C))
|
||||
ED_object_enter_editmode(C, EM_WAITCURSOR);
|
||||
else
|
||||
ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */
|
||||
|
||||
ED_space_image_uv_sculpt_update(CTX_wm_manager(C), toolsettings);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ set(INC
|
|||
../../imbuf
|
||||
../../makesdna
|
||||
../../makesrna
|
||||
../uvedit
|
||||
../../render/extern/include
|
||||
../../windowmanager
|
||||
../../../../intern/guardedalloc
|
||||
|
@ -45,6 +46,7 @@ set(SRC
|
|||
paint_vertex.c
|
||||
sculpt.c
|
||||
sculpt_undo.c
|
||||
sculpt_uv.c
|
||||
|
||||
paint_intern.h
|
||||
sculpt_intern.h
|
||||
|
|
|
@ -8,7 +8,7 @@ defs = []
|
|||
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
|
||||
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
|
||||
incs += ' ../../render/extern/include'
|
||||
incs += ' ../../gpu ../../makesrna ../../blenloader'
|
||||
incs += ' ../../gpu ../../makesrna ../../blenloader ../uvedit'
|
||||
|
||||
if env['OURPLATFORM'] == 'linux':
|
||||
cflags='-pthread'
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "BLI_memarena.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_editVert.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
|
@ -80,6 +81,8 @@
|
|||
#include "BKE_paint.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_deform.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
#include "BIF_glutil.h"
|
||||
|
@ -91,6 +94,7 @@
|
|||
#include "ED_sculpt.h"
|
||||
#include "ED_uvedit.h"
|
||||
#include "ED_view3d.h"
|
||||
#include "ED_mesh.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
@ -100,6 +104,7 @@
|
|||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_extensions.h"
|
||||
|
||||
#include "paint_intern.h"
|
||||
|
||||
|
@ -3742,15 +3747,13 @@ static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, floa
|
|||
|
||||
static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2])
|
||||
{
|
||||
unsigned char rgba_ub[4];
|
||||
unsigned char rgba_smear[4];
|
||||
float rgba[4];
|
||||
|
||||
if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0)
|
||||
if (project_paint_PickColor(ps, co, rgba, NULL, 1)==0)
|
||||
return;
|
||||
|
||||
IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_smear, projPixel->pixel.f_pt);
|
||||
/* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
|
||||
blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, rgba_smear, (rgba_ub), (int)(alpha*mask*255));
|
||||
blend_color_mix_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, alpha*mask);
|
||||
BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
|
||||
}
|
||||
|
||||
|
@ -3782,8 +3785,8 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, flo
|
|||
{
|
||||
if (ps->is_texbrush) {
|
||||
/* rgba already holds a texture result here from higher level function */
|
||||
float rgba_br[3];
|
||||
if(use_color_correction){
|
||||
float rgba_br[3];
|
||||
srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb);
|
||||
mul_v3_v3(rgba, rgba_br);
|
||||
}
|
||||
|
@ -3999,7 +4002,7 @@ static void *do_projectpaint_thread(void *ph_v)
|
|||
|
||||
for (node= smearPixels_f; node; node= node->next) {
|
||||
projPixel = node->link;
|
||||
IMAPAINT_CHAR_RGBA_TO_FLOAT(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.ch);
|
||||
copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f);
|
||||
}
|
||||
|
||||
BLI_memarena_free(smearArena);
|
||||
|
@ -4167,7 +4170,8 @@ static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s
|
|||
if(texpaint || (sima && sima->lock)) {
|
||||
int w = imapaintpartial.x2 - imapaintpartial.x1;
|
||||
int h = imapaintpartial.y2 - imapaintpartial.y1;
|
||||
GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h, !texpaint);
|
||||
/* Testing with partial update in uv editor too */
|
||||
GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h, 0);//!texpaint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4606,6 +4610,16 @@ static Brush *image_paint_brush(bContext *C)
|
|||
return paint_brush(&settings->imapaint.paint);
|
||||
}
|
||||
|
||||
static Brush *uv_sculpt_brush(bContext *C)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
ToolSettings *settings= scene->toolsettings;
|
||||
|
||||
if(!settings->uvsculpt)
|
||||
return NULL;
|
||||
return paint_brush(&settings->uvsculpt->paint);
|
||||
}
|
||||
|
||||
static int image_paint_poll(bContext *C)
|
||||
{
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
|
@ -4630,6 +4644,30 @@ static int image_paint_poll(bContext *C)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int uv_sculpt_brush_poll(bContext *C)
|
||||
{
|
||||
EditMesh *em;
|
||||
int ret;
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
SpaceImage *sima= CTX_wm_space_image(C);
|
||||
ToolSettings *toolsettings = CTX_data_scene(C)->toolsettings;
|
||||
|
||||
if(!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH)
|
||||
return 0;
|
||||
|
||||
em = BKE_mesh_get_editmesh(obedit->data);
|
||||
ret = EM_texFaceCheck(em);
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
|
||||
if(ret && sima) {
|
||||
ARegion *ar= CTX_wm_region(C);
|
||||
if((toolsettings->use_uv_sculpt) && ar->regiontype==RGN_TYPE_WINDOW)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int image_paint_3d_poll(bContext *C)
|
||||
{
|
||||
if(CTX_wm_region_view3d(C))
|
||||
|
@ -5086,7 +5124,7 @@ void PAINT_OT_image_paint(wmOperatorType *ot)
|
|||
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
|
||||
}
|
||||
|
||||
static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
|
||||
int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
|
||||
{
|
||||
RegionView3D *rv3d= CTX_wm_region_view3d(C);
|
||||
|
||||
|
@ -5112,16 +5150,27 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)
|
|||
#define PX_SIZE_FADE_MIN 4.0f
|
||||
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Brush *brush= image_paint_brush(C);
|
||||
//Brush *brush= image_paint_brush(C);
|
||||
Paint *paint= paint_get_active(scene);
|
||||
Brush *brush= paint_brush(paint);
|
||||
|
||||
if(paint && brush && paint->flags & PAINT_SHOW_BRUSH) {
|
||||
ToolSettings *ts;
|
||||
float zoomx, zoomy;
|
||||
const float size= (float)brush_size(scene, brush);
|
||||
const short use_zoom= get_imapaint_zoom(C, &zoomx, &zoomy);
|
||||
const float pixel_size= MAX2(size * zoomx, size * zoomy);
|
||||
float pixel_size;
|
||||
float alpha= 0.5f;
|
||||
|
||||
ts = CTX_data_scene(C)->toolsettings;
|
||||
|
||||
if(use_zoom && !ts->use_uv_sculpt){
|
||||
pixel_size = MAX2(size * zoomx, size * zoomy);
|
||||
}
|
||||
else {
|
||||
pixel_size = size;
|
||||
}
|
||||
|
||||
/* fade out the brush (cheap trick to work around brush interfearing with sampling [#])*/
|
||||
if(pixel_size < PX_SIZE_FADE_MIN) {
|
||||
return;
|
||||
|
@ -5134,7 +5183,8 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)
|
|||
|
||||
glTranslatef((float)x, (float)y, 0.0f);
|
||||
|
||||
if(use_zoom)
|
||||
/* No need to scale for uv sculpting, on the contrary it might be useful to keep unscaled */
|
||||
if(use_zoom && !ts->use_uv_sculpt)
|
||||
glScalef(zoomx, zoomy, 1.0f);
|
||||
|
||||
glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], alpha);
|
||||
|
@ -5178,6 +5228,27 @@ void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings)
|
||||
{
|
||||
if(settings->use_uv_sculpt) {
|
||||
if(!settings->uvsculpt) {
|
||||
settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint");
|
||||
settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB;
|
||||
settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS;
|
||||
settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
|
||||
}
|
||||
|
||||
paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT);
|
||||
|
||||
WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
|
||||
brush_drawcursor, NULL);
|
||||
}
|
||||
else {
|
||||
if(settings->uvsculpt)
|
||||
settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH;
|
||||
}
|
||||
}
|
||||
/************************ grab clone operator ************************/
|
||||
|
||||
typedef struct GrabClone {
|
||||
|
@ -5499,6 +5570,11 @@ int image_texture_paint_poll(bContext *C)
|
|||
return (texture_paint_poll(C) || image_paint_poll(C));
|
||||
}
|
||||
|
||||
int uv_sculpt_poll(bContext *C)
|
||||
{
|
||||
return uv_sculpt_brush_poll(C);
|
||||
}
|
||||
|
||||
int facemask_paint_poll(bContext *C)
|
||||
{
|
||||
return paint_facesel_test(CTX_data_active_object(C));
|
||||
|
|
|
@ -103,6 +103,10 @@ void PAINT_OT_texture_paint_toggle(struct wmOperatorType *ot);
|
|||
void PAINT_OT_project_image(struct wmOperatorType *ot);
|
||||
void PAINT_OT_image_from_view(struct wmOperatorType *ot);
|
||||
|
||||
/* uv sculpting */
|
||||
int uv_sculpt_poll(struct bContext *C);
|
||||
|
||||
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
|
||||
|
||||
/* paint_utils.c */
|
||||
|
||||
|
|
|
@ -340,6 +340,39 @@ static void BRUSH_OT_image_tool_set(wmOperatorType *ot)
|
|||
}
|
||||
|
||||
|
||||
static int brush_uv_sculpt_tool_set_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Brush *brush;
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
ts->uv_sculpt_tool = RNA_enum_get(op->ptr, "tool");
|
||||
brush = ts->uvsculpt->paint.brush;
|
||||
/* To update toolshelf */
|
||||
WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void BRUSH_OT_uv_sculpt_tool_set(wmOperatorType *ot)
|
||||
{
|
||||
/* from rna_scene.c */
|
||||
extern EnumPropertyItem uv_sculpt_tool_items[];
|
||||
/* identifiers */
|
||||
ot->name = "UV Sculpt Tool Set";
|
||||
ot->description = "Set the uv sculpt tool";
|
||||
ot->idname = "BRUSH_OT_uv_sculpt_tool_set";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = brush_uv_sculpt_tool_set_exec;
|
||||
ot->poll = uv_sculpt_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
|
||||
/* props */
|
||||
ot->prop = RNA_def_enum(ot->srna, "tool", uv_sculpt_tool_items, 0, "Tool", "");
|
||||
}
|
||||
|
||||
/**************************** registration **********************************/
|
||||
|
||||
void ED_operatortypes_paint(void)
|
||||
|
@ -355,6 +388,7 @@ void ED_operatortypes_paint(void)
|
|||
WM_operatortype_append(BRUSH_OT_vertex_tool_set);
|
||||
WM_operatortype_append(BRUSH_OT_weight_tool_set);
|
||||
WM_operatortype_append(BRUSH_OT_image_tool_set);
|
||||
WM_operatortype_append(BRUSH_OT_uv_sculpt_tool_set);
|
||||
|
||||
/* image */
|
||||
WM_operatortype_append(PAINT_OT_texture_paint_toggle);
|
||||
|
@ -373,6 +407,9 @@ void ED_operatortypes_paint(void)
|
|||
WM_operatortype_append(PAINT_OT_weight_sample);
|
||||
WM_operatortype_append(PAINT_OT_weight_sample_group);
|
||||
|
||||
/* uv */
|
||||
WM_operatortype_append(SCULPT_OT_uv_sculpt_stroke);
|
||||
|
||||
/* vertex selection */
|
||||
WM_operatortype_append(PAINT_OT_vert_select_all);
|
||||
WM_operatortype_append(PAINT_OT_vert_select_inverse);
|
||||
|
@ -619,4 +656,22 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
|
|||
|
||||
WM_keymap_add_item(keymap, "PAINT_OT_face_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
|
||||
WM_keymap_add_item(keymap, "PAINT_OT_face_select_linked_pick", LKEY, KM_PRESS, 0, 0);
|
||||
|
||||
keymap= WM_keymap_find(keyconf, "UV Sculpt", 0, 0);
|
||||
keymap->poll= uv_sculpt_poll;
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0);
|
||||
RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_uv_sculpt");
|
||||
|
||||
WM_keymap_add_item(keymap, "SCULPT_OT_uv_sculpt_stroke", LEFTMOUSE, KM_PRESS, 0, 0);
|
||||
RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_uv_sculpt_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
|
||||
RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_uv_sculpt_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "temp_relax", 1);
|
||||
|
||||
ed_keymap_paint_brush_size(keymap, "tool_settings.uv_sculpt.brush.size");
|
||||
ed_keymap_paint_brush_radial_control(keymap, "uv_sculpt", 0);
|
||||
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "BRUSH_OT_uv_sculpt_tool_set", SKEY, KM_PRESS, 0, 0)->ptr, "tool", UV_SCULPT_TOOL_RELAX);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "BRUSH_OT_uv_sculpt_tool_set", PKEY, KM_PRESS, 0, 0)->ptr, "tool", UV_SCULPT_TOOL_PINCH);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "BRUSH_OT_uv_sculpt_tool_set", GKEY, KM_PRESS, 0, 0)->ptr, "tool", UV_SCULPT_TOOL_GRAB);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,769 @@
|
|||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) Blender Foundation, 2002-2009
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Antony Riakiotakis
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
* UV Sculpt tools
|
||||
*
|
||||
*/
|
||||
|
||||
/** \file blender/editors/sculpt_paint/sculpt_uv.c
|
||||
* \ingroup edsculpt
|
||||
*/
|
||||
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_editVert.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_ghash.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_brush.h"
|
||||
#include "BKE_paint.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_customdata.h"
|
||||
|
||||
#include "ED_screen.h"
|
||||
#include "ED_image.h"
|
||||
#include "ED_mesh.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "paint_intern.h"
|
||||
#include "uvedit_intern.h"
|
||||
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#define MARK_BOUNDARY 1
|
||||
|
||||
typedef struct UvAdjacencyElement {
|
||||
/* pointer to original uvelement */
|
||||
UvElement *element;
|
||||
/* uv pointer for convenience. Caution, this points to the original UVs! */
|
||||
float *uv;
|
||||
/* general use flag (Used to check if Element is boundary here) */
|
||||
char flag;
|
||||
} UvAdjacencyElement;
|
||||
|
||||
typedef struct UvEdge {
|
||||
unsigned int uv1;
|
||||
unsigned int uv2;
|
||||
/* general use flag (Used to check if edge is boundary here, and propagates to adjacency elements) */
|
||||
char flag;
|
||||
}UvEdge;
|
||||
|
||||
typedef struct UVInitialStrokeElement{
|
||||
/* index to unique uv */
|
||||
int uv;
|
||||
|
||||
/* strength of brush on initial position */
|
||||
float strength;
|
||||
|
||||
/* initial uv position */
|
||||
float initial_uv[2];
|
||||
}UVInitialStrokeElement;
|
||||
|
||||
typedef struct UVInitialStroke{
|
||||
/* Initial Selection,for grab brushes for instance */
|
||||
UVInitialStrokeElement *initialSelection;
|
||||
|
||||
/* total initially selected UVs*/
|
||||
int totalInitialSelected;
|
||||
|
||||
/* initial mouse coordinates */
|
||||
float init_coord[2];
|
||||
}UVInitialStroke;
|
||||
|
||||
|
||||
/* custom data for uv smoothing brush */
|
||||
typedef struct UvSculptData{
|
||||
/* Contains the first of each set of coincident uvs.
|
||||
* These will be used to perform smoothing on and propagate the changes
|
||||
* to their coincident uvs */
|
||||
UvAdjacencyElement *uv;
|
||||
|
||||
/* ...Is what it says */
|
||||
int totalUniqueUvs;
|
||||
|
||||
/* Edges used for adjacency info, used with laplacian smoothing */
|
||||
UvEdge *uvedges;
|
||||
|
||||
/* Need I say more? */
|
||||
int totalUvEdges;
|
||||
|
||||
/* data for initial stroke, used by tools like grab */
|
||||
UVInitialStroke *initial_stroke;
|
||||
|
||||
/* Timer to be used for airbrush-type brush */
|
||||
wmTimer *timer;
|
||||
|
||||
/* To determine quickly adjacent uvs */
|
||||
UvElementMap *elementMap;
|
||||
|
||||
/* uvsmooth Paint for fast reference */
|
||||
Paint *uvsculpt;
|
||||
}UvSculptData;
|
||||
|
||||
/*********** Improved Laplacian Relaxation Operator ************************/
|
||||
/* Original code by Raul Fernandez Hernandez "farsthary" *
|
||||
* adapted to uv smoothing by Antony Riakiatakis *
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct Temp_UvData{
|
||||
float sum_co[2], p[2], b[2], sum_b[2];
|
||||
int ncounter;
|
||||
}Temp_UVData;
|
||||
|
||||
|
||||
|
||||
void HC_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio){
|
||||
Temp_UVData *tmp_uvdata;
|
||||
float diff[2];
|
||||
int i;
|
||||
float radius_root = sqrt(radius);
|
||||
Brush *brush = paint_brush(sculptdata->uvsculpt);
|
||||
|
||||
tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
|
||||
|
||||
/* counting neighbors */
|
||||
for (i = 0; i < sculptdata->totalUvEdges; i++){
|
||||
UvEdge *tmpedge = sculptdata->uvedges+i;
|
||||
tmp_uvdata[tmpedge->uv1].ncounter++;
|
||||
tmp_uvdata[tmpedge->uv2].ncounter++;
|
||||
|
||||
add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
|
||||
add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
|
||||
}
|
||||
|
||||
for (i = 0; i < sculptdata->totalUniqueUvs; i++){
|
||||
copy_v2_v2(diff,tmp_uvdata[i].sum_co);
|
||||
mul_v2_fl(diff,1.f/tmp_uvdata[i].ncounter);
|
||||
copy_v2_v2(tmp_uvdata[i].p,diff);
|
||||
|
||||
tmp_uvdata[i].b[0] = diff[0] - sculptdata->uv[i].uv[0];
|
||||
tmp_uvdata[i].b[1] = diff[1] - sculptdata->uv[i].uv[1];
|
||||
}
|
||||
|
||||
for (i = 0; i < sculptdata->totalUvEdges; i++){
|
||||
UvEdge *tmpedge = sculptdata->uvedges+i;
|
||||
add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_b, tmp_uvdata[tmpedge->uv2].b);
|
||||
add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_b, tmp_uvdata[tmpedge->uv1].b);
|
||||
}
|
||||
|
||||
for (i = 0; i < sculptdata->totalUniqueUvs; i++){
|
||||
float dist;
|
||||
/* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
|
||||
* If ever uv brushes get their own mode we should check for toolsettings option too */
|
||||
if((sculptdata->uv[i].flag & MARK_BOUNDARY)){
|
||||
continue;
|
||||
}
|
||||
|
||||
sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
|
||||
diff[1] /= aspectRatio;
|
||||
if((dist = dot_v2v2(diff, diff)) <= radius){
|
||||
UvElement *element;
|
||||
float strength;
|
||||
strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
|
||||
|
||||
sculptdata->uv[i].uv[0] = (1.0-strength)*sculptdata->uv[i].uv[0] + strength*(tmp_uvdata[i].p[0] - 0.5f*(tmp_uvdata[i].b[0] + tmp_uvdata[i].sum_b[0]/tmp_uvdata[i].ncounter));
|
||||
sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*(tmp_uvdata[i].p[1] - 0.5f*(tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1]/tmp_uvdata[i].ncounter));
|
||||
|
||||
for(element = sculptdata->uv[i].element; element; element = element->next){
|
||||
MTFace *mt;
|
||||
if(element->separate && element != sculptdata->uv[i].element)
|
||||
break;
|
||||
mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
|
||||
copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(tmp_uvdata);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void laplacian_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio)
|
||||
{
|
||||
Temp_UVData *tmp_uvdata;
|
||||
float diff[2];
|
||||
int i;
|
||||
float radius_root = sqrt(radius);
|
||||
Brush *brush = paint_brush(sculptdata->uvsculpt);
|
||||
|
||||
tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
|
||||
|
||||
/* counting neighbors */
|
||||
for (i = 0; i < sculptdata->totalUvEdges; i++){
|
||||
UvEdge *tmpedge = sculptdata->uvedges+i;
|
||||
tmp_uvdata[tmpedge->uv1].ncounter++;
|
||||
tmp_uvdata[tmpedge->uv2].ncounter++;
|
||||
|
||||
add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
|
||||
add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
|
||||
}
|
||||
|
||||
/* Original Lacplacian algorithm included removal of normal component of translation. here it is not
|
||||
* needed since we translate along the UV plane always.*/
|
||||
for (i = 0; i < sculptdata->totalUniqueUvs; i++){
|
||||
copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
|
||||
mul_v2_fl(tmp_uvdata[i].p, 1.f/tmp_uvdata[i].ncounter);
|
||||
}
|
||||
|
||||
for (i = 0; i < sculptdata->totalUniqueUvs; i++){
|
||||
float dist;
|
||||
/* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
|
||||
* If ever uv brushes get their own mode we should check for toolsettings option too */
|
||||
if((sculptdata->uv[i].flag & MARK_BOUNDARY)){
|
||||
continue;
|
||||
}
|
||||
|
||||
sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
|
||||
diff[1] /= aspectRatio;
|
||||
if((dist = dot_v2v2(diff, diff)) <= radius){
|
||||
UvElement *element;
|
||||
float strength;
|
||||
strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
|
||||
|
||||
sculptdata->uv[i].uv[0] = (1.0-strength)*sculptdata->uv[i].uv[0] + strength*tmp_uvdata[i].p[0];
|
||||
sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*tmp_uvdata[i].p[1];
|
||||
|
||||
for(element = sculptdata->uv[i].element; element; element = element->next){
|
||||
MTFace *mt;
|
||||
if(element->separate && element != sculptdata->uv[i].element)
|
||||
break;
|
||||
mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
|
||||
copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(tmp_uvdata);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event, Object *obedit)
|
||||
{
|
||||
float co[2], radius, radius_root;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
|
||||
unsigned int tool;
|
||||
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
|
||||
SpaceImage *sima;
|
||||
int invert;
|
||||
int width, height;
|
||||
float aspectRatio;
|
||||
float alpha, zoomx, zoomy;
|
||||
Brush *brush = paint_brush(sculptdata->uvsculpt);
|
||||
ToolSettings *toolsettings = CTX_data_tool_settings(C);
|
||||
tool = RNA_boolean_get(op->ptr, "temp_relax")? UV_SCULPT_TOOL_RELAX : toolsettings->uv_sculpt_tool;
|
||||
|
||||
invert = RNA_boolean_get(op->ptr, "invert")? -1 : 1;
|
||||
alpha = brush_alpha(scene, brush);
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
|
||||
|
||||
sima = CTX_wm_space_image(C);
|
||||
ED_space_image_size(sima, &width, &height);
|
||||
ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
|
||||
|
||||
radius = brush_size(scene, brush)/(width*zoomx);
|
||||
aspectRatio = width/(float)height;
|
||||
|
||||
/* We will compare squares to save some computation */
|
||||
radius = radius*radius;
|
||||
radius_root = sqrt(radius);
|
||||
|
||||
/*
|
||||
* Pinch Tool
|
||||
*/
|
||||
if(tool == UV_SCULPT_TOOL_PINCH){
|
||||
int i;
|
||||
alpha *= invert;
|
||||
for (i = 0; i < sculptdata->totalUniqueUvs; i++){
|
||||
float dist, diff[2];
|
||||
/* This is supposed to happen only if "Lock Borders" is on, since we have initialization on stroke start
|
||||
* If ever uv brushes get their own mode we should check for toolsettings option too */
|
||||
if(sculptdata->uv[i].flag & MARK_BOUNDARY){
|
||||
continue;
|
||||
}
|
||||
|
||||
sub_v2_v2v2(diff, sculptdata->uv[i].uv, co);
|
||||
diff[1] /= aspectRatio;
|
||||
if((dist = dot_v2v2(diff, diff)) <= radius){
|
||||
UvElement *element;
|
||||
float strength;
|
||||
strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
|
||||
normalize_v2(diff);
|
||||
|
||||
sculptdata->uv[i].uv[0] -= strength*diff[0]*0.001;
|
||||
sculptdata->uv[i].uv[1] -= strength*diff[1]*0.001;
|
||||
|
||||
for(element = sculptdata->uv[i].element; element; element = element->next){
|
||||
MTFace *mt;
|
||||
if(element->separate && element != sculptdata->uv[i].element)
|
||||
break;
|
||||
mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
|
||||
copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Smooth Tool
|
||||
*/
|
||||
else if(tool == UV_SCULPT_TOOL_RELAX){
|
||||
unsigned int method = toolsettings->uv_relax_method;
|
||||
if(method == UV_SCULPT_TOOL_RELAX_HC){
|
||||
HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
|
||||
}else{
|
||||
laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab Tool
|
||||
*/
|
||||
else if(tool == UV_SCULPT_TOOL_GRAB){
|
||||
int i;
|
||||
float diff[2];
|
||||
sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord);
|
||||
|
||||
for(i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++ ){
|
||||
UvElement *element;
|
||||
int uvindex = sculptdata->initial_stroke->initialSelection[i].uv;
|
||||
float strength = sculptdata->initial_stroke->initialSelection[i].strength;
|
||||
sculptdata->uv[uvindex].uv[0] = sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength*diff[0];
|
||||
sculptdata->uv[uvindex].uv[1] = sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength*diff[1];
|
||||
|
||||
for(element = sculptdata->uv[uvindex].element; element; element = element->next){
|
||||
MTFace *mt;
|
||||
if(element->separate && element != sculptdata->uv[uvindex].element)
|
||||
break;
|
||||
mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
|
||||
copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[uvindex].uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
}
|
||||
|
||||
|
||||
static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
|
||||
{
|
||||
UvSculptData *data = op->customdata;
|
||||
if(data->timer){
|
||||
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer);
|
||||
}
|
||||
if(data->elementMap)
|
||||
{
|
||||
EM_free_uv_element_map(data->elementMap);
|
||||
}
|
||||
if(data->uv){
|
||||
MEM_freeN(data->uv);
|
||||
}
|
||||
if(data->uvedges){
|
||||
MEM_freeN(data->uvedges);
|
||||
}
|
||||
if(data->initial_stroke){
|
||||
if(data->initial_stroke->initialSelection){
|
||||
MEM_freeN(data->initial_stroke->initialSelection);
|
||||
}
|
||||
MEM_freeN(data->initial_stroke);
|
||||
}
|
||||
|
||||
MEM_freeN(data);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
||||
static int get_uv_element_offset_from_face(UvElementMap *map, EditFace *efa, int index, int island_index, int doIslands){
|
||||
UvElement *element = ED_get_uv_element(map, efa, index);
|
||||
if(!element || (doIslands && element->island != island_index)){
|
||||
return -1;
|
||||
}
|
||||
return element - map->buf;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int uv_edge_hash(const void *key){
|
||||
UvEdge *edge = (UvEdge *)key;
|
||||
return
|
||||
BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) +
|
||||
BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1));
|
||||
}
|
||||
|
||||
static int uv_edge_compare(const void *a, const void *b){
|
||||
UvEdge *edge1 = (UvEdge *)a;
|
||||
UvEdge *edge2 = (UvEdge *)b;
|
||||
|
||||
if((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data");
|
||||
EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
|
||||
|
||||
op->customdata = data;
|
||||
|
||||
if(data){
|
||||
int counter = 0, i;
|
||||
ARegion *ar= CTX_wm_region(C);
|
||||
float co[2];
|
||||
EditFace *efa;
|
||||
UvEdge *edges;
|
||||
GHash *edgeHash;
|
||||
GHashIterator* ghi;
|
||||
MTFace *mt;
|
||||
int do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
|
||||
int island_index = 0;
|
||||
/* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/
|
||||
int *uniqueUv;
|
||||
|
||||
data->uvsculpt = &ts->uvsculpt->paint;
|
||||
|
||||
if(do_island_optimization){
|
||||
/* We will need island information */
|
||||
if(ts->uv_flag & UV_SYNC_SELECTION){
|
||||
data->elementMap = EM_make_uv_element_map(em, 0, 1);
|
||||
}else{
|
||||
data->elementMap = EM_make_uv_element_map(em, 1, 1);
|
||||
}
|
||||
}else {
|
||||
if(ts->uv_flag & UV_SYNC_SELECTION){
|
||||
data->elementMap = EM_make_uv_element_map(em, 0, 0);
|
||||
}else{
|
||||
data->elementMap = EM_make_uv_element_map(em, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(!data->elementMap){
|
||||
uv_sculpt_stroke_exit(C, op);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mouse coordinates, useful for some functions like grab and sculpt all islands */
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
|
||||
|
||||
/* we need to find the active island here */
|
||||
if(do_island_optimization){
|
||||
UvElement *element;
|
||||
NearestHit hit;
|
||||
Image *ima= CTX_data_edit_image(C);
|
||||
uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
|
||||
|
||||
element = ED_get_uv_element(data->elementMap, hit.efa, hit.uv);
|
||||
island_index = element->island;
|
||||
}
|
||||
|
||||
|
||||
/* Count 'unique' uvs */
|
||||
for(i = 0; i < data->elementMap->totalUVs; i++){
|
||||
if(data->elementMap->buf[i].separate
|
||||
&& (!do_island_optimization || data->elementMap->buf[i].island == island_index)){
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate the unique uv buffers */
|
||||
data->uv = MEM_mallocN(sizeof(*data->uv)*counter, "uv_brush_unique_uvs");
|
||||
uniqueUv = MEM_mallocN(sizeof(*uniqueUv)*data->elementMap->totalUVs, "uv_brush_unique_uv_map");
|
||||
edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash");
|
||||
/* we have at most totalUVs edges */
|
||||
edges = MEM_mallocN(sizeof(*edges)*data->elementMap->totalUVs, "uv_brush_all_edges");
|
||||
if(!data->uv || !uniqueUv || !edgeHash || !edges){
|
||||
if(edges){
|
||||
MEM_freeN(edges);
|
||||
}
|
||||
if(uniqueUv){
|
||||
MEM_freeN(uniqueUv);
|
||||
}
|
||||
if(edgeHash){
|
||||
MEM_freeN(edgeHash);
|
||||
}
|
||||
uv_sculpt_stroke_exit(C, op);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->totalUniqueUvs = counter;
|
||||
/* So that we can use this as index for the UvElements */
|
||||
counter = -1;
|
||||
/* initialize the unique UVs */
|
||||
for(i = 0; i < em->totvert; i++){
|
||||
UvElement *element = data->elementMap->vert[i];
|
||||
for(; element; element = element->next){
|
||||
if(element->separate){
|
||||
if(do_island_optimization && (element->island != island_index)){
|
||||
/* skip this uv if not on the active island */
|
||||
for(; element->next && !(element->next->separate); element = element->next)
|
||||
;
|
||||
continue;
|
||||
}
|
||||
efa = element->face;
|
||||
mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
|
||||
counter++;
|
||||
data->uv[counter].element = element;
|
||||
data->uv[counter].flag = 0;
|
||||
data->uv[counter].uv = mt->uv[element->tfindex];
|
||||
}
|
||||
/* pointer arithmetic to the rescue, as always :)*/
|
||||
uniqueUv[element - data->elementMap->buf] = counter;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, on to generate our uv connectivity data */
|
||||
for(efa = em->faces.first, counter = 0; efa; efa = efa->next){
|
||||
int nverts = efa->v4 ? 4 : 3;
|
||||
for(i = 0; i < nverts; i++){
|
||||
int offset1, itmp1 = get_uv_element_offset_from_face(data->elementMap, efa, i, island_index, do_island_optimization);
|
||||
int offset2, itmp2 = get_uv_element_offset_from_face(data->elementMap, efa, (i+1)%nverts, island_index, do_island_optimization);
|
||||
|
||||
/* Skip edge if not found(unlikely) or not on valid island */
|
||||
if(itmp1 == -1 || itmp2 == -1)
|
||||
continue;
|
||||
|
||||
offset1 = uniqueUv[itmp1];
|
||||
offset2 = uniqueUv[itmp2];
|
||||
|
||||
edges[counter].flag = 0;
|
||||
/* using an order policy, sort uvs according to address space. This avoids
|
||||
* Having two different UvEdges with the same uvs on different positions */
|
||||
if(offset1 < offset2){
|
||||
edges[counter].uv1 = offset1;
|
||||
edges[counter].uv2 = offset2;
|
||||
}
|
||||
else{
|
||||
edges[counter].uv1 = offset2;
|
||||
edges[counter].uv2 = offset1;
|
||||
}
|
||||
/* Hack! Set the value of the key to its flag. Now we can set the flag when an edge exists twice :) */
|
||||
if(BLI_ghash_haskey(edgeHash, &edges[counter])){
|
||||
char *flag = BLI_ghash_lookup(edgeHash, &edges[counter]);
|
||||
*flag = 1;
|
||||
}
|
||||
else{
|
||||
/* Hack mentioned */
|
||||
BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
MEM_freeN(uniqueUv);
|
||||
|
||||
/* Allocate connectivity data, we allocate edges once */
|
||||
data->uvedges = MEM_mallocN(sizeof(*data->uvedges)*BLI_ghash_size(edgeHash), "uv_brush_edge_connectivity_data");
|
||||
if(!data->uvedges){
|
||||
BLI_ghash_free(edgeHash, NULL, NULL);
|
||||
MEM_freeN(edges);
|
||||
uv_sculpt_stroke_exit(C, op);
|
||||
return NULL;
|
||||
}
|
||||
ghi = BLI_ghashIterator_new(edgeHash);
|
||||
if(!ghi){
|
||||
BLI_ghash_free(edgeHash, NULL, NULL);
|
||||
MEM_freeN(edges);
|
||||
uv_sculpt_stroke_exit(C, op);
|
||||
return NULL;
|
||||
}
|
||||
/* fill the edges with data */
|
||||
for(i = 0; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)){
|
||||
data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
|
||||
}
|
||||
data->totalUvEdges = BLI_ghash_size(edgeHash);
|
||||
|
||||
/* cleanup temporary stuff */
|
||||
BLI_ghashIterator_free(ghi);
|
||||
BLI_ghash_free(edgeHash, NULL, NULL);
|
||||
MEM_freeN(edges);
|
||||
|
||||
/* transfer boundary edge property to uvs */
|
||||
if(ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS){
|
||||
for(i = 0; i < data->totalUvEdges; i++){
|
||||
if(!data->uvedges[i].flag){
|
||||
data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY;
|
||||
data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate initial selection for grab tool */
|
||||
if(ts->uv_sculpt_tool == UV_SCULPT_TOOL_GRAB){
|
||||
float radius, radius_root;
|
||||
unsigned int tool;
|
||||
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
|
||||
SpaceImage *sima;
|
||||
int width, height;
|
||||
float aspectRatio;
|
||||
float alpha, zoomx, zoomy;
|
||||
Brush *brush = paint_brush(sculptdata->uvsculpt);
|
||||
tool = CTX_data_scene(C)->toolsettings->uv_sculpt_tool;
|
||||
|
||||
alpha = brush_alpha(scene, brush);
|
||||
|
||||
radius = brush_size(scene, brush);
|
||||
sima = CTX_wm_space_image(C);
|
||||
ED_space_image_size(sima, &width, &height);
|
||||
ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
|
||||
|
||||
aspectRatio = width/(float)height;
|
||||
radius /= (width*zoomx);
|
||||
radius = radius*radius;
|
||||
radius_root = sqrt(radius);
|
||||
|
||||
/* Allocate selection stack */
|
||||
data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke), "uv_sculpt_initial_stroke");
|
||||
if(!data->initial_stroke){
|
||||
uv_sculpt_stroke_exit(C, op);
|
||||
}
|
||||
data->initial_stroke->initialSelection = MEM_mallocN(sizeof(*data->initial_stroke->initialSelection)*data->totalUniqueUvs, "uv_sculpt_initial_selection");
|
||||
if(!data->initial_stroke->initialSelection){
|
||||
uv_sculpt_stroke_exit(C, op);
|
||||
}
|
||||
|
||||
copy_v2_v2(data->initial_stroke->init_coord, co);
|
||||
|
||||
counter = 0;
|
||||
|
||||
for(i = 0; i < data->totalUniqueUvs; i++){
|
||||
float dist, diff[2];
|
||||
if(data->uv[i].flag & MARK_BOUNDARY){
|
||||
continue;
|
||||
}
|
||||
|
||||
sub_v2_v2v2(diff, data->uv[i].uv, co);
|
||||
diff[1] /= aspectRatio;
|
||||
if((dist = dot_v2v2(diff, diff)) <= radius){
|
||||
float strength;
|
||||
strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
|
||||
|
||||
data->initial_stroke->initialSelection[counter].uv = i;
|
||||
data->initial_stroke->initialSelection[counter].strength = strength;
|
||||
copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
data->initial_stroke->totalInitialSelected = counter;
|
||||
}
|
||||
}
|
||||
|
||||
return op->customdata;
|
||||
}
|
||||
|
||||
static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
UvSculptData *data;
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
|
||||
if(!(data = uv_sculpt_stroke_init(C, op, event))) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
uv_sculpt_stroke_apply(C, op, event, obedit);
|
||||
|
||||
data->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.001f);
|
||||
|
||||
if(!data->timer){
|
||||
uv_sculpt_stroke_exit(C, op);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
|
||||
static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
UvSculptData *data = (UvSculptData *)op->customdata;
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
|
||||
switch(event->type) {
|
||||
case LEFTMOUSE:
|
||||
case MIDDLEMOUSE:
|
||||
case RIGHTMOUSE:
|
||||
uv_sculpt_stroke_exit(C, op);
|
||||
return OPERATOR_FINISHED;
|
||||
|
||||
case MOUSEMOVE:
|
||||
case INBETWEEN_MOUSEMOVE:
|
||||
uv_sculpt_stroke_apply(C, op, event, obedit);
|
||||
break;
|
||||
case TIMER:
|
||||
if(event->customdata == data->timer)
|
||||
uv_sculpt_stroke_apply(C, op, event, obedit);
|
||||
break;
|
||||
default:
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
||||
DAG_id_tag_update(obedit->data, 0);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Sculpt UVs";
|
||||
ot->description = "Sculpt UVs using a brush";
|
||||
ot->idname = "SCULPT_OT_uv_sculpt_stroke";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = uv_sculpt_stroke_invoke;
|
||||
ot->modal = uv_sculpt_stroke_modal;
|
||||
ot->poll = uv_sculpt_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* props */
|
||||
RNA_def_boolean(ot->srna, "invert", 0, "Invert", "Inverts the operator");
|
||||
RNA_def_boolean(ot->srna, "temp_relax", 0, "Relax", "Relax Tool");
|
||||
}
|
|
@ -178,6 +178,30 @@ int space_image_main_area_poll(bContext *C)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* For IMAGE_OT_curves_point_set to avoid sampling when in uv smooth mode */
|
||||
int space_image_main_area_not_uv_brush_poll(bContext *C)
|
||||
{
|
||||
SpaceImage *sima= CTX_wm_space_image(C);
|
||||
|
||||
ToolSettings *toolsettings = CTX_data_scene(C)->toolsettings;
|
||||
if(sima && !toolsettings->uvsculpt)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int space_image_image_sample_poll(bContext *C)
|
||||
{
|
||||
SpaceImage *sima= CTX_wm_space_image(C);
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
ToolSettings *toolsettings = CTX_data_scene(C)->toolsettings;
|
||||
|
||||
if(obedit){
|
||||
if(ED_space_image_show_uvedit(sima, obedit) && (toolsettings->use_uv_sculpt))
|
||||
return 0;
|
||||
}
|
||||
return space_image_main_area_poll(C);
|
||||
}
|
||||
/********************** view pan operator *********************/
|
||||
|
||||
typedef struct ViewPanData {
|
||||
|
@ -1949,7 +1973,7 @@ void IMAGE_OT_sample(wmOperatorType *ot)
|
|||
ot->invoke= image_sample_invoke;
|
||||
ot->modal= image_sample_modal;
|
||||
ot->cancel= image_sample_cancel;
|
||||
ot->poll= space_image_main_area_poll;
|
||||
ot->poll= space_image_image_sample_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_BLOCKING;
|
||||
|
@ -2086,7 +2110,7 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
|
|||
ot->invoke= image_sample_invoke;
|
||||
ot->modal= image_sample_modal;
|
||||
ot->cancel= image_sample_cancel;
|
||||
ot->poll= space_image_main_area_poll;
|
||||
ot->poll= space_image_main_area_not_uv_brush_poll;
|
||||
|
||||
/* properties */
|
||||
RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
|
||||
|
|
|
@ -773,6 +773,9 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar)
|
|||
keymap= WM_keymap_find(wm->defaultconf, "UV Editor", 0, 0);
|
||||
WM_event_add_keymap_handler(&ar->handlers, keymap);
|
||||
|
||||
keymap= WM_keymap_find(wm->defaultconf, "UV Sculpt", 0, 0);
|
||||
WM_event_add_keymap_handler(&ar->handlers, keymap);
|
||||
|
||||
/* own keymaps */
|
||||
keymap= WM_keymap_find(wm->defaultconf, "Image Generic", SPACE_IMAGE, 0);
|
||||
WM_event_add_keymap_handler(&ar->handlers, keymap);
|
||||
|
@ -785,6 +788,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
|
|||
{
|
||||
/* draw entirely, view changes should be handled here */
|
||||
SpaceImage *sima= CTX_wm_space_image(C);
|
||||
Object *obact= CTX_data_active_object(C);
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
View2D *v2d= &ar->v2d;
|
||||
|
@ -810,7 +814,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
|
|||
|
||||
/* and uvs in 0.0-1.0 space */
|
||||
UI_view2d_view_ortho(v2d);
|
||||
draw_uvedit_main(sima, ar, scene, obedit);
|
||||
draw_uvedit_main(sima, ar, scene, obedit, obact);
|
||||
|
||||
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ set(SRC
|
|||
uvedit_draw.c
|
||||
uvedit_ops.c
|
||||
uvedit_parametrizer.c
|
||||
uvedit_smart_stitch.c
|
||||
uvedit_unwrap_ops.c
|
||||
|
||||
uvedit_intern.h
|
||||
|
|
|
@ -380,12 +380,9 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
|
|||
}
|
||||
}
|
||||
|
||||
static void draw_uvs_other(Scene *scene, Object *obedit, MTFace *activetf)
|
||||
static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage)
|
||||
{
|
||||
Base *base;
|
||||
Image *curimage;
|
||||
|
||||
curimage= (activetf)? activetf->tpage: NULL;
|
||||
|
||||
glColor3ub(96, 96, 96);
|
||||
|
||||
|
@ -419,6 +416,34 @@ static void draw_uvs_other(Scene *scene, Object *obedit, MTFace *activetf)
|
|||
}
|
||||
}
|
||||
|
||||
static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
|
||||
{
|
||||
Mesh *me= ob->data;
|
||||
Image *curimage = ED_space_image(sima);
|
||||
|
||||
if(sima->flag & SI_DRAW_OTHER)
|
||||
draw_uvs_other(scene, ob, curimage);
|
||||
|
||||
glColor3ub(112, 112, 112);
|
||||
|
||||
if(me->mtface) {
|
||||
MFace *mface= me->mface;
|
||||
MTFace *tface= me->mtface;
|
||||
int a;
|
||||
|
||||
for(a=me->totface; a>0; a--, tface++, mface++) {
|
||||
if(tface->tpage == curimage) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2fv(tface->uv[0]);
|
||||
glVertex2fv(tface->uv[1]);
|
||||
glVertex2fv(tface->uv[2]);
|
||||
if(mface->v4) glVertex2fv(tface->uv[3]);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* draws uv's in the image space */
|
||||
static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
|
||||
{
|
||||
|
@ -432,6 +457,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
|
|||
float pointsize;
|
||||
int drawfaces, interpedges;
|
||||
Image *ima= sima->image;
|
||||
StitchPreviewer *stitch_preview = uv_get_stitch_previewer();
|
||||
|
||||
em= BKE_mesh_get_editmesh(me);
|
||||
activetf= EM_get_active_mtface(em, &efa_act, NULL, 0); /* will be set to NULL if hidden */
|
||||
|
@ -445,8 +471,11 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
|
|||
interpedges= (ts->uv_selectmode == UV_SELECT_VERTEX);
|
||||
|
||||
/* draw other uvs */
|
||||
if(sima->flag & SI_DRAW_OTHER)
|
||||
draw_uvs_other(scene, obedit, activetf);
|
||||
if(sima->flag & SI_DRAW_OTHER) {
|
||||
Image *curimage= (activetf)? activetf->tpage: NULL;
|
||||
|
||||
draw_uvs_other(scene, obedit, curimage);
|
||||
}
|
||||
|
||||
/* 1. draw shadow mesh */
|
||||
|
||||
|
@ -522,7 +551,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* 3. draw active face stippled */
|
||||
|
||||
if(activetf) {
|
||||
|
@ -831,24 +860,81 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
|
|||
bglEnd();
|
||||
}
|
||||
|
||||
/* finally draw stitch preview */
|
||||
if(stitch_preview) {
|
||||
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_tris);
|
||||
glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_static_tris*3);
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_quads);
|
||||
glDrawArrays(GL_QUADS, 0, stitch_preview->num_static_quads*4);
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_tris);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
UI_ThemeColor4(TH_STITCH_PREVIEW_FACE);
|
||||
glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris*3);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE);
|
||||
glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris*3);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
|
||||
/*UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
|
||||
glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris*3);*/
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_quads);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
UI_ThemeColor4(TH_STITCH_PREVIEW_FACE);
|
||||
glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE);
|
||||
glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
|
||||
/*UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
|
||||
glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);*/
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
/* draw vert preview */
|
||||
glPointSize(pointsize*2.0);
|
||||
UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
|
||||
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
|
||||
glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
|
||||
|
||||
UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
|
||||
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
|
||||
glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable);
|
||||
|
||||
glPopClientAttrib();
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
glPointSize(1.0);
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
}
|
||||
|
||||
void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit)
|
||||
void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact)
|
||||
{
|
||||
int show_uvedit, show_uvshadow;
|
||||
ToolSettings *toolsettings = scene->toolsettings;
|
||||
int show_uvedit, show_uvshadow, show_texpaint_uvshadow;
|
||||
|
||||
show_texpaint_uvshadow = (obact && obact->type == OB_MESH && obact->mode == OB_MODE_TEXTURE_PAINT);
|
||||
show_uvedit= ED_space_image_show_uvedit(sima, obedit);
|
||||
show_uvshadow= ED_space_image_show_uvshadow(sima, obedit);
|
||||
|
||||
if(show_uvedit || show_uvshadow) {
|
||||
if(show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
|
||||
if(show_uvshadow)
|
||||
draw_uvs_shadow(obedit);
|
||||
else
|
||||
else if(show_uvedit)
|
||||
draw_uvs(sima, scene, obedit);
|
||||
else
|
||||
draw_uvs_texpaint(sima, scene, obact);
|
||||
|
||||
if(show_uvedit)
|
||||
if(show_uvedit && !(toolsettings->use_uv_sculpt))
|
||||
drawcursor_sima(sima, ar);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,25 +32,74 @@
|
|||
#ifndef ED_UVEDIT_INTERN_H
|
||||
#define ED_UVEDIT_INTERN_H
|
||||
|
||||
struct SpaceImage;
|
||||
struct EditFace;
|
||||
struct MTFace;
|
||||
struct Scene;
|
||||
struct EditMesh;
|
||||
struct Image;
|
||||
struct MTFace;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
struct SpaceImage;
|
||||
struct UvElementMap;
|
||||
struct wmOperatorType;
|
||||
|
||||
/* id can be from 0 to 3 */
|
||||
#define TF_PIN_MASK(id) (TF_PIN1 << id)
|
||||
#define TF_SEL_MASK(id) (TF_SEL1 << id)
|
||||
|
||||
|
||||
/* geometric utilities */
|
||||
|
||||
void uv_center(float uv[][2], float cent[2], int quad);
|
||||
float uv_area(float uv[][2], int quad);
|
||||
void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy);
|
||||
|
||||
/* find nearest */
|
||||
|
||||
typedef struct NearestHit {
|
||||
struct EditFace *efa;
|
||||
struct MTFace *tf;
|
||||
|
||||
int vert, uv;
|
||||
int edge, vert2;
|
||||
} NearestHit;
|
||||
|
||||
void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct EditMesh *em, float co[2], float penalty[2], struct NearestHit *hit);
|
||||
void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct EditMesh *em, float co[2], struct NearestHit *hit);
|
||||
|
||||
/* utility tool functions */
|
||||
|
||||
struct UvElement *ED_get_uv_element(struct UvElementMap *map, struct EditFace *efa, int index);
|
||||
void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit);
|
||||
|
||||
/* smart stitch */
|
||||
|
||||
/* object that stores display data for previewing before accepting stitching */
|
||||
typedef struct StitchPreviewer {
|
||||
/* OpenGL requires different calls for Triangles and Quads.
|
||||
* here we'll store the quads of the mesh */
|
||||
float *preview_quads;
|
||||
/* ...and here we'll store the triangles*/
|
||||
float *preview_tris;
|
||||
/* preview data. These will be either the previewed vertices or edges depending on stitch mode settings */
|
||||
float *preview_stitchable;
|
||||
float *preview_unstitchable;
|
||||
/* here we'll store the number of triangles and quads to be drawn */
|
||||
unsigned int num_tris;
|
||||
unsigned int num_quads;
|
||||
unsigned int num_stitchable;
|
||||
unsigned int num_unstitchable;
|
||||
|
||||
/* store static island Quads */
|
||||
float *static_quads;
|
||||
/* ...and here we'll store the triangles*/
|
||||
float *static_tris;
|
||||
unsigned int num_static_tris;
|
||||
unsigned int num_static_quads;
|
||||
} StitchPreviewer;
|
||||
|
||||
StitchPreviewer *uv_get_stitch_previewer(void);
|
||||
|
||||
/* 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);
|
||||
|
@ -60,6 +109,7 @@ 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_stitch(struct wmOperatorType *ot);
|
||||
|
||||
#endif /* ED_UVEDIT_INTERN_H */
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
* Contributor(s): Antony Riakiotakis.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
@ -94,6 +94,28 @@ int ED_uvedit_test(Object *obedit)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ED_operator_uvedit_can_uv_sculpt(struct bContext *C)
|
||||
{
|
||||
SpaceImage *sima= CTX_wm_space_image(C);
|
||||
ToolSettings *toolsettings = CTX_data_tool_settings(C);
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
|
||||
return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
|
||||
}
|
||||
|
||||
static int ED_operator_uvmap_mesh(bContext *C)
|
||||
{
|
||||
Object *ob= CTX_data_active_object(C);
|
||||
|
||||
if(ob && ob->type==OB_MESH) {
|
||||
Mesh *me = ob->data;
|
||||
|
||||
if(CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**************************** object active image *****************************/
|
||||
|
||||
static int is_image_texture_node(bNode *node)
|
||||
|
@ -400,7 +422,7 @@ void uvedit_uv_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
|
|||
|
||||
/*********************** live unwrap utilities ***********************/
|
||||
|
||||
static void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
|
||||
void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
|
||||
{
|
||||
if(sima && (sima->flag & SI_LIVE_UNWRAP)) {
|
||||
ED_uvedit_live_unwrap_begin(scene, obedit);
|
||||
|
@ -527,15 +549,7 @@ static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent,
|
|||
|
||||
/************************** find nearest ****************************/
|
||||
|
||||
typedef struct NearestHit {
|
||||
EditFace *efa;
|
||||
MTFace *tf;
|
||||
|
||||
int vert, uv;
|
||||
int edge, vert2;
|
||||
} NearestHit;
|
||||
|
||||
static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
|
||||
void uv_find_nearest_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
|
||||
{
|
||||
MTFace *tf;
|
||||
EditFace *efa;
|
||||
|
@ -633,7 +647,7 @@ static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float
|
|||
return (c1*c2 >= 0.0f);
|
||||
}
|
||||
|
||||
static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
|
||||
void uv_find_nearest_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
|
||||
{
|
||||
EditFace *efa;
|
||||
EditVert *eve;
|
||||
|
@ -750,6 +764,17 @@ static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
UvElement *ED_get_uv_element(UvElementMap *map, EditFace *efa, int index)
|
||||
{
|
||||
UvElement *element = map->vert[(*(&efa->v1 + index))->tmp.l];
|
||||
|
||||
for(; element; element = element->next)
|
||||
if(element->face == efa)
|
||||
return element;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
|
||||
{
|
||||
UvMapVert *iterv1, *iterv2;
|
||||
|
@ -1296,197 +1321,6 @@ static void UV_OT_weld(wmOperatorType *ot)
|
|||
ot->poll= ED_operator_uvedit;
|
||||
}
|
||||
|
||||
/* ******************** stitch operator **************** */
|
||||
|
||||
/* just for averaging UVs */
|
||||
typedef struct UVVertAverage {
|
||||
float uv[2];
|
||||
int count;
|
||||
} UVVertAverage;
|
||||
|
||||
static int stitch_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
SpaceImage *sima;
|
||||
Scene *scene;
|
||||
Object *obedit;
|
||||
EditMesh *em;
|
||||
EditFace *efa;
|
||||
EditVert *eve;
|
||||
Image *ima;
|
||||
MTFace *tf;
|
||||
|
||||
scene= CTX_data_scene(C);
|
||||
obedit= CTX_data_edit_object(C);
|
||||
em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
|
||||
ima= CTX_data_edit_image(C);
|
||||
sima= CTX_wm_space_image(C);
|
||||
|
||||
if(RNA_boolean_get(op->ptr, "use_limit")) {
|
||||
UvVertMap *vmap;
|
||||
UvMapVert *vlist, *iterv;
|
||||
float newuv[2], limit[2];
|
||||
int a, vtot;
|
||||
|
||||
limit[0]= RNA_float_get(op->ptr, "limit");
|
||||
limit[1]= limit[0];
|
||||
|
||||
EM_init_index_arrays(em, 0, 0, 1);
|
||||
vmap= EM_make_uv_vert_map(em, 1, 0, limit);
|
||||
|
||||
if(vmap == NULL) {
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
for(a=0, eve= em->verts.first; eve; a++, eve= eve->next) {
|
||||
vlist= EM_get_uv_map_vert(vmap, a);
|
||||
|
||||
while(vlist) {
|
||||
newuv[0]= 0; newuv[1]= 0;
|
||||
vtot= 0;
|
||||
|
||||
for(iterv=vlist; iterv; iterv=iterv->next) {
|
||||
if((iterv != vlist) && iterv->separate)
|
||||
break;
|
||||
|
||||
efa = EM_get_face_for_index(iterv->f);
|
||||
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
|
||||
if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
|
||||
newuv[0] += tf->uv[iterv->tfindex][0];
|
||||
newuv[1] += tf->uv[iterv->tfindex][1];
|
||||
vtot++;
|
||||
}
|
||||
}
|
||||
|
||||
if(vtot > 1) {
|
||||
newuv[0] /= vtot; newuv[1] /= vtot;
|
||||
|
||||
for(iterv=vlist; iterv; iterv=iterv->next) {
|
||||
if((iterv != vlist) && iterv->separate)
|
||||
break;
|
||||
|
||||
efa = EM_get_face_for_index(iterv->f);
|
||||
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
|
||||
if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
|
||||
tf->uv[iterv->tfindex][0]= newuv[0];
|
||||
tf->uv[iterv->tfindex][1]= newuv[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vlist= iterv;
|
||||
}
|
||||
}
|
||||
|
||||
EM_free_uv_vert_map(vmap);
|
||||
EM_free_index_arrays();
|
||||
}
|
||||
else {
|
||||
UVVertAverage *uv_average, *uvav;
|
||||
int count;
|
||||
|
||||
// index and count verts
|
||||
for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
|
||||
eve->tmp.l = count;
|
||||
|
||||
uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch");
|
||||
|
||||
// gather uv averages per vert
|
||||
for(efa= em->faces.first; efa; efa= efa->next) {
|
||||
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
|
||||
if(uvedit_face_visible(scene, ima, efa, tf)) {
|
||||
if(uvedit_uv_selected(scene, efa, tf, 0)) {
|
||||
uvav = uv_average + efa->v1->tmp.l;
|
||||
uvav->count++;
|
||||
uvav->uv[0] += tf->uv[0][0];
|
||||
uvav->uv[1] += tf->uv[0][1];
|
||||
}
|
||||
|
||||
if(uvedit_uv_selected(scene, efa, tf, 1)) {
|
||||
uvav = uv_average + efa->v2->tmp.l;
|
||||
uvav->count++;
|
||||
uvav->uv[0] += tf->uv[1][0];
|
||||
uvav->uv[1] += tf->uv[1][1];
|
||||
}
|
||||
|
||||
if(uvedit_uv_selected(scene, efa, tf, 2)) {
|
||||
uvav = uv_average + efa->v3->tmp.l;
|
||||
uvav->count++;
|
||||
uvav->uv[0] += tf->uv[2][0];
|
||||
uvav->uv[1] += tf->uv[2][1];
|
||||
}
|
||||
|
||||
if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
|
||||
uvav = uv_average + efa->v4->tmp.l;
|
||||
uvav->count++;
|
||||
uvav->uv[0] += tf->uv[3][0];
|
||||
uvav->uv[1] += tf->uv[3][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply uv welding
|
||||
for(efa= em->faces.first; efa; efa= efa->next) {
|
||||
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
|
||||
if(uvedit_face_visible(scene, ima, efa, tf)) {
|
||||
if(uvedit_uv_selected(scene, efa, tf, 0)) {
|
||||
uvav = uv_average + efa->v1->tmp.l;
|
||||
tf->uv[0][0] = uvav->uv[0]/uvav->count;
|
||||
tf->uv[0][1] = uvav->uv[1]/uvav->count;
|
||||
}
|
||||
|
||||
if(uvedit_uv_selected(scene, efa, tf, 1)) {
|
||||
uvav = uv_average + efa->v2->tmp.l;
|
||||
tf->uv[1][0] = uvav->uv[0]/uvav->count;
|
||||
tf->uv[1][1] = uvav->uv[1]/uvav->count;
|
||||
}
|
||||
|
||||
if(uvedit_uv_selected(scene, efa, tf, 2)) {
|
||||
uvav = uv_average + efa->v3->tmp.l;
|
||||
tf->uv[2][0] = uvav->uv[0]/uvav->count;
|
||||
tf->uv[2][1] = uvav->uv[1]/uvav->count;
|
||||
}
|
||||
|
||||
if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
|
||||
uvav = uv_average + efa->v4->tmp.l;
|
||||
tf->uv[3][0] = uvav->uv[0]/uvav->count;
|
||||
tf->uv[3][1] = uvav->uv[1]/uvav->count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(uv_average);
|
||||
}
|
||||
|
||||
uvedit_live_unwrap_update(sima, scene, obedit);
|
||||
DAG_id_tag_update(obedit->data, 0);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
||||
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void UV_OT_stitch(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Stitch";
|
||||
ot->description= "Stitch selected UV vertices by proximity";
|
||||
ot->idname= "UV_OT_stitch";
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= stitch_exec;
|
||||
ot->poll= ED_operator_uvedit;
|
||||
|
||||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance");
|
||||
RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates", -FLT_MAX, FLT_MAX);
|
||||
}
|
||||
|
||||
/* ******************** (de)select all operator **************** */
|
||||
|
||||
static void select_all_perform(bContext *C, int action)
|
||||
|
@ -1660,7 +1494,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
|
|||
/* find nearest element */
|
||||
if(loop) {
|
||||
/* find edge */
|
||||
find_nearest_uv_edge(scene, ima, em, co, &hit);
|
||||
uv_find_nearest_edge(scene, ima, em, co, &hit);
|
||||
if(hit.efa == NULL) {
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
|
@ -1668,7 +1502,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
|
|||
}
|
||||
else if(selectmode == UV_SELECT_VERTEX) {
|
||||
/* find vertex */
|
||||
find_nearest_uv_vert(scene, ima, em, co, penalty, &hit);
|
||||
uv_find_nearest_vert(scene, ima, em, co, penalty, &hit);
|
||||
if(hit.efa == NULL) {
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
|
@ -1683,7 +1517,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
|
|||
}
|
||||
else if(selectmode == UV_SELECT_EDGE) {
|
||||
/* find edge */
|
||||
find_nearest_uv_edge(scene, ima, em, co, &hit);
|
||||
uv_find_nearest_edge(scene, ima, em, co, &hit);
|
||||
if(hit.efa == NULL) {
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
|
@ -1723,7 +1557,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
|
|||
else hitv[3]= 0xFFFFFFFF;
|
||||
}
|
||||
else if(selectmode == UV_SELECT_ISLAND) {
|
||||
find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
|
||||
uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
|
||||
|
||||
if(hit.efa==NULL) {
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
|
@ -2015,7 +1849,7 @@ static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, i
|
|||
RNA_float_get_array(op->ptr, "location", co);
|
||||
}
|
||||
|
||||
find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
|
||||
uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
|
||||
hit_p= &hit;
|
||||
}
|
||||
|
||||
|
@ -3312,6 +3146,180 @@ static void UV_OT_tile_set(wmOperatorType *ot)
|
|||
RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate", 0, 10);
|
||||
}
|
||||
|
||||
|
||||
static int seams_from_islands_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
UvVertMap *vmap;
|
||||
Object *ob = CTX_data_edit_object(C);
|
||||
Mesh *me= (Mesh*)ob->data;
|
||||
EditMesh *em;
|
||||
EditEdge *editedge;
|
||||
float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
|
||||
char mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
|
||||
char mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
|
||||
|
||||
em = BKE_mesh_get_editmesh(me);
|
||||
|
||||
if(!EM_texFaceCheck(em)) {
|
||||
BKE_mesh_end_editmesh(ob->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* This code sets editvert->tmp.l to the index. This will be useful later on. */
|
||||
EM_init_index_arrays(em, 0, 0, 1);
|
||||
vmap = EM_make_uv_vert_map(em, 0, 0, limit);
|
||||
|
||||
for(editedge = em->edges.first; editedge; editedge = editedge->next) {
|
||||
/* flags to determine if we uv is separated from first editface match */
|
||||
char separated1 = 0, separated2;
|
||||
/* set to denote edge must be flagged as seam */
|
||||
char faces_separated = 0;
|
||||
/* flag to keep track if uv1 is disconnected from first editface match */
|
||||
char v1coincident = 1;
|
||||
/* For use with v1coincident. v1coincident will change only if we've had commonFaces */
|
||||
int commonFaces = 0;
|
||||
|
||||
EditFace *efa1, *efa2;
|
||||
|
||||
UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
|
||||
/* mv2cache stores the first of the list of coincident uv's for later comparison
|
||||
* mv2sep holds the last separator and is copied to mv2cache when a hit is first found */
|
||||
UvMapVert *mv2cache = NULL, *mv2sep = NULL;
|
||||
|
||||
mvinit1 = vmap->vert[editedge->v1->tmp.l];
|
||||
if(mark_seams)
|
||||
editedge->seam = 0;
|
||||
|
||||
for(mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
|
||||
if(mv1->separate && commonFaces)
|
||||
v1coincident = 0;
|
||||
|
||||
separated2 = 0;
|
||||
efa1 = EM_get_face_for_index(mv1->f);
|
||||
mvinit2 = vmap->vert[editedge->v2->tmp.l];
|
||||
|
||||
for(mv2 = mvinit2; mv2; mv2 = mv2->next) {
|
||||
if(mv2->separate)
|
||||
mv2sep = mv2;
|
||||
|
||||
efa2 = EM_get_face_for_index(mv2->f);
|
||||
if(efa1 == efa2) {
|
||||
/* if v1 is not coincident no point in comparing */
|
||||
if(v1coincident) {
|
||||
/* have we found previously anything? */
|
||||
if(mv2cache) {
|
||||
/* flag seam unless proved to be coincident with previous hit */
|
||||
separated2 = 1;
|
||||
for(mviter = mv2cache; mviter; mviter = mviter->next) {
|
||||
if(mviter->separate && mviter != mv2cache)
|
||||
break;
|
||||
/* coincident with previous hit, do not flag seam */
|
||||
if(mviter == mv2)
|
||||
separated2 = 0;
|
||||
}
|
||||
}
|
||||
/* First hit case, store the hit in the cache */
|
||||
else {
|
||||
mv2cache = mv2sep;
|
||||
commonFaces = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
separated1 = 1;
|
||||
|
||||
if(separated1 || separated2) {
|
||||
faces_separated = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(faces_separated) {
|
||||
if(mark_seams)
|
||||
editedge->seam = 1;
|
||||
if(mark_sharp)
|
||||
editedge->sharp = 1;
|
||||
}
|
||||
}
|
||||
|
||||
me->drawflag |= ME_DRAWSEAMS;
|
||||
|
||||
EM_free_uv_vert_map(vmap);
|
||||
EM_free_index_arrays();
|
||||
BKE_mesh_end_editmesh(me, em);
|
||||
|
||||
DAG_id_tag_update(&me->id, 0);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
||||
static void UV_OT_seams_from_islands(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Seams From Islands";
|
||||
ot->description= "Set mesh seams according to island setup in the UV editor";
|
||||
ot->idname= "UV_OT_seams_from_islands";
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= seams_from_islands_exec;
|
||||
ot->poll= ED_operator_uvedit;
|
||||
|
||||
RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams");
|
||||
RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
|
||||
}
|
||||
|
||||
static int mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Object *ob = CTX_data_edit_object(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Mesh *me= (Mesh*)ob->data;
|
||||
EditMesh *em= BKE_mesh_get_editmesh(me);
|
||||
EditFace *efa;
|
||||
|
||||
for(efa = em->faces.first; efa; efa = efa->next) {
|
||||
MTFace *mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
||||
int i, nverts = efa->v4? 4 : 3;
|
||||
|
||||
for(i = 0; i < nverts; i++)
|
||||
if(uvedit_edge_selected(scene, efa, mt, i))
|
||||
(*(&efa->e1 + i))->seam = 1;
|
||||
}
|
||||
|
||||
me->drawflag |= ME_DRAWSEAMS;
|
||||
|
||||
if(scene->toolsettings->edge_mode_live_unwrap)
|
||||
ED_unwrap_lscm(scene, ob, FALSE);
|
||||
|
||||
BKE_mesh_end_editmesh(me, em);
|
||||
|
||||
DAG_id_tag_update(&me->id, 0);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void UV_OT_mark_seam(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Mark Seams";
|
||||
ot->description= "Mark selected UV edges as seams";
|
||||
ot->idname= "UV_OT_mark_seam";
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= mark_seam_exec;
|
||||
ot->poll= ED_operator_uvedit;
|
||||
}
|
||||
|
||||
|
||||
/* ************************** registration **********************************/
|
||||
|
||||
void ED_operatortypes_uvedit(void)
|
||||
|
@ -3331,6 +3339,8 @@ void ED_operatortypes_uvedit(void)
|
|||
|
||||
WM_operatortype_append(UV_OT_align);
|
||||
WM_operatortype_append(UV_OT_stitch);
|
||||
WM_operatortype_append(UV_OT_seams_from_islands);
|
||||
WM_operatortype_append(UV_OT_mark_seam);
|
||||
WM_operatortype_append(UV_OT_weld);
|
||||
WM_operatortype_append(UV_OT_pin);
|
||||
|
||||
|
@ -3357,7 +3367,14 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
|
|||
wmKeyMapItem *kmi;
|
||||
|
||||
keymap= WM_keymap_find(keyconf, "UV Editor", 0, 0);
|
||||
keymap->poll= ED_operator_uvedit;
|
||||
keymap->poll= ED_operator_uvedit_can_uv_sculpt;
|
||||
|
||||
/* Uv sculpt toggle */
|
||||
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0);
|
||||
RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_uv_sculpt");
|
||||
|
||||
/* Mark edge seam */
|
||||
WM_keymap_add_item(keymap, "UV_OT_mark_seam", EKEY, KM_PRESS, KM_CTRL, 0);
|
||||
|
||||
/* pick selection */
|
||||
RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0)->ptr, "extend", FALSE);
|
||||
|
|
|
@ -91,7 +91,7 @@ typedef struct PVert {
|
|||
} u;
|
||||
|
||||
struct PEdge *edge;
|
||||
float *co;
|
||||
float co[3];
|
||||
float uv[2];
|
||||
unsigned char flag;
|
||||
|
||||
|
@ -655,11 +655,15 @@ static void p_face_backup_uvs(PFace *f)
|
|||
{
|
||||
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
|
||||
|
||||
if (e1->orig_uv && e2->orig_uv && e3->orig_uv) {
|
||||
if (e1->orig_uv) {
|
||||
e1->old_uv[0] = e1->orig_uv[0];
|
||||
e1->old_uv[1] = e1->orig_uv[1];
|
||||
}
|
||||
if (e2->orig_uv) {
|
||||
e2->old_uv[0] = e2->orig_uv[0];
|
||||
e2->old_uv[1] = e2->orig_uv[1];
|
||||
}
|
||||
if (e3->orig_uv) {
|
||||
e3->old_uv[0] = e3->orig_uv[0];
|
||||
e3->old_uv[1] = e3->orig_uv[1];
|
||||
}
|
||||
|
@ -669,11 +673,15 @@ static void p_face_restore_uvs(PFace *f)
|
|||
{
|
||||
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
|
||||
|
||||
if (e1->orig_uv && e2->orig_uv && e3->orig_uv) {
|
||||
if (e1->orig_uv) {
|
||||
e1->orig_uv[0] = e1->old_uv[0];
|
||||
e1->orig_uv[1] = e1->old_uv[1];
|
||||
}
|
||||
if (e2->orig_uv) {
|
||||
e2->orig_uv[0] = e2->old_uv[0];
|
||||
e2->orig_uv[1] = e2->old_uv[1];
|
||||
}
|
||||
if (e3->orig_uv) {
|
||||
e3->orig_uv[0] = e3->old_uv[0];
|
||||
e3->orig_uv[1] = e3->old_uv[1];
|
||||
}
|
||||
|
@ -684,7 +692,7 @@ static void p_face_restore_uvs(PFace *f)
|
|||
static PVert *p_vert_add(PHandle *handle, PHashKey key, float *co, PEdge *e)
|
||||
{
|
||||
PVert *v = (PVert*)BLI_memarena_alloc(handle->arena, sizeof *v);
|
||||
v->co = co;
|
||||
copy_v3_v3(v->co, co);
|
||||
v->u.key = key;
|
||||
v->edge = e;
|
||||
v->flag = 0;
|
||||
|
@ -708,7 +716,7 @@ static PVert *p_vert_copy(PChart *chart, PVert *v)
|
|||
{
|
||||
PVert *nv = (PVert*)BLI_memarena_alloc(chart->handle->arena, sizeof *nv);
|
||||
|
||||
nv->co = v->co;
|
||||
copy_v3_v3(nv->co, v->co);
|
||||
nv->uv[0] = v->uv[0];
|
||||
nv->uv[1] = v->uv[1];
|
||||
nv->u.key = v->u.key;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,6 +40,7 @@
|
|||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_edgehash.h"
|
||||
|
@ -48,12 +49,15 @@
|
|||
#include "BLI_utildefines.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_cdderivedmesh.h"
|
||||
#include "BKE_subsurf.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
|
@ -272,6 +276,201 @@ static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short imp
|
|||
return handle;
|
||||
}
|
||||
|
||||
|
||||
static void texface_from_original_index(EditFace *editFace, MTFace *texFace, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene)
|
||||
{
|
||||
int i, nverts = (editFace->v4)? 4: 3;
|
||||
|
||||
*uv = NULL;
|
||||
*pin = 0;
|
||||
*select = 1;
|
||||
|
||||
if(index == ORIGINDEX_NONE)
|
||||
return;
|
||||
|
||||
for(i = 0; i < nverts; i++) {
|
||||
if((*(&editFace->v1 + i))->tmp.t == index) {
|
||||
*uv = texFace->uv[i];
|
||||
*pin = ((texFace->unwrap & TF_PIN_MASK(i)) != 0);
|
||||
*select = (uvedit_uv_selected(scene, editFace, texFace, i) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above)
|
||||
* work justified the existence of a new function. */
|
||||
static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *editMesh, short fill, short sel, short correct_aspect)
|
||||
{
|
||||
ParamHandle *handle;
|
||||
/* index pointers */
|
||||
MFace *face;
|
||||
MEdge *edge;
|
||||
EditVert *editVert;
|
||||
MTFace *texface;
|
||||
EditFace *editFace, **editFaceTmp;
|
||||
EditEdge *editEdge, **editEdgeTmp;
|
||||
int i;
|
||||
|
||||
/* modifier initialization data, will control what type of subdivision will happen*/
|
||||
SubsurfModifierData smd = {{0}};
|
||||
/* Used to hold subsurfed Mesh */
|
||||
DerivedMesh *derivedMesh, *initialDerived;
|
||||
/* holds original indices for subsurfed mesh */
|
||||
int *origVertIndices, *origFaceIndices, *origEdgeIndices;
|
||||
/* Holds vertices of subsurfed mesh */
|
||||
MVert *subsurfedVerts;
|
||||
MEdge *subsurfedEdges;
|
||||
MFace *subsurfedFaces;
|
||||
MTFace *subsurfedTexfaces;
|
||||
/* number of vertices and faces for subsurfed mesh*/
|
||||
int numOfEdges, numOfFaces;
|
||||
|
||||
/* holds a map to editfaces for every subsurfed MFace. These will be used to get hidden/ selected flags etc. */
|
||||
EditFace **faceMap;
|
||||
/* Mini container to hold all EditFaces so that they may be indexed easily and fast. */
|
||||
EditFace **editFaceArray;
|
||||
/* similar to the above, we need a way to map edges to their original ones */
|
||||
EditEdge **edgeMap;
|
||||
EditEdge **editEdgeArray;
|
||||
|
||||
handle = param_construct_begin();
|
||||
|
||||
if(correct_aspect) {
|
||||
EditFace *eface = EM_get_actFace(editMesh, 1);
|
||||
|
||||
if(eface) {
|
||||
float aspx, aspy;
|
||||
texface= CustomData_em_get(&editMesh->fdata, eface->data, CD_MTFACE);
|
||||
|
||||
ED_image_uv_aspect(texface->tpage, &aspx, &aspy);
|
||||
|
||||
if(aspx!=aspy)
|
||||
param_aspect_ratio(handle, aspx, aspy);
|
||||
}
|
||||
}
|
||||
|
||||
/* number of subdivisions to perform */
|
||||
smd.levels = scene->toolsettings->uv_subsurf_level;
|
||||
smd.subdivType = ME_CC_SUBSURF;
|
||||
|
||||
initialDerived = CDDM_from_editmesh(editMesh, NULL);
|
||||
derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd,
|
||||
0, NULL, 0, 0, 1);
|
||||
|
||||
initialDerived->release(initialDerived);
|
||||
|
||||
/* get the derived data */
|
||||
subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
|
||||
subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
|
||||
subsurfedFaces = derivedMesh->getFaceArray(derivedMesh);
|
||||
|
||||
origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
|
||||
origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
|
||||
origFaceIndices = derivedMesh->getFaceDataArray(derivedMesh, CD_ORIGINDEX);
|
||||
|
||||
subsurfedTexfaces = derivedMesh->getFaceDataArray(derivedMesh, CD_MTFACE);
|
||||
|
||||
numOfEdges = derivedMesh->getNumEdges(derivedMesh);
|
||||
numOfFaces = derivedMesh->getNumFaces(derivedMesh);
|
||||
|
||||
faceMap = MEM_mallocN(numOfFaces*sizeof(EditFace *), "unwrap_edit_face_map");
|
||||
editFaceArray = MEM_mallocN(editMesh->totface*sizeof(EditFace *), "unwrap_editFaceArray");
|
||||
|
||||
/* fill edit face array with edit faces */
|
||||
for(editFace = editMesh->faces.first, editFaceTmp = editFaceArray; editFace; editFace= editFace->next, editFaceTmp++)
|
||||
*editFaceTmp = editFace;
|
||||
|
||||
/* map subsurfed faces to original editFaces */
|
||||
for(i = 0; i < numOfFaces; i++)
|
||||
faceMap[i] = editFaceArray[origFaceIndices[i]];
|
||||
|
||||
MEM_freeN(editFaceArray);
|
||||
|
||||
edgeMap = MEM_mallocN(numOfEdges*sizeof(EditEdge *), "unwrap_edit_edge_map");
|
||||
editEdgeArray = MEM_mallocN(editMesh->totedge*sizeof(EditEdge *), "unwrap_editEdgeArray");
|
||||
|
||||
/* fill edit edge array with edit edges */
|
||||
for(editEdge = editMesh->edges.first, editEdgeTmp = editEdgeArray; editEdge; editEdge= editEdge->next, editEdgeTmp++)
|
||||
*editEdgeTmp = editEdge;
|
||||
|
||||
/* map subsurfed edges to original editEdges */
|
||||
for(i = 0; i < numOfEdges; i++) {
|
||||
/* not all edges correspond to an old edge */
|
||||
edgeMap[i] = (origEdgeIndices[i] != -1)?
|
||||
editEdgeArray[origEdgeIndices[i]] : NULL;
|
||||
}
|
||||
|
||||
MEM_freeN(editEdgeArray);
|
||||
|
||||
/* we need the editvert indices too */
|
||||
for(editVert = editMesh->verts.first, i=0; editVert; editVert = editVert->next, i++)
|
||||
editVert->tmp.t = i;
|
||||
|
||||
/* Prepare and feed faces to the solver */
|
||||
for(i = 0; i < numOfFaces; i++) {
|
||||
ParamKey key, vkeys[4];
|
||||
ParamBool pin[4], select[4];
|
||||
float *co[4];
|
||||
float *uv[4];
|
||||
EditFace *origFace = faceMap[i];
|
||||
MTFace *origtexface = (MTFace *)CustomData_em_get(&editMesh->fdata, origFace->data, CD_MTFACE);
|
||||
|
||||
face = subsurfedFaces+i;
|
||||
|
||||
if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
|
||||
if(origFace->h)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if((origFace->h) || (sel && (origFace->f & SELECT)==0))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now we feed the rest of the data from the subsurfed faces */
|
||||
texface= subsurfedTexfaces+i;
|
||||
|
||||
/* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
|
||||
key = (ParamKey)face;
|
||||
vkeys[0] = (ParamKey)face->v1;
|
||||
vkeys[1] = (ParamKey)face->v2;
|
||||
vkeys[2] = (ParamKey)face->v3;
|
||||
vkeys[3] = (ParamKey)face->v4;
|
||||
|
||||
co[0] = subsurfedVerts[face->v1].co;
|
||||
co[1] = subsurfedVerts[face->v2].co;
|
||||
co[2] = subsurfedVerts[face->v3].co;
|
||||
co[3] = subsurfedVerts[face->v4].co;
|
||||
|
||||
/* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
|
||||
* flushing the solution to the edit mesh. */
|
||||
texface_from_original_index(origFace, origtexface, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene);
|
||||
texface_from_original_index(origFace, origtexface, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene);
|
||||
texface_from_original_index(origFace, origtexface, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene);
|
||||
texface_from_original_index(origFace, origtexface, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene);
|
||||
|
||||
param_face_add(handle, key, 4, vkeys, co, uv, pin, select);
|
||||
}
|
||||
|
||||
/* these are calculated from original mesh too */
|
||||
for(edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
|
||||
if((edgeMap[i] != NULL) && edgeMap[i]->seam) {
|
||||
ParamKey vkeys[2];
|
||||
vkeys[0] = (ParamKey)edge->v1;
|
||||
vkeys[1] = (ParamKey)edge->v2;
|
||||
param_edge_set_seam(handle, vkeys);
|
||||
}
|
||||
}
|
||||
|
||||
param_construct_end(handle, fill, 0);
|
||||
|
||||
/* cleanup */
|
||||
MEM_freeN(faceMap);
|
||||
MEM_freeN(edgeMap);
|
||||
derivedMesh->release(derivedMesh);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/* ******************** Minimize Stretch operator **************** */
|
||||
|
||||
typedef struct MinStretch {
|
||||
|
@ -582,13 +781,17 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
|
|||
EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
|
||||
short abf = scene->toolsettings->unwrapper == 0;
|
||||
short fillholes = scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
|
||||
short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF;
|
||||
|
||||
if(!ED_uvedit_test(obedit)) {
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return;
|
||||
}
|
||||
|
||||
liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1);
|
||||
if(use_subsurf)
|
||||
liveHandle = construct_param_handle_subsurfed(scene, em, fillholes, 0, 1);
|
||||
else
|
||||
liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1);
|
||||
|
||||
param_lscm_begin(liveHandle, PARAM_TRUE, abf);
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
|
@ -900,14 +1103,17 @@ static void uv_map_clip_correct(EditMesh *em, wmOperator *op)
|
|||
/* assumes UV Map is checked, doesn't run update funcs */
|
||||
void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
|
||||
{
|
||||
EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
|
||||
ParamHandle *handle;
|
||||
|
||||
EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
|
||||
const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
|
||||
const short correct_aspect= !(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT);
|
||||
short implicit= 0;
|
||||
const short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF;
|
||||
|
||||
handle= construct_param_handle(scene, em, implicit, fill_holes, sel, correct_aspect);
|
||||
if(use_subsurf)
|
||||
handle = construct_param_handle_subsurfed(scene, em, fill_holes, sel, correct_aspect);
|
||||
else
|
||||
handle= construct_param_handle(scene, em, 0, fill_holes, sel, correct_aspect);
|
||||
|
||||
param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
|
||||
param_lscm_solve(handle);
|
||||
|
@ -930,6 +1136,9 @@ static int unwrap_exec(bContext *C, wmOperator *op)
|
|||
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");
|
||||
int use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
|
||||
int subsurf_level = RNA_int_get(op->ptr, "uv_subsurf_level");
|
||||
float obsize[3], unitsize[3] = {1.0f, 1.0f, 1.0f};
|
||||
short implicit= 0;
|
||||
|
||||
if(!uvedit_have_selection(scene, em, implicit)) {
|
||||
|
@ -944,8 +1153,14 @@ static int unwrap_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
mat4_to_size(obsize, obedit->obmat);
|
||||
if(!compare_v3v3(obsize, unitsize, 1e-4f))
|
||||
BKE_report(op->reports, RPT_INFO, "Object scale is not 1.0. Unwrap will operate on a non-scaled version of the mesh.");
|
||||
|
||||
/* remember last method for live unwrap */
|
||||
scene->toolsettings->unwrapper = method;
|
||||
|
||||
scene->toolsettings->uv_subsurf_level = subsurf_level;
|
||||
|
||||
if(fill_holes) scene->toolsettings->uvcalc_flag |= UVCALC_FILLHOLES;
|
||||
else scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES;
|
||||
|
@ -953,6 +1168,9 @@ static int unwrap_exec(bContext *C, wmOperator *op)
|
|||
if(correct_aspect) scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT;
|
||||
else scene->toolsettings->uvcalc_flag |= UVCALC_NO_ASPECT_CORRECT;
|
||||
|
||||
if(use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF;
|
||||
else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF;
|
||||
|
||||
/* execute unwrap */
|
||||
ED_unwrap_lscm(scene, obedit, TRUE);
|
||||
|
||||
|
@ -986,6 +1204,8 @@ void UV_OT_unwrap(wmOperatorType *ot)
|
|||
"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 UVs taking image aspect ratio into account");
|
||||
RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Data", "Map UV's taking vertex position after subsurf into account");
|
||||
RNA_def_int(ot->srna, "uv_subsurf_level", 1, 1, 6, "SubSurf Target", "Number of times to subdivide before calculating UV's", 1, 6);
|
||||
}
|
||||
|
||||
/**************** Project From View operator **************/
|
||||
|
|
|
@ -410,9 +410,12 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
|
|||
ImBuf *ibuf = NULL;
|
||||
unsigned int *bind = NULL;
|
||||
int rectw, recth, tpx=0, tpy=0, y;
|
||||
unsigned int *rectrow, *tilerectrow;
|
||||
unsigned int *tilerect= NULL, *scalerect= NULL, *rect= NULL;
|
||||
float *ftilerect= NULL, *fscalerect = NULL, *frect = NULL;
|
||||
float *srgb_frect = NULL;
|
||||
short texwindx, texwindy, texwinsx, texwinsy;
|
||||
/* flag to determine whether high resolution format is used */
|
||||
int use_high_bit_depth = FALSE, do_color_management = FALSE;
|
||||
|
||||
/* initialize tile mode and number of repeats */
|
||||
GTS.ima = ima;
|
||||
|
@ -462,9 +465,20 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
|
|||
if(ibuf==NULL)
|
||||
return 0;
|
||||
|
||||
/* ensure we have a char buffer and not only float */
|
||||
if ((ibuf->rect==NULL) && ibuf->rect_float)
|
||||
IMB_rect_from_float(ibuf);
|
||||
if(ibuf->rect_float) {
|
||||
if(U.use_16bit_textures) {
|
||||
/* use high precision textures. This is relatively harmless because OpenGL gives us
|
||||
a high precision format only if it is available */
|
||||
use_high_bit_depth = TRUE;
|
||||
}
|
||||
|
||||
/* TODO unneeded when float images are correctly treated as linear always */
|
||||
if(ibuf->profile == IB_PROFILE_LINEAR_RGB)
|
||||
do_color_management = TRUE;
|
||||
|
||||
if(ibuf->rect==NULL)
|
||||
IMB_rect_from_float(ibuf);
|
||||
}
|
||||
|
||||
/* currently, tpage refresh is used by ima sequences */
|
||||
if(ima->tpageflag & IMA_TPAGE_REFRESH) {
|
||||
|
@ -498,17 +512,39 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
|
|||
tpx= texwindx;
|
||||
tpy= texwindy;
|
||||
|
||||
rect= ibuf->rect + texwinsy*ibuf->x + texwinsx;
|
||||
if(use_high_bit_depth) {
|
||||
if(do_color_management) {
|
||||
srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(float)*4, "floar_buf_col_cor");
|
||||
IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
|
||||
ibuf->channels, IB_PROFILE_SRGB, ibuf->profile, 0,
|
||||
ibuf->x, ibuf->y, ibuf->x, ibuf->x);
|
||||
frect= srgb_frect + texwinsy*ibuf->x + texwinsx;
|
||||
}
|
||||
else
|
||||
frect= ibuf->rect_float + texwinsy*ibuf->x + texwinsx;
|
||||
}
|
||||
else
|
||||
rect= ibuf->rect + texwinsy*ibuf->x + texwinsx;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* regular image mode */
|
||||
bind= &ima->bindcode;
|
||||
|
||||
|
||||
if(*bind==0) {
|
||||
tpx= ibuf->x;
|
||||
tpy= ibuf->y;
|
||||
rect= ibuf->rect;
|
||||
if(use_high_bit_depth) {
|
||||
if(do_color_management) {
|
||||
frect = srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(*srgb_frect)*4, "floar_buf_col_cor");
|
||||
IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
|
||||
ibuf->channels, IB_PROFILE_SRGB, ibuf->profile, 0,
|
||||
ibuf->x, ibuf->y, ibuf->x, ibuf->x);
|
||||
}
|
||||
else
|
||||
frect= ibuf->rect_float;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,26 +559,57 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
|
|||
|
||||
/* for tiles, copy only part of image into buffer */
|
||||
if (GTS.tilemode) {
|
||||
tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
|
||||
if(use_high_bit_depth) {
|
||||
float *frectrow, *ftilerectrow;
|
||||
|
||||
for (y=0; y<recth; y++) {
|
||||
rectrow= &rect[y*ibuf->x];
|
||||
tilerectrow= &tilerect[y*rectw];
|
||||
|
||||
memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
|
||||
ftilerect= MEM_mallocN(rectw*recth*sizeof(*ftilerect), "tilerect");
|
||||
|
||||
for (y=0; y<recth; y++) {
|
||||
frectrow= &frect[y*ibuf->x];
|
||||
ftilerectrow= &ftilerect[y*rectw];
|
||||
|
||||
memcpy(ftilerectrow, frectrow, tpx*sizeof(*frectrow));
|
||||
}
|
||||
|
||||
frect= ftilerect;
|
||||
}
|
||||
else {
|
||||
unsigned int *rectrow, *tilerectrow;
|
||||
|
||||
tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
|
||||
|
||||
for (y=0; y<recth; y++) {
|
||||
rectrow= &rect[y*ibuf->x];
|
||||
tilerectrow= &tilerect[y*rectw];
|
||||
|
||||
memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
|
||||
}
|
||||
|
||||
rect= tilerect;
|
||||
rect= tilerect;
|
||||
}
|
||||
}
|
||||
|
||||
/* scale if not a power of two */
|
||||
/* scale if not a power of two. this is not strictly necessary for newer
|
||||
GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures */
|
||||
if (!is_pow2_limit(rectw) || !is_pow2_limit(recth)) {
|
||||
rectw= smaller_pow2_limit(rectw);
|
||||
recth= smaller_pow2_limit(recth);
|
||||
|
||||
scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
|
||||
gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
|
||||
rect= scalerect;
|
||||
if(use_high_bit_depth) {
|
||||
fscalerect= MEM_mallocN(rectw*recth*sizeof(*fscalerect)*4, "fscalerect");
|
||||
gluScaleImage(GL_RGBA, tpx, tpy, GL_FLOAT, frect, rectw, recth, GL_FLOAT, fscalerect);
|
||||
/* frect will refer to ibuf->rect_float when not color converting. We don't want to free that */
|
||||
if(do_color_management)
|
||||
MEM_freeN(frect);
|
||||
|
||||
frect = fscalerect;
|
||||
}
|
||||
else {
|
||||
scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
|
||||
gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
|
||||
|
||||
rect= scalerect;
|
||||
}
|
||||
}
|
||||
|
||||
/* create image */
|
||||
|
@ -550,12 +617,18 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
|
|||
glBindTexture( GL_TEXTURE_2D, *bind);
|
||||
|
||||
if (!(gpu_get_mipmap() && mipmap)) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
|
||||
if(use_high_bit_depth)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
|
||||
else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
|
||||
}
|
||||
else {
|
||||
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
|
||||
if(use_high_bit_depth)
|
||||
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA16, rectw, recth, GL_RGBA, GL_FLOAT, frect);
|
||||
else
|
||||
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
|
||||
|
||||
|
@ -570,9 +643,14 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
|
|||
/* clean up */
|
||||
if (tilerect)
|
||||
MEM_freeN(tilerect);
|
||||
if (ftilerect)
|
||||
MEM_freeN(ftilerect);
|
||||
if (scalerect)
|
||||
MEM_freeN(scalerect);
|
||||
|
||||
if (fscalerect)
|
||||
MEM_freeN(fscalerect);
|
||||
if (srgb_frect)
|
||||
MEM_freeN(srgb_frect);
|
||||
return *bind;
|
||||
}
|
||||
|
||||
|
@ -692,23 +770,21 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h, int mipmap)
|
|||
glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
|
||||
glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows);
|
||||
|
||||
if (ibuf->rect_float){
|
||||
/*This case needs a whole new buffer*/
|
||||
if(ibuf->rect==NULL) {
|
||||
IMB_rect_from_float(ibuf);
|
||||
}
|
||||
else {
|
||||
/* Do partial drawing. 'buffer' holds only the changed part. Needed for color corrected result */
|
||||
float *buffer = (float *)MEM_mallocN(w*h*sizeof(float)*4, "temp_texpaint_float_buf");
|
||||
IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h);
|
||||
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
|
||||
/* if color correction is needed, we must update the part that needs updating. */
|
||||
if(ibuf->rect_float && (!U.use_16bit_textures || (ibuf->profile == IB_PROFILE_LINEAR_RGB))) {
|
||||
float *buffer = MEM_mallocN(w*h*sizeof(float)*4, "temp_texpaint_float_buf");
|
||||
IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
|
||||
GL_FLOAT, buffer);
|
||||
MEM_freeN(buffer);
|
||||
if(ima->tpageflag & IMA_MIPMAP_COMPLETE)
|
||||
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
|
||||
return;
|
||||
}
|
||||
|
||||
MEM_freeN(buffer);
|
||||
|
||||
if(ima->tpageflag & IMA_MIPMAP_COMPLETE)
|
||||
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
|
||||
|
@ -717,8 +793,12 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h, int mipmap)
|
|||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, ibuf->rect);
|
||||
if(ibuf->rect_float)
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
|
||||
GL_FLOAT, ibuf->rect_float);
|
||||
else
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, ibuf->rect);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
|
||||
|
|
|
@ -671,10 +671,20 @@ typedef struct GameData {
|
|||
#define GAME_MAT_MULTITEX 1
|
||||
#define GAME_MAT_GLSL 2
|
||||
|
||||
/* *************************************************************** */
|
||||
/* UV Paint */
|
||||
#define UV_SCULPT_LOCK_BORDERS 1
|
||||
#define UV_SCULPT_ALL_ISLANDS 2
|
||||
|
||||
#define UV_SCULPT_TOOL_PINCH 1
|
||||
#define UV_SCULPT_TOOL_RELAX 2
|
||||
#define UV_SCULPT_TOOL_GRAB 3
|
||||
|
||||
#define UV_SCULPT_TOOL_RELAX_LAPLACIAN 1
|
||||
#define UV_SCULPT_TOOL_RELAX_HC 2
|
||||
|
||||
/* Markers */
|
||||
|
||||
typedef struct TimeMarker {
|
||||
typedef struct TimeMarker {
|
||||
struct TimeMarker *next, *prev;
|
||||
int frame;
|
||||
char name[64];
|
||||
|
@ -780,6 +790,9 @@ typedef struct Sculpt {
|
|||
int pad;
|
||||
} Sculpt;
|
||||
|
||||
typedef struct UvSculpt {
|
||||
Paint paint;
|
||||
} UvSculpt;
|
||||
/* ------------------------------------------- */
|
||||
/* Vertex Paint */
|
||||
|
||||
|
@ -855,6 +868,7 @@ typedef struct ToolSettings {
|
|||
VPaint *vpaint; /* vertex paint */
|
||||
VPaint *wpaint; /* weight paint */
|
||||
Sculpt *sculpt;
|
||||
UvSculpt *uvsculpt; /* uv smooth */
|
||||
|
||||
/* Vertex groups */
|
||||
float vgroup_weight;
|
||||
|
@ -894,7 +908,7 @@ typedef struct ToolSettings {
|
|||
short uvcalc_mapalign;
|
||||
short uvcalc_flag;
|
||||
short uv_flag, uv_selectmode;
|
||||
short uv_pad;
|
||||
short uv_subsurf_level;
|
||||
|
||||
/* Grease Pencil */
|
||||
short gpencil_flags;
|
||||
|
@ -966,10 +980,14 @@ typedef struct ToolSettings {
|
|||
char auto_normalize; /*auto normalizing mode in wpaint*/
|
||||
char multipaint; /* paint multiple bones in wpaint */
|
||||
|
||||
/* UV painting */
|
||||
int use_uv_sculpt;
|
||||
int uv_sculpt_settings;
|
||||
int uv_sculpt_tool;
|
||||
int uv_relax_method;
|
||||
/* XXX: these sculpt_paint_* fields are deprecated, use the
|
||||
unified_paint_settings field instead! */
|
||||
short sculpt_paint_settings DNA_DEPRECATED;
|
||||
short pad1;
|
||||
short sculpt_paint_settings DNA_DEPRECATED; short pad1;
|
||||
int sculpt_paint_unified_size DNA_DEPRECATED;
|
||||
float sculpt_paint_unified_unprojected_radius DNA_DEPRECATED;
|
||||
float sculpt_paint_unified_alpha DNA_DEPRECATED;
|
||||
|
@ -1421,6 +1439,7 @@ typedef enum SculptFlags {
|
|||
#define UVCALC_FILLHOLES 1
|
||||
#define UVCALC_NO_ASPECT_CORRECT 2 /* would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */
|
||||
#define UVCALC_TRANSFORM_CORRECT 4 /* adjust UV's while transforming to avoid distortion */
|
||||
#define UVCALC_USESUBSURF 8 /* Use mesh data after subsurf to compute UVs*/
|
||||
|
||||
/* toolsettings->uv_flag */
|
||||
#define UV_SYNC_SELECTION 1
|
||||
|
|
|
@ -252,7 +252,12 @@ typedef struct ThemeSpace {
|
|||
char hpad[7];
|
||||
|
||||
char preview_back[4];
|
||||
|
||||
char preview_stitch_face[4];
|
||||
char preview_stitch_edge[4];
|
||||
char preview_stitch_vert[4];
|
||||
char preview_stitch_stitchable[4];
|
||||
char preview_stitch_unstitchable[4];
|
||||
char preview_stitch_active[4];
|
||||
} ThemeSpace;
|
||||
|
||||
|
||||
|
@ -391,7 +396,7 @@ typedef struct UserDef {
|
|||
|
||||
short widget_unit; /* defaults to 20 for 72 DPI setting */
|
||||
short anisotropic_filter;
|
||||
/*short pad[3]; */
|
||||
short use_16bit_textures, pad8;
|
||||
|
||||
float ndof_sensitivity; /* overall sensitivity of 3D mouse */
|
||||
int ndof_flag; /* flags for 3D mouse */
|
||||
|
@ -403,7 +408,7 @@ typedef struct UserDef {
|
|||
short autokey_mode; /* autokeying mode */
|
||||
short autokey_flag; /* flags for autokeying */
|
||||
|
||||
short text_render, pad9[3]; /*options for text rendering*/
|
||||
short text_render, pad9; /*options for text rendering*/
|
||||
|
||||
struct ColorBand coba_weight; /* from texture.h */
|
||||
|
||||
|
|
|
@ -416,6 +416,7 @@ extern StructRNA RNA_Scopes;
|
|||
extern StructRNA RNA_Screen;
|
||||
extern StructRNA RNA_ScrewModifier;
|
||||
extern StructRNA RNA_Sculpt;
|
||||
extern StructRNA RNA_SelectedUvElement;
|
||||
extern StructRNA RNA_Sensor;
|
||||
extern StructRNA RNA_Sequence;
|
||||
extern StructRNA RNA_SequenceColorBalance;
|
||||
|
|
|
@ -63,6 +63,18 @@
|
|||
|
||||
#include "BLI_threads.h"
|
||||
|
||||
EnumPropertyItem uv_sculpt_relaxation_items[] = {
|
||||
{UV_SCULPT_TOOL_RELAX_LAPLACIAN, "LAPLACIAN", 0, "Laplacian", "Use Laplacian method for relaxation"},
|
||||
{UV_SCULPT_TOOL_RELAX_HC, "HC", 0, "HC", "Use HC method for relaxation"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
EnumPropertyItem uv_sculpt_tool_items[] = {
|
||||
{UV_SCULPT_TOOL_PINCH, "PINCH", 0, "Pinch", "Pinch UVs"},
|
||||
{UV_SCULPT_TOOL_RELAX, "RELAX", 0, "Relax", "Relax UVs"},
|
||||
{UV_SCULPT_TOOL_GRAB, "GRAB", 0, "Grab", "Grab UVs"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
|
||||
EnumPropertyItem snap_target_items[] = {
|
||||
{SCE_SNAP_TARGET_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
|
||||
{SCE_SNAP_TARGET_CENTER, "CENTER", 0, "Center", "Snap center onto target"},
|
||||
|
@ -267,9 +279,15 @@ EnumPropertyItem image_color_depth_items[] = {
|
|||
#include "ED_view3d.h"
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_keyframing.h"
|
||||
#include "ED_image.h"
|
||||
|
||||
#include "RE_engine.h"
|
||||
|
||||
static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
|
||||
{
|
||||
ED_space_image_uv_sculpt_update(bmain->wm.first, scene->toolsettings);
|
||||
}
|
||||
|
||||
static int rna_Scene_object_bases_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr)
|
||||
{
|
||||
Scene *scene= (Scene*)ptr->data;
|
||||
|
@ -1429,10 +1447,38 @@ static void rna_def_tool_settings(BlenderRNA *brna)
|
|||
RNA_def_property_pointer_sdna(prop, NULL, "imapaint");
|
||||
RNA_def_property_ui_text(prop, "Image Paint", "");
|
||||
|
||||
prop= RNA_def_property(srna, "uv_sculpt", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "uvsculpt");
|
||||
RNA_def_property_ui_text(prop, "UV Sculpt", "");
|
||||
|
||||
prop= RNA_def_property(srna, "particle_edit", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "particle");
|
||||
RNA_def_property_ui_text(prop, "Particle Edit", "");
|
||||
|
||||
prop= RNA_def_property(srna, "use_uv_sculpt", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "use_uv_sculpt", 1);
|
||||
RNA_def_property_ui_text(prop, "UV Sculpt", "Enable brush for uv sculpting");
|
||||
RNA_def_property_ui_icon(prop, ICON_TPAINT_HLT, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE|ND_SPACE_IMAGE, "rna_SpaceImageEditor_uv_sculpt_update");
|
||||
|
||||
prop= RNA_def_property(srna, "uv_sculpt_lock_borders", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "uv_sculpt_settings", UV_SCULPT_LOCK_BORDERS);
|
||||
RNA_def_property_ui_text(prop, "Lock Borders", "Disables editing of boundary edges");
|
||||
|
||||
prop= RNA_def_property(srna, "uv_sculpt_all_islands", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "uv_sculpt_settings", UV_SCULPT_ALL_ISLANDS);
|
||||
RNA_def_property_ui_text(prop, "Sculpt All Islands", "Brush operates on all islands");
|
||||
|
||||
prop= RNA_def_property(srna, "uv_sculpt_tool", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "uv_sculpt_tool");
|
||||
RNA_def_property_enum_items(prop, uv_sculpt_tool_items);
|
||||
RNA_def_property_ui_text(prop, "UV Sculpt Tools", "Select Tools for the UV sculpt brushes");
|
||||
|
||||
prop= RNA_def_property(srna, "uv_relax_method", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "uv_relax_method");
|
||||
RNA_def_property_enum_items(prop, uv_sculpt_relaxation_items);
|
||||
RNA_def_property_ui_text(prop, "Relaxation Method", "Algorithm used for UV relaxation");
|
||||
|
||||
/* Transform */
|
||||
prop= RNA_def_property(srna, "proportional_edit", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "proportional");
|
||||
|
@ -3842,6 +3888,28 @@ static void rna_def_scene_keying_sets_all(BlenderRNA *brna, PropertyRNA *cprop)
|
|||
RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET, NULL);
|
||||
}
|
||||
|
||||
/* Runtime property, used to remember uv indices, used only in UV stitch for now.
|
||||
*/
|
||||
static void rna_def_selected_uv_element(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna= RNA_def_struct(brna, "SelectedUvElement", "PropertyGroup");
|
||||
RNA_def_struct_ui_text(srna, "Selected Uv Element", "");
|
||||
|
||||
/* store the index to the UV element selected */
|
||||
prop= RNA_def_property(srna, "element_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
||||
RNA_def_property_ui_text(prop, "Element Index", "");
|
||||
|
||||
prop= RNA_def_property(srna, "face_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
||||
RNA_def_property_ui_text(prop, "Face Index", "");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RNA_def_scene(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -4175,6 +4243,7 @@ void RNA_def_scene(BlenderRNA *brna)
|
|||
rna_def_scene_game_data(brna);
|
||||
rna_def_scene_render_layer(brna);
|
||||
rna_def_transform_orientation(brna);
|
||||
rna_def_selected_uv_element(brna);
|
||||
|
||||
/* Scene API */
|
||||
RNA_api_scene(srna);
|
||||
|
|
|
@ -289,6 +289,16 @@ static void rna_def_sculpt(BlenderRNA *brna)
|
|||
RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Sculpt_update");
|
||||
}
|
||||
|
||||
|
||||
static void rna_def_uv_sculpt(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
||||
srna= RNA_def_struct(brna, "UvSculpt", "Paint");
|
||||
RNA_def_struct_ui_text(srna, "UV Sculpting", "");
|
||||
}
|
||||
|
||||
|
||||
/* use for weight paint too */
|
||||
static void rna_def_vertex_paint(BlenderRNA *brna)
|
||||
{
|
||||
|
@ -548,6 +558,7 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
|
|||
{
|
||||
rna_def_paint(brna);
|
||||
rna_def_sculpt(brna);
|
||||
rna_def_uv_sculpt(brna);
|
||||
rna_def_vertex_paint(brna);
|
||||
rna_def_image_paint(brna);
|
||||
rna_def_particle_edit(brna);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "DNA_userdef_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
@ -147,6 +148,12 @@ static void rna_userdef_gl_texture_limit_update(Main *bmain, Scene *scene, Point
|
|||
rna_userdef_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_userdef_gl_use_16bit_textures(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
GPU_free_images();
|
||||
rna_userdef_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_userdef_select_mouse_set(PointerRNA *ptr,int value)
|
||||
{
|
||||
UserDef *userdef = (UserDef*)ptr->data;
|
||||
|
@ -1623,6 +1630,42 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna)
|
|||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_ui_text(prop, "Scope region background color", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop= RNA_def_property(srna, "preview_stitch_face", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "preview_stitch_face");
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_ui_text(prop, "Stitch preview face color", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop= RNA_def_property(srna, "preview_stitch_edge", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "preview_stitch_edge");
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_ui_text(prop, "Stitch preview edge color", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop= RNA_def_property(srna, "preview_stitch_vert", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "preview_stitch_vert");
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_ui_text(prop, "Stitch preview vertex color", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop= RNA_def_property(srna, "preview_stitch_stitchable", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "preview_stitch_stitchable");
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_ui_text(prop, "Stitch preview stitchable color", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop= RNA_def_property(srna, "preview_stitch_unstitchable", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "preview_stitch_unstitchable");
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_ui_text(prop, "Stitch preview unstitchable color", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop= RNA_def_property(srna, "preview_stitch_active", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "preview_stitch_active");
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_ui_text(prop, "Stitch preview active island", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
|
||||
|
@ -2900,6 +2943,11 @@ static void rna_def_userdef_system(BlenderRNA *brna)
|
|||
"Scale textures for the 3D View (looks nicer but uses more memory and slows image reloading)");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_mipmap_update");
|
||||
|
||||
prop= RNA_def_property(srna, "use_16bit_textures", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "use_16bit_textures", 1);
|
||||
RNA_def_property_ui_text(prop, "16 Bit Float Textures", "Use 16 bit per component texture for float images.");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_gl_use_16bit_textures");
|
||||
|
||||
prop= RNA_def_property(srna, "use_vertex_buffer_objects", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_VBO);
|
||||
RNA_def_property_ui_text(prop, "VBOs", "Use Vertex Buffer Objects (or Vertex Arrays, if unsupported) for viewport rendering");
|
||||
|
|
|
@ -1213,7 +1213,14 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
|
|||
km = WM_keymap_find_all(C, "Pose", 0, 0);
|
||||
}
|
||||
else if (strstr(opname, "SCULPT_OT")) {
|
||||
km = WM_keymap_find_all(C, "Sculpt", 0, 0);
|
||||
switch(CTX_data_mode_enum(C)) {
|
||||
case OB_MODE_SCULPT:
|
||||
km = WM_keymap_find_all(C, "Sculpt", 0, 0);
|
||||
break;
|
||||
case OB_MODE_EDIT:
|
||||
km = WM_keymap_find_all(C, "UV Sculpt", 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (strstr(opname, "MBALL_OT")) {
|
||||
km = WM_keymap_find_all(C, "Metaball", 0, 0);
|
||||
|
|
|
@ -202,6 +202,8 @@ int ED_space_image_show_paint(struct SpaceImage *sima){return 0;}
|
|||
void ED_space_image_paint_update(struct wmWindowManager *wm, struct ToolSettings *settings){}
|
||||
void ED_space_image_set(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima){}
|
||||
struct ImBuf *ED_space_image_buffer(struct SpaceImage *sima){return (struct ImBuf *) NULL;}
|
||||
void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct ToolSettings *settings){}
|
||||
|
||||
void ED_screen_set_scene(struct bContext *C, struct Scene *scene){}
|
||||
void ED_space_clip_set(struct bContext *C, struct SpaceClip *sc, struct MovieClip *clip){}
|
||||
|
||||
|
|
Loading…
Reference in New Issue