ImagePaint Refactoring:

- ImagePaint now uses ImBuf directly, and the rect blending functions
  were moved into the imbuf module.
- The brush spacing, timing and sampling was abstracted into brush.c, for
  later reuse in other paint modes.

Float ImagePaint support.

Textured Brushes:
- Only the first texture channel is used now.
- Options for size and offset should be added, but need to find some space
  in the panel, or add a second one ..
This commit is contained in:
Brecht Van Lommel 2006-07-31 15:53:03 +00:00
parent 6bc2ada6fc
commit e168d67b32
19 changed files with 1270 additions and 778 deletions

@ -36,22 +36,37 @@
struct ID;
struct Brush;
struct ImBuf;
/* datablock functions */
struct Brush *add_brush(char *name);
struct Brush *copy_brush(struct Brush *brush);
void make_local_brush(struct Brush *brush);
void free_brush(struct Brush *brush);
/* implementation of blending modes for use by different paint modes */
void brush_blend_rgb(char *outcol, char *col1, char *col2, int fac, short mode);
/* functions for brush datablock browsing used by different paint panels */
/* brush library operations used by different paint panels */
int brush_set_nr(struct Brush **current_brush, int nr);
int brush_delete(struct Brush **current_brush);
void brush_toggle_fake_user(struct Brush *brush);
int brush_clone_image_delete(struct Brush *brush);
int brush_clone_image_set_nr(struct Brush *brush, int nr);
void brush_check_exists(struct Brush **brush);
void brush_toggle_fake_user(struct Brush *brush);
int brush_texture_set_nr(struct Brush *brush, int nr);
int brush_texture_delete(struct Brush *brush);
int brush_clone_image_set_nr(struct Brush *brush, int nr);
int brush_clone_image_delete(struct Brush *brush);
/* sampling */
void brush_sample(struct Brush *brush, float *xy, float dist, float *rgb, float *alpha, short texonly);
struct ImBuf *brush_imbuf_new(struct Brush *brush, short flt, short texonly, int size);
/* painting */
struct BrushPainter;
typedef struct BrushPainter BrushPainter;
typedef int (*BrushFunc)(void *user, struct ImBuf *ibuf, float *lastpos, float *pos);
BrushPainter *brush_painter_new(struct Brush *brush);
void brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size);
int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, void *user);
void brush_painter_free(BrushPainter *painter);
#endif

@ -228,7 +228,7 @@ void fluidsimSettingsFree(struct FluidsimSettings* sb) {}
void fluidsimSettingsCopy(struct FluidsimSettings* sb) {}
/*new render funcs */
void externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) {}
int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) { return 0; }
int multitex(struct Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, struct TexResult *texres) {return 0;}
struct Render *RE_GetRender(const char *name) {return (struct Render *)NULL;}
struct RenderResult *RE_GetResult(Render *re) {return (struct RenderResult *)NULL;}

