Created
July 28, 2022 06:02
-
-
Save xsbee/fc9b99f924e013334069d3be2541d7de to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// g++ -Wall -Wextra -shared -Ofast -march=native -o vhs.dll vhs.cxx | |
#include <random> | |
struct vhs | |
{ | |
unsigned int m_width; | |
unsigned int m_height; | |
unsigned int m_sr_off = 0; | |
unsigned int m_sr_sz; | |
std::random_device m_dev; | |
std::uniform_int_distribution<unsigned int> m_right_shift; | |
std::uniform_int_distribution<size_t> m_white_stroke_pos; | |
std::uniform_int_distribution<unsigned int> m_white_stroke_len; | |
vhs(unsigned int width, unsigned int height) | |
: m_width(width), m_height(height), | |
m_sr_sz(height * 0.08), | |
m_right_shift(4, 8), | |
m_white_stroke_pos(0, static_cast<size_t>(width) * height), | |
m_white_stroke_len(16, 64) | |
{} | |
void process(const uint32_t *inframe, uint32_t *outframe) | |
{ | |
unsigned int sr_end = std::min(m_sr_off + m_sr_sz, m_height); | |
// TODO: add chroma-shift, some noise, lowpass to image (using FFTW?) | |
// Row-shift distortion and colour fade. | |
for (unsigned int j = 0; j < m_height; ++j) | |
{ | |
unsigned int shift = m_right_shift(m_dev); | |
const size_t r = static_cast<size_t>(j) * m_width; | |
// Fill left-side with zeros. | |
std::fill(outframe + r, outframe + r + shift, 0); | |
size_t in_row_end = r + m_width - shift; | |
for (size_t i = r; i < in_row_end; ++i) | |
{ | |
const uint8_t *P0 = reinterpret_cast<const uint8_t*>(inframe + i); | |
uint8_t *P1 = reinterpret_cast<uint8_t*>(&outframe[i + shift]); | |
// 50% contrast reduction (y = 1/n * (x - 128) + 128) | |
P1[0] = P0[0] / 2 + 64; | |
P1[1] = P0[1] / 2 + 64; | |
P1[2] = P0[2] / 2 + 64; | |
P1[3] = P0[3]; | |
} | |
} | |
// Sliding horizontal blur-like effect. | |
for (unsigned int j = m_sr_off; j < sr_end; ++j) | |
{ | |
for (unsigned int i = 0; i < m_width; ++i) | |
{ | |
const size_t p0 = static_cast<size_t>(j) * m_width + i; | |
const size_t p1 = static_cast<size_t>(m_sr_off) * m_width + i; | |
outframe[p0] = outframe[p1]; | |
} | |
} | |
// Ocassional white strokes, as in VHS. | |
// TODO: Make the apperance of this random. | |
for (unsigned int j = 0; j < 4; ++j) | |
{ | |
unsigned int stroke_len = m_white_stroke_len(m_dev); | |
size_t stroke_end = m_white_stroke_pos(m_dev); | |
size_t stroke_begin = std::max<size_t>(stroke_len, stroke_end) - stroke_len; | |
for (size_t i = stroke_begin; i < stroke_end; ++i) | |
{ | |
uint8_t* P = reinterpret_cast<uint8_t*>(&outframe[i]); | |
P[0] = P[1] = P[2] = 255; | |
} | |
} | |
m_sr_off = (m_sr_off + 8) % m_height; | |
} | |
}; | |
extern "C" { | |
#include <frei0r.h> | |
int f0r_init() | |
{ | |
return 0; | |
} | |
f0r_instance_t f0r_construct(unsigned int width, unsigned int height) | |
{ | |
vhs *instance = new vhs(width, height); | |
return instance; | |
} | |
void f0r_get_plugin_info(f0r_plugin_info_t *info) | |
{ | |
info->name = "vhs"; | |
info->author = "xsbee"; | |
info->explanation = "VHS tape-like effect"; | |
info->major_version = 1; | |
info->minor_version = 0; | |
info->frei0r_version = FREI0R_MAJOR_VERSION; | |
info->color_model = F0R_COLOR_MODEL_RGBA8888; | |
info->plugin_type = F0R_PLUGIN_TYPE_FILTER; | |
info->num_params = 0; | |
} | |
void f0r_get_param_info (f0r_param_info_t *info, int param_index) {} | |
void f0r_get_param_value( | |
f0r_instance_t instance, | |
f0r_param_t param, | |
int param_index | |
) {} | |
void f0r_set_param_value( | |
f0r_instance_t instance, | |
f0r_param_t param, | |
int param_index | |
) {} | |
void f0r_update ( | |
f0r_instance_t instance, | |
double, | |
const uint32_t *inframe, | |
uint32_t *outframe | |
) | |
{ | |
static_cast<vhs*>(instance)->process(inframe, outframe); | |
} | |
void f0r_deinit() {} | |
void f0r_destruct (f0r_instance_t instance) | |
{ | |
delete static_cast<vhs*>(instance); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment