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

@@ -87,13 +87,15 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel):
def draw(self, context):
layout = self.layout
space = context.space_data
tex = context.texture
wide_ui = context.region.width > narrowui
idblock = context_tex_datablock(context)
tex_collection = space.pin_id == None and type(idblock) != bpy.types.Brush
space = context.space_data
if idblock:
if tex_collection:
row = layout.row()
row.template_list(idblock, "textures", idblock, "active_texture_index", rows=2)
@@ -102,15 +104,22 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel):
col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
if wide_ui:
split = layout.split(percentage=0.65)
if idblock:
split.template_ID(idblock, "active_texture", new="texture.new")
elif tex:
split.template_ID(space, "pin_id")
col = split.column()
else:
layout.template_ID(idblock, "active_texture", new="texture.new")
col = layout.column()
if tex_collection:
col.template_ID(idblock, "active_texture", new="texture.new")
elif idblock:
col.template_ID(idblock, "texture", new="texture.new")
if space.pin_id:
col.template_ID(space, "pin_id")
if wide_ui:
col = split.column()
if (not space.pin_id) and (
context.sculpt_object or
@@ -118,7 +127,7 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel):
context.weight_paint_object or
context.texture_paint_object):
split.prop(space, "brush_texture", text="Brush", toggle=True)
col.prop(space, "brush_texture", text="Brush", toggle=True)
if tex:
layout.prop(tex, "use_nodes")
@@ -268,6 +277,10 @@ class TEXTURE_PT_influence(TextureSlotPanel):
bl_label = "Influence"
def poll(self, context):
idblock = context_tex_datablock(context)
if type(idblock) == bpy.types.Brush:
return False
return context.texture_slot
def draw(self, context):

View File

@@ -624,6 +624,29 @@ class VIEW3D_PT_tools_brush(PaintPanel):
#row.prop(brush, "jitter", slider=True)
#row.prop(brush, "use_jitter_pressure", toggle=True, text="")
class VIEW3D_PT_tools_brush_texture(PaintPanel):
bl_label = "Texture"
bl_default_closed = True
def poll(self, context):
settings = self.paint_settings(context)
return (settings and settings.brush and (context.sculpt_object or
context.texture_paint_object))
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
brush = settings.brush
tex_slot = brush.texture_slot
col = layout.column()
col.template_ID_preview(brush, "texture", new="texture.new", rows=2, cols=4)
col.row().prop(tex_slot, "map_mode", expand=True)
class VIEW3D_PT_tools_brush_tool(PaintPanel):
bl_label = "Tool"
bl_default_closed = True
@@ -975,6 +998,7 @@ bpy.types.register(VIEW3D_PT_tools_latticeedit)
bpy.types.register(VIEW3D_PT_tools_posemode)
bpy.types.register(VIEW3D_PT_tools_posemode_options)
bpy.types.register(VIEW3D_PT_tools_brush)
bpy.types.register(VIEW3D_PT_tools_brush_texture)
bpy.types.register(VIEW3D_PT_tools_brush_tool)
bpy.types.register(VIEW3D_PT_tools_brush_stroke)
bpy.types.register(VIEW3D_PT_tools_brush_curve)

View File