@ -30,18 +30,31 @@
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#include <math.h>
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
#include "DNA_image_types.h"
#include "DNA_texture_types.h"
#include "DNA_scene_types.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BKE_brush.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "RE_render_ext.h" /* externtex */
/* Datablock add/copy/free/make_local */
Brush *add_brush(char *name)
{
@ -68,9 +81,19 @@ Brush *add_brush(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);
}
}
/* enable fake user by default */
if (!(brushn->id.flag & LIB_FAKEUSER))
brush_toggle_fake_user(brushn);
@ -81,12 +104,20 @@ 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);
}
}
}
void make_local_brush(Brush *brush)
{
/* don't forget: add stuff texture make local once texture bruses are added*/
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
@ -135,103 +166,7 @@ void make_local_brush(Brush *brush)
}
}
static void brush_blend_mix(char *cp, char *cp1, char *cp2, int fac)
{
/* this and other blending modes previously used >>8 instead of /255. both
are not equivalent (>>8 is /256), and the former results in rounding
errors that can turn colors black fast */
int mfac= 255-fac;
cp[0]= (mfac*cp1[0]+fac*cp2[0])/255;
cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
}
static void brush_blend_add(char *cp, char *cp1, char *cp2, int fac)
{
int temp;
temp= cp1[0] + ((fac*cp2[0])/255);
if(temp>254) cp[0]= 255; else cp[0]= temp;
temp= cp1[1] + ((fac*cp2[1])/255);
if(temp>254) cp[1]= 255; else cp[1]= temp;
temp= cp1[2] + ((fac*cp2[2])/255);
if(temp>254) cp[2]= 255; else cp[2]= temp;
}
static void brush_blend_sub(char *cp, char *cp1, char *cp2, int fac)
{
int temp;
temp= cp1[0] - ((fac*cp2[0])/255);
if(temp<0) cp[0]= 0; else cp[0]= temp;
temp= cp1[1] - ((fac*cp2[1])/255);
if(temp<0) cp[1]= 0; else cp[1]= temp;
temp= cp1[2] - ((fac*cp2[2])/255);
if(temp<0) cp[2]= 0; else cp[2]= temp;
}
static void brush_blend_mul(char *cp, char *cp1, char *cp2, int fac)
{
int mfac= 255-fac;
/* first mul, then blend the fac */
cp[0]= (mfac*cp1[0] + fac*((cp2[0]*cp1[0])/255))/255;
cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255))/255;
cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255))/255;
}
static void brush_blend_lighten(char *cp, char *cp1, char *cp2, int fac)
{
/* See if are lighter, if so mix, else dont do anything.
if the paint col is darker then the original, then ignore */
if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
cp[0]= cp1[0];
cp[1]= cp1[1];
cp[2]= cp1[2];
}
else
brush_blend_mix(cp, cp1, cp2, fac);
}
static void brush_blend_darken(char *cp, char *cp1, char *cp2, int fac)
{
/* See if were darker, if so mix, else dont do anything.
if the paint col is brighter then the original, then ignore */
if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
cp[0]= cp1[0];
cp[1]= cp1[1];
cp[2]= cp1[2];
}
else
brush_blend_mix(cp, cp1, cp2, fac);
}
void brush_blend_rgb(char *outcol, char *col1, char *col2, int fac, short mode)
{
if (fac==0) {
outcol[0]= col1[0];
outcol[1]= col1[1];
outcol[2]= col1[2];
}
else {
switch (mode) {
case BRUSH_BLEND_MIX:
brush_blend_mix(outcol, col1, col2, fac); break;
case BRUSH_BLEND_ADD:
brush_blend_add(outcol, col1, col2, fac); break;
case BRUSH_BLEND_SUB:
brush_blend_sub(outcol, col1, col2, fac); break;
case BRUSH_BLEND_MUL:
brush_blend_mul(outcol, col1, col2, fac); break;
case BRUSH_BLEND_LIGHTEN:
brush_blend_lighten(outcol, col1, col2, fac); break;
case BRUSH_BLEND_DARKEN:
brush_blend_darken(outcol, col1, col2, fac); break;
default:
brush_blend_mix(outcol, col1, col2, fac); break;
}
}
}
/* Library Operations */
int brush_set_nr(Brush **current_brush, int nr)
{
@ -261,6 +196,7 @@ int brush_delete(Brush **current_brush)
if (*current_brush) {
(*current_brush)->id.us--;
*current_brush= NULL;
return 1;
}
@ -281,6 +217,51 @@ void brush_toggle_fake_user(Brush *brush)
}
}
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;
idtest= (ID*)BLI_findlink(&G.main->tex, nr-1);
if(idtest==0) { /* new tex */
if(id) idtest= (ID *)copy_texture((Tex *)id);
else idtest= (ID *)add_texture("Tex");
idtest->us--;
}
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;
id_us_plus(idtest);
return 1;
}
return 0;
}
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;
return 1;
}
return 0;
}
int brush_clone_image_set_nr(Brush *brush, int nr)
{
if(brush && nr > 0) {
@ -316,3 +297,292 @@ void brush_check_exists(Brush **brush)
brush_set_nr(brush, 1);
}
/* Brush Sampling */
static float brush_sample_falloff(Brush *brush, float dist)
{
float a, outer, inner;
outer = brush->size >> 1;
inner = outer*brush->innerradius;
if (dist <= inner) {
return brush->alpha;
}
else if ((dist < outer) && (inner < outer)) {
/* formula used by sculpt:
0.5f * (cos(3*(dist - inner)/(outer - inner)) + 1); */
a = sqrt((dist - inner)/(outer - inner));
return (1 - a)*brush->alpha;
}
else
return 0.0f;
}
void brush_sample(Brush *brush, float *xy, float dist, float *rgb, float *alpha, short texonly)
{
if (alpha) {
if (texonly) *alpha= 1.0;
else *alpha= brush_sample_falloff(brush, dist);
}
if (xy && brush->mtex[0] && brush->mtex[0]->tex) {
float co[3], tin, tr, tg, tb, ta;
int hasrgb;
co[0]= xy[0]/(brush->size >> 1);
co[1]= xy[1]/(brush->size >> 1);
co[2]= 0.0f;
hasrgb= externtex(brush->mtex[0], co, &tin, &tr, &tg, &tb, &ta);
if (rgb) {
if (hasrgb) {
rgb[0]= tr*brush->rgb[0];
rgb[1]= tg*brush->rgb[1];
rgb[2]= tb*brush->rgb[2];
}
else {
rgb[0]= tin*brush->rgb[0];
rgb[1]= tin*brush->rgb[1];
rgb[2]= tin*brush->rgb[2];
}
}
if (alpha && hasrgb)
*alpha *= ta;
}
else if (rgb)
VECCOPY(rgb, brush->rgb)
}
#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
ImBuf *brush_imbuf_new(Brush *brush, short flt, short texonly, int size)
{
ImBuf *ibuf;
float w_2, h_2, xy[2], dist, rgba[3], *dstf;
unsigned int x, y, rowbytes;
char *dst;
if (texonly && !(brush->mtex[0] && brush->mtex[0]->tex))
return NULL;
w_2 = size/2.0f;
h_2 = size/2.0f;
rowbytes= size*4;
if (flt) {
ibuf= IMB_allocImBuf(size, size, 32, IB_rectfloat, 0);
for (y=0; y < ibuf->y; y++) {
dstf = ibuf->rect_float + y*rowbytes;
for (x=0; x < ibuf->x; x++, dstf+=4) {
xy[0] = x + 0.5f - w_2;
xy[1] = y + 0.5f - h_2;
dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
brush_sample(brush, xy, dist, dstf, dstf+3, texonly);
}
}
}
else {
ibuf= IMB_allocImBuf(size, size, 32, IB_rect, 0);
for (y=0; y < ibuf->y; y++) {
dst = (char*)ibuf->rect + y*rowbytes;
for (x=0; x < ibuf->x; x++, dst+=4) {
xy[0] = x + 0.5f - w_2;
xy[1] = y + 0.5f - h_2;
dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
brush_sample(brush, xy, dist, rgba, rgba+3, texonly);
dst[0]= FTOCHAR(rgba[0]);
dst[1]= FTOCHAR(rgba[1]);
dst[2]= FTOCHAR(rgba[2]);
dst[3]= FTOCHAR(rgba[3]);
}
}
}
return ibuf;
}
/* Brush Painting */
struct BrushPainter {
Brush *brush;
float lastmousepos[2]; /* mouse position of last paint call */
float accumdistance; /* accumulated distance of brush since last paint op */
float lastpaintpos[2]; /* position of last paint op */
double accumtime; /* accumulated time since last paint op (airbrush) */
double lasttime; /* time of last update */
short firsttouch; /* first paint op */
struct BrushPainterImbufCache {
int size; /* size override, if 0 uses brush->size */
short flt; /* need float imbuf? */
short texonly; /* no alpha, color or fallof, only texture in imbuf */
short enabled;
int lastsize;
float lastalpha;
float lastinnerradius;
ImBuf *ibuf;
} cache;
};
BrushPainter *brush_painter_new(Brush *brush)
{
BrushPainter *painter= MEM_callocN(sizeof(BrushPainter), "BrushPainter");
painter->brush= brush;
painter->firsttouch= 1;
return painter;
}
void brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size)
{
painter->cache.size = size;
painter->cache.flt = flt;
painter->cache.texonly = texonly;
painter->cache.enabled = 1;
}
void brush_painter_free(BrushPainter *painter)
{
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
MEM_freeN(painter);
}
static void brush_painter_refresh_cache(BrushPainter *painter)
{
Brush *brush= painter->brush;
if ((brush->size != painter->cache.lastsize)
|| (brush->alpha != painter->cache.lastalpha)
|| (brush->innerradius != painter->cache.lastinnerradius)) {
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
painter->cache.ibuf= brush_imbuf_new(brush,
painter->cache.flt, painter->cache.texonly,
painter->cache.size? painter->cache.size: brush->size);
painter->cache.lastsize= brush->size;
painter->cache.lastalpha= brush->alpha;
painter->cache.lastinnerradius= brush->innerradius;
}
}
int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, void *user)
{
Brush *brush= painter->brush;
int totpaintops= 0;
if (painter->firsttouch) {
/* paint exactly once on first touch */
if (painter->cache.enabled) brush_painter_refresh_cache(painter);
totpaintops += func(user, painter->cache.ibuf, pos, pos);
painter->lastpaintpos[0]= pos[0];
painter->lastpaintpos[1]= pos[1];
painter->lasttime= time;
painter->firsttouch= 0;
}
#if 0
else if (painter->brush->flag & BRUSH_AIRBRUSH) {
float spacing, step, paintpos[2], dmousepos[2], len;
double starttime, curtime= time;
/* compute brush spacing adapted to brush size */
spacing= brush->rate; //brush->size*brush->spacing*0.01f;
/* setup starting time, direction vector and accumulated time */
starttime= painter->accumtime;
Vec2Subf(dmousepos, pos, painter->lastmousepos);
len= Normalise2(dmousepos);
painter->accumtime += curtime - painter->lasttime;
/* do paint op over unpainted time distance */
while (painter->accumtime >= spacing) {
step= (spacing - starttime)*len;
paintpos[0]= painter->lastmousepos[0] + dmousepos[0]*step;
paintpos[1]= painter->lastmousepos[1] + dmousepos[1]*step;
if (painter->cache.enabled) brush_painter_refresh_cache(painter);
totpaintops += func(user, painter->cache.ibuf, painter->lastpaintpos, paintpos);
painter->lastpaintpos[0]= paintpos[0];
painter->lastpaintpos[1]= paintpos[1];
painter->accumtime -= spacing;
starttime -= spacing;
}
painter->lasttime= curtime;
}
#endif
else {
float startdistance, spacing, step, paintpos[2], dmousepos[2];
/* compute brush spacing adapted to brush size */
spacing= brush->size*brush->spacing*0.01f;
/* setup starting distance, direction vector and accumulated distance */
startdistance= painter->accumdistance;
Vec2Subf(dmousepos, pos, painter->lastmousepos);
painter->accumdistance += Normalise2(dmousepos);
/* do paint op over unpainted distance */
while (painter->accumdistance >= spacing) {
step= spacing - startdistance;
paintpos[0]= painter->lastmousepos[0] + dmousepos[0]*step;
paintpos[1]= painter->lastmousepos[1] + dmousepos[1]*step;
if (painter->cache.enabled) brush_painter_refresh_cache(painter);
totpaintops += func(user, painter->cache.ibuf, painter->lastpaintpos, paintpos);
painter->lastpaintpos[0]= paintpos[0];
painter->lastpaintpos[1]= paintpos[1];
painter->accumdistance -= spacing;
startdistance -= spacing;
}
/* do airbrush paint ops, based on the number of paint ops left over
from regular painting. this is a temporary solution until we have
accurate time stamps for mouse move events */
if (brush->flag & BRUSH_AIRBRUSH) {
double curtime= time;
double painttime= brush->rate*totpaintops;
painter->accumtime += curtime - painter->lasttime;
if (painter->accumtime <= painttime)
painter->accumtime= 0.0;
else
painter->accumtime -= painttime;
while (painter->accumtime >= brush->rate) {
if (painter->cache.enabled) brush_painter_refresh_cache(painter);
totpaintops += func(user, painter->cache.ibuf, painter->lastmousepos, pos);
painter->accumtime -= brush->rate;
}
painter->lasttime= curtime;
}
}
painter->lastmousepos[0]= pos[0];
painter->lastmousepos[1]= pos[1];
return totpaintops;
}

