Changes to Brush texture workflow

This changes how textures are accessed from Brushes, with the intention of simplifying 
the workflow, and reducing the amount of clicking. Rather than the previous texture slots 
(which didn't work as a stack anyway), brushes now have a single texture linked. Rather 
than taking time having to set up your slots in advance, you can now select and change 
textures directly as you sculpt/paint on the fly. For complex brushes, node textures can 
be used, or for fast access, it's easy to make a duplicate of your brush with the texture 
you like and assign a hotkey.

Brush textures can now be chosen from a new Textures panel in the brush tool 
properties - click on the thumbnail to open a texture selector. This is done using a new 
variation on the ID template - the number of rows and columns to display in the popup 
can be customised in the UI scripts.
This commit is contained in:
2010-01-03 08:37:18 +00:00
parent ca4a5f309e
commit 251ef0a47f
25 changed files with 357 additions and 223 deletions

View File

@@ -3171,9 +3171,10 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, char *str, short x1, short
/* arg is pointer to string/name, use uiButSetSearchFunc() below to make this work */
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, char *tip)
/* here a1 and a2, if set, control thumbnail preview rows/cols */
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, float a1, float a2, char *tip)
{
uiBut *but= ui_def_but(block, SEARCH_MENU, retval, "", x1, y1, x2, y2, arg, 0.0, maxlen, 0.0, 0.0, tip);
uiBut *but= ui_def_but(block, SEARCH_MENU, retval, "", x1, y1, x2, y2, arg, 0.0, maxlen, a1, a2, tip);
but->icon= (BIFIconID) icon;
but->flag|= UI_HAS_ICON;

View File

@@ -940,7 +940,7 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al
}
}
void ui_id_icon_render(bContext *C, ID *id)
void ui_id_icon_render(bContext *C, ID *id, int preview)
{
PreviewImage *pi = BKE_previewimg_get(id);
@@ -948,13 +948,17 @@ void ui_id_icon_render(bContext *C, ID *id)
if ((pi->changed[0] ||!pi->rect[0])) /* changed only ever set by dynamic icons */
{
/* create the preview rect if necessary */
icon_set_image(C, id, pi, 0);
icon_set_image(C, id, pi, 0); /* icon size */
if (preview)
icon_set_image(C, id, pi, 1); /* preview size */
pi->changed[0] = 0;
}
}
}
int ui_id_icon_get(bContext *C, ID *id)
int ui_id_icon_get(bContext *C, ID *id, int preview)
{
int iconid= 0;
@@ -968,7 +972,7 @@ int ui_id_icon_get(bContext *C, ID *id)
case ID_LA: /* fall through */
iconid= BKE_icon_getid(id);
/* checks if not exists, or changed */
ui_id_icon_render(C, id);
ui_id_icon_render(C, id, preview);
break;
default:
break;
@@ -1004,8 +1008,18 @@ void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha)
icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, 0, size, 1);
}
void UI_icon_draw_preview(float x, float y, int icon_id, int nocreate)
void UI_icon_draw_preview(float x, float y, int icon_id)
{
icon_draw_mipmap(x, y, icon_id, 1.0f, 1.0f, PREVIEW_MIPMAP_LARGE, nocreate);
icon_draw_mipmap(x, y, icon_id, 1.0f, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
}
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
{
icon_draw_mipmap(x, y, icon_id, aspect, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
}
void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size)
{
icon_draw_size(x, y, icon_id, aspect, 1.0f, NULL, PREVIEW_MIPMAP_LARGE, size, 0);
}

View File

@@ -450,13 +450,14 @@ struct ThemeUI;
void ui_widget_color_init(struct ThemeUI *tui);
void ui_draw_menu_item(struct uiFontStyle *fstyle, rcti *rect, char *name, int iconid, int state);
void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, char *name, int iconid, int state);
/* interface_style.c */
void uiStyleInit(void);
/* interface_icons.c */
void ui_id_icon_render(struct bContext *C, struct ID *id);
int ui_id_icon_get(struct bContext *C, struct ID *id);
void ui_id_icon_render(struct bContext *C, struct ID *id, int preview);
int ui_id_icon_get(struct bContext *C, struct ID *id, int preview);
/* resources.c */
void init_userdef_do_versions(void);