@@ -100,18 +100,10 @@ Brush *add_brush(const char *name)
Brush *copy_brush(Brush *brush)
{
Brush *brushn;
MTex *mtex;
int a;
brushn= copy_libblock(brush);
for(a=0; a<MAX_MTEX; a++) {
mtex= brush->mtex[a];
if(mtex) {
brushn->mtex[a]= MEM_dupallocN(mtex);
if(mtex->tex) id_us_plus((ID*)mtex->tex);
}
}
if(brush->mtex.tex) id_us_plus((ID*)brush->mtex.tex);
brushn->curve= curvemapping_copy(brush->curve);
@@ -127,16 +119,7 @@ Brush *copy_brush(Brush *brush)
/* not brush itself */
void free_brush(Brush *brush)
{
MTex *mtex;
int a;
for(a=0; a<MAX_MTEX; a++) {
mtex= brush->mtex[a];
if(mtex) {
if(mtex->tex) mtex->tex->id.us--;
MEM_freeN(mtex);
}
}
if(brush->mtex.tex) brush->mtex.tex->id.us--;
curvemapping_free(brush->curve);
}
@@ -295,8 +278,8 @@ void brush_curve_preset(Brush *b, BrushCurvePreset preset)
static MTex *brush_active_texture(Brush *brush)
{
if(brush && brush->texact >= 0)
return brush->mtex[brush->texact];
if(brush)
return &brush->mtex;
return NULL;
}
@@ -304,8 +287,7 @@ int brush_texture_set_nr(Brush *brush, int nr)
{
ID *idtest, *id=NULL;
if(brush->mtex[brush->texact])
id= (ID *)brush->mtex[brush->texact]->tex;
id= (ID *)brush->mtex.tex;
idtest= (ID*)BLI_findlink(&G.main->tex, nr-1);
if(idtest==0) { /* new tex */
@@ -316,13 +298,7 @@ int brush_texture_set_nr(Brush *brush, int nr)
if(idtest!=id) {
brush_texture_delete(brush);
if(brush->mtex[brush->texact]==NULL) {
brush->mtex[brush->texact]= add_mtex();
brush->mtex[brush->texact]->r = 1.0f;
brush->mtex[brush->texact]->g = 1.0f;
brush->mtex[brush->texact]->b = 1.0f;
}
brush->mtex[brush->texact]->tex= (Tex*)idtest;
brush->mtex.tex= (Tex*)idtest;
id_us_plus(idtest);
return 1;
@@ -333,16 +309,10 @@ int brush_texture_set_nr(Brush *brush, int nr)
int brush_texture_delete(Brush *brush)
{
if(brush->mtex[brush->texact]) {
if(brush->mtex[brush->texact]->tex)
brush->mtex[brush->texact]->tex->id.us--;
MEM_freeN(brush->mtex[brush->texact]);
brush->mtex[brush->texact]= NULL;
if(brush->mtex.tex)
brush->mtex.tex->id.us--;
return 1;
}
return 0;
}
int brush_clone_image_set_nr(Brush *brush, int nr)
@@ -383,7 +353,7 @@ void brush_check_exists(Brush **brush, const char *name)
/* Brush Sampling */
void brush_sample_tex(Brush *brush, float *xy, float *rgba)
{
MTex *mtex= brush->mtex[brush->texact];
MTex *mtex= &brush->mtex;
if (mtex && mtex->tex) {
float co[3], tin, tr, tg, tb, ta;
@@ -741,7 +711,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, float *pos)
{
Brush *brush= painter->brush;
BrushPainterCache *cache= &painter->cache;
MTex *mtex= brush->mtex[brush->texact];
MTex *mtex= &brush->mtex;
int size;
short flt;
@@ -976,7 +946,7 @@ float brush_curve_strength(Brush *br, float p, const float len)
unsigned int *brush_gen_texture_cache(Brush *br, int half_side)
{
unsigned int *texcache = NULL;
MTex *mtex = br->mtex[br->texact];
MTex *mtex = &br->mtex;
TexResult texres;
int hasrgb, ix, iy;
int side = half_side * 2;

View File

@@ -703,12 +703,10 @@ void make_local_texture(Tex *tex)
}
br= G.main->brush.first;
while(br) {
for(a=0; a<MAX_MTEX; a++) {
if(br->mtex[a] && br->mtex[a]->tex==tex) {
if(br->mtex.tex==tex) {
if(br->id.lib) lib= 1;
else local= 1;
}
}
br= br->id.next;
}
@@ -762,15 +760,13 @@ void make_local_texture(Tex *tex)
}
br= G.main->brush.first;
while(br) {
for(a=0; a<MAX_MTEX; a++) {
if(br->mtex[a] && br->mtex[a]->tex==tex) {
if(br->mtex.tex==tex) {
if(br->id.lib==0) {
br->mtex[a]->tex= texn;
br->mtex.tex= texn;
texn->id.us++;
tex->id.us--;
}
}
}
br= br->id.next;
}
}
@@ -904,10 +900,6 @@ int give_active_mtex(ID *id, MTex ***mtex_ar, short *act)
*mtex_ar= ((Lamp *)id)->mtex;
if(act) *act= (((Lamp *)id)->texact);
break;
case ID_BR:
*mtex_ar= ((Brush *)id)->mtex;
if(act) *act= (((Brush *)id)->texact);
break;
default:
*mtex_ar = NULL;
if(act) *act= 0;
@@ -932,9 +924,6 @@ void set_active_mtex(ID *id, short act)
case ID_LA:
((Lamp *)id)->texact= act;
break;
case ID_BR:
((Brush *)id)->texact= act;
break;
}
}
@@ -1016,35 +1005,18 @@ void set_current_world_texture(World *wo, Tex *newtex)
Tex *give_current_brush_texture(Brush *br)
{
MTex *mtex= NULL;
Tex *tex= NULL;
if(br) {
mtex= br->mtex[(int)(br->texact)];
if(mtex) tex= mtex->tex;
}
return tex;
return br->mtex.tex;
}
void set_current_brush_texture(Brush *br, Tex *newtex)
{
int act= br->texact;
if(br->mtex[act] && br->mtex[act]->tex)
id_us_min(&br->mtex[act]->tex->id);
if(br->mtex.tex)
id_us_min(&br->mtex.tex->id);
if(newtex) {
if(!br->mtex[act])
br->mtex[act]= add_mtex();
br->mtex[act]->tex= newtex;
br->mtex.tex= newtex;
id_us_plus(&newtex->id);
}
else if(br->mtex[act]) {
MEM_freeN(br->mtex[act]);
br->mtex[act]= NULL;
}
}
/* ------------------------------------------------------------------------- */

View File

@@ -1532,22 +1532,13 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
static void lib_link_brush(FileData *fd, Main *main)
{
Brush *brush;
MTex *mtex;
int a;
/* only link ID pointers */
for(brush= main->brush.first; brush; brush= brush->id.next) {
if(brush->id.flag & LIB_NEEDLINK) {
brush->id.flag -= LIB_NEEDLINK;
brush->clone.image= newlibadr_us(fd, brush->id.lib, brush->clone.image);
for(a=0; a<MAX_MTEX; a++) {
mtex= brush->mtex[a];
if(mtex)
mtex->tex= newlibadr_us(fd, brush->id.lib, mtex->tex);
}
brush->mtex.tex= newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->clone.image= newlibadr_us(fd, brush->id.lib, brush->clone.image);
}
}
@@ -1556,10 +1547,6 @@ static void lib_link_brush(FileData *fd, Main *main)
static void direct_link_brush(FileData *fd, Brush *brush)
{
/* brush itself has been read */
int a;
for(a=0; a<MAX_MTEX; a++)
brush->mtex[a]= newdataadr(fd, brush->mtex[a]);
/* fallof curve */
brush->curve= newdataadr(fd, brush->curve);
@@ -10336,6 +10323,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
if (1) {
Scene *sce;
Object *ob;
Brush *brush;
/* game engine changes */
for(sce = main->scene.first; sce; sce = sce->id.next) {
@@ -10393,6 +10381,11 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
avs->path_step= arm->pathsize;
}
}
/* brush texture changes */
for (brush= main->brush.first; brush; brush= brush->id.next) {
default_mtex(&brush->mtex);
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
@@ -10891,11 +10884,7 @@ static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
{
int a;
for(a=0; a<MAX_MTEX; a++)
if(brush->mtex[a])
expand_doit(fd, mainvar, brush->mtex[a]->tex);
expand_doit(fd, mainvar, brush->mtex.tex);
expand_doit(fd, mainvar, brush->clone.image);
}

View File

@@ -2317,15 +2317,11 @@ static void write_nodetrees(WriteData *wd, ListBase *idbase)
static void write_brushes(WriteData *wd, ListBase *idbase)
{
Brush *brush;
int a;
for(brush=idbase->first; brush; brush= brush->id.next) {
if(brush->id.us>0 || wd->current) {
writestruct(wd, ID_BR, "Brush", 1, brush);
if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd);
for(a=0; a<MAX_MTEX; a++)
if(brush->mtex[a])
writestruct(wd, DATA, "MTex", 1, brush->mtex[a]);
if(brush->curve)
write_curvemapping(wd, brush->curve);

View File

@@ -126,11 +126,12 @@ typedef struct uiLayout uiLayout;
#define UI_TEXT_LEFT 64
#define UI_ICON_LEFT 128
#define UI_ICON_SUBMENU 256
#define UI_ICON_PREVIEW 512
/* control for button type block */
#define UI_MAKE_TOP 512
#define UI_MAKE_DOWN 1024
#define UI_MAKE_LEFT 2048
#define UI_MAKE_RIGHT 4096
#define UI_MAKE_TOP 1024
#define UI_MAKE_DOWN 2048
#define UI_MAKE_LEFT 4096
#define UI_MAKE_RIGHT 8192
/* button align flag, for drawing groups together */
#define UI_BUT_ALIGN (15<<14)
@@ -427,6 +428,7 @@ struct PointerRNA *uiButGetOperatorPtrRNA(uiBut *but);
#define UI_ID_FAKE_USER 256
#define UI_ID_PIN 512
#define UI_ID_BROWSE_RENDER 1024
#define UI_ID_PREVIEWS 2048
#define UI_ID_FULL (UI_ID_RENAME|UI_ID_BROWSE|UI_ID_ADD_NEW|UI_ID_OPEN|UI_ID_ALONE|UI_ID_DELETE|UI_ID_LOCAL)
typedef void (*uiIDPoinFuncFP)(struct bContext *C, char *str, struct ID **idpp);
@@ -451,7 +453,7 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg,
uiBut *uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip);
uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *keypoin, short *modkeypoin, char *tip);
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, char *tip);
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);
void uiBlockPickerButtons(struct uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval);
void uiBlockColorbandButtons(struct uiBlock *block, struct ColorBand *coba, struct rctf *butr, int event);
@@ -641,6 +643,8 @@ void uiTemplateHeader(uiLayout *layout, struct bContext *C, int menus);
void uiTemplateDopeSheetFilter(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
char *newop, char *openop, char *unlinkop);
void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
char *newop, char *openop, char *unlinkop, int rows, int cols);
void uiTemplateAnyID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
char *proptypename, char *text);
void uiTemplatePathBuilder(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,

View File

@@ -55,7 +55,9 @@ int UI_icon_get_width(int icon_id);
int UI_icon_get_height(int icon_id);
void UI_icon_draw(float x, float y, int icon_id);
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);
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect);
void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size);
void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha);
void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, float *rgb);

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,6 +630,25 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
static void ui_searchbox_butrect(rcti *rect, uiSearchboxData *data, int itemnr)
{
/* 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;
@@ -636,6 +657,7 @@ static void ui_searchbox_butrect(rcti *rect, uiSearchboxData *data, int itemnr)
rect->ymax= data->bbox.ymax - MENU_TOP - itemnr*buth;
rect->ymin= rect->ymax - buth;
}
}
@@ -800,6 +822,33 @@ static void ui_searchbox_region_draw(const bContext *C, ARegion *ar)
rcti rect;
int a;
if (data->preview) {
/* 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);
}
/* 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);
}
} else {
/* draw items */
for(a=0; a<data->items.totitem; a++) {
ui_searchbox_butrect(&rect, data, a);
@@ -822,6 +871,7 @@ static void ui_searchbox_region_draw(const bContext *C, ARegion *ar)
glDisable(GL_BLEND);
}
}
}
}
static void ui_searchbox_region_free(ARegion *ar)
@@ -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 */
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);
/* 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, "");
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,6 +462,8 @@ 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;
@@ -437,6 +471,8 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname
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);
}

View File

@@ -2890,7 +2890,7 @@ static void project_paint_begin(ProjPaintState *ps)
ps->is_airbrush = (ps->brush->flag & BRUSH_AIRBRUSH) ? 1 : 0;
ps->is_texbrush = (ps->brush->mtex[ps->brush->texact] && ps->brush->mtex[ps->brush->texact]->tex) ? 1 : 0;
ps->is_texbrush = (ps->brush->mtex.tex) ? 1 : 0;
/* calculate vert screen coords

View File

@@ -614,12 +614,9 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float
/* Return a multiplier for brush strength on a particular vertex. */
static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
{
MTex *tex = NULL;
MTex *tex = &br->mtex;
float avg= 1;
if(br->texact >= 0)
tex = br->mtex[br->texact];
if(!tex) {
avg= 1;
}

View File

@@ -626,7 +626,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
Brush *br= ptr->data;
if(br)
CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, br->mtex[(int)br->texact]);
CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, &br->mtex);
}
return 1;