@ -58,6 +58,7 @@
#include "DNA_material_types.h"
#include "DNA_image_types.h"
#include "DNA_world_types.h"
#include "DNA_brush_types.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@ -77,6 +78,7 @@
#include "BKE_key.h"
#include "BKE_icons.h"
#include "BKE_ipo.h"
#include "BKE_brush.h"
/* ------------------------------------------------------------------------- */
@ -545,6 +547,7 @@ void make_local_texture(Tex *tex)
Material *ma;
World *wrld;
Lamp *la;
Brush *br;
int a, local=0, lib=0;
/* - only lib users: do nothing
@ -599,6 +602,16 @@ void make_local_texture(Tex *tex)
}
wrld= wrld->id.next;
}
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->id.lib) lib= 1;
else local= 1;
}
}
br= br->id.next;
}
if(local && lib==0) {
tex->id.lib= 0;
@ -648,7 +661,19 @@ void make_local_texture(Tex *tex)
}
wrld= wrld->id.next;
}
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->id.lib==0) {
br->mtex[a]->tex= texn;
texn->id.us++;
tex->id.us--;
}
}
}
br= br->id.next;
}
}
}

@ -1183,26 +1183,36 @@ static void test_pointer_array(FileData *fd, void **mat)
}
}
/* ************ READ BRUSH *************** */
/* ************ READ Brush *************** */
/* library brush linking after fileread */
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;
/* nothing to do yet - until brush gets textures */
for(a=0; a<MAX_MTEX; a++) {
mtex= brush->mtex[a];
if(mtex)
mtex->tex= newlibadr_us(fd, brush->id.lib, mtex->tex);
}
}
}
}
/* brush itself has been read! */
static void direct_link_brush(FileData *fd, Brush *brush)
{
/* nothing to do yet - until brush gets textures */
/* brush itself has been read */
int a;
for(a=0; a<MAX_MTEX; a++)
brush->mtex[a]= newdataadr(fd, brush->mtex[a]);
}
/* ************ READ CurveMapping *************** */
@ -5802,7 +5812,12 @@ static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
{
/* nothing to do yet - until brush gets texture */
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->clone.image);
}
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)

