libobs: Implement additional source blending modes
parent
33a6d2a5fd
commit
447b17e75e
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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;
|
||||
|
|
15
libobs/obs.h
15
libobs/obs.h
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue