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:
Antony Riakiotakis 2012-01-17 16:31:13 +00:00
parent fcc54520d1
commit a8081c1d2b
42 changed files with 3727 additions and 320 deletions

View File

@ -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', [])
]),

View File

@ -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__)

View File

@ -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")

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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]);

View File

@ -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];

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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! */

View File

@ -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;

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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

View File

@ -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'

View File

@ -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));

View File

@ -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 */

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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");

View File

@ -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);

View File

@ -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

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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 **************/

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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){}