From d7983e3638896e5742fcf1bafe49c49a6b0aa08f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sat, 12 Oct 2013 14:09:05 +0000 Subject: [PATCH] Option to overlay mask over the footage Currently supports only two modes: - Show alpha channel of the mask - Multiply footage by the mask, which will give you final-looking combined image. TODO: Currently rasterization happens on every redraw, need to cache rasterized mask somewhere to make redraw more realtime. --- .../startup/bl_ui/properties_mask_common.py | 5 + source/blender/editors/include/ED_mask.h | 2 +- source/blender/editors/mask/mask_draw.c | 118 +++++++++++++++++- source/blender/editors/screen/glutil.c | 2 +- .../blender/editors/space_clip/space_clip.c | 4 +- .../blender/editors/space_image/space_image.c | 7 +- .../editors/space_sequencer/sequencer_draw.c | 2 +- source/blender/makesdna/DNA_mask_types.h | 7 ++ source/blender/makesdna/DNA_space_types.h | 3 +- source/blender/makesrna/intern/rna_space.c | 17 +++ 10 files changed, 159 insertions(+), 8 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index aa4d671e938..45f3471ad35 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -222,6 +222,11 @@ class MASK_PT_display(): layout.prop(space_data, "mask_draw_type", text="") layout.prop(space_data, "show_mask_smooth") + layout.prop(space_data, "show_mask_overlay") + row = layout.row() + row.active = space_data.show_mask_overlay + row.prop(space_data, "mask_overlay_mode", text="") + class MASK_PT_tools(): # subclasses must define... diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 3e2dbe255df..8da36f015dc 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -57,7 +57,7 @@ void ED_operatormacros_mask(void); /* mask_draw.c */ void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type); void ED_mask_draw_region(struct Mask *mask, struct ARegion *ar, - const char draw_flag, const char draw_type, + const char draw_flag, const char draw_type, const char overlay_mode, const int width_i, const int height_i, const float aspx, const float aspy, const short do_scale_applied, const short do_draw_cb, diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index fec4ab87996..50d8e653737 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -35,6 +35,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_rect.h" +#include "BLI_task.h" #include "BKE_context.h" #include "BKE_mask.h" @@ -48,6 +49,7 @@ #include "ED_mask.h" /* own include */ #include "ED_space_api.h" #include "BIF_gl.h" +#include "BIF_glutil.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -535,10 +537,93 @@ void ED_mask_draw(const bContext *C, draw_masklays(C, mask, draw_flag, draw_type, width, height); } +typedef struct ThreadedMaskRasterizeState { + MaskRasterHandle *handle; + float *buffer; + int width, height; +} ThreadedMaskRasterizeState; + +typedef struct ThreadedMaskRasterizeData { + int start_scanline; + int num_scanlines; +} ThreadedMaskRasterizeData; + +static void mask_rasterize_func(TaskPool *pool, void *taskdata, int UNUSED(threadid)) +{ + ThreadedMaskRasterizeState *state = (ThreadedMaskRasterizeState *) BLI_task_pool_userdata(pool); + ThreadedMaskRasterizeData *data = (ThreadedMaskRasterizeData *) taskdata; + int scanline; + + for (scanline = 0; scanline < data->num_scanlines; scanline++) { + int x, y = data->start_scanline + scanline; + for (x = 0; x < state->width; x++) { + int index = y * state->width + x; + float xy[2]; + + xy[0] = (float) x / state->width; + xy[1] = (float) y / state->height; + + state->buffer[index] = BKE_maskrasterize_handle_sample(state->handle, xy); + } + } +} + +static float *threaded_mask_rasterize(Mask *mask, const int width, const int height) +{ + TaskScheduler *task_scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool; + MaskRasterHandle *handle; + ThreadedMaskRasterizeState state; + float *buffer; + int i, num_threads = BLI_task_scheduler_num_threads(task_scheduler), scanlines_per_thread; + + buffer = MEM_mallocN(sizeof(float) * height * width, "rasterized mask buffer"); + + /* Initialize rasterization handle. */ + handle = BKE_maskrasterize_handle_new(); + BKE_maskrasterize_handle_init(handle, mask, width, height, TRUE, TRUE, TRUE); + + state.handle = handle; + state.buffer = buffer; + state.width = width; + state.height = height; + + task_pool = BLI_task_pool_create(task_scheduler, &state); + + BLI_begin_threaded_malloc(); + + scanlines_per_thread = height / num_threads; + for (i = 0; i < num_threads; i++) { + ThreadedMaskRasterizeData *data = MEM_mallocN(sizeof(ThreadedMaskRasterizeData), + "threaded mask rasterize data"); + + data->start_scanline = i * scanlines_per_thread; + + if (i < num_threads - 1) { + data->num_scanlines = scanlines_per_thread; + } + else { + data->num_scanlines = height - data->start_scanline; + } + + BLI_task_pool_push(task_pool, mask_rasterize_func, data, true, TASK_PRIORITY_LOW); + } + + /* work and wait until tasks are done */ + BLI_task_pool_work_and_wait(task_pool); + + /* Free memory. */ + BLI_task_pool_free(task_pool); + BLI_end_threaded_malloc(); + BKE_maskrasterize_handle_free(handle); + + return buffer; +} + /* sets up the opengl context. * width, height are to match the values from ED_mask_get_size() */ void ED_mask_draw_region(Mask *mask, ARegion *ar, - const char draw_flag, const char draw_type, + const char draw_flag, const char draw_type, const char overlay_mode, const int width_i, const int height_i, /* convert directly into aspect corrected vars */ const float aspx, const float aspy, const short do_scale_applied, const short do_draw_cb, @@ -592,6 +677,37 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar, yofs = ((width - height) / -2.0f) * zoomy; } + if (draw_flag & MASK_DRAWFLAG_OVERLAY) { + float *buffer = threaded_mask_rasterize(mask, width, height); + int format; + + if (overlay_mode == MASK_OVERLAY_ALPHACHANNEL) { + glColor3f(1.0f, 1.0f, 1.0f); + format = GL_LUMINANCE; + } + else { + /* More blending types could be supported in the future. */ + glEnable(GL_BLEND); + glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); + format = GL_ALPHA; + } + + glPushMatrix(); + glTranslatef(x, y, 0); + glScalef(zoomx, zoomy, 0); + if (stabmat) { + glMultMatrixf(stabmat); + } + glaDrawPixelsTex(0.0f, 0.0f, width, height, format, GL_FLOAT, GL_NEAREST, buffer); + glPopMatrix(); + + if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) { + glDisable(GL_BLEND); + } + + MEM_freeN(buffer); + } + /* apply transformation so mask editing tools will assume drawing from the origin in normalized space */ glPushMatrix(); glTranslatef(x + xofs, y + yofs, 0); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index b70b06f2aa4..d356c3d8de3 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -531,7 +531,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, components = 4; else if (format == GL_RGB) components = 3; - else if (format == GL_LUMINANCE) + else if (ELEM(format, GL_LUMINANCE, GL_ALPHA)) components = 1; else { BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled"); diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 3ede63adb72..adc902bf4ba 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -1191,7 +1191,9 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) int mask_width, mask_height; ED_mask_get_size(sa, &mask_width, &mask_height); ED_mask_draw_region(mask, ar, - sc->mask_info.draw_flag, sc->mask_info.draw_type, + sc->mask_info.draw_flag, + sc->mask_info.draw_type, + sc->mask_info.overlay_mode, mask_width, mask_height, aspx, aspy, TRUE, TRUE, diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 5a8292abcab..7b20af340ae 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -674,7 +674,6 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) } else if (sima->mode == SI_MODE_MASK) { mask = ED_space_image_get_mask(sima); - draw_image_cursor(ar, sima->cursor); } ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); @@ -715,7 +714,9 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) BLI_unlock_thread(LOCK_DRAW_IMAGE); ED_mask_draw_region(mask, ar, - sima->mask_info.draw_flag, sima->mask_info.draw_type, + sima->mask_info.draw_flag, + sima->mask_info.draw_type, + sima->mask_info.overlay_mode, width, height, aspx, aspy, TRUE, FALSE, @@ -723,7 +724,9 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) ED_mask_draw_frames(mask, ar, CFRA, mask->sfra, mask->efra); + UI_view2d_view_ortho(v2d); draw_image_cursor(ar, sima->cursor); + UI_view2d_view_restore(C); } /* scrollers? */ diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index dca1b481334..cb69a7fe654 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -1251,7 +1251,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq height = (scene->r.size * scene->r.ysch) / 100; ED_mask_draw_region(mask, ar, - 0, 0, /* TODO */ + 0, 0, 0, /* TODO */ width, height, aspx, aspy, FALSE, TRUE, diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h index 4307ea57f15..a72e287c16f 100644 --- a/source/blender/makesdna/DNA_mask_types.h +++ b/source/blender/makesdna/DNA_mask_types.h @@ -178,6 +178,7 @@ enum { /* SpaceClip->mask_draw_flag */ #define MASK_DRAWFLAG_SMOOTH 1 +#define MASK_DRAWFLAG_OVERLAY 2 /* copy of eSpaceImage_UVDT */ /* SpaceClip->mask_draw_type */ @@ -188,6 +189,12 @@ enum { MASK_DT_WHITE = 3 }; +/* MaskSpaceInfo->overlay_mode */ +enum { + MASK_OVERLAY_ALPHACHANNEL = 0, + MASK_OVERLAY_COMBINED = 1 +}; + /* masklay->blend */ enum { MASK_BLEND_ADD = 0, diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 0478ff567a0..5befaa87e7f 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -546,7 +546,8 @@ typedef struct MaskSpaceInfo /* draw options */ char draw_flag; char draw_type; - char pad3[6]; + char overlay_mode; + char pad3[5]; } MaskSpaceInfo; /* sseq->mainb */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index aee6b060221..41ea74ebb8c 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1336,6 +1336,12 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m { PropertyRNA *prop; + static EnumPropertyItem overlay_mode_items[] = { + {MASK_OVERLAY_ALPHACHANNEL, "ALPHACHANNEL", ICON_NONE, "Alpha Channel", "Show alpha channel of the mask"}, + {MASK_OVERLAY_COMBINED, "COMBINED", ICON_NONE, "Combined", "Combine space background image with the mask"}, + {0, NULL, 0, NULL, NULL} + }; + prop = RNA_def_property(srna, "mask", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "mask_info.mask"); RNA_def_property_flag(prop, PROP_EDITABLE); @@ -1354,6 +1360,17 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_SMOOTH); RNA_def_property_ui_text(prop, "Draw Smooth Splines", ""); RNA_def_property_update(prop, noteflag, NULL); + + prop = RNA_def_property(srna, "show_mask_overlay", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_OVERLAY); + RNA_def_property_ui_text(prop, "Show Mask Overlay", ""); + RNA_def_property_update(prop, noteflag, NULL); + + prop = RNA_def_property(srna, "mask_overlay_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mask_info.overlay_mode"); + RNA_def_property_enum_items(prop, overlay_mode_items); + RNA_def_property_ui_text(prop, "Overlay Mode", "Overlay mode of rasterized mask"); + RNA_def_property_update(prop, noteflag, NULL); } static void rna_def_space_image_uv(BlenderRNA *brna)