View File

@@ -335,6 +335,10 @@ static void buttons_area_listener(ScrArea *sa, wmNotifier *wmn)
buttons_area_redraw(sa, BCONTEXT_DATA);
sbuts->preview= 1;
break;
case NC_BRUSH:
buttons_area_redraw(sa, BCONTEXT_TEXTURE);
sbuts->preview= 1;
break;
case NC_TEXTURE:
ED_area_tag_redraw(sa);
sbuts->preview= 1;

View File

@@ -5029,7 +5029,7 @@ static uiBlock *operator_search_menu(bContext *C, ARegion *ar, void *arg_kmi)
/* 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, "");
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
uiButSetSearchFunc(but, operator_search_cb, arg_kmi, operator_call_cb, ot);
uiBoundsBlock(block, 6);

View File

@@ -239,7 +239,7 @@ static uiBlock *tool_search_menu(bContext *C, ARegion *ar, void *arg_listbase)
/* 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, OP_MAX_TYPENAME, 10, 0, 150, 19, "");
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, OP_MAX_TYPENAME, 10, 0, 150, 19, 0, 0, "");
uiButSetSearchFunc(but, operator_search_cb, arg_listbase, operator_call_cb, NULL);
uiBoundsBlock(block, 6);

View File

@@ -31,6 +31,7 @@
#define DNA_BRUSH_TYPES_H
#include "DNA_ID.h"
#include "DNA_texture_types.h"
#ifndef MAX_MTEX
#define MAX_MTEX 18
@@ -50,9 +51,8 @@ typedef struct Brush {
ID id;
struct BrushClone clone;
struct CurveMapping *curve; /* falloff curve */
struct MTex *mtex[18]; /* MAX_MTEX */
struct MTex mtex;
short flag, blend; /* general purpose flag, blend mode */
int size; /* brush diameter */
@@ -65,10 +65,8 @@ typedef struct Brush {
float rgb[3]; /* color */
float alpha; /* opacity */
short texact; /* active texture */
char sculpt_tool; /* active tool */
char pad[1];
char pad2[3];
} Brush;
/* Brush.flag */

