]> git.sesse.net Git - ultimatescore/blobdiff - stinger/blur.cpp
Add some code for generating a simple stinger.
[ultimatescore] / stinger / blur.cpp
diff --git a/stinger/blur.cpp b/stinger/blur.cpp
new file mode 100644 (file)
index 0000000..76c9ca8
--- /dev/null
@@ -0,0 +1,218 @@
+#define NO_SDL_GLEXT 1
+
+#define WIDTH 1280
+#define HEIGHT 720
+
+#include <epoxy/gl.h>
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_events.h>
+#include <SDL2/SDL_image.h>
+#include <SDL2/SDL_keyboard.h>
+#include <SDL2/SDL_mouse.h>
+#include <SDL2/SDL_video.h>
+
+#include <assert.h>
+#include <features.h>
+#include <math.h>
+#include <png.h>
+#include <pngconf.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <movit/effect_chain.h>
+#include <movit/flat_input.h>
+#include <movit/init.h>
+#include <movit/mix_effect.h>
+#include <movit/util.h>
+
+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; 
+}