forked from bartvdbraak/blender
More image painting fixes:
* 2D image painting support for masking to limit the max contribution of a stroke to a pixel, to get it working compatible with projection painting. Not strictly a bugfix, but the inconsistency here was annoying. * Fix python errors in Texture Mask panel in image editor, was missing overlay options. * Clamp paint mask to 0..1 in case some texture exceeds it, this could give black pixels due to integer overflow.
This commit is contained in:
parent
b735402c19
commit
63f05576b8
@ -763,6 +763,12 @@ class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
|
||||
col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
|
||||
|
||||
brush_mask_texture_settings(col, brush)
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.active = brush.brush_capabilities.has_overlay
|
||||
col.label(text="Overlay:")
|
||||
|
||||
row = col.row()
|
||||
if tex_slot_alpha.map_mode != 'STENCIL':
|
||||
if brush.use_secondary_overlay:
|
||||
row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
|
||||
|
@ -82,7 +82,7 @@ float BKE_brush_sample_tex_2D(const struct Scene *scene, struct Brush *brush, co
|
||||
float BKE_brush_sample_masktex(const Scene *scene, struct Brush *br, const float point[3],
|
||||
const int thread, struct ImagePool *pool);
|
||||
void BKE_brush_imbuf_new(const struct Scene *scene, struct Brush *brush, short flt, short texfalloff, int size,
|
||||
struct ImBuf **imbuf, int use_color_correction);
|
||||
struct ImBuf **imbuf, bool use_color_correction, bool use_brush_alpha);
|
||||
|
||||
/* texture */
|
||||
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side);
|
||||
|
@ -828,14 +828,15 @@ float BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2
|
||||
|
||||
/* TODO, use define for 'texfall' arg
|
||||
* NOTE: only used for 2d brushes currently! */
|
||||
void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction)
|
||||
void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize,
|
||||
ImBuf **outbuf, bool use_color_correction, bool use_brush_alpha)
|
||||
{
|
||||
ImBuf *ibuf;
|
||||
float xy[2], rgba[4], *dstf;
|
||||
int x, y, rowbytes, xoff, yoff, imbflag;
|
||||
const int radius = BKE_brush_size_get(scene, brush);
|
||||
unsigned char *dst, crgb[3];
|
||||
const float alpha = BKE_brush_alpha_get(scene, brush);
|
||||
const float alpha = (use_brush_alpha)? BKE_brush_alpha_get(scene, brush): 1.0f;
|
||||
float brush_rgb[3];
|
||||
|
||||
imbflag = (flt) ? IB_rectfloat : IB_rect;
|
||||
|
@ -372,12 +372,17 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co
|
||||
{
|
||||
if (src2[3] != 0.0f && src1[3] > 0.0f) {
|
||||
/* subtract alpha and remap RGB channels to match */
|
||||
const float alpha = max_ff(src1[3] - src2[3], 0.0f);
|
||||
const float map_alpha = alpha / src1[3];
|
||||
float alpha = max_ff(src1[3] - src2[3], 0.0f);
|
||||
float map_alpha;
|
||||
|
||||
dst[0] *= map_alpha;
|
||||
dst[1] *= map_alpha;
|
||||
dst[2] *= map_alpha;
|
||||
if (alpha <= 0.0005f)
|
||||
alpha = 0.0f;
|
||||
|
||||
map_alpha = alpha / src1[3];
|
||||
|
||||
dst[0] = src1[0] * map_alpha;
|
||||
dst[1] = src1[1] * map_alpha;
|
||||
dst[2] = src1[2] * map_alpha;
|
||||
dst[3] = alpha;
|
||||
}
|
||||
else {
|
||||
@ -393,12 +398,17 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons
|
||||
{
|
||||
if (src2[3] != 0.0f && src1[3] < 1.0f) {
|
||||
/* add alpha and remap RGB channels to match */
|
||||
const float alpha = min_ff(src1[3] + src2[3], 1.0f);
|
||||
const float map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
|
||||
float alpha = min_ff(src1[3] + src2[3], 1.0f);
|
||||
float map_alpha;
|
||||
|
||||
dst[0] *= map_alpha;
|
||||
dst[1] *= map_alpha;
|
||||
dst[2] *= map_alpha;
|
||||
if (alpha >= 1.0f - 0.0005f)
|
||||
alpha = 1.0f;
|
||||
|
||||
map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
|
||||
|
||||
dst[0] = src1[0] * map_alpha;
|
||||
dst[1] = src1[1] * map_alpha;
|
||||
dst[2] = src1[2] * map_alpha;
|
||||
dst[3] = alpha;
|
||||
}
|
||||
else {
|
||||
|
@ -101,9 +101,6 @@
|
||||
|
||||
#include "paint_intern.h"
|
||||
|
||||
#define IMAPAINT_TILE_BITS 6
|
||||
#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
|
||||
|
||||
typedef struct UndoImageTile {
|
||||
struct UndoImageTile *next, *prev;
|
||||
|
||||
@ -115,6 +112,9 @@ typedef struct UndoImageTile {
|
||||
unsigned int *uint;
|
||||
void *pt;
|
||||
} rect;
|
||||
|
||||
unsigned short *mask;
|
||||
|
||||
int x, y;
|
||||
|
||||
short source, use_float;
|
||||
@ -156,18 +156,45 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int
|
||||
tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
|
||||
}
|
||||
|
||||
void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask)
|
||||
{
|
||||
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
|
||||
UndoImageTile *tile;
|
||||
short use_float = ibuf->rect_float ? 1 : 0;
|
||||
|
||||
for (tile = lb->first; tile; tile = tile->next) {
|
||||
if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
|
||||
if (tile->use_float == use_float) {
|
||||
if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0) {
|
||||
if (mask) {
|
||||
/* allocate mask if requested */
|
||||
if (!tile->mask)
|
||||
tile->mask = MEM_callocN(sizeof(unsigned short)*IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE, "UndoImageTile.mask");
|
||||
|
||||
*mask = tile->mask;
|
||||
}
|
||||
|
||||
return tile->rect.pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
|
||||
{
|
||||
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
|
||||
UndoImageTile *tile;
|
||||
int allocsize;
|
||||
short use_float = ibuf->rect_float ? 1 : 0;
|
||||
void *data;
|
||||
|
||||
for (tile = lb->first; tile; tile = tile->next)
|
||||
if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source)
|
||||
if (tile->use_float == use_float)
|
||||
if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0)
|
||||
return tile->rect.pt;
|
||||
/* check if tile is already pushed */
|
||||
data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL);
|
||||
if (data)
|
||||
return data;
|
||||
|
||||
if (*tmpibuf == NULL)
|
||||
*tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
|
||||
@ -195,6 +222,19 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
|
||||
return tile->rect.pt;
|
||||
}
|
||||
|
||||
void image_undo_remove_masks(void)
|
||||
{
|
||||
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
|
||||
UndoImageTile *tile;
|
||||
|
||||
for (tile = lb->first; tile; tile = tile->next) {
|
||||
if (tile->mask) {
|
||||
MEM_freeN(tile->mask);
|
||||
tile->mask = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void image_undo_restore(bContext *C, ListBase *lb)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
@ -276,10 +316,23 @@ void imapaint_clear_partial_redraw(void)
|
||||
memset(&imapaintpartial, 0, sizeof(imapaintpartial));
|
||||
}
|
||||
|
||||
void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
|
||||
{
|
||||
int srcx = 0, srcy = 0;
|
||||
|
||||
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
|
||||
|
||||
*tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
|
||||
*th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
|
||||
*tx = (x >> IMAPAINT_TILE_BITS);
|
||||
*ty = (y >> IMAPAINT_TILE_BITS);
|
||||
}
|
||||
|
||||
void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
|
||||
{
|
||||
ImBuf *tmpibuf = NULL;
|
||||
int srcx = 0, srcy = 0, origx;
|
||||
int tilex, tiley, tilew, tileh, tx, ty;
|
||||
int srcx = 0, srcy = 0;
|
||||
|
||||
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
|
||||
|
||||
@ -300,14 +353,11 @@ void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
|
||||
imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
|
||||
}
|
||||
|
||||
w = ((x + w - 1) >> IMAPAINT_TILE_BITS);
|
||||
h = ((y + h - 1) >> IMAPAINT_TILE_BITS);
|
||||
origx = (x >> IMAPAINT_TILE_BITS);
|
||||
y = (y >> IMAPAINT_TILE_BITS);
|
||||
|
||||
for (; y <= h; y++)
|
||||
for (x = origx; x <= w; x++)
|
||||
image_undo_push_tile(ima, ibuf, &tmpibuf, x, y);
|
||||
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
|
||||
|
||||
for (ty = tiley; ty <= tileh; ty++)
|
||||
for (tx = tilex; tx <= tilew; tx++)
|
||||
image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty);
|
||||
|
||||
ibuf->userflags |= IB_BITMAPDIRTY;
|
||||
|
||||
|
@ -133,6 +133,8 @@ typedef struct ImagePaintState {
|
||||
char *warnpackedfile;
|
||||
char *warnmultifile;
|
||||
|
||||
bool do_masking;
|
||||
|
||||
/* viewport texture paint only, but _not_ project paint */
|
||||
Object *ob;
|
||||
int faceindex;
|
||||
@ -327,7 +329,7 @@ static void brush_painter_2d_tiled_tex_partial_update(BrushPainter *painter, con
|
||||
brush_painter_2d_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
|
||||
}
|
||||
|
||||
static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction)
|
||||
static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], bool use_color_correction, bool use_brush_alpha)
|
||||
{
|
||||
const Scene *scene = painter->scene;
|
||||
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
||||
@ -347,7 +349,7 @@ static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float po
|
||||
}
|
||||
|
||||
if (diameter != cache->lastsize ||
|
||||
alpha != cache->lastalpha ||
|
||||
(use_brush_alpha && alpha != cache->lastalpha) ||
|
||||
brush->jitter != cache->lastjitter ||
|
||||
rotation != cache->last_rotation ||
|
||||
do_random)
|
||||
@ -365,11 +367,13 @@ static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float po
|
||||
size = (cache->size) ? cache->size : diameter;
|
||||
|
||||
if (do_tiled) {
|
||||
BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction);
|
||||
BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf,
|
||||
use_color_correction, use_brush_alpha);
|
||||
brush_painter_2d_tiled_tex_partial_update(painter, pos);
|
||||
}
|
||||
else
|
||||
BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction);
|
||||
BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf,
|
||||
use_color_correction, use_brush_alpha);
|
||||
|
||||
cache->lastsize = diameter;
|
||||
cache->lastalpha = alpha;
|
||||
@ -552,7 +556,8 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
|
||||
tot = paint_2d_torus_split_region(region, ibufb, ibuf);
|
||||
|
||||
for (a = 0; a < tot; a++)
|
||||
IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty,
|
||||
IMB_rectblend(ibufb, ibufb, ibuf, NULL, 0, region[a].destx, region[a].desty,
|
||||
region[a].destx, region[a].desty,
|
||||
region[a].srcx, region[a].srcy,
|
||||
region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
|
||||
}
|
||||
@ -565,9 +570,9 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
|
||||
ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
|
||||
|
||||
IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
|
||||
IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h,
|
||||
IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
|
||||
IMB_BLEND_COPY_RGB);
|
||||
IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h,
|
||||
IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
|
||||
IMB_BLEND_COPY_ALPHA);
|
||||
|
||||
return clonebuf;
|
||||
@ -582,12 +587,14 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
|
||||
static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2])
|
||||
{
|
||||
ImagePaintState *s = ((ImagePaintState *)state);
|
||||
ImBuf *clonebuf = NULL, *frombuf;
|
||||
ImBuf *clonebuf = NULL, *frombuf, *tmpbuf = NULL;
|
||||
ImagePaintRegion region[4];
|
||||
short torus = s->brush->flag & BRUSH_TORUS;
|
||||
short blend = s->blend;
|
||||
float *offset = s->brush->clone.offset;
|
||||
float liftpos[2];
|
||||
float brush_alpha = BKE_brush_alpha_get(s->scene, s->brush);
|
||||
unsigned short mask_max = (unsigned short)(brush_alpha * 65535.0f);
|
||||
int bpos[2], blastpos[2], bliftpos[2];
|
||||
int a, tot;
|
||||
|
||||
@ -623,19 +630,55 @@ static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const
|
||||
tot = 1;
|
||||
}
|
||||
|
||||
if (s->do_masking)
|
||||
tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
|
||||
|
||||
/* blend into canvas */
|
||||
for (a = 0; a < tot; a++) {
|
||||
imapaint_dirty_region(s->image, s->canvas,
|
||||
region[a].destx, region[a].desty,
|
||||
region[a].width, region[a].height);
|
||||
|
||||
if (s->do_masking) {
|
||||
/* masking, find original pixels tiles from undo buffer to composite over */
|
||||
int tilex, tiley, tilew, tileh, tx, ty;
|
||||
|
||||
IMB_rectblend(s->canvas, frombuf,
|
||||
region[a].destx, region[a].desty,
|
||||
region[a].srcx, region[a].srcy,
|
||||
region[a].width, region[a].height, blend);
|
||||
imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty,
|
||||
region[a].width, region[a].height,
|
||||
&tilex, &tiley, &tilew, &tileh);
|
||||
|
||||
for (ty = tiley; ty <= tileh; ty++) {
|
||||
for (tx = tilex; tx <= tilew; tx++) {
|
||||
/* retrieve original pixels + mask from undo buffer */
|
||||
unsigned short *mask;
|
||||
int origx = region[a].destx - tx * IMAPAINT_TILE_SIZE;
|
||||
int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE;
|
||||
|
||||
if (s->canvas->rect_float)
|
||||
tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
|
||||
else
|
||||
tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
|
||||
|
||||
IMB_rectblend(s->canvas, tmpbuf, frombuf, mask, mask_max,
|
||||
region[a].destx, region[a].desty,
|
||||
origx, origy,
|
||||
region[a].srcx, region[a].srcy,
|
||||
region[a].width, region[a].height, blend);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* no masking, composite brush directly onto canvas */
|
||||
IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, 0,
|
||||
region[a].destx, region[a].desty,
|
||||
region[a].destx, region[a].desty,
|
||||
region[a].srcx, region[a].srcy,
|
||||
region[a].width, region[a].height, blend);
|
||||
}
|
||||
}
|
||||
|
||||
if (clonebuf) IMB_freeImBuf(clonebuf);
|
||||
if (tmpbuf) IMB_freeImBuf(tmpbuf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -684,6 +727,11 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
|
||||
IMB_rect_from_float(s->clonecanvas);
|
||||
}
|
||||
|
||||
/* set masking */
|
||||
s->do_masking = (s->brush->flag & BRUSH_AIRBRUSH || (s->brush->mtex.tex &&
|
||||
!ELEM(s->brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL)))
|
||||
? false : true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -691,6 +739,9 @@ static void paint_2d_canvas_free(ImagePaintState *s)
|
||||
{
|
||||
BKE_image_release_ibuf(s->image, s->canvas, NULL);
|
||||
BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
|
||||
|
||||
if (s->do_masking)
|
||||
image_undo_remove_masks();
|
||||
}
|
||||
|
||||
int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int eraser)
|
||||
@ -734,7 +785,7 @@ int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int era
|
||||
*/
|
||||
brush_painter_2d_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0);
|
||||
|
||||
brush_painter_2d_refresh_cache(painter, newuv, is_data == false);
|
||||
brush_painter_2d_refresh_cache(painter, newuv, is_data == false, s->do_masking);
|
||||
|
||||
if (paint_2d_op(s, painter->cache.ibuf, olduv, newuv)) {
|
||||
imapaint_image_update(s->sima, s->image, ibuf, false);
|
||||
|
@ -3887,6 +3887,8 @@ static void *do_projectpaint_thread(void *ph_v)
|
||||
mask *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
|
||||
}
|
||||
|
||||
CLAMP(mask, 0.0f, 1.0f);
|
||||
|
||||
if (ps->do_masking) {
|
||||
/* masking to keep brush contribution to a pixel limited. note we do not do
|
||||
* a simple max(mask, mask_accum), as this is very sensitive to spacing and
|
||||
|
@ -126,7 +126,9 @@ typedef struct ImagePaintPartialRedraw {
|
||||
#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f)
|
||||
|
||||
int image_texture_paint_poll(struct bContext *C);
|
||||
void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask);
|
||||
void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile);
|
||||
void image_undo_remove_masks(void);
|
||||
void image_undo_restore(struct bContext *C, struct ListBase *lb);
|
||||
void image_undo_free(struct ListBase *lb);
|
||||
void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
|
||||
@ -134,6 +136,7 @@ struct ImagePaintPartialRedraw *get_imapaintpartial(void);
|
||||
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
|
||||
void imapaint_clear_partial_redraw(void);
|
||||
void imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
|
||||
void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
|
||||
int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
|
||||
void *paint_2d_new_stroke(struct bContext *, struct wmOperator *);
|
||||
void paint_2d_redraw(const bContext *C, void *ps, int final);
|
||||
|
@ -178,8 +178,10 @@ 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(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf,
|
||||
unsigned short *mask, unsigned short mask_max,
|
||||
int destx, int desty, int origx, int origy, int srcx, int srcy,
|
||||
int width, int height, IMB_BlendMode mode);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -104,7 +104,7 @@ void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_Blend
|
||||
|
||||
/* clipping */
|
||||
|
||||
void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
|
||||
void IMB_rectclip(ImBuf *dbuf, ImBuf *sbuf, int *destx,
|
||||
int *desty, int *srcx, int *srcy, int *width, int *height)
|
||||
{
|
||||
int tmp;
|
||||
@ -150,43 +150,125 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
|
||||
}
|
||||
}
|
||||
|
||||
static void imb_rectclip3(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, int *destx,
|
||||
int *desty, int *origx, int *origy, int *srcx, int *srcy,
|
||||
int *width, int *height)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
if (dbuf == NULL) return;
|
||||
|
||||
if (*destx < 0) {
|
||||
*srcx -= *destx;
|
||||
*origx -= *destx;
|
||||
*width += *destx;
|
||||
*destx = 0;
|
||||
}
|
||||
if (*origx < 0) {
|
||||
*destx -= *origx;
|
||||
*srcx -= *origx;
|
||||
*width += *origx;
|
||||
*origx = 0;
|
||||
}
|
||||
if (*srcx < 0) {
|
||||
*destx -= *srcx;
|
||||
*origx -= *srcx;
|
||||
*width += *srcx;
|
||||
*srcx = 0;
|
||||
}
|
||||
|
||||
if (*desty < 0) {
|
||||
*srcy -= *desty;
|
||||
*origy -= *desty;
|
||||
*height += *desty;
|
||||
*desty = 0;
|
||||
}
|
||||
if (*origy < 0) {
|
||||
*desty -= *origy;
|
||||
*srcy -= *origy;
|
||||
*height += *origy;
|
||||
*origy = 0;
|
||||
}
|
||||
if (*srcy < 0) {
|
||||
*desty -= *srcy;
|
||||
*origy -= *srcy;
|
||||
*height += *srcy;
|
||||
*srcy = 0;
|
||||
}
|
||||
|
||||
tmp = dbuf->x - *destx;
|
||||
if (*width > tmp) *width = tmp;
|
||||
tmp = dbuf->y - *desty;
|
||||
if (*height > tmp) *height = tmp;
|
||||
|
||||
if (obuf) {
|
||||
tmp = obuf->x - *origx;
|
||||
if (*width > tmp) *width = tmp;
|
||||
tmp = obuf->y - *origy;
|
||||
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 ((*height <= 0) || (*width <= 0)) {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy and blend */
|
||||
|
||||
void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
|
||||
void IMB_rectcpy(ImBuf *dbuf, 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);
|
||||
IMB_rectblend(dbuf, dbuf, sbuf, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY);
|
||||
}
|
||||
|
||||
typedef void (*IMB_blend_func)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2);
|
||||
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
|
||||
|
||||
|
||||
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(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *maskrect, unsigned short mask_max,
|
||||
int destx, int desty, int origx, int origy, 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;
|
||||
unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr;
|
||||
float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf;
|
||||
unsigned short *mr;
|
||||
int do_float, do_char, srcskip, destskip, origskip, x;
|
||||
IMB_blend_func func = NULL;
|
||||
IMB_blend_func_float func_float = NULL;
|
||||
|
||||
if (dbuf == NULL) return;
|
||||
if (dbuf == NULL || obuf == NULL) return;
|
||||
|
||||
IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height);
|
||||
imb_rectclip3(dbuf, obuf, sbuf, &destx, &desty, &origx, &origy, &srcx, &srcy, &width, &height);
|
||||
|
||||
if (width == 0 || height == 0) return;
|
||||
if (sbuf && sbuf->channels != 4) return;
|
||||
if (dbuf->channels != 4) 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;
|
||||
do_char = (sbuf && sbuf->rect && dbuf->rect && obuf->rect);
|
||||
do_float = (sbuf && sbuf->rect_float && dbuf->rect_float && obuf->rect_float);
|
||||
|
||||
if (do_char) {
|
||||
drect = dbuf->rect + desty * dbuf->x + destx;
|
||||
orect = obuf->rect + origy * obuf->x + origx;
|
||||
}
|
||||
if (do_float) {
|
||||
drectf = dbuf->rect_float + (desty * dbuf->x + destx) * 4;
|
||||
orectf = obuf->rect_float + (origy * obuf->x + origx) * 4;
|
||||
}
|
||||
|
||||
if (maskrect)
|
||||
maskrect += origy * obuf->x + origx;
|
||||
|
||||
destskip = dbuf->x;
|
||||
origskip = obuf->x;
|
||||
|
||||
if (sbuf) {
|
||||
if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
|
||||
@ -307,24 +389,92 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
|
||||
for (; height > 0; height--) {
|
||||
if (do_char) {
|
||||
dr = drect;
|
||||
or = orect;
|
||||
sr = srect;
|
||||
for (x = width; x > 0; x--, dr++, sr++) {
|
||||
if (((unsigned char *)sr)[3])
|
||||
func((unsigned char *)dr, (unsigned char *)dr, (unsigned char *)sr);
|
||||
|
||||
if (maskrect) {
|
||||
/* mask accumulation for painting */
|
||||
mr = maskrect;
|
||||
|
||||
for (x = width; x > 0; x--, dr++, or++, sr++, mr++) {
|
||||
unsigned char *src = (unsigned char*)sr;
|
||||
|
||||
if (src[3]) {
|
||||
unsigned short mask = *mr + divide_round_i((mask_max - *mr) * src[3], 255);
|
||||
|
||||
if (mask > *mr) {
|
||||
unsigned char mask_src[4];
|
||||
|
||||
*mr = mask;
|
||||
|
||||
mask_src[0] = src[0];
|
||||
mask_src[1] = src[1];
|
||||
mask_src[2] = src[2];
|
||||
mask_src[3] = mask >> 8;
|
||||
|
||||
func((unsigned char *)dr, (unsigned char *)or, mask_src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maskrect += origskip;
|
||||
}
|
||||
else {
|
||||
/* regular blending */
|
||||
for (x = width; x > 0; x--, dr++, or++, sr++) {
|
||||
if (((unsigned char *)sr)[3])
|
||||
func((unsigned char *)dr, (unsigned char *)or, (unsigned char *)sr);
|
||||
}
|
||||
}
|
||||
|
||||
drect += destskip;
|
||||
orect += origskip;
|
||||
srect += srcskip;
|
||||
}
|
||||
|
||||
if (do_float) {
|
||||
drf = drectf;
|
||||
orf = orectf;
|
||||
srf = srectf;
|
||||
for (x = width; x > 0; x--, drf += 4, srf += 4) {
|
||||
if (srf[3] != 0)
|
||||
func_float(drf, drf, srf);
|
||||
|
||||
if (maskrect) {
|
||||
/* mask accumulation for painting */
|
||||
mr = maskrect;
|
||||
|
||||
for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, mr++) {
|
||||
if (srf[3] != 0) {
|
||||
float alpha = CLAMPIS(srf[3], 0.0f, 1.0f);
|
||||
unsigned short mask = (unsigned short)(*mr + (mask_max - *mr) * alpha);
|
||||
|
||||
if (mask > *mr) {
|
||||
float mask_srf[4];
|
||||
float new_alpha = mask * (1.0f/65535.0f);
|
||||
float map_alpha = new_alpha / srf[3];
|
||||
|
||||
*mr = mask;
|
||||
|
||||
mask_srf[0] = map_alpha * srf[0];
|
||||
mask_srf[1] = map_alpha * srf[1];
|
||||
mask_srf[2] = map_alpha * srf[2];
|
||||
mask_srf[3] = new_alpha;
|
||||
|
||||
func_float(drf, orf, mask_srf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maskrect += origskip;
|
||||
}
|
||||
else {
|
||||
/* regular blending */
|
||||
for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4) {
|
||||
if (srf[3] != 0)
|
||||
func_float(drf, orf, srf);
|
||||
}
|
||||
}
|
||||
|
||||
drectf += destskip * 4;
|
||||
orectf += origskip * 4;
|
||||
srectf += srcskip * 4;
|
||||
}
|
||||
}
|
||||
@ -333,7 +483,7 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
|
||||
|
||||
/* fill */
|
||||
|
||||
void IMB_rectfill(struct ImBuf *drect, const float col[4])
|
||||
void IMB_rectfill(ImBuf *drect, const float col[4])
|
||||
{
|
||||
int num;
|
||||
|
||||
@ -462,7 +612,7 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height,
|
||||
}
|
||||
}
|
||||
|
||||
void IMB_rectfill_area(struct ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2, struct ColorManagedDisplay *display)
|
||||
void IMB_rectfill_area(ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2, struct ColorManagedDisplay *display)
|
||||
{
|
||||
if (!ibuf) return;
|
||||
buf_rectfill_area((unsigned char *) ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, col, display,
|
||||
|
@ -163,7 +163,7 @@ void ImageBuff::plot(unsigned char *img, short width, short height, short x, sho
|
||||
// assign temporarily our buffer to the ImBuf buffer, we use the same format
|
||||
tmpbuf->rect = (unsigned int*)img;
|
||||
m_imbuf->rect = m_image;
|
||||
IMB_rectblend(m_imbuf, tmpbuf, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
|
||||
IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
|
||||
// remove so that MB_freeImBuf will free our buffer
|
||||
m_imbuf->rect = NULL;
|
||||
tmpbuf->rect = NULL;
|
||||
@ -186,7 +186,7 @@ void ImageBuff::plot(ImageBuff *img, short x, short y, short mode)
|
||||
// assign temporarily our buffer to the ImBuf buffer, we use the same format
|
||||
img->m_imbuf->rect = img->m_image;
|
||||
m_imbuf->rect = m_image;
|
||||
IMB_rectblend(m_imbuf, img->m_imbuf, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
|
||||
IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
|
||||
// remove so that MB_freeImBuf will free our buffer
|
||||
m_imbuf->rect = NULL;
|
||||
img->m_imbuf->rect = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user