From 780f5f18be8d28389a6ac9433aa6d8e5d5b80338 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 17 Oct 2018 21:10:52 +0200 Subject: [PATCH] Add some code for generating a simple stinger. --- stinger/Makefile | 2 + stinger/blur.cpp | 218 ++++++++ stinger/sting.pl | 58 ++ stinger/stinger.svg | 1300 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1578 insertions(+) create mode 100644 stinger/Makefile create mode 100644 stinger/blur.cpp create mode 100644 stinger/sting.pl create mode 100644 stinger/stinger.svg diff --git a/stinger/Makefile b/stinger/Makefile new file mode 100644 index 0000000..963df2f --- /dev/null +++ b/stinger/Makefile @@ -0,0 +1,2 @@ +blur: blur.cpp + g++ -O2 -o blur blur.cpp -lpng `pkg-config --cflags --libs movit` -lSDL2 -lSDL2_image -g diff --git a/stinger/blur.cpp b/stinger/blur.cpp new file mode 100644 index 0000000..76c9ca8 --- /dev/null +++ b/stinger/blur.cpp @@ -0,0 +1,218 @@ +#define NO_SDL_GLEXT 1 + +#define WIDTH 1280 +#define HEIGHT 720 + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace movit; + +unsigned char result[WIDTH * HEIGHT * 4]; + +unsigned char *load_image(const char *filename, unsigned *w, unsigned *h) +{ + SDL_Surface *img = IMG_Load(filename); + if (img == nullptr) { + fprintf(stderr, "Load of '%s' failed\n", filename); + exit(1); + } + + SDL_PixelFormat rgba_fmt; + rgba_fmt.palette = nullptr; + rgba_fmt.BitsPerPixel = 32; + rgba_fmt.BytesPerPixel = 8; + rgba_fmt.Rloss = rgba_fmt.Gloss = rgba_fmt.Bloss = rgba_fmt.Aloss = 0; + + // NOTE: Assumes little endian. + rgba_fmt.Rmask = 0x00ff0000; + rgba_fmt.Gmask = 0x0000ff00; + rgba_fmt.Bmask = 0x000000ff; + rgba_fmt.Amask = 0xff000000; + + rgba_fmt.Rshift = 16; + rgba_fmt.Gshift = 8; + rgba_fmt.Bshift = 0; + rgba_fmt.Ashift = 24; + + SDL_Surface *converted = SDL_ConvertSurface(img, &rgba_fmt, SDL_SWSURFACE); + + *w = img->w; + *h = img->h; + + SDL_FreeSurface(img); + + unsigned char *crop_img = new unsigned char[1280 * 720 * 4]; + + int img_w = *w; + int img_h = *h; + + int xoffs = (1280 - int(img_w)) / 2; + int yoffs = (720 - int(img_h)) / 2; + + for (unsigned y = 0; y < 720; ++y) { + unsigned char *dptr = crop_img + y * 1280 * 4; + int ysrc = y - yoffs; + if (ysrc < 0 || ysrc >= int(img_h)) { + memset(dptr, 0, 1280 * 4); + continue; + } + unsigned char *sptr = (unsigned char *)converted->pixels + ysrc * img_w * 4; + if (img_w >= 1280) { + memcpy(dptr, sptr - xoffs * 4, 1280 * 4); + } else { + memset(dptr, 0, 1280 * 4); + memcpy(dptr + xoffs * 4, sptr, img_w * 4); + } + } + + SDL_FreeSurface(converted); + + *w = 1280; + *h = 720; + + return crop_img; +} + +void write_png(const char *filename, unsigned char *screenbuf) +{ + FILE *fp = fopen(filename, "wb"); + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (setjmp(png_jmpbuf(png_ptr))) { + fclose(fp); + fprintf(stderr, "Write to %s failed; exiting.\n", filename); + exit(1); + } + + png_set_IHDR(png_ptr, info_ptr, WIDTH, HEIGHT, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + png_bytep *row_pointers = new png_bytep[HEIGHT]; + for (unsigned y = 0; y < HEIGHT; ++y) { + row_pointers[y] = screenbuf + ((HEIGHT - y - 1) * WIDTH) * 4; + } + + png_init_io(png_ptr, fp); + png_set_rows(png_ptr, info_ptr, row_pointers); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, nullptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + + delete[] row_pointers; +} + +class BouncingIdentityEffect : public Effect { +public: + BouncingIdentityEffect() {} + std::string effect_type_id() const override { return "IdentityEffect"; } + std::string output_fragment_shader() override { return read_file("identity.frag"); } + bool needs_texture_bounce() const override { return true; } + AlphaHandling alpha_handling() const override { return DONT_CARE_ALPHA_TYPE; } +}; + + +int main(int argc, char **argv) +{ + if (SDL_Init(SDL_INIT_EVERYTHING) == -1) { + fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); + exit(1); + } + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + // SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); + SDL_Window *window = SDL_CreateWindow("OpenGL window", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + WIDTH, HEIGHT, + SDL_WINDOW_OPENGL); + SDL_GLContext context = SDL_GL_CreateContext(window); + assert(context != nullptr); + + CHECK(init_movit("/usr/share/movit", MOVIT_DEBUG_OFF)); + + EffectChain chain(WIDTH, HEIGHT); + glViewport(0, 0, WIDTH, HEIGHT); + + ImageFormat inout_format; + inout_format.color_space = COLORSPACE_sRGB; + inout_format.gamma_curve = GAMMA_sRGB; + + Effect *last_effect = nullptr; + for (int i = 1; i < argc; ++i) { + fprintf(stderr, "%s...\n", argv[i]); + unsigned img_w, img_h; + unsigned char *src_img = load_image(argv[i], &img_w, &img_h); + + FlatInput *input = new FlatInput(inout_format, FORMAT_BGRA_POSTMULTIPLIED_ALPHA, GL_UNSIGNED_BYTE, img_w, img_h); + input->set_pixel_data(src_img); + chain.add_input(input); + + if (i == 1) { + last_effect = input; + } else { + Effect *mix_effect = chain.add_effect(new MixEffect(), last_effect, input); + float z = 1.0f / i; + CHECK(mix_effect->set_float("strength_first", 1.0f - z)); + CHECK(mix_effect->set_float("strength_second", z)); + last_effect = mix_effect; + } + + if (i % 10 == 0) { + last_effect = chain.add_effect(new BouncingIdentityEffect()); + } + } + + chain.add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); + chain.set_dither_bits(8); + chain.finalize(); + + // generate a PBO to hold the data we read back with glReadPixels() + // (Intel/DRI goes into a slow path if we don't read to PBO) + GLuint pbo; + glGenBuffers(1, &pbo); + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); + glBufferData(GL_PIXEL_PACK_BUFFER_ARB, WIDTH * HEIGHT * 4, nullptr, GL_STREAM_READ); + + chain.render_to_screen(); + + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); + check_error(); + glReadPixels(0, 0, WIDTH, HEIGHT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, BUFFER_OFFSET(0)); + check_error(); + + unsigned char *screenbuf = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + write_png("blurout.png", screenbuf); + + return 0; +} diff --git a/stinger/sting.pl b/stinger/sting.pl new file mode 100644 index 0000000..480eff6 --- /dev/null +++ b/stinger/sting.pl @@ -0,0 +1,58 @@ +#! /usr/bin/perl +use strict; +use warnings; +use POSIX qw(ceil floor); + +for my $i (0..24) { +#for my $i (23..23) { + my @args = ("./stinger/blur"); + my ($x1, $y1, $x2, $y2) = (0, 0, 346.547, 202.492); # From Inkscape output when converting by default. + my $convfactor = 0.26458; # mm to SVG units, empirical :-/ + + for my $j (0..97) { # 98 hits a movit limit! + #my $f = $i / 50.0; + my $f = $i / 25.0 + ($j * 0.010) / 25.0; + #my $f = $i / 255.0; + + my $d = 90.0 / (1.0 - $f) - 80.0; + my $outfilename = sprintf("stinger%03d.png", $i * 10 + $j); + print "$outfilename [$d]...\n"; + + my $w = int((($x2 - $x1) / 25.4) * $d * $convfactor + 0.5); + my $h = int((($y2 - $y1) / 25.4) * $d * $convfactor + 0.5); + + while ($w >= 1280*2 && $h >= 720*2) { + my $newx1 = $x1 + 0.25 * ($x2 - $x1); + my $newy1 = $y1 + 0.25 * ($y2 - $y1); + my $newx2 = $x1 + 0.75 * ($x2 - $x1); + my $newy2 = $y1 + 0.75 * ($y2 - $y1); + ($x1, $y1, $x2, $y2) = ($newx1, $newy1, $newx2, $newy2); + + $w = floor($w / 2); + $h = floor($h / 2); + } + + my $cmd = "LANG=C inkscape --export-png=$outfilename --export-area=$x1:$y1:$x2:$y2 --export-width=$w --export-height=$h stinger.svg"; + # print "$cmd\n"; + system("$cmd 2>/dev/null >/dev/null"); + #my $x = `$cmd 2>/dev/null`; + #$x =~ /exported to (\d+) x (\d+)/ or die "$x"; + #my ($w, $h) = ($1, $2); + +# my $extent = ""; +# if ($w < 1280 || $h < 720) { +# $w = 1280 if ($w < 1280); +# $h = 720 if ($h < 720); +# $extent = sprintf("-background #00000000 -gravity center -extent %dx%d", $w, $h); +# } +# +# my $left = int(($w - 1280) / 2); +# my $top = int(($h - 720) / 2); +# +# system("convert $extent -crop 1280x720+${left}+$top stinger.png $outfilename"); + push @args, $outfilename; + } + system(@args); + print join(' ', @args), " -> $i\n"; + rename("blurout.png", sprintf("blur%03d.png", $i)); +} diff --git a/stinger/stinger.svg b/stinger/stinger.svg new file mode 100644 index 0000000..e4472a0 --- /dev/null +++ b/stinger/stinger.svg @@ -0,0 +1,1300 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.39.2