@ -1596,10 +1596,16 @@ 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)
for(brush=idbase->first; brush; brush= brush->id.next) {
if(brush->id.us>0 || wd->current) {
writestruct(wd, ID_BR, "Brush", 1, brush);
for(a=0; a<MAX_MTEX; a++)
if(brush->mtex[a])
writestruct(wd, DATA, "MTex", 1, brush->mtex[a]);
}
}
}
static void write_global(WriteData *wd)

@ -219,8 +219,33 @@ void IMB_freecmapImBuf(struct ImBuf * ibuf);
*
* @attention Defined in rectop.c
*/
typedef enum IMB_BlendMode {
IMB_BLEND_MIX = 0,
IMB_BLEND_ADD = 1,
IMB_BLEND_SUB = 2,
IMB_BLEND_MUL = 3,
IMB_BLEND_LIGHTEN = 4,
IMB_BLEND_DARKEN = 5,
IMB_BLEND_COPY = 1000,
IMB_BLEND_COPY_RGB = 1001,
IMB_BLEND_COPY_ALPHA = 1002
} IMB_BlendMode;
unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac,
IMB_BlendMode mode);
void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac,
IMB_BlendMode mode);
void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
int *desty, int *srcx, int *srcy, int *width, int *height);
void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx,
int desty, int srcx, int srcy, int width, int height);
void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode);
void IMB_rectblend_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode);
/**
* Return the length (in frames) of the given @a anim.

@ -41,104 +41,433 @@
#include "IMB_allocimbuf.h"
void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height)
/* blend modes */
static void blend_color_mix(char *cp, char *cp1, char *cp2, int fac)
{
unsigned int *drect, *srect;
float *drectf = NULL;
float *srectf = NULL;
int tmp, do_float = 0;
/* this and other blending modes previously used >>8 instead of /255. both
are not equivalent (>>8 is /256), and the former results in rounding
errors that can turn colors black fast after repeated blending */
int mfac= 255-fac;
cp[0]= (mfac*cp1[0]+fac*cp2[0])/255;
cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
}
static void blend_color_add(char *cp, char *cp1, char *cp2, int fac)
{
int temp;
temp= cp1[0] + ((fac*cp2[0])/255);
if(temp>254) cp[0]= 255; else cp[0]= temp;
temp= cp1[1] + ((fac*cp2[1])/255);
if(temp>254) cp[1]= 255; else cp[1]= temp;
temp= cp1[2] + ((fac*cp2[2])/255);
if(temp>254) cp[2]= 255; else cp[2]= temp;
}
static void blend_color_sub(char *cp, char *cp1, char *cp2, int fac)
{
int temp;
temp= cp1[0] - ((fac*cp2[0])/255);
if(temp<0) cp[0]= 0; else cp[0]= temp;
temp= cp1[1] - ((fac*cp2[1])/255);
if(temp<0) cp[1]= 0; else cp[1]= temp;
temp= cp1[2] - ((fac*cp2[2])/255);
if(temp<0) cp[2]= 0; else cp[2]= temp;
}
static void blend_color_mul(char *cp, char *cp1, char *cp2, int fac)
{
int mfac= 255-fac;
/* first mul, then blend the fac */
cp[0]= (mfac*cp1[0] + fac*((cp1[0]*cp2[0])/255))/255;
cp[1]= (mfac*cp1[1] + fac*((cp1[1]*cp2[1])/255))/255;
cp[2]= (mfac*cp1[2] + fac*((cp1[2]*cp2[2])/255))/255;
}
static void blend_color_lighten(char *cp, char *cp1, char *cp2, int fac)
{
/* See if are lighter, if so mix, else dont do anything.
if the paint col is darker then the original, then ignore */
if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
cp[0]= cp1[0];
cp[1]= cp1[1];
cp[2]= cp1[2];
}
else
blend_color_mix(cp, cp1, cp2, fac);
}
static void blend_color_darken(char *cp, char *cp1, char *cp2, int fac)
{
/* See if were darker, if so mix, else dont do anything.
if the paint col is brighter then the original, then ignore */
if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
cp[0]= cp1[0];
cp[1]= cp1[1];
cp[2]= cp1[2];
}
else
blend_color_mix(cp, cp1, cp2, fac);
}
unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, IMB_BlendMode mode)
{
unsigned int dst;
char *cp, *cp1, *cp2;
if (fac==0)
return src1;
cp = (char*)&dst;
cp1 = (char*)&src1;
cp2 = (char*)&src2;
switch (mode) {
case IMB_BLEND_MIX:
blend_color_mix(cp, cp1, cp2, fac); break;
case IMB_BLEND_ADD:
blend_color_add(cp, cp1, cp2, fac); break;
case IMB_BLEND_SUB:
blend_color_sub(cp, cp1, cp2, fac); break;
case IMB_BLEND_MUL:
blend_color_mul(cp, cp1, cp2, fac); break;
case IMB_BLEND_LIGHTEN:
blend_color_lighten(cp, cp1, cp2, fac); break;
case IMB_BLEND_DARKEN:
blend_color_darken(cp, cp1, cp2, fac); break;
default:
return src1;
}
return dst;
}
static void blend_color_mix_float(float *cp, float *cp1, float *cp2, float fac)
{
float mfac= 1.0-fac;
cp[0]= mfac*cp1[0] + fac*cp2[0];
cp[1]= mfac*cp1[1] + fac*cp2[1];
cp[2]= mfac*cp1[2] + fac*cp2[2];
}
static void blend_color_add_float(float *cp, float *cp1, float *cp2, float fac)
{
cp[0] = cp1[0] + fac*cp2[0];
cp[1] = cp1[1] + fac*cp2[1];
cp[2] = cp1[2] + fac*cp2[2];
if (cp[0] > 1.0f) cp[0]= 1.0f;
if (cp[1] > 1.0f) cp[1]= 1.0f;
if (cp[2] > 1.0f) cp[2]= 1.0f;
}
static void blend_color_sub_float(float *cp, float *cp1, float *cp2, float fac)
{
cp[0] = cp1[0] - fac*cp2[0];
cp[1] = cp1[1] - fac*cp2[1];
cp[2] = cp1[2] - fac*cp2[2];
if (cp[0] < 0.0f) cp[0]= 0.0f;
if (cp[1] < 0.0f) cp[1]= 0.0f;
if (cp[2] < 0.0f) cp[2]= 0.0f;
}
static void blend_color_mul_float(float *cp, float *cp1, float *cp2, float fac)
{
float mfac= 1.0-fac;
cp[0]= mfac*cp1[0] + fac*(cp1[0]*cp2[0]);
cp[1]= mfac*cp1[1] + fac*(cp1[1]*cp2[1]);
cp[2]= mfac*cp1[2] + fac*(cp1[2]*cp2[2]);
}
static void blend_color_lighten_float(float *cp, float *cp1, float *cp2, float fac)
{
/* See if are lighter, if so mix, else dont do anything.
if the pafloat col is darker then the original, then ignore */
if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
cp[0]= cp1[0];
cp[1]= cp1[1];
cp[2]= cp1[2];
}
else
blend_color_mix_float(cp, cp1, cp2, fac);
}
static void blend_color_darken_float(float *cp, float *cp1, float *cp2, float fac)
{
/* See if were darker, if so mix, else dont do anything.
if the pafloat col is brighter then the original, then ignore */
if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
cp[0]= cp1[0];
cp[1]= cp1[1];
cp[2]= cp1[2];
}
else
blend_color_mix_float(cp, cp1, cp2, fac);
}
void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_BlendMode mode)
{
if (fac==0) {
dst[0]= src1[0];
dst[1]= src1[1];
dst[2]= src1[2];
return;
}
switch (mode) {
case IMB_BLEND_MIX:
blend_color_mix_float(dst, src1, src2, fac); break;
case IMB_BLEND_ADD:
blend_color_add_float(dst, src1, src2, fac); break;
case IMB_BLEND_SUB:
blend_color_sub_float(dst, src1, src2, fac); break;
case IMB_BLEND_MUL:
blend_color_mul_float(dst, src1, src2, fac); break;
case IMB_BLEND_LIGHTEN:
blend_color_lighten_float(dst, src1, src2, fac); break;
case IMB_BLEND_DARKEN:
blend_color_darken_float(dst, src1, src2, fac); break;
default:
dst[0]= src1[0];
dst[1]= src1[1];
dst[2]= src1[2];
}
}
/* clipping */
void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
int *desty, int *srcx, int *srcy, int *width, int *height)
{
int tmp;
if (dbuf == NULL) return;
if (sbuf && sbuf->rect_float && dbuf->rect_float) do_float = 1;
if (destx < 0){
srcx -= destx ;
width += destx ;
destx = 0;
if (*destx < 0) {
*srcx -= *destx ;
*width += *destx ;
*destx = 0;
}
if (srcx < 0){
destx -= srcx ;
width += destx ;
srcx = 0;
if (*srcx < 0) {
*destx -= *srcx ;
*width += *destx ;
*srcx = 0;
}
if (desty < 0){
srcy -= desty ;
height += desty ;
desty = 0;
if (*desty < 0) {
*srcy -= *desty ;
*height += *desty ;
*desty = 0;
}
if (srcy < 0){
desty -= srcy ;
height += desty ;
srcy = 0;
if (*srcy < 0) {
*desty -= *srcy ;
*height += *desty ;
*srcy = 0;
}
tmp = dbuf->x - destx;
if (width > tmp) width = tmp;
tmp = dbuf->y - desty;
if (height > tmp) height = tmp;
drect = dbuf->rect + desty * dbuf->x + destx;
if (do_float) drectf = dbuf->rect_float + desty * dbuf->x + destx;
destx = dbuf->x;
tmp = dbuf->x - *destx;
if (*width > tmp) *width = tmp;
tmp = dbuf->y - *desty;
if (*height > tmp) *height = tmp;
if (sbuf) {
tmp = sbuf->x - srcx;
if (width > tmp) width = tmp;
tmp = sbuf->y - srcy;
if (height > tmp) height = tmp;
if (width <= 0) return;
if (height <= 0) return;
srect = sbuf->rect;
srect += srcy * sbuf->x;
srect += srcx;
if (do_float) {
srectf = sbuf->rect_float;
srectf += srcy * sbuf->x;
srectf += srcx;
tmp = sbuf->x - *srcx;
if (*width > tmp) *width = tmp;
tmp = sbuf->y - *srcy;
if (*height > tmp) *height = tmp;
}
}
srcx = sbuf->x;
} else{
if (width <= 0) return;
if (height <= 0) return;
/* copy and blend */
void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height)
{
IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, width, height,
IMB_BLEND_COPY);
}
void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
{
unsigned int *drect = NULL, *srect = NULL, *dr, *sr;
float *drectf = NULL, *srectf = NULL, *drf, *srf;
int do_float, do_char, srcskip, destskip, x;
if (dbuf == NULL) return;
IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height);
if (width == 0 || height == 0) return;
do_char = (sbuf && sbuf->rect && dbuf->rect);
do_float = (sbuf && sbuf->rect_float && dbuf->rect_float);
if (do_char) drect = dbuf->rect + desty * dbuf->x + destx;
if (do_float) drectf = dbuf->rect_float + (desty * dbuf->x + destx)*4;
destskip = dbuf->x;
if (sbuf) {
if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx)*4;
srcskip = sbuf->x;
} else {
srect = drect;
srectf = drectf;
srcx = destx;
srcskip = destskip;
}
if (mode == IMB_BLEND_COPY) {
/* copy */
for (;height > 0; height--) {
if (do_char) {
memcpy(drect,srect, width * sizeof(int));
drect += destx;
srect += srcx;
drect += destskip;
srect += srcskip;
}
if (do_float) {
memcpy(drectf,srectf, width * sizeof(float) * 4);
drectf += destx;
srectf += srcx;
drectf += destskip*4;
srectf += srcskip*4;
}
}
}
else if (mode == IMB_BLEND_COPY_RGB) {
/* copy rgb only */
for (;height > 0; height--) {
if (do_char) {
dr = drect;
sr = srect;
for (x=width; x > 0; x--, dr++, sr++) {
((char*)dr)[0]= ((char*)sr)[0];
((char*)dr)[1]= ((char*)sr)[1];
((char*)dr)[2]= ((char*)sr)[2];
}
drect += destskip;
srect += srcskip;
}
if (do_float) {
drf = drectf;
srf = srectf;
for (x=width; x > 0; x--, drf+=4, srf+=4) {
drf[0]= srf[0];
drf[1]= srf[1];
drf[2]= srf[2];
}
drectf += destskip*4;
srectf += srcskip*4;
}
}
}
else if (mode == IMB_BLEND_COPY_ALPHA) {
/* copy alpha only */
for (;height > 0; height--) {
if (do_char) {
dr = drect;
sr = srect;
for (x=width; x > 0; x--, dr++, sr++)
((char*)dr)[3]= ((char*)sr)[3];
drect += destskip;
srect += srcskip;
}
if (do_float) {
drf = drectf;
srf = srectf;
for (x=width; x > 0; x--, drf+=4, srf+=4)
drf[3]= srf[3];
drectf += destskip*4;
srectf += srcskip*4;
}
}
}
else {
/* blend */
for (;height > 0; height--) {
if (do_char) {
dr = drect;
sr = srect;
for (x=width; x > 0; x--, dr++, sr++)
*dr = IMB_blend_color(*dr, *sr, ((char*)sr)[3], mode);
drect += destskip;
srect += srcskip;
}
if (do_float) {
drf = drectf;
srf = srectf;
for (x=width; x > 0; x--, drf+=4, srf+=4)
IMB_blend_color_float(drf, drf, srf, srf[3], mode);
drectf += destskip*4;
srectf += srcskip*4;
}
}
}
}
void IMB_rectblend_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
{
int origw, origh, w, h;
/* convert destination and source coordinates too be withing image */
destx = destx % dbuf->x;
if (destx < 0) destx += dbuf->x;
desty = desty % dbuf->y;
if (desty < 0) desty += dbuf->y;
srcx = srcx % sbuf->x;
if (srcx < 0) srcx += sbuf->x;
srcy = srcy % sbuf->y;
if (srcy < 0) srcy += sbuf->y;
/* clip width of blending area to destination imbuf, to avoid writing the
same pixel twice */
origw = w = (width > dbuf->x)? dbuf->x: width;
origh = h = (height > dbuf->y)? dbuf->y: height;
/* clip and blend */
IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, w, h, mode);
/* do 3 other rects if needed */
if (w < origw)
IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, desty, (srcx+w)%sbuf->x, srcy,
origw-w, h, mode);
if (h < origh)
IMB_rectblend(dbuf, sbuf, destx, (desty+h)%dbuf->y, srcx, (srcy+h)%sbuf->y,
w, origh-h, mode);
if ((w < origw) && (h < origh))
IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, (desty+h)%dbuf->y,
(srcx+w)%sbuf->x, (srcy+h)%sbuf->y, origw-w, origh-h, mode);
}
/* fill */
void IMB_rectfill(struct ImBuf *drect, float col[4])
{
int num;
unsigned int *rrect = drect->rect;
unsigned char *spot;
char ccol[4];
ccol[0]= (int)(col[0]*255);
ccol[1]= (int)(col[1]*255);
ccol[2]= (int)(col[2]*255);
ccol[3]= (int)(col[3]*255);
num = drect->x * drect->y;
for (;num > 0; num--) {
spot = (unsigned char *)rrect;
spot[0] = (int)(col[0]*255);
spot[1] = (int)(col[1]*255);
spot[2] = (int)(col[2]*255);
spot[3] = (int)(col[3]*255);
*rrect++;
}
for (;num > 0; num--)
*rrect++ = *((unsigned int*)ccol);
if(drect->rect_float) {
float *rrectf = drect->rect_float;

@ -320,6 +320,8 @@
#define B_SIMABRUSHDELETE 375
#define B_SIMABRUSHLOCAL 376
#define B_SIMABRUSHCHANGE 377
#define B_SIMABTEXBROWSE 378
#define B_SIMABTEXDELETE 379
/* BUTS: 400 */
#define B_BUTSHOME 401

@ -541,6 +541,7 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
#define B_BRUSHDELETE 2852
#define B_BRUSHLOCAL 2853
#define B_BRUSHCHANGE 2854
#define B_BTEXBROWSE 2855
/* *********************** */
#define B_RADIOBUTS 3000

@ -32,6 +32,13 @@
#include "DNA_ID.h"
#ifndef MAX_MTEX
#define MAX_MTEX 10
#endif
struct MTex;
struct Image;
typedef struct Brush {
ID id;
@ -44,6 +51,9 @@ typedef struct Brush {
float rgb[3]; /* color */
float alpha; /* opacity */
short texact, pad;
struct MTex *mtex[10];
struct Clone {
struct Image *image; /* image for clone tool */
float offset[2]; /* offset of clone image from canvas */

@ -44,8 +44,8 @@ struct Render;
struct MTex;
void RE_zbufferall_radio(struct RadView *vw, struct RNode **rg_elem, int rg_totelem, struct Render *re);
/* effect.c and editmesh_modes. */
void externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta);
/* effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta);
#endif /* RE_RENDER_EXT_H */

@ -2362,7 +2362,7 @@ void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf)
/* ------------------------------------------------------------------------- */
void externtex(MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta)
int externtex(MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta)
{
Tex *tex;
TexResult texr;
@ -2404,6 +2404,8 @@ void externtex(MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *
*tg= texr.tg;
*tb= texr.tb;
*ta= texr.ta;
return (rgb != 0);
}

@ -3889,6 +3889,23 @@ void do_fpaintbuts(unsigned short event)
}
}
break;
case B_BTEXBROWSE:
if(G.scene->toolsettings->imapaint.brush==0) return;
if(G.buts->menunr==-2) {
MTex *mtex= G.scene->toolsettings->imapaint.brush->mtex[0];
ID *id= (ID*)((mtex)? mtex->tex: NULL);
activate_databrowse(id, ID_TE, 0, B_BTEXBROWSE, &G.buts->menunr, do_global_buttons);
break;
}
else if(G.buts->menunr < 0) break;
if(brush_texture_set_nr(G.scene->toolsettings->imapaint.brush, G.buts->menunr)) {
BIF_undo_push("Browse Brush Texture");
allqueue(REDRAWBUTSSHADING, 0);
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWIMAGE, 0);
}
break;
}
}