View File

@@ -33,6 +33,7 @@
#include "DNA_texture_types.h"
#include "IMB_imbuf.h"
#include "WM_types.h"
EnumPropertyItem brush_sculpt_tool_items[] = {
{SCULPT_TOOL_DRAW, "DRAW", 0, "Draw", ""},
@@ -52,29 +53,6 @@ EnumPropertyItem brush_sculpt_tool_items[] = {
#include "BKE_texture.h"
#include "WM_api.h"
#include "WM_types.h"
static void rna_Brush_mtex_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Brush *brush= (Brush*)ptr->data;
rna_iterator_array_begin(iter, (void*)brush->mtex, sizeof(MTex*), MAX_MTEX, 0, NULL);
}
static PointerRNA rna_Brush_active_texture_get(PointerRNA *ptr)
{
Brush *br= (Brush*)ptr->data;
Tex *tex;
tex= give_current_brush_texture(br);
return rna_pointer_inherit_refine(ptr, &RNA_Texture, tex);
}
static void rna_Brush_active_texture_set(PointerRNA *ptr, PointerRNA value)
{
Brush *br= (Brush*)ptr->data;
set_current_brush_texture(br, value.data);
}
static void rna_Brush_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
@@ -291,8 +269,17 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* texture */
rna_def_mtex_common(srna, "rna_Brush_mtex_begin", "rna_Brush_active_texture_get",
"rna_Brush_active_texture_set", "BrushTextureSlot", "rna_Brush_update");
prop= RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BrushTextureSlot");
RNA_def_property_pointer_sdna(prop, NULL, "mtex");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Texture Slot", "");
prop= RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "mtex.tex");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Texture", "");
RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_update");
/* clone tool */
prop= RNA_def_property(srna, "clone_image", PROP_POINTER, PROP_NONE);

View File

@@ -269,6 +269,15 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a file for creating a new ID block.");
RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
func= RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block.");
RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a file for creating a new ID block.");
RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
func= RNA_def_function(srna, "template_any_ID", "uiTemplateAnyID");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property.");

View File

@@ -1037,7 +1037,7 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *arg_op)
block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 10, 180, 19, "");
but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 10, 180, 19, 0, 0, "");
uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
/* fake button, it holds space for search items */