obs-filters: Apply color correction filter in linear space
The newly versioned filter also has color overlay removed. We can add it back if the demand is there, but I'd rather not maintain it. Also consolidate behavior of contrast/brightness/gamma across chroma key, color correction, and color key filters. The contrast range has been expanded to approximtely match the range when the filter applied to nonlinear colors.
This commit is contained in:
parent
47da18e26c
commit
e812a133ee
@ -46,13 +46,7 @@ struct color_correction_filter_data {
|
||||
gs_eparam_t *gamma_param;
|
||||
gs_eparam_t *final_matrix_param;
|
||||
|
||||
struct vec3 gamma;
|
||||
float contrast;
|
||||
float brightness;
|
||||
float saturation;
|
||||
float hue_shift;
|
||||
float opacity;
|
||||
struct vec4 color;
|
||||
float gamma;
|
||||
|
||||
/* Pre-Computes */
|
||||
struct matrix4 con_matrix;
|
||||
@ -62,14 +56,26 @@ struct color_correction_filter_data {
|
||||
struct matrix4 color_matrix;
|
||||
struct matrix4 final_matrix;
|
||||
|
||||
struct vec3 rot_quaternion;
|
||||
float rot_quaternion_w;
|
||||
struct vec3 cross;
|
||||
struct vec3 square;
|
||||
struct vec3 wimag;
|
||||
struct vec3 diag;
|
||||
struct vec3 a_line;
|
||||
struct vec3 b_line;
|
||||
struct vec3 half_unit;
|
||||
};
|
||||
|
||||
struct color_correction_filter_data_v2 {
|
||||
obs_source_t *context;
|
||||
|
||||
gs_effect_t *effect;
|
||||
|
||||
gs_eparam_t *gamma_param;
|
||||
gs_eparam_t *final_matrix_param;
|
||||
|
||||
float gamma;
|
||||
|
||||
/* Pre-Computes */
|
||||
struct matrix4 con_matrix;
|
||||
struct matrix4 bright_matrix;
|
||||
struct matrix4 sat_matrix;
|
||||
struct matrix4 hue_op_matrix;
|
||||
struct matrix4 final_matrix;
|
||||
|
||||
struct vec3 half_unit;
|
||||
};
|
||||
|
||||
@ -94,40 +100,29 @@ static const char *color_correction_filter_name(void *unused)
|
||||
* with a slider this function is called to update the internal settings
|
||||
* in OBS, and hence the settings being passed to the CPU/GPU.
|
||||
*/
|
||||
static void color_correction_filter_update(void *data, obs_data_t *settings)
|
||||
static void color_correction_filter_update_v1(void *data, obs_data_t *settings)
|
||||
{
|
||||
struct color_correction_filter_data *filter = data;
|
||||
|
||||
/* Build our Gamma numbers. */
|
||||
double gamma = obs_data_get_double(settings, SETTING_GAMMA);
|
||||
gamma = (gamma < 0.0) ? (-gamma + 1.0) : (1.0 / (gamma + 1.0));
|
||||
vec3_set(&filter->gamma, (float)gamma, (float)gamma, (float)gamma);
|
||||
filter->gamma = (float)gamma;
|
||||
|
||||
/* Build our contrast number. */
|
||||
filter->contrast =
|
||||
float contrast =
|
||||
(float)obs_data_get_double(settings, SETTING_CONTRAST) + 1.0f;
|
||||
float one_minus_con = (1.0f - filter->contrast) / 2.0f;
|
||||
float one_minus_con = (1.0f - contrast) / 2.0f;
|
||||
|
||||
/* Now let's build our Contrast matrix. */
|
||||
filter->con_matrix = (struct matrix4){filter->contrast,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
filter->contrast,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
filter->contrast,
|
||||
0.0f,
|
||||
one_minus_con,
|
||||
one_minus_con,
|
||||
one_minus_con,
|
||||
1.0f};
|
||||
filter->con_matrix = (struct matrix4){
|
||||
contrast, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, contrast, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, contrast, 0.0f,
|
||||
one_minus_con, one_minus_con, one_minus_con, 1.0f};
|
||||
|
||||
/* Build our brightness number. */
|
||||
filter->brightness =
|
||||
float brightness =
|
||||
(float)obs_data_get_double(settings, SETTING_BRIGHTNESS);
|
||||
|
||||
/*
|
||||
@ -136,21 +131,21 @@ static void color_correction_filter_update(void *data, obs_data_t *settings)
|
||||
* this matrix to the identity matrix, so now we only need
|
||||
* to set the 3 variables that have changed.
|
||||
*/
|
||||
filter->bright_matrix.t.x = filter->brightness;
|
||||
filter->bright_matrix.t.y = filter->brightness;
|
||||
filter->bright_matrix.t.z = filter->brightness;
|
||||
filter->bright_matrix.t.x = brightness;
|
||||
filter->bright_matrix.t.y = brightness;
|
||||
filter->bright_matrix.t.z = brightness;
|
||||
|
||||
/* Build our Saturation number. */
|
||||
filter->saturation =
|
||||
float saturation =
|
||||
(float)obs_data_get_double(settings, SETTING_SATURATION) + 1.0f;
|
||||
|
||||
/* Factor in the selected color weights. */
|
||||
float one_minus_sat_red = (1.0f - filter->saturation) * red_weight;
|
||||
float one_minus_sat_green = (1.0f - filter->saturation) * green_weight;
|
||||
float one_minus_sat_blue = (1.0f - filter->saturation) * blue_weight;
|
||||
float sat_val_red = one_minus_sat_red + filter->saturation;
|
||||
float sat_val_green = one_minus_sat_green + filter->saturation;
|
||||
float sat_val_blue = one_minus_sat_blue + filter->saturation;
|
||||
float one_minus_sat_red = (1.0f - saturation) * red_weight;
|
||||
float one_minus_sat_green = (1.0f - saturation) * green_weight;
|
||||
float one_minus_sat_blue = (1.0f - saturation) * blue_weight;
|
||||
float sat_val_red = one_minus_sat_red + saturation;
|
||||
float sat_val_green = one_minus_sat_green + saturation;
|
||||
float sat_val_blue = one_minus_sat_blue + saturation;
|
||||
|
||||
/* Now we build our Saturation matrix. */
|
||||
filter->sat_matrix = (struct matrix4){sat_val_red,
|
||||
@ -171,57 +166,62 @@ static void color_correction_filter_update(void *data, obs_data_t *settings)
|
||||
1.0f};
|
||||
|
||||
/* Build our Hue number. */
|
||||
filter->hue_shift =
|
||||
float hue_shift =
|
||||
(float)obs_data_get_double(settings, SETTING_HUESHIFT);
|
||||
|
||||
/* Build our Transparency number. */
|
||||
filter->opacity =
|
||||
float opacity =
|
||||
(float)obs_data_get_int(settings, SETTING_OPACITY) * 0.01f;
|
||||
|
||||
/* Hue is the radian of 0 to 360 degrees. */
|
||||
float half_angle = 0.5f * (float)(filter->hue_shift / (180.0f / M_PI));
|
||||
float half_angle = 0.5f * (float)(hue_shift / (180.0f / M_PI));
|
||||
|
||||
/* Pseudo-Quaternion To Matrix. */
|
||||
float rot_quad1 = root3 * (float)sin(half_angle);
|
||||
vec3_set(&filter->rot_quaternion, rot_quad1, rot_quad1, rot_quad1);
|
||||
filter->rot_quaternion_w = (float)cos(half_angle);
|
||||
struct vec3 rot_quaternion;
|
||||
vec3_set(&rot_quaternion, rot_quad1, rot_quad1, rot_quad1);
|
||||
float rot_quaternion_w = (float)cos(half_angle);
|
||||
|
||||
vec3_mul(&filter->cross, &filter->rot_quaternion,
|
||||
&filter->rot_quaternion);
|
||||
vec3_mul(&filter->square, &filter->rot_quaternion,
|
||||
&filter->rot_quaternion);
|
||||
vec3_mulf(&filter->wimag, &filter->rot_quaternion,
|
||||
filter->rot_quaternion_w);
|
||||
struct vec3 cross;
|
||||
vec3_mul(&cross, &rot_quaternion, &rot_quaternion);
|
||||
struct vec3 square;
|
||||
vec3_mul(&square, &rot_quaternion, &rot_quaternion);
|
||||
struct vec3 wimag;
|
||||
vec3_mulf(&wimag, &rot_quaternion, rot_quaternion_w);
|
||||
|
||||
vec3_mulf(&filter->square, &filter->square, 2.0f);
|
||||
vec3_sub(&filter->diag, &filter->half_unit, &filter->square);
|
||||
vec3_add(&filter->a_line, &filter->cross, &filter->wimag);
|
||||
vec3_sub(&filter->b_line, &filter->cross, &filter->wimag);
|
||||
vec3_mulf(&square, &square, 2.0f);
|
||||
struct vec3 diag;
|
||||
vec3_sub(&diag, &filter->half_unit, &square);
|
||||
struct vec3 a_line;
|
||||
vec3_add(&a_line, &cross, &wimag);
|
||||
struct vec3 b_line;
|
||||
vec3_sub(&b_line, &cross, &wimag);
|
||||
|
||||
/* Now we build our Hue and Opacity matrix. */
|
||||
filter->hue_op_matrix = (struct matrix4){filter->diag.x * 2.0f,
|
||||
filter->b_line.z * 2.0f,
|
||||
filter->a_line.y * 2.0f,
|
||||
filter->hue_op_matrix = (struct matrix4){diag.x * 2.0f,
|
||||
b_line.z * 2.0f,
|
||||
a_line.y * 2.0f,
|
||||
0.0f,
|
||||
|
||||
filter->a_line.z * 2.0f,
|
||||
filter->diag.y * 2.0f,
|
||||
filter->b_line.x * 2.0f,
|
||||
a_line.z * 2.0f,
|
||||
diag.y * 2.0f,
|
||||
b_line.x * 2.0f,
|
||||
0.0f,
|
||||
|
||||
filter->b_line.y * 2.0f,
|
||||
filter->a_line.x * 2.0f,
|
||||
filter->diag.z * 2.0f,
|
||||
b_line.y * 2.0f,
|
||||
a_line.x * 2.0f,
|
||||
diag.z * 2.0f,
|
||||
0.0f,
|
||||
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
filter->opacity};
|
||||
opacity};
|
||||
|
||||
/* Now get the overlay color data. */
|
||||
uint32_t color = (uint32_t)obs_data_get_int(settings, SETTING_COLOR);
|
||||
vec4_from_rgba(&filter->color, color);
|
||||
struct vec4 color_v4;
|
||||
vec4_from_rgba(&color_v4, color);
|
||||
|
||||
/*
|
||||
* Now let's build our Color 'overlay' matrix.
|
||||
@ -229,13 +229,13 @@ static void color_correction_filter_update(void *data, obs_data_t *settings)
|
||||
* this matrix to the identity matrix, so now we only need
|
||||
* to set the 6 variables that have changed.
|
||||
*/
|
||||
filter->color_matrix.x.x = filter->color.x;
|
||||
filter->color_matrix.y.y = filter->color.y;
|
||||
filter->color_matrix.z.z = filter->color.z;
|
||||
filter->color_matrix.x.x = color_v4.x;
|
||||
filter->color_matrix.y.y = color_v4.y;
|
||||
filter->color_matrix.z.z = color_v4.z;
|
||||
|
||||
filter->color_matrix.t.x = filter->color.w * filter->color.x;
|
||||
filter->color_matrix.t.y = filter->color.w * filter->color.y;
|
||||
filter->color_matrix.t.z = filter->color.w * filter->color.z;
|
||||
filter->color_matrix.t.x = color_v4.w * color_v4.x;
|
||||
filter->color_matrix.t.y = color_v4.w * color_v4.y;
|
||||
filter->color_matrix.t.z = color_v4.w * color_v4.z;
|
||||
|
||||
/* First we apply the Contrast & Brightness matrix. */
|
||||
matrix4_mul(&filter->final_matrix, &filter->bright_matrix,
|
||||
@ -251,12 +251,140 @@ static void color_correction_filter_update(void *data, obs_data_t *settings)
|
||||
&filter->color_matrix);
|
||||
}
|
||||
|
||||
static void color_correction_filter_update_v2(void *data, obs_data_t *settings)
|
||||
{
|
||||
struct color_correction_filter_data_v2 *filter = data;
|
||||
|
||||
/* Build our Gamma numbers. */
|
||||
double gamma = obs_data_get_double(settings, SETTING_GAMMA);
|
||||
gamma = (gamma < 0.0) ? (-gamma + 1.0) : (1.0 / (gamma + 1.0));
|
||||
filter->gamma = (float)gamma;
|
||||
|
||||
/* Build our contrast number. */
|
||||
float contrast = (float)obs_data_get_double(settings, SETTING_CONTRAST);
|
||||
contrast = (contrast < 0.0f) ? (1.0f / (-contrast + 1.0f))
|
||||
: (contrast + 1.0f);
|
||||
|
||||
/* Now let's build our Contrast matrix. */
|
||||
filter->con_matrix = (struct matrix4){contrast, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||
contrast, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||
contrast, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||
1.0f};
|
||||
|
||||
/* Build our brightness number. */
|
||||
float brightness =
|
||||
(float)obs_data_get_double(settings, SETTING_BRIGHTNESS);
|
||||
|
||||
/*
|
||||
* Now let's build our Brightness matrix.
|
||||
* Earlier (in the function color_correction_filter_create) we set
|
||||
* this matrix to the identity matrix, so now we only need
|
||||
* to set the 3 variables that have changed.
|
||||
*/
|
||||
filter->bright_matrix.t.x = brightness;
|
||||
filter->bright_matrix.t.y = brightness;
|
||||
filter->bright_matrix.t.z = brightness;
|
||||
|
||||
/* Build our Saturation number. */
|
||||
float saturation =
|
||||
(float)obs_data_get_double(settings, SETTING_SATURATION) + 1.0f;
|
||||
|
||||
/* Factor in the selected color weights. */
|
||||
float one_minus_sat_red = (1.0f - saturation) * red_weight;
|
||||
float one_minus_sat_green = (1.0f - saturation) * green_weight;
|
||||
float one_minus_sat_blue = (1.0f - saturation) * blue_weight;
|
||||
float sat_val_red = one_minus_sat_red + saturation;
|
||||
float sat_val_green = one_minus_sat_green + saturation;
|
||||
float sat_val_blue = one_minus_sat_blue + saturation;
|
||||
|
||||
/* Now we build our Saturation matrix. */
|
||||
filter->sat_matrix = (struct matrix4){sat_val_red,
|
||||
one_minus_sat_red,
|
||||
one_minus_sat_red,
|
||||
0.0f,
|
||||
one_minus_sat_green,
|
||||
sat_val_green,
|
||||
one_minus_sat_green,
|
||||
0.0f,
|
||||
one_minus_sat_blue,
|
||||
one_minus_sat_blue,
|
||||
sat_val_blue,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f};
|
||||
|
||||
/* Build our Hue number. */
|
||||
float hue_shift =
|
||||
(float)obs_data_get_double(settings, SETTING_HUESHIFT);
|
||||
|
||||
/* Build our Transparency number. */
|
||||
float opacity =
|
||||
(float)obs_data_get_int(settings, SETTING_OPACITY) * 0.01f;
|
||||
|
||||
/* Hue is the radian of 0 to 360 degrees. */
|
||||
float half_angle = 0.5f * (float)(hue_shift / (180.0f / M_PI));
|
||||
|
||||
/* Pseudo-Quaternion To Matrix. */
|
||||
float rot_quad1 = root3 * (float)sin(half_angle);
|
||||
struct vec3 rot_quaternion;
|
||||
vec3_set(&rot_quaternion, rot_quad1, rot_quad1, rot_quad1);
|
||||
float rot_quaternion_w = (float)cos(half_angle);
|
||||
|
||||
struct vec3 cross;
|
||||
vec3_mul(&cross, &rot_quaternion, &rot_quaternion);
|
||||
struct vec3 square;
|
||||
vec3_mul(&square, &rot_quaternion, &rot_quaternion);
|
||||
struct vec3 wimag;
|
||||
vec3_mulf(&wimag, &rot_quaternion, rot_quaternion_w);
|
||||
|
||||
vec3_mulf(&square, &square, 2.0f);
|
||||
struct vec3 diag;
|
||||
vec3_sub(&diag, &filter->half_unit, &square);
|
||||
struct vec3 a_line;
|
||||
vec3_add(&a_line, &cross, &wimag);
|
||||
struct vec3 b_line;
|
||||
vec3_sub(&b_line, &cross, &wimag);
|
||||
|
||||
/* Now we build our Hue and Opacity matrix. */
|
||||
filter->hue_op_matrix = (struct matrix4){diag.x * 2.0f,
|
||||
b_line.z * 2.0f,
|
||||
a_line.y * 2.0f,
|
||||
0.0f,
|
||||
|
||||
a_line.z * 2.0f,
|
||||
diag.y * 2.0f,
|
||||
b_line.x * 2.0f,
|
||||
0.0f,
|
||||
|
||||
b_line.y * 2.0f,
|
||||
a_line.x * 2.0f,
|
||||
diag.z * 2.0f,
|
||||
0.0f,
|
||||
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
opacity};
|
||||
|
||||
/* First we apply the Contrast & Brightness matrix. */
|
||||
matrix4_mul(&filter->final_matrix, &filter->con_matrix,
|
||||
&filter->bright_matrix);
|
||||
/* Now we apply the Saturation matrix. */
|
||||
matrix4_mul(&filter->final_matrix, &filter->final_matrix,
|
||||
&filter->sat_matrix);
|
||||
/* Next we apply the Hue+Opacity matrix. */
|
||||
matrix4_mul(&filter->final_matrix, &filter->final_matrix,
|
||||
&filter->hue_op_matrix);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since this is C we have to be careful when destroying/removing items from
|
||||
* OBS. Jim has added several useful functions to help keep memory leaks to
|
||||
* a minimum, and handle the destruction and construction of these filters.
|
||||
*/
|
||||
static void color_correction_filter_destroy(void *data)
|
||||
static void color_correction_filter_destroy_v1(void *data)
|
||||
{
|
||||
struct color_correction_filter_data *filter = data;
|
||||
|
||||
@ -269,14 +397,27 @@ static void color_correction_filter_destroy(void *data)
|
||||
bfree(data);
|
||||
}
|
||||
|
||||
static void color_correction_filter_destroy_v2(void *data)
|
||||
{
|
||||
struct color_correction_filter_data_v2 *filter = data;
|
||||
|
||||
if (filter->effect) {
|
||||
obs_enter_graphics();
|
||||
gs_effect_destroy(filter->effect);
|
||||
obs_leave_graphics();
|
||||
}
|
||||
|
||||
bfree(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* When you apply a filter OBS creates it, and adds it to the source. OBS also
|
||||
* starts rendering it immediately. This function doesn't just 'create' the
|
||||
* filter, it also calls the render function (farther below) that contains the
|
||||
* actual rendering code.
|
||||
*/
|
||||
static void *color_correction_filter_create(obs_data_t *settings,
|
||||
obs_source_t *context)
|
||||
static void *color_correction_filter_create_v1(obs_data_t *settings,
|
||||
obs_source_t *context)
|
||||
{
|
||||
/*
|
||||
* Because of limitations of pre-c99 compilers, you can't create an
|
||||
@ -324,7 +465,7 @@ static void *color_correction_filter_create(obs_data_t *settings,
|
||||
* values that don't exist anymore.
|
||||
*/
|
||||
if (!filter->effect) {
|
||||
color_correction_filter_destroy(filter);
|
||||
color_correction_filter_destroy_v1(filter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -333,12 +474,73 @@ static void *color_correction_filter_create(obs_data_t *settings,
|
||||
* we could end up with the user controlled sliders and values
|
||||
* updating, but the visuals not updating to match.
|
||||
*/
|
||||
color_correction_filter_update(filter, settings);
|
||||
color_correction_filter_update_v1(filter, settings);
|
||||
return filter;
|
||||
}
|
||||
|
||||
static void *color_correction_filter_create_v2(obs_data_t *settings,
|
||||
obs_source_t *context)
|
||||
{
|
||||
/*
|
||||
* Because of limitations of pre-c99 compilers, you can't create an
|
||||
* array that doesn't have a known size at compile time. The below
|
||||
* function calculates the size needed and allocates memory to
|
||||
* handle the source.
|
||||
*/
|
||||
struct color_correction_filter_data_v2 *filter =
|
||||
bzalloc(sizeof(struct color_correction_filter_data_v2));
|
||||
|
||||
/*
|
||||
* By default the effect file is stored in the ./data directory that
|
||||
* your filter resides in.
|
||||
*/
|
||||
char *effect_path = obs_module_file("color_correction_filter.effect");
|
||||
|
||||
filter->context = context;
|
||||
|
||||
/* Set/clear/assign for all necessary vectors. */
|
||||
vec3_set(&filter->half_unit, 0.5f, 0.5f, 0.5f);
|
||||
matrix4_identity(&filter->bright_matrix);
|
||||
|
||||
/* Here we enter the GPU drawing/shader portion of our code. */
|
||||
obs_enter_graphics();
|
||||
|
||||
/* Load the shader on the GPU. */
|
||||
filter->effect = gs_effect_create_from_file(effect_path, NULL);
|
||||
|
||||
/* If the filter is active pass the parameters to the filter. */
|
||||
if (filter->effect) {
|
||||
filter->gamma_param = gs_effect_get_param_by_name(
|
||||
filter->effect, SETTING_GAMMA);
|
||||
filter->final_matrix_param = gs_effect_get_param_by_name(
|
||||
filter->effect, "color_matrix");
|
||||
}
|
||||
|
||||
obs_leave_graphics();
|
||||
|
||||
bfree(effect_path);
|
||||
|
||||
/*
|
||||
* If the filter has been removed/deactivated, destroy the filter
|
||||
* and exit out so we don't crash OBS by telling it to update
|
||||
* values that don't exist anymore.
|
||||
*/
|
||||
if (!filter->effect) {
|
||||
color_correction_filter_destroy_v2(filter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's important to call the update function here. If we don't
|
||||
* we could end up with the user controlled sliders and values
|
||||
* updating, but the visuals not updating to match.
|
||||
*/
|
||||
color_correction_filter_update_v2(filter, settings);
|
||||
return filter;
|
||||
}
|
||||
|
||||
/* This is where the actual rendering of the filter takes place. */
|
||||
static void color_correction_filter_render(void *data, gs_effect_t *effect)
|
||||
static void color_correction_filter_render_v1(void *data, gs_effect_t *effect)
|
||||
{
|
||||
struct color_correction_filter_data *filter = data;
|
||||
|
||||
@ -347,7 +549,7 @@ static void color_correction_filter_render(void *data, gs_effect_t *effect)
|
||||
return;
|
||||
|
||||
/* Now pass the interface variables to the .effect file. */
|
||||
gs_effect_set_vec3(filter->gamma_param, &filter->gamma);
|
||||
gs_effect_set_float(filter->gamma_param, filter->gamma);
|
||||
gs_effect_set_matrix4(filter->final_matrix_param,
|
||||
&filter->final_matrix);
|
||||
|
||||
@ -356,13 +558,33 @@ static void color_correction_filter_render(void *data, gs_effect_t *effect)
|
||||
UNUSED_PARAMETER(effect);
|
||||
}
|
||||
|
||||
static void color_correction_filter_render_v2(void *data, gs_effect_t *effect)
|
||||
{
|
||||
struct color_correction_filter_data_v2 *filter = data;
|
||||
|
||||
if (!obs_source_process_filter_begin(filter->context, GS_RGBA,
|
||||
OBS_ALLOW_DIRECT_RENDERING))
|
||||
return;
|
||||
|
||||
/* Now pass the interface variables to the .effect file. */
|
||||
gs_effect_set_float(filter->gamma_param, filter->gamma);
|
||||
gs_effect_set_matrix4(filter->final_matrix_param,
|
||||
&filter->final_matrix);
|
||||
|
||||
const bool previous = gs_set_linear_srgb(true);
|
||||
obs_source_process_filter_end(filter->context, filter->effect, 0, 0);
|
||||
gs_set_linear_srgb(previous);
|
||||
|
||||
UNUSED_PARAMETER(effect);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function sets the interface. the types (add_*_Slider), the type of
|
||||
* data collected (int), the internal name, user-facing name, minimum,
|
||||
* maximum and step values. While a custom interface can be built, for a
|
||||
* simple filter like this it's better to use the supplied functions.
|
||||
*/
|
||||
static obs_properties_t *color_correction_filter_properties(void *data)
|
||||
static obs_properties_t *color_correction_filter_properties_v1(void *data)
|
||||
{
|
||||
obs_properties_t *props = obs_properties_create();
|
||||
|
||||
@ -386,6 +608,28 @@ static obs_properties_t *color_correction_filter_properties(void *data)
|
||||
return props;
|
||||
}
|
||||
|
||||
static obs_properties_t *color_correction_filter_properties_v2(void *data)
|
||||
{
|
||||
obs_properties_t *props = obs_properties_create();
|
||||
|
||||
obs_properties_add_float_slider(props, SETTING_GAMMA, TEXT_GAMMA, -3.0,
|
||||
3.0, 0.01);
|
||||
|
||||
obs_properties_add_float_slider(props, SETTING_CONTRAST, TEXT_CONTRAST,
|
||||
-4.0, 4.0, 0.01);
|
||||
obs_properties_add_float_slider(props, SETTING_BRIGHTNESS,
|
||||
TEXT_BRIGHTNESS, -1.0, 1.0, 0.01);
|
||||
obs_properties_add_float_slider(props, SETTING_SATURATION,
|
||||
TEXT_SATURATION, -1.0, 5.0, 0.01);
|
||||
obs_properties_add_float_slider(props, SETTING_HUESHIFT, TEXT_HUESHIFT,
|
||||
-180.0, 180.0, 0.01);
|
||||
obs_properties_add_int_slider(props, SETTING_OPACITY, TEXT_OPACITY, 0,
|
||||
100, 1);
|
||||
|
||||
UNUSED_PARAMETER(data);
|
||||
return props;
|
||||
}
|
||||
|
||||
/*
|
||||
* As the functions' namesake, this provides the default settings for any
|
||||
* options you wish to provide a default for. Try to select defaults that
|
||||
@ -393,17 +637,27 @@ static obs_properties_t *color_correction_filter_properties(void *data)
|
||||
* *NOTE* this function is completely optional, as is providing a default
|
||||
* for any particular setting.
|
||||
*/
|
||||
static void color_correction_filter_defaults(obs_data_t *settings)
|
||||
static void color_correction_filter_defaults_v1(obs_data_t *settings)
|
||||
{
|
||||
obs_data_set_default_double(settings, SETTING_GAMMA, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_SATURATION, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_HUESHIFT, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_OPACITY, 100.0);
|
||||
obs_data_set_default_int(settings, SETTING_OPACITY, 100);
|
||||
obs_data_set_default_int(settings, SETTING_COLOR, 0x00FFFFFF);
|
||||
}
|
||||
|
||||
static void color_correction_filter_defaults_v2(obs_data_t *settings)
|
||||
{
|
||||
obs_data_set_default_double(settings, SETTING_GAMMA, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_SATURATION, 0.0);
|
||||
obs_data_set_default_double(settings, SETTING_HUESHIFT, 0.0);
|
||||
obs_data_set_default_int(settings, SETTING_OPACITY, 100);
|
||||
}
|
||||
|
||||
/*
|
||||
* So how does OBS keep track of all these plug-ins/filters? How does OBS know
|
||||
* which function to call when it needs to update a setting? Or a source? Or
|
||||
@ -417,12 +671,26 @@ static void color_correction_filter_defaults(obs_data_t *settings)
|
||||
struct obs_source_info color_filter = {
|
||||
.id = "color_filter",
|
||||
.type = OBS_SOURCE_TYPE_FILTER,
|
||||
.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CAP_OBSOLETE,
|
||||
.get_name = color_correction_filter_name,
|
||||
.create = color_correction_filter_create_v1,
|
||||
.destroy = color_correction_filter_destroy_v1,
|
||||
.video_render = color_correction_filter_render_v1,
|
||||
.update = color_correction_filter_update_v1,
|
||||
.get_properties = color_correction_filter_properties_v1,
|
||||
.get_defaults = color_correction_filter_defaults_v1,
|
||||
};
|
||||
|
||||
struct obs_source_info color_filter_v2 = {
|
||||
.id = "color_filter",
|
||||
.version = 2,
|
||||
.type = OBS_SOURCE_TYPE_FILTER,
|
||||
.output_flags = OBS_SOURCE_VIDEO,
|
||||
.get_name = color_correction_filter_name,
|
||||
.create = color_correction_filter_create,
|
||||
.destroy = color_correction_filter_destroy,
|
||||
.video_render = color_correction_filter_render,
|
||||
.update = color_correction_filter_update,
|
||||
.get_properties = color_correction_filter_properties,
|
||||
.get_defaults = color_correction_filter_defaults,
|
||||
.create = color_correction_filter_create_v2,
|
||||
.destroy = color_correction_filter_destroy_v2,
|
||||
.video_render = color_correction_filter_render_v2,
|
||||
.update = color_correction_filter_update_v2,
|
||||
.get_properties = color_correction_filter_properties_v2,
|
||||
.get_defaults = color_correction_filter_defaults_v2,
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
uniform float4x4 ViewProj;
|
||||
uniform texture2d image;
|
||||
|
||||
uniform float3 gamma;
|
||||
uniform float gamma;
|
||||
|
||||
/* Pre-Compute variables. */
|
||||
uniform float4x4 color_matrix;
|
||||
|
@ -12,6 +12,7 @@ extern struct obs_source_info mask_filter;
|
||||
extern struct obs_source_info crop_filter;
|
||||
extern struct obs_source_info gain_filter;
|
||||
extern struct obs_source_info color_filter;
|
||||
extern struct obs_source_info color_filter_v2;
|
||||
extern struct obs_source_info scale_filter;
|
||||
extern struct obs_source_info scroll_filter;
|
||||
extern struct obs_source_info gpu_delay_filter;
|
||||
@ -38,6 +39,7 @@ bool obs_module_load(void)
|
||||
obs_register_source(&crop_filter);
|
||||
obs_register_source(&gain_filter);
|
||||
obs_register_source(&color_filter);
|
||||
obs_register_source(&color_filter_v2);
|
||||
obs_register_source(&scale_filter);
|
||||
obs_register_source(&scroll_filter);
|
||||
obs_register_source(&gpu_delay_filter);
|
||||
|
Loading…
x
Reference in New Issue
Block a user