@ -41,6 +41,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
#include "DNA_curve_types.h"
#include "DNA_image_types.h"
#include "DNA_lamp_types.h"
@ -1215,7 +1216,7 @@ static void texture_panel_colors(Tex *tex)
}
static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *la, bNode *node)
static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *la, bNode *node, Brush *br)
{
MTex *mt=NULL;
uiBlock *block;
@ -1236,6 +1237,7 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
if(ma) idfrom= &ma->id;
else if(wrld) idfrom= &wrld->id;
else if(la) idfrom= &la->id;
else if(br) idfrom= &br->id;
else idfrom= NULL;
uiBlockSetCol(block, TH_BUT_SETTING2);
@ -1248,6 +1250,9 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
else if(la) {
std_libbuttons(block, 10, 180, 0, NULL, B_LTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
}
else if(br) {
std_libbuttons(block, 10, 180, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
}
else if(node) {
}
@ -1264,6 +1269,7 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
if(ma) mt= ma->mtex[a];
else if(wrld) mt= wrld->mtex[a];
else if(la) mt= la->mtex[a];
else if(br) mt= br->mtex[a];
if(mt && mt->tex) splitIDname(mt->tex->id.name+2, str, &loos);
else strcpy(str, "");
@ -1281,6 +1287,10 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
uiDefButS(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(la->texact), 0.0, (float)a, 0, 0, "");
yco-= 20;
}
else if(br) {
uiDefButS(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(br->texact), 0.0, (float)a, 0, 0, "");
yco-= 20;
}
}
uiBlockEndAlign(block);
}
@ -1323,6 +1333,7 @@ static void texture_panel_preview(MTex *mtex, int preview)
uiDefButC(block, ROW, B_TEXREDR_PRV, "Mat", 200,175,80,25, &G.buts->texfrom, 3.0, 0.0, 0, 0, "Displays the textures of the active material");
uiDefButC(block, ROW, B_TEXREDR_PRV, "World", 200,150,80,25, &G.buts->texfrom, 3.0, 1.0, 0, 0, "Displays the textures of the world block");
uiDefButC(block, ROW, B_TEXREDR_PRV, "Lamp", 200,125,80,25, &G.buts->texfrom, 3.0, 2.0, 0, 0, "Displays the textures of the selected lamp");
uiDefButC(block, ROW, B_TEXREDR_PRV, "Brush", 200,100,80,25, &G.buts->texfrom, 3.0, 3.0, 0, 0, "Displays the textures of the selected lamp");
uiBlockEndAlign(block);
if(mtex && mtex->tex)
@ -3399,6 +3410,7 @@ void world_panels()
void texture_panels()
{
Material *ma=NULL;
Brush *br=NULL;
Lamp *la=NULL;
World *wrld=NULL;
bNode *node=NULL;
@ -3431,13 +3443,17 @@ void texture_panels()
mtex= la->mtex[ la->texact ];
}
}
else if(G.buts->texfrom==3) {
br= G.scene->toolsettings->imapaint.brush;
if(br) mtex= br->mtex[br->texact];
}
texture_panel_preview(mtex, ma || wrld || la || node); // for 'from' buttons
texture_panel_preview(mtex, ma || wrld || la || br || node); // for 'from' buttons
if(ma || wrld || la || node) {
if(ma || wrld || la || br || node) {
Tex *tex= NULL;
texture_panel_texture(mtex, ma, wrld, la, node);
texture_panel_texture(mtex, ma, wrld, la, node, br);
if(mtex) tex= mtex->tex;
else if(node) tex= (Tex *)node->id;

@ -61,6 +61,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_texture_types.h"
#include "DNA_userdef_types.h"
#include "BKE_brush.h"
@ -944,6 +945,36 @@ void do_imagebuts(unsigned short event)
}
}
break;
case B_SIMABTEXBROWSE:
if(settings->imapaint.brush) {
Brush *brush= settings->imapaint.brush;
if(G.sima->menunr==-2) {
MTex *mtex= brush->mtex[brush->texact];
ID *id= (ID*)((mtex)? mtex->tex: NULL);
activate_databrowse(id, ID_TE, 0, B_SIMABTEXBROWSE, &G.sima->menunr, do_global_buttons);
break;
}
else if(G.sima->menunr < 0) break;
if(brush_texture_set_nr(brush, G.sima->menunr)) {
BIF_undo_push("Browse Brush Texture");
allqueue(REDRAWBUTSSHADING, 0);
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWIMAGE, 0);
}
}
break;
case B_SIMABTEXDELETE:
if(settings->imapaint.brush) {
if (brush_texture_delete(settings->imapaint.brush)) {
BIF_undo_push("Unlink Brush Texture");
allqueue(REDRAWBUTSSHADING, 0);
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWIMAGE, 0);
}
}
break;
}
}
@ -1062,6 +1093,12 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES
uiDefButF(block, NUMSLI, B_SIMABRUSHCHANGE, "B ",xco+5,yco,butw,19, &brush->clone.alpha , 0.0, 1.0, 0, 0, "Opacity of clone image display");
}
}
else {
uiBlockSetCol(block, TH_BUT_SETTING2);
id= (brush->mtex[0])? (ID*)brush->mtex[0]->tex: NULL;
xco= std_libbuttons(block, 0, yco, 0, NULL, B_SIMABTEXBROWSE, ID_TE, 0, id, NULL, &(G.sima->menunr), 0, 0, B_SIMABTEXDELETE, 0, 0);
uiBlockSetCol(block, TH_AUTO);
}
}
#if 0

