9 #include <SDL2/SDL_error.h>
10 #include <SDL2/SDL_events.h>
11 #include <SDL2/SDL_image.h>
12 #include <SDL2/SDL_keyboard.h>
13 #include <SDL2/SDL_mouse.h>
14 #include <SDL2/SDL_video.h>
27 #include <movit/effect_chain.h>
28 #include <movit/flat_input.h>
29 #include <movit/init.h>
30 #include <movit/mix_effect.h>
31 #include <movit/util.h>
33 using namespace movit;
35 unsigned char result[WIDTH * HEIGHT * 4];
37 unsigned char *load_image(const char *filename, unsigned *w, unsigned *h)
39 SDL_Surface *img = IMG_Load(filename);
41 fprintf(stderr, "Load of '%s' failed\n", filename);
45 SDL_PixelFormat rgba_fmt;
46 rgba_fmt.palette = nullptr;
47 rgba_fmt.BitsPerPixel = 32;
48 rgba_fmt.BytesPerPixel = 8;
49 rgba_fmt.Rloss = rgba_fmt.Gloss = rgba_fmt.Bloss = rgba_fmt.Aloss = 0;
51 // NOTE: Assumes little endian.
52 rgba_fmt.Rmask = 0x00ff0000;
53 rgba_fmt.Gmask = 0x0000ff00;
54 rgba_fmt.Bmask = 0x000000ff;
55 rgba_fmt.Amask = 0xff000000;
62 SDL_Surface *converted = SDL_ConvertSurface(img, &rgba_fmt, SDL_SWSURFACE);
69 unsigned char *crop_img = new unsigned char[1280 * 720 * 4];
74 int xoffs = (1280 - int(img_w)) / 2;
75 int yoffs = (720 - int(img_h)) / 2;
77 for (unsigned y = 0; y < 720; ++y) {
78 unsigned char *dptr = crop_img + y * 1280 * 4;
80 if (ysrc < 0 || ysrc >= int(img_h)) {
81 memset(dptr, 0, 1280 * 4);
84 unsigned char *sptr = (unsigned char *)converted->pixels + ysrc * img_w * 4;
86 memcpy(dptr, sptr - xoffs * 4, 1280 * 4);
88 memset(dptr, 0, 1280 * 4);
89 memcpy(dptr + xoffs * 4, sptr, img_w * 4);
93 SDL_FreeSurface(converted);
101 void write_png(const char *filename, unsigned char *screenbuf)
103 FILE *fp = fopen(filename, "wb");
104 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
105 png_infop info_ptr = png_create_info_struct(png_ptr);
107 if (setjmp(png_jmpbuf(png_ptr))) {
109 fprintf(stderr, "Write to %s failed; exiting.\n", filename);
113 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);
115 png_bytep *row_pointers = new png_bytep[HEIGHT];
116 for (unsigned y = 0; y < HEIGHT; ++y) {
117 row_pointers[y] = screenbuf + ((HEIGHT - y - 1) * WIDTH) * 4;
120 png_init_io(png_ptr, fp);
121 png_set_rows(png_ptr, info_ptr, row_pointers);
122 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, nullptr);
123 png_destroy_write_struct(&png_ptr, &info_ptr);
126 delete[] row_pointers;
129 class BouncingIdentityEffect : public Effect {
131 BouncingIdentityEffect() {}
132 std::string effect_type_id() const override { return "IdentityEffect"; }
133 std::string output_fragment_shader() override { return read_file("identity.frag"); }
134 bool needs_texture_bounce() const override { return true; }
135 AlphaHandling alpha_handling() const override { return DONT_CARE_ALPHA_TYPE; }
139 int main(int argc, char **argv)
141 if (SDL_Init(SDL_INIT_EVERYTHING) == -1) {
142 fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
145 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
146 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
147 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
148 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
150 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
151 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
152 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
153 // SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
154 SDL_Window *window = SDL_CreateWindow("OpenGL window",
155 SDL_WINDOWPOS_UNDEFINED,
156 SDL_WINDOWPOS_UNDEFINED,
159 SDL_GLContext context = SDL_GL_CreateContext(window);
160 assert(context != nullptr);
162 CHECK(init_movit("/usr/share/movit", MOVIT_DEBUG_OFF));
164 EffectChain chain(WIDTH, HEIGHT);
165 glViewport(0, 0, WIDTH, HEIGHT);
167 ImageFormat inout_format;
168 inout_format.color_space = COLORSPACE_sRGB;
169 inout_format.gamma_curve = GAMMA_sRGB;
171 Effect *last_effect = nullptr;
172 for (int i = 1; i < argc; ++i) {
173 fprintf(stderr, "%s...\n", argv[i]);
174 unsigned img_w, img_h;
175 unsigned char *src_img = load_image(argv[i], &img_w, &img_h);
177 FlatInput *input = new FlatInput(inout_format, FORMAT_BGRA_POSTMULTIPLIED_ALPHA, GL_UNSIGNED_BYTE, img_w, img_h);
178 input->set_pixel_data(src_img);
179 chain.add_input(input);
184 Effect *mix_effect = chain.add_effect(new MixEffect(), last_effect, input);
186 CHECK(mix_effect->set_float("strength_first", 1.0f - z));
187 CHECK(mix_effect->set_float("strength_second", z));
188 last_effect = mix_effect;
192 last_effect = chain.add_effect(new BouncingIdentityEffect());
196 chain.add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
197 chain.set_dither_bits(8);
200 // generate a PBO to hold the data we read back with glReadPixels()
201 // (Intel/DRI goes into a slow path if we don't read to PBO)
203 glGenBuffers(1, &pbo);
204 glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
205 glBufferData(GL_PIXEL_PACK_BUFFER_ARB, WIDTH * HEIGHT * 4, nullptr, GL_STREAM_READ);
207 chain.render_to_screen();
209 glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
211 glReadPixels(0, 0, WIDTH, HEIGHT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, BUFFER_OFFSET(0));
214 unsigned char *screenbuf = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
215 write_png("blurout.png", screenbuf);