View File

@@ -1115,7 +1115,7 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, char *str, ui
continue;
if(RNA_struct_is_ID(itemptr.type))
iconid= ui_id_icon_get((bContext*)C, itemptr.data);
iconid= ui_id_icon_get((bContext*)C, itemptr.data, 0);
name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);

View File

@@ -547,6 +547,8 @@ typedef struct uiSearchboxData {
uiSearchItems items;
int active; /* index in items array */
int noback; /* when menu opened with enough space for this */
int preview; /* draw thumbnail previews, rather than list */
int prv_rows, prv_cols;
} uiSearchboxData;
#define SEARCH_ITEMS 10
@@ -628,14 +630,34 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
static void ui_searchbox_butrect(rcti *rect, uiSearchboxData *data, int itemnr)
{
int buth= (data->bbox.ymax-data->bbox.ymin - 2*MENU_TOP)/SEARCH_ITEMS;
*rect= data->bbox;
rect->xmin= data->bbox.xmin + 3.0f;
rect->xmax= data->bbox.xmax - 3.0f;
rect->ymax= data->bbox.ymax - MENU_TOP - itemnr*buth;
rect->ymin= rect->ymax - buth;
/* thumbnail preview */
if (data->preview) {
int buth = (data->bbox.ymax - data->bbox.ymin - 2*MENU_TOP) / data->prv_rows;
int butw = (data->bbox.xmax - data->bbox.xmin) / data->prv_cols;
int row, col;
*rect= data->bbox;
col = itemnr % data->prv_cols;
row = itemnr / data->prv_cols;
rect->xmin += col * butw;
rect->xmax = rect->xmin + butw;
rect->ymax = data->bbox.ymax - (row * buth);
rect->ymin = rect->ymax - buth;
}
/* list view */
else {
int buth= (data->bbox.ymax-data->bbox.ymin - 2*MENU_TOP)/SEARCH_ITEMS;
*rect= data->bbox;
rect->xmin= data->bbox.xmin + 3.0f;
rect->xmax= data->bbox.xmax - 3.0f;
rect->ymax= data->bbox.ymax - MENU_TOP - itemnr*buth;
rect->ymin= rect->ymax - buth;
}
}
@@ -799,27 +821,55 @@ static void ui_searchbox_region_draw(const bContext *C, ARegion *ar)
if(data->items.totitem) {
rcti rect;
int a;
if (data->preview) {
/* draw items */
for(a=0; a<data->items.totitem; a++) {
ui_searchbox_butrect(&rect, data, a);
/* draw items */
for(a=0; a<data->items.totitem; a++) {
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
if (data->preview)
ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
else
ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
}
/* widget itself */
ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
/* indicate more */
if(data->items.more) {
ui_searchbox_butrect(&rect, data, data->items.maxitem-1);
glEnable(GL_BLEND);
UI_icon_draw(rect.xmax-18, rect.ymin-7, ICON_TRIA_DOWN);
glDisable(GL_BLEND);
}
if(data->items.offset) {
ui_searchbox_butrect(&rect, data, 0);
glEnable(GL_BLEND);
UI_icon_draw(rect.xmin, rect.ymax-9, ICON_TRIA_UP);
glDisable(GL_BLEND);
}
}
/* indicate more */
if(data->items.more) {
ui_searchbox_butrect(&rect, data, data->items.maxitem-1);
glEnable(GL_BLEND);
UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymin-9, ICON_TRIA_DOWN);
glDisable(GL_BLEND);
}
if(data->items.offset) {
ui_searchbox_butrect(&rect, data, 0);
glEnable(GL_BLEND);
UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymax-7, ICON_TRIA_UP);
glDisable(GL_BLEND);
} else {
/* draw items */
for(a=0; a<data->items.totitem; a++) {
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
}
/* indicate more */
if(data->items.more) {
ui_searchbox_butrect(&rect, data, data->items.maxitem-1);
glEnable(GL_BLEND);
UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymin-9, ICON_TRIA_DOWN);
glDisable(GL_BLEND);
}
if(data->items.offset) {
ui_searchbox_butrect(&rect, data, 0);
glEnable(GL_BLEND);
UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymax-7, ICON_TRIA_UP);
glDisable(GL_BLEND);
}
}
}
}
@@ -830,7 +880,7 @@ static void ui_searchbox_region_free(ARegion *ar)
int a;
/* free search data */
for(a=0; a<SEARCH_ITEMS; a++)
for(a=0; a<data->items.maxitem; a++)
MEM_freeN(data->items.names[a]);
MEM_freeN(data->items.names);
MEM_freeN(data->items.pointers);
@@ -876,8 +926,13 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
if(but->block->flag & UI_BLOCK_LOOP)
data->noback= 1;
/* compute position */
if (but->a1 > 0 && but->a2 > 0) {
data->preview = 1;
data->prv_rows = but->a1;
data->prv_cols = but->a2;
}
/* compute position */
if(but->block->flag & UI_BLOCK_LOOP) {
/* this case is search menu inside other menu */
/* we copy region size */
@@ -972,13 +1027,17 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
ED_region_tag_redraw(ar);
/* prepare search data */
data->items.maxitem= SEARCH_ITEMS;
if (data->preview) {
data->items.maxitem= data->prv_rows * data->prv_cols;
} else {
data->items.maxitem= SEARCH_ITEMS;
}
data->items.maxstrlen= but->hardmax;
data->items.totitem= 0;
data->items.names= MEM_callocN(SEARCH_ITEMS*sizeof(void *), "search names");
data->items.pointers= MEM_callocN(SEARCH_ITEMS*sizeof(void *), "search pointers");
data->items.icons= MEM_callocN(SEARCH_ITEMS*sizeof(int), "search icons");
for(x1=0; x1<SEARCH_ITEMS; x1++)
data->items.names= MEM_callocN(data->items.maxitem*sizeof(void *), "search names");
data->items.pointers= MEM_callocN(data->items.maxitem*sizeof(void *), "search pointers");
data->items.icons= MEM_callocN(data->items.maxitem*sizeof(int), "search icons");
for(x1=0; x1<data->items.maxitem; x1++)
data->items.names[x1]= MEM_callocN(but->hardmax+1, "search pointers");
return ar;

View File

@@ -122,6 +122,7 @@ typedef struct TemplateID {
PropertyRNA *prop;
ListBase *idlb;
int prv_rows, prv_cols;
} TemplateID;
/* Search browse menu, assign */
@@ -150,7 +151,7 @@ static void id_search_cb(const bContext *C, void *arg_template, char *str, uiSea
/* ID listbase */
for(id= lb->first; id; id= id->next) {
if(BLI_strcasestr(id->name+2, str)) {
iconid= ui_id_icon_get((bContext*)C, id);
iconid= ui_id_icon_get((bContext*)C, id, 0);
if(!uiSearchItemAdd(items, id->name+2, id, iconid))
break;
@@ -180,11 +181,26 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
/* fake button, it holds space for search items */
uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, "");
uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
/* preview thumbnails */
if (template.prv_rows > 0 && template.prv_cols > 0) {
int w = 96 * template.prv_cols;
int h = 96 * template.prv_rows + 20;
/* fake button, it holds space for search items */
uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
}
/* list view */
else {
/* fake button, it holds space for search items */
uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
}
uiBoundsBlock(block, 6);
uiBlockSetDirection(block, UI_DOWN);
@@ -293,9 +309,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
}
static void template_ID(bContext *C, uiBlock *block, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop)
static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop)
{
uiBut *but;
uiBlock *block;
PointerRNA idptr;
ListBase *lb;
ID *id, *idfrom;
@@ -305,11 +322,27 @@ static void template_ID(bContext *C, uiBlock *block, TemplateID *template, Struc
idfrom= template->ptr.id.data;
lb= template->idlb;
block= uiLayoutGetBlock(layout);
uiBlockBeginAlign(block);
if(idptr.type)
type= idptr.type;
if(flag & UI_ID_PREVIEWS) {
but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, "Browse ID data");
if(type) {
but->icon= RNA_struct_ui_icon(type);
if (id) but->icon = ui_id_icon_get(C, id, 1);
uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
}
if((idfrom && idfrom->lib))
uiButSetFlag(but, UI_BUT_DISABLED);
uiLayoutRow(layout, 1);
} else
if(flag & UI_ID_BROWSE) {
but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*1.6, UI_UNIT_Y, "Browse ID data");
if(type) {
@@ -412,10 +445,9 @@ static void template_ID(bContext *C, uiBlock *block, TemplateID *template, Struc
uiBlockEndAlign(block);
}
void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int previews, int prv_rows, int prv_cols)
{
TemplateID *template;
uiBlock *block;
PropertyRNA *prop;
StructRNA *type;
int flag;
@@ -430,14 +462,18 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname
template= MEM_callocN(sizeof(TemplateID), "TemplateID");
template->ptr= *ptr;
template->prop= prop;
template->prv_rows = prv_rows;
template->prv_cols = prv_cols;
flag= UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE;
if(newop)
flag |= UI_ID_ADD_NEW;
if(openop)
flag |= UI_ID_OPEN;
if(previews)
flag |= UI_ID_PREVIEWS;
type= RNA_property_pointer_type(ptr, prop);
template->idlb= wich_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
@@ -446,11 +482,21 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname
*/
if(template->idlb) {
uiLayoutRow(layout, 1);
block= uiLayoutGetBlock(layout);
template_ID(C, block, template, type, flag, newop, openop, unlinkop);
template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
}
MEM_freeN(template);
}
void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, 0, 0, 0);
}
void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int rows, int cols)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, 1, rows, cols);
}
/************************ ID Chooser Template ***************************/
@@ -1944,7 +1990,7 @@ static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon)
/* get icon from ID */
if(id) {
icon= ui_id_icon_get(C, id);
icon= ui_id_icon_get(C, id, 1);
if(icon)
return icon;
@@ -2245,7 +2291,7 @@ void uiTemplateOperatorSearch(uiLayout *layout)
block= uiLayoutGetBlock(layout);
uiBlockSetCurLayout(block, layout);
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, "");
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
}