@ -44,6 +44,7 @@
#include "DNA_ID.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@ -321,6 +322,13 @@ void buttons_active_id(ID **id, ID **idfrom)
if(mtex) *id= (ID *)mtex->tex;
}
}
else if(G.buts->texfrom==3) {
Brush *brush= G.scene->toolsettings->imapaint.brush;
if (brush) {
mtex= brush->mtex[brush->texact];
if(mtex) *id= (ID*)mtex->tex;
}
}
}
}
else if(G.buts->mainb==CONTEXT_OBJECT || G.buts->mainb==CONTEXT_LOGIC) {

@ -58,6 +58,7 @@
#include "DNA_ID.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_group_types.h"
@ -87,10 +88,11 @@
#include "BKE_utildefines.h"
#include "BKE_constraint.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_blender.h"
#include "BKE_brush.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_exotic.h"
@ -550,6 +552,7 @@ void do_global_buttons(unsigned short event)
bAction *act;
ID *id, *idtest, *from=NULL;
ScrArea *sa;
Brush *br;
int nr= 1;
char buf[FILE_MAXDIR+FILE_MAXFILE];
@ -767,7 +770,7 @@ void do_global_buttons(unsigned short event)
}
}
}
else { /* from lamp */
else if(G.buts->texfrom==2) { /* from lamp */
la= ob->data;
if(la && ob->type==OB_LAMP) { /* to be sure */
mtex= la->mtex[ la->texact ];
@ -781,6 +784,21 @@ void do_global_buttons(unsigned short event)
}
}
}
else { /* from brush */
br= G.scene->toolsettings->imapaint.brush;
if(br) {
mtex= br->mtex[ br->texact ];
if(mtex) {
if(mtex->tex) mtex->tex->id.us--;
MEM_freeN(mtex);
br->mtex[ br->texact ]= NULL;
allqueue(REDRAWBUTSSHADING, 0);
allqueue(REDRAWIMAGE, 0);
allqueue(REDRAWIPO, 0);
/*BIF_preview_changed(ID_BR);*/
}
}
}
BIF_undo_push("Unlink Texture");
}
break;
@ -1244,6 +1262,7 @@ void do_global_buttons(unsigned short event)
BIF_undo_push("Auto name");
allqueue(REDRAWBUTSSHADING, 0);
allqueue(REDRAWOOPS, 0);
allqueue(REDRAWIMAGE, 0);
}
break;
@ -1501,6 +1520,7 @@ void do_global_buttons2(short event)
World *wrld;
ID *idfrom;
bAction *act;
Brush *br;
/* general: Single User is allowed when from==LOCAL
* Make Local is allowed when (from==LOCAL && id==LIB)
@ -1772,6 +1792,20 @@ void do_global_buttons2(short event)
}
}
}
else if(G.buts->texfrom==3) { /* from brush */
br= G.scene->toolsettings->imapaint.brush;
if(br==0) return;
if(br->id.lib==0) {
mtex= br->mtex[ br->texact ];
if(mtex->tex && mtex->tex->id.us>1) {
if(okee("Single user")) {
mtex->tex->id.us--;
mtex->tex= copy_texture(mtex->tex);
allqueue(REDRAWIMAGE, 0);
}
}
}
}
break;
case B_TEXLOCAL:
if(G.buts->texfrom==0) { /* from mat */
@ -1810,6 +1844,19 @@ void do_global_buttons2(short event)
}
}
}
else if(G.buts->texfrom==3) { /* from brush */
br= G.scene->toolsettings->imapaint.brush;
if(br==0) return;
if(br->id.lib==0) {
mtex= br->mtex[ br->texact ];
if(mtex->tex && mtex->tex->id.lib) {
if(okee("Make local")) {
make_local_texture(mtex->tex);
allqueue(REDRAWIMAGE, 0);
}
}
}
}
break;
case B_IPOALONE:

File diff suppressed because it is too large Load Diff