libobs: Implement additional source blending modes

master
jw0z96 2021-10-24 16:45:15 +01:00 committed by Jim
parent 33a6d2a5fd
commit 447b17e75e
7 changed files with 227 additions and 1 deletions

View File

@ -478,6 +478,16 @@ ScaleFiltering.Bicubic="Bicubic"
ScaleFiltering.Lanczos="Lanczos"
ScaleFiltering.Area="Area"
# blending modes
BlendingMode="Blending Mode"
BlendingMode.Normal="Normal"
BlendingMode.Additive="Additive"
BlendingMode.Subtract="Subtract"
BlendingMode.Screen="Screen"
BlendingMode.Multiply="Multiply"
BlendingMode.Lighten="Lighten"
BlendingMode.Darken="Darken"
# deinterlacing
Deinterlacing="Deinterlacing"
Deinterlacing.Discard="Discard"

View File

@ -2568,6 +2568,7 @@ OBSBasic::~OBSBasic()
delete sourceProjector;
delete sceneProjectorMenu;
delete scaleFilteringMenu;
delete blendingModeMenu;
delete colorMenu;
delete colorWidgetAction;
delete colorSelect;
@ -5268,6 +5269,40 @@ QMenu *OBSBasic::AddScaleFilteringMenu(QMenu *menu, obs_sceneitem_t *item)
return menu;
}
void OBSBasic::SetBlendingMode()
{
QAction *action = reinterpret_cast<QAction *>(sender());
obs_blending_type mode =
(obs_blending_type)action->property("mode").toInt();
OBSSceneItem sceneItem = GetCurrentSceneItem();
obs_sceneitem_set_blending_mode(sceneItem, mode);
}
QMenu *OBSBasic::AddBlendingModeMenu(QMenu *menu, obs_sceneitem_t *item)
{
obs_blending_type blendingMode = obs_sceneitem_get_blending_mode(item);
QAction *action;
#define ADD_MODE(name, mode) \
action = menu->addAction(QTStr("" name), this, \
SLOT(SetBlendingMode())); \
action->setProperty("mode", (int)mode); \
action->setCheckable(true); \
action->setChecked(blendingMode == mode);
ADD_MODE("BlendingMode.Normal", OBS_BLEND_NORMAL);
ADD_MODE("BlendingMode.Additive", OBS_BLEND_ADDITIVE);
ADD_MODE("BlendingMode.Subtract", OBS_BLEND_SUBTRACT);
ADD_MODE("BlendingMode.Screen", OBS_BLEND_SCREEN);
ADD_MODE("BlendingMode.Multiply", OBS_BLEND_MULTIPLY);
ADD_MODE("BlendingMode.Lighten", OBS_BLEND_LIGHTEN);
ADD_MODE("BlendingMode.Darken", OBS_BLEND_DARKEN);
#undef ADD_MODE
return menu;
}
QMenu *OBSBasic::AddBackgroundColorMenu(QMenu *menu,
QWidgetAction *widgetAction,
ColorSelect *select,
@ -5338,6 +5373,7 @@ void OBSBasic::CreateSourcePopupMenu(int idx, bool preview)
delete previewProjectorSource;
delete sourceProjector;
delete scaleFilteringMenu;
delete blendingModeMenu;
delete colorMenu;
delete colorWidgetAction;
delete colorSelect;
@ -5469,6 +5505,10 @@ void OBSBasic::CreateSourcePopupMenu(int idx, bool preview)
AddScaleFilteringMenu(scaleFilteringMenu, sceneItem));
popup.addSeparator();
blendingModeMenu = new QMenu(QTStr("BlendingMode"));
popup.addMenu(AddBlendingModeMenu(blendingModeMenu, sceneItem));
popup.addSeparator();
popup.addMenu(sourceProjector);
popup.addAction(sourceWindow);
popup.addAction(QTStr("Screenshot.Source"), this,

View File

@ -308,6 +308,7 @@ private:
QPointer<QMenu> sceneProjectorMenu;
QPointer<QMenu> sourceProjector;
QPointer<QMenu> scaleFilteringMenu;
QPointer<QMenu> blendingModeMenu;
QPointer<QMenu> colorMenu;
QPointer<QWidgetAction> colorWidgetAction;
QPointer<ColorSelect> colorSelect;
@ -707,6 +708,8 @@ private slots:
void SetScaleFilter();
void SetBlendingMode();
void IconActivated(QSystemTrayIcon::ActivationReason reason);
void SetShowing(bool showing);
@ -880,6 +883,7 @@ public:
QMenu *AddDeinterlacingMenu(QMenu *menu, obs_source_t *source);
QMenu *AddScaleFilteringMenu(QMenu *menu, obs_sceneitem_t *item);
QMenu *AddBlendingModeMenu(QMenu *menu, obs_sceneitem_t *item);
QMenu *AddBackgroundColorMenu(QMenu *menu, QWidgetAction *widgetAction,
ColorSelect *select,
obs_sceneitem_t *item);

View File

@ -492,6 +492,22 @@ Scene Item Functions
---------------------
.. function:: void obs_sceneitem_set_blending_mode(obs_sceneitem_t *item, enum obs_blending_type type)
enum obs_blending_type obs_sceneitem_get_blending_mode(obs_sceneitem_t *item)
Sets/gets the blending mode used for the scene item.
:param type: | Can be one of the following values:
| OBS_BLEND_NORMAL
| OBS_BLEND_ADDITIVE
| OBS_BLEND_SUBTRACT
| OBS_BLEND_SCREEN
| OBS_BLEND_MULTIPLY
| OBS_BLEND_LIGHTEN
| OBS_BLEND_DARKEN
---------------------
.. function:: void obs_sceneitem_defer_update_begin(obs_sceneitem_t *item)
void obs_sceneitem_defer_update_end(obs_sceneitem_t *item)

View File

@ -59,6 +59,73 @@ static const char *obs_scene_signals[] = {
NULL,
};
static const struct {
enum gs_blend_type src_color;
enum gs_blend_type src_alpha;
enum gs_blend_type dst_color;
enum gs_blend_type dst_alpha;
enum gs_blend_op_type op;
} obs_blend_mode_params[] = {
/* clang-format off */
// OBS_BLEND_NORMAL
{
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_INVSRCALPHA,
GS_BLEND_INVSRCALPHA,
GS_BLEND_OP_ADD,
},
// OBS_BLEND_ADDITIVE
{
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_OP_ADD,
},
// OBS_BLEND_SUBTRACT
{
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_OP_REVERSE_SUBTRACT,
},
// OBS_BLEND_SCREEN
{
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_INVSRCCOLOR,
GS_BLEND_INVSRCALPHA,
GS_BLEND_OP_ADD
},
// OBS_BLEND_MULTIPLY
{
GS_BLEND_DSTCOLOR,
GS_BLEND_DSTALPHA,
GS_BLEND_INVSRCALPHA,
GS_BLEND_INVSRCALPHA,
GS_BLEND_OP_ADD
},
// OBS_BLEND_LIGHTEN
{
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_OP_MAX,
},
// OBS_BLEND_DARKEN
{
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_ONE,
GS_BLEND_OP_MIN,
},
/* clang-format on */
};
static inline void signal_item_remove(struct obs_scene_item *item)
{
struct calldata params;
@ -472,6 +539,11 @@ static inline bool scale_filter_enabled(const struct obs_scene_item *item)
return item->scale_filter != OBS_SCALE_DISABLE;
}
static inline bool default_blending_enabled(const struct obs_scene_item *item)
{
return item->blend_type == OBS_BLEND_NORMAL;
}
static inline bool item_is_scene(const struct obs_scene_item *item)
{
return item->source && item->source->info.type == OBS_SOURCE_TYPE_SCENE;
@ -480,6 +552,7 @@ static inline bool item_is_scene(const struct obs_scene_item *item)
static inline bool item_texture_enabled(const struct obs_scene_item *item)
{
return crop_enabled(&item->crop) || scale_filter_enabled(item) ||
!default_blending_enabled(item) ||
(item_is_scene(item) && !item->is_group);
}
@ -545,7 +618,13 @@ static void render_item_texture(struct obs_scene_item *item)
}
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
gs_blend_function_separate(
obs_blend_mode_params[item->blend_type].src_color,
obs_blend_mode_params[item->blend_type].dst_color,
obs_blend_mode_params[item->blend_type].src_alpha,
obs_blend_mode_params[item->blend_type].dst_alpha);
gs_blend_op(obs_blend_mode_params[item->blend_type].op);
while (gs_effect_loop(effect, tech))
obs_source_draw(tex, 0, 0, 0, 0, 0);
@ -789,6 +868,7 @@ static void scene_load_item(struct obs_scene *scene, obs_data_t *item_data)
const char *name = obs_data_get_string(item_data, "name");
obs_source_t *source;
const char *scale_filter_str;
const char *blend_str;
struct obs_scene_item *item;
bool visible;
bool lock;
@ -868,6 +948,26 @@ static void scene_load_item(struct obs_scene *scene, obs_data_t *item_data)
item->scale_filter = OBS_SCALE_AREA;
}
blend_str = obs_data_get_string(item_data, "blend_type");
item->blend_type = OBS_BLEND_NORMAL;
if (blend_str) {
if (astrcmpi(blend_str, "normal") == 0)
item->blend_type = OBS_BLEND_NORMAL;
else if (astrcmpi(blend_str, "additive") == 0)
item->blend_type = OBS_BLEND_ADDITIVE;
else if (astrcmpi(blend_str, "subtract") == 0)
item->blend_type = OBS_BLEND_SUBTRACT;
else if (astrcmpi(blend_str, "screen") == 0)
item->blend_type = OBS_BLEND_SCREEN;
else if (astrcmpi(blend_str, "multiply") == 0)
item->blend_type = OBS_BLEND_MULTIPLY;
else if (astrcmpi(blend_str, "lighten") == 0)
item->blend_type = OBS_BLEND_LIGHTEN;
else if (astrcmpi(blend_str, "darken") == 0)
item->blend_type = OBS_BLEND_DARKEN;
}
obs_data_t *show_data = obs_data_get_obj(item_data, "show_transition");
if (show_data) {
obs_sceneitem_transition_load(item, show_data, true);
@ -937,6 +1037,7 @@ static void scene_save_item(obs_data_array_t *array,
obs_data_t *item_data = obs_data_create();
const char *name = obs_source_get_name(item->source);
const char *scale_filter;
const char *blend_type;
struct vec2 pos = item->pos;
struct vec2 scale = item->scale;
float rot = item->rot;
@ -995,6 +1096,25 @@ static void scene_save_item(obs_data_array_t *array,
obs_data_set_string(item_data, "scale_filter", scale_filter);
if (item->blend_type == OBS_BLEND_NORMAL)
blend_type = "normal";
else if (item->blend_type == OBS_BLEND_ADDITIVE)
blend_type = "additive";
else if (item->blend_type == OBS_BLEND_SUBTRACT)
blend_type = "subtract";
else if (item->blend_type == OBS_BLEND_SCREEN)
blend_type = "screen";
else if (item->blend_type == OBS_BLEND_MULTIPLY)
blend_type = "multiply";
else if (item->blend_type == OBS_BLEND_LIGHTEN)
blend_type = "lighten";
else if (item->blend_type == OBS_BLEND_DARKEN)
blend_type = "darken";
else
blend_type = "normal";
obs_data_set_string(item_data, "blend_type", blend_type);
obs_data_t *show_data = obs_sceneitem_transition_save(item, true);
obs_data_set_obj(item_data, "show_transition", show_data);
obs_data_release(show_data);
@ -1393,6 +1513,7 @@ static inline void duplicate_item_data(struct obs_scene_item *dst,
dst->last_height = src->last_height;
dst->output_scale = src->output_scale;
dst->scale_filter = src->scale_filter;
dst->blend_type = src->blend_type;
dst->box_transform = src->box_transform;
dst->box_scale = src->box_scale;
dst->draw_transform = src->draw_transform;
@ -2741,6 +2862,24 @@ enum obs_scale_type obs_sceneitem_get_scale_filter(obs_sceneitem_t *item)
: OBS_SCALE_DISABLE;
}
void obs_sceneitem_set_blending_mode(obs_sceneitem_t *item,
enum obs_blending_type type)
{
if (!obs_ptr_valid(item, "obs_sceneitem_set_blending_mode"))
return;
item->blend_type = type;
os_atomic_set_bool(&item->update_transform, true);
}
enum obs_blending_type obs_sceneitem_get_blending_mode(obs_sceneitem_t *item)
{
return obs_ptr_valid(item, "obs_sceneitem_get_blending_mode")
? item->blend_type
: OBS_BLEND_NORMAL;
}
void obs_sceneitem_defer_update_begin(obs_sceneitem_t *item)
{
if (!obs_ptr_valid(item, "obs_sceneitem_defer_update_begin"))

View File

@ -63,6 +63,8 @@ struct obs_scene_item {
struct vec2 output_scale;
enum obs_scale_type scale_filter;
enum obs_blending_type blend_type;
struct matrix4 box_transform;
struct vec2 box_scale;
struct matrix4 draw_transform;

View File

@ -121,6 +121,16 @@ enum obs_scale_type {
OBS_SCALE_AREA,
};
enum obs_blending_type {
OBS_BLEND_NORMAL,
OBS_BLEND_ADDITIVE,
OBS_BLEND_SUBTRACT,
OBS_BLEND_SCREEN,
OBS_BLEND_MULTIPLY,
OBS_BLEND_LIGHTEN,
OBS_BLEND_DARKEN,
};
/**
* Used with scene items to indicate the type of bounds to use for scene items.
* Mostly determines how the image will be scaled within those bounds, or
@ -1752,6 +1762,11 @@ EXPORT void obs_sceneitem_set_scale_filter(obs_sceneitem_t *item,
EXPORT enum obs_scale_type
obs_sceneitem_get_scale_filter(obs_sceneitem_t *item);
EXPORT void obs_sceneitem_set_blending_mode(obs_sceneitem_t *item,
enum obs_blending_type type);
EXPORT enum obs_blending_type
obs_sceneitem_get_blending_mode(obs_sceneitem_t *item);
EXPORT void obs_sceneitem_force_update_transform(obs_sceneitem_t *item);
EXPORT void obs_sceneitem_defer_update_begin(obs_sceneitem_t *item);