View File

@@ -695,6 +695,27 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
/* *********************** text/icon ************************************** */
#define PREVIEW_PAD 4
static void widget_draw_preview(BIFIconID icon, float aspect, float alpha, rcti *rect)
{
int w, h, x, y, size;
/* only display previews for actual preview images .. ? */
if (icon < BIFICONID_LAST)
return;
w = rect->xmax - rect->xmin;
h = rect->ymax - rect->ymin;
size = MIN2(w, h);
size -= PREVIEW_PAD*2; /* padding */
x = rect->xmin + w/2 - size/2;
y = rect->ymin + h/2 - size/2;
UI_icon_draw_preview_aspect_size(x, y, icon, aspect, size);
}
/* icons have been standardized... and this call draws in untransformed coordinates */
#define ICON_HEIGHT 16.0f
@@ -704,6 +725,11 @@ static void widget_draw_icon(uiBut *but, BIFIconID icon, float alpha, rcti *rect
int xs=0, ys=0;
float aspect, height;
if (but->flag & UI_ICON_PREVIEW) {
widget_draw_preview(icon, but->block->aspect, alpha, rect);
return;
}
/* this icon doesn't need draw... */
if(icon==ICON_BLANK1 && (but->flag & UI_ICON_SUBMENU)==0) return;
@@ -2692,3 +2718,25 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, char *name, int iconid,
}
}
void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, char *name, int iconid, int state)
{
rcti trect = *rect;
uiWidgetType *wt= widget_type(UI_WTYPE_MENU_ITEM);
wt->state(wt, state);
wt->draw(&wt->wcol, rect, 0, 0);
widget_draw_preview(iconid, 1.f, 1.f, rect);
if (state == UI_ACTIVE)
glColor3ubv((unsigned char*)wt->wcol.text);
else
glColor3ubv((unsigned char*)wt->wcol.text_sel);
trect.xmin += 0;
trect.xmax = trect.xmin + BLF_width(name) + 10;
trect.ymin += 10;
trect.ymax = trect.ymin + BLF_height(name);
uiStyleFontDraw(fstyle, &trect, name);
}