atomes 1.1.15
atomes: an atomic scale modeling tool box
Loading...
Searching...
No Matches
movie.c
Go to the documentation of this file.
1/* This file is part of the 'atomes' software
2
3'atomes' is free software: you can redistribute it and/or modify it under the terms
4of the GNU Affero General Public License as published by the Free Software Foundation,
5either version 3 of the License, or (at your option) any later version.
6
7'atomes' is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9See the GNU General Public License for more details.
10
11You should have received a copy of the GNU Affero General Public License along with 'atomes'.
12If not, see <https://www.gnu.org/licenses/>
13
14Copyright (C) 2022-2024 by CNRS and University of Strasbourg */
15
22/*
23* This file: 'movie.c'
24*
25* Contains:
26*
27
28 - The functions to encode a movie / render an image from the OpenGL rendering
29
30*
31* List of functions:
32
33 gboolean check_to_update_shaders (glwin * view, image * img_a, image * img_b, int ogl_q);
34 gboolean create_movie (glwin * view, video_options * vopts, gchar * videofile);
35
36 void convert_rgb_pixbuf_to_yuv (GdkPixbuf * pixbuf, AVFrame * picture, int w, int h);
37 void fill_image (VideoStream * vs, int width, int height, glwin * view);
38 void set_old_cmap (image * img, int stp, int id);
39 void init_frame_buffer (int x, int y);
40 void close_frame_buffer ();
41 void save_movie (glwin * view, video_options * vopts);
42
43 static void ffmpeg_encoder_set_frame_yuv_from_rgb (uint8_t * rgb, VideoStream * vs);
44 static void write_video_frame (AVFormatContext * f_context, VideoStream * vs, int frame_id, glwin * view);
45 static void close_stream (AVFormatContext * fc, VideoStream * vs);
46
47 G_MODULE_EXPORT void run_save_movie (GtkNativeDialog * info, gint response_id, gpointer data);
48 G_MODULE_EXPORT void run_save_movie (GtkDialog * info, gint response_id, gpointer data);
49
50 static GLubyte * capture_opengl_image (unsigned int width, unsigned int height);
51
52 AVCodecContext * add_codec_context (AVFormatContext * fc, const AVCodec * vc, video_options * vopts);
53 static AVFrame * alloc_video_frame (AVCodecContext * cc);
54
55 VideoStream * add_video_stream (AVFormatContext * fc, const AVCodec * vc, video_options * vopts);
56
57*/
58
59#include "global.h"
60#include "interface.h"
61#include "project.h"
62#include "glwindow.h"
63#include "glview.h"
64#include "movie.h"
65
66#if LIBAVCODEC_VERSION_MAJOR < 56
67# define PIXEL_FORMAT PIX_FMT_YUV420P
68#else
69# define PIXEL_FORMAT AV_PIX_FMT_YUV420P
70#endif
71
72#define AVS_FRAME_ALIGN 16
73
74#define RGB_TO_Y(pixels, loc) (0.29900 * pixels[loc] + 0.58700 * pixels[loc+1] + 0.11400 * pixels[loc+2])
75#define RGB_TO_U(pixels, loc)(-0.16874 * pixels[loc] - 0.33126 * pixels[loc+1] + 0.50000 * pixels[loc+2]+128.0)
76#define RGB_TO_V(pixels, loc) (0.50000 * pixels[loc] - 0.41869 * pixels[loc+1] - 0.08131 * pixels[loc+2]+128.0)
77
78#define AVIO_FLAG_READ 1
79#define AVIO_FLAG_WRITE 2
80#define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE)
81
82#ifndef AV_ROUND_PASS_MINMAX
83#define AV_ROUND_PASS_MINMAX 8192
84#endif
85
86#ifndef URL_WRONLY
87# define URL_WRONLY 1
88#endif
89
90char * codec_name[VIDEO_CODECS] = {"MPEG-1/2",
91 "MPEG-4",
92 "H264",
93 "Theora",
94 "Flash"};
95
96char * codec_list[VIDEO_CODECS] = {"mpeg",
97 "avi",
98 "mkv",
99 "ogv",
100 "flv"};
101
102#if LIBAVCODEC_VERSION_MAJOR > 54
103int codec_id[VIDEO_CODECS] = {AV_CODEC_ID_MPEG2VIDEO,
104 AV_CODEC_ID_MPEG4,
105 AV_CODEC_ID_H264,
106 AV_CODEC_ID_THEORA,
107 AV_CODEC_ID_FLV1};
108#else
109int codec_id[VIDEO_CODECS] = {CODEC_ID_MPEG2VIDEO,
110 CODEC_ID_MPEG4,
111 CODEC_ID_H264,
112 CODEC_ID_THEORA,
113 CODEC_ID_FLV1};
114#endif
115
116/*#else
117GdkGLDrawable * gldrawable;
118GdkGLContext * glcontext;
119GdkPixmap * pixmap;
120GdkGLPixmap * glpixmap;
121#endif*/
122GdkPixbuf * pixbuf;
123uint8_t * video_outbuf;
127
138void convert_rgb_pixbuf_to_yuv (GdkPixbuf * pixbuf, AVFrame * picture, int w, int h)
139{
140 gint x, y, location, location2;
141 gint inner_x, inner_y, half_location;
142 gfloat cr, cb;
143 gint pixbuf_xsize, pixbuf_ysize;
144 guchar * pixels;
145 gint row_stride;
146 gboolean x_odd, y_odd;
147
148 pixbuf_xsize = gdk_pixbuf_get_width (pixbuf);
149 pixbuf_ysize = gdk_pixbuf_get_height (pixbuf);
150 pixels = gdk_pixbuf_get_pixels (pixbuf);
151 row_stride = gdk_pixbuf_get_rowstride (pixbuf);
152 y_odd = (pixbuf_ysize & 0x1);
153 x_odd = (pixbuf_xsize & 0x1);
154
155 /* note, the Cr and Cb info is subsampled by 2x2 */
156 for (y=0; y<pixbuf_ysize-1; y+=2)
157 {
158 for (x=0; x<pixbuf_xsize-1; x+=2)
159 {
160 cb = 0.0;
161 cr = 0.0;
162 for (inner_y = y; inner_y < y+2; inner_y++)
163 for (inner_x = x; inner_x < x+2; inner_x++)
164 {
165 location = inner_y*row_stride+3*inner_x;
166 picture -> data[0][inner_x+inner_y*w] = RGB_TO_Y (pixels, location);
167 cb += RGB_TO_U (pixels, location);
168 cr += RGB_TO_V (pixels, location);
169 }
170 half_location = x/2 + y*w/4;
171 picture -> data[1][half_location] = cb/4.0;
172 picture -> data[2][half_location] = cr/4.0;
173 }
174 if (x_odd)
175 {
176 location = y*row_stride+3*x;
177 location2 = (y+1)*row_stride+3*x;
178
179 picture -> data[0][x+y*w] = RGB_TO_Y (pixels, location);
180 picture -> data[0][x+1+y*w] = 0;
181 picture -> data[0][x+(y+1)*w] = RGB_TO_Y (pixels, location2);
182 picture -> data[0][x+1+(y+1)*w] = 0;
183
184 half_location = x/2 + y*w/4;
185 picture -> data[1][half_location] = (RGB_TO_U(pixels, location) + RGB_TO_U(pixels, location2)+256)/4.0;
186 picture -> data[2][half_location] = (RGB_TO_V(pixels, location) + RGB_TO_V(pixels, location2)+256)/4.0;
187 }
188 }
189 if (y_odd)
190 {
191 for (x=0; x<pixbuf_xsize-1; x+=2)
192 {
193 location = y*row_stride+3*x;
194 location2 = y*row_stride+3*(x+1);
195
196 picture -> data[0][x+y*w] = RGB_TO_Y(pixels, location);
197 picture -> data[0][x+1+y*w] = RGB_TO_Y(pixels, location2);
198 picture -> data[0][x+(y+1)*w] = 0;
199 picture -> data[0][x+1+(y+1)*w] = 0;
200
201 half_location = x/2 + y*w/4;
202 picture -> data[1][half_location] = (RGB_TO_U(pixels, location)+RGB_TO_U(pixels, location2)+256)/4.0;
203 picture -> data[2][half_location] = (RGB_TO_V(pixels, location)+RGB_TO_V(pixels, location2)+256)/4.0;
204 }
205 if (x_odd)
206 {
207 location = y*row_stride+3*x;
208
209 picture -> data[0][x+y*w] = RGB_TO_Y(pixels, location);
210 picture -> data[0][x+1+y*w] = 0;
211 picture -> data[0][x+(y+1)*w] = 0;
212 picture -> data[0][x+1+(y+1)*w] = 0;
213
214 half_location = x/2 + y*w/4;
215 picture -> data[1][half_location] = (RGB_TO_U(pixels, location)+384)/4.0;
216 picture -> data[2][half_location] = (RGB_TO_V(pixels, location)+384)/4.0;
217 }
218 }
219}
220
229static void ffmpeg_encoder_set_frame_yuv_from_rgb (uint8_t * rgb, VideoStream * vs)
230{
231 const int in_linesize = 4 * vs -> cc -> width;
232 vs -> sws_ctx = sws_getCachedContext (vs -> sws_ctx,
233 vs -> cc -> width, vs -> cc -> height, AV_PIX_FMT_BGRA,
234 vs -> cc -> width, vs -> cc -> height, PIXEL_FORMAT,
235 0, NULL, NULL, NULL);
236 sws_scale (vs -> sws_ctx, (const uint8_t * const *)&rgb,
237 & in_linesize, 0, vs -> cc -> height,
238 vs -> frame -> data, vs -> frame -> linesize);
239}
240
246static GLubyte * capture_opengl_image (unsigned int width, unsigned int height)
247{
248 size_t i, nvals;
249 nvals = width * height * 4;
250 GLubyte * pixels = g_malloc (nvals * sizeof(GLubyte));
251 GLubyte * rgb = g_malloc (nvals * sizeof(GLubyte));
252 glReadPixels (0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
253 // Flip data veritcally
254 for (i = 0; i < height; i++)
255 {
256 memcpy (rgb + 4 * width * i, pixels + 4 * width * (height - i - 1), 4 * width);
257 }
258 g_free (pixels);
259 return rgb;
260}
261//#endif
262
273void fill_image (VideoStream * vs, int width, int height, glwin * view)
274{
275 // opengl call is here !!!
276 reshape (view, width, height, FALSE);
277 draw (view);
278 // Might need some correction(s) here for HiDPI screens
279 GLubyte * image = capture_opengl_image (width, height);
280 if (vs != NULL)
281 {
282 //if (movie) convert_rgb_pixbuf_to_yuv (pixbuf, frame, width, height);
283 ffmpeg_encoder_set_frame_yuv_from_rgb (image, vs);
284 }
285 else
286 {
287 cairo_surface_t * surf = cairo_image_surface_create_for_data ((guchar *)image, CAIRO_FORMAT_ARGB32,
288 width, height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
289 pixbuf = convert_to_pixbuf (surf);
290 cairo_surface_destroy (surf);
291 }
292 g_free (image);
293}
294
305static void write_video_frame (AVFormatContext * f_context, VideoStream * vs, int frame_id, glwin * view)
306{
307 int out_size = 0;
308
309 fill_image (vs, vs -> cc -> width, vs -> cc -> height, view);
310
311 AVPacket packet;
312#if LIBAVCODEC_VERSION_MAJOR > 57
313 out_size = av_new_packet (& packet, 0);
314 if (out_size != 0)
315 {
316 // "Error while encoding video frame"
317 g_warning ("MOVIE_ENCODING:: VIDEO_FRAME:: error:: %s", av_err2str(out_size));
318 }
319 // get_packet_defaults (& packet);
320#else
321 av_init_packet (& packet);
322#endif
323
324 if (! out_size)
325 {
326 packet.dts = packet.pts = AV_NOPTS_VALUE;
327 packet.data = NULL;
328 packet.size = 0;
329
330 vs -> frame -> pts = frame_id + 1;
331 out_size = avcodec_send_frame (vs -> cc, vs -> frame);
332 if (out_size < 0)
333 {
334 // "Error while encoding video frame"
335 g_warning ("MOVIE_ENCODING:: VIDEO_FRAME:: error:: %s", av_err2str (out_size));
336 }
337 else
338 {
339 if (avcodec_receive_packet (vs -> cc, & packet) < 0)
340 {
341 // "Error while encoding video frame"
342 if (frame_id + 1 > frame_start) g_warning ("MOVIE_ENCODING:: VIDEO_FRAME:: warning:: packet empty, ignoring frame= %d", frame_id);
343 }
344 else
345 {
346 av_packet_rescale_ts (& packet, vs -> cc -> time_base, vs -> st -> time_base);
347
348 packet.stream_index = vs -> st -> index;
349 packet.flags |= AV_PKT_FLAG_KEY;
350 out_size = av_interleaved_write_frame (f_context, & packet);
351 if (out_size != 0)
352 {
353 // "Error while encoding video frame"
354 g_warning ("MOVIE_ENCODING:: VIDEO_FRAME:: error:: %s", av_err2str(out_size));
355 }
356 av_packet_unref(& packet);
357 }
358 }
359 }
360}
361
369static AVFrame * alloc_video_frame (AVCodecContext * cc)
370{
371 AVFrame * frame;
372 frame = av_frame_alloc ();
373 if (! frame)
374 {
375 return NULL;
376 }
377 frame -> format = cc -> pix_fmt;
378 frame -> width = cc -> width;
379 frame -> height = cc -> height;
380 if (av_frame_get_buffer (frame, 32) < 0)
381 {
382 return NULL;
383 }
384 return frame;
385}
386
396AVCodecContext * add_codec_context (AVFormatContext * fc, const AVCodec * vc, video_options * vopts)
397{
398 AVCodecContext * cc;
399 if (! (vc = avcodec_find_encoder (codec_id[vopts -> codec])))
400 {
401 // Codec not found
402 g_warning ("MOVIE_ENCODING:: Could not find codec:: %s", codec_name[vopts -> codec]);
403 return NULL;
404 }
405 if (! (cc = avcodec_alloc_context3(vc)))
406 {
407 g_warning ("MOVIE_ENCODING:: Could not allocate encoding context");
408 return NULL;
409 }
410 //g_debug ("Codec_id= %d", cc -> codec_id);
411 cc -> codec_id = codec_id[vopts -> codec];
412 //g_debug ("Codec_id= %d", cc -> codec_id);
413 /* put sample parameters */
414 cc -> bit_rate_tolerance = vopts -> bitrate*1000;
415 cc -> bit_rate = vopts -> bitrate*1000;
416
417 /* resolution must be a multiple of two */
418 cc -> width = vopts -> video_res[0];
419 cc -> height = vopts -> video_res[1];
420
421 cc -> time_base = (AVRational){1, vopts -> framesec};
422 cc -> framerate = (AVRational){vopts -> framesec, 1};
423
424 if (vopts -> codec != 1 && vopts -> codec != 4) cc -> max_b_frames = 1;
425
426 cc -> gop_size = vopts -> extraframes; /* emit one intra frame every n frames */
427 cc -> pix_fmt = PIXEL_FORMAT;
428
429 if (vopts -> codec == 2) av_opt_set (cc -> priv_data, "preset", "slow", 0);
430 /*
431 Some container formats (like MP4) require global headers to be present
432 Mark the encoder so that it behaves accordingly.
433 */
434#if LIBAVCODEC_VERSION_MAJOR > 57
435 if (fc -> oformat -> flags & AVFMT_GLOBALHEADER) cc -> flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
436#else
437 if (fc -> oformat -> flags & AVFMT_GLOBALHEADER) cc -> flags |= CODEC_FLAG_GLOBAL_HEADER;
438#endif
439 return cc;
440}
441
451VideoStream * add_video_stream (AVFormatContext * fc, const AVCodec * vc, video_options * vopts)
452{
453 VideoStream * stream = g_malloc0 (sizeof*stream);
454 stream -> cc = add_codec_context (fc, vc, vopts);
455 if (stream -> cc == NULL) return NULL;
456
457#if LIBAVCODEC_VERSION_MAJOR > 53
458 stream -> st = avformat_new_stream (fc, vc);
459#else
460 st = av_new_stream (fc, vc);
461#endif
462 if (! stream -> st)
463 {
464 g_warning ("MOVIE_ENCODING:: Could not allocate video stream");
465 return NULL;
466 }
467 stream -> st -> time_base = stream -> cc -> time_base;
468 stream -> frame = alloc_video_frame (stream -> cc);
469 if (stream -> frame == NULL)
470 {
471 g_warning ("MOVIE_ENCODING:: Could not allocate raw frame buffer");
472 return NULL;
473 }
474 return stream;
475}
476
485static void close_stream (AVFormatContext * fc, VideoStream * vs)
486{
487 avcodec_free_context (& vs -> cc);
488 av_frame_free (& vs -> frame);
489 sws_freeContext (vs -> sws_ctx);
490 avformat_free_context (fc);
491}
492
493int * old_cmap[2];
494
504void set_old_cmap (image * img, int stp, int id)
505{
506 old_cmap[id][stp] = img -> color_map[id];
507}
508
519gboolean check_to_update_shaders (glwin * view, image * img_a, image * img_b, int ogl_q)
520{
521 gboolean shaders = FALSE;
522 int i, j, k;
523 int stp = img_b -> step;
524
525 if (ogl_q == 0 && img_a -> quality != img_b -> quality)
526 {
527 view -> create_shaders[MDBOX] = TRUE;
528 view -> create_shaders[MAXIS] = TRUE;
529 view -> n_shaders[ATOMS][stp] = -1;
530 view -> create_shaders[ATOMS] = TRUE;
531 view -> n_shaders[BONDS][stp] = -1;
532 view -> create_shaders[BONDS] = TRUE;
533 view -> n_shaders[POLYS][stp] = -1;
534 view -> create_shaders[POLYS] = TRUE;
535 view -> n_shaders[RINGS][stp] = -1;
536 view -> create_shaders[RINGS] = TRUE;
537 view -> n_shaders[VOLMS][stp] = -1;
538 view -> create_shaders[VOLMS] = TRUE;
539 view -> n_shaders[SELEC][stp] = -1;
540 view -> create_shaders[SELEC] = TRUE;
541 view -> create_shaders[LABEL] = TRUE;
542 view -> create_shaders[MEASU] = TRUE;
543 for (i=0; i<2; i++) set_old_cmap (img_b, stp, i);
544 return TRUE;
545 }
546
547 for (i=0; i<3; i++)
548 {
549 if (img_a -> extra_cell[i] != img_b -> extra_cell[i])
550 {
551 view -> create_shaders[MDBOX] = TRUE;
552 view -> create_shaders[MAXIS] = TRUE;
553 view -> n_shaders[ATOMS][stp] = -1;
554 view -> create_shaders[ATOMS] = TRUE;
555 view -> n_shaders[BONDS][stp] = -1;
556 view -> create_shaders[BONDS] = TRUE;
557 view -> n_shaders[POLYS][stp] = -1;
558 view -> create_shaders[POLYS] = TRUE;
559 view -> n_shaders[RINGS][stp] = -1;
560 view -> create_shaders[RINGS] = TRUE;
561 view -> n_shaders[VOLMS][stp] = -1;
562 view -> create_shaders[VOLMS] = TRUE;
563 view -> n_shaders[SELEC][stp] = -1;
564 view -> create_shaders[SELEC] = TRUE;
565 view -> create_shaders[LABEL] = TRUE;
566 view -> create_shaders[MEASU] = TRUE;
567 for (i=0; i<2; i++) set_old_cmap (img_b, stp, i);
568 return TRUE;
569 }
570 }
571
573 coord_info * this_coord = tmp_proj -> coord;
574 for (i=0; i<9; i++)
575 {
576 for (j=0; j<this_coord -> totcoord[i]; j++)
577 {
578 if (img_a -> show_coord[i][j] != img_b -> show_coord[i][j])
579 {
580 view -> n_shaders[ATOMS][stp] = -1;
581 view -> create_shaders[ATOMS] = TRUE;
582 view -> n_shaders[BONDS][stp] = -1;
583 view -> create_shaders[BONDS] = TRUE;
584 view -> n_shaders[SELEC][stp] = -1;
585 view -> create_shaders[SELEC] = TRUE;
586 view -> create_shaders[LABEL] = TRUE;
587 view -> create_shaders[MEASU] = TRUE;
588 }
589 }
590 if (i < 2)
591 {
592 for (j=0; j<this_coord -> totcoord[i]; j++)
593 {
594 if (img_a -> show_poly[i][j] != img_b -> show_poly[i][j])
595 {
596 view -> n_shaders[POLYS][stp] = -1;
597 view -> create_shaders[POLYS] = TRUE;
598 }
599 }
600 }
601 else if (i > 3)
602 {
603 for (j=0; j<this_coord -> totcoord[i]; j++)
604 {
605 if (img_a -> show_poly[i][j] != img_b -> show_poly[i][j])
606 {
607 view -> n_shaders[RINGS][stp] = -1;
608 view -> create_shaders[RINGS] = TRUE;
609 }
610 }
611 }
612 }
613 for (j=0; j<this_coord -> totcoord[9]; j++)
614 {
615 if (img_a -> show_coord[9][j] != img_b -> show_coord[9][j])
616 {
617 view -> n_shaders[ATOMS][stp] = -1;
618 view -> create_shaders[ATOMS] = TRUE;
619 view -> n_shaders[BONDS][stp] = -1;
620 view -> create_shaders[BONDS] = TRUE;
621 view -> create_shaders[LABEL] = TRUE;
622 view -> create_shaders[MEASU] = TRUE;
623 }
624 }
625
626 if (img_a -> draw_clones != img_b -> draw_clones)
627 {
628 view -> n_shaders[ATOMS][stp] = -1;
629 view -> create_shaders[ATOMS] = TRUE;
630 view -> n_shaders[BONDS][stp] = -1;
631 view -> create_shaders[BONDS] = TRUE;
632 view -> n_shaders[POLYS][stp] = -1;
633 view -> create_shaders[POLYS] = TRUE;
634 view -> n_shaders[RINGS][stp] = -1;
635 view -> create_shaders[RINGS] = TRUE;
636 view -> n_shaders[SELEC][stp] = -1;
637 view -> create_shaders[SELEC] = TRUE;
638 view -> create_shaders[LABEL] = TRUE;
639 shaders = TRUE;
640 }
641
642 if (img_a -> color_map[0] != img_b -> color_map[0] || img_b -> color_map[0] != old_cmap[0][stp])
643 {
644 view -> n_shaders[ATOMS][stp] = -1;
645 view -> create_shaders[ATOMS] = TRUE;
646 view -> n_shaders[BONDS][stp] = -1;
647 view -> create_shaders[BONDS] = TRUE;
648 view -> create_shaders[LABEL] = TRUE;
649 set_old_cmap (img_b, stp, 0);
650 shaders = TRUE;
651 }
652
653 if (img_a -> color_map[1] != img_b -> color_map[1] || img_b -> color_map[1] != old_cmap[1][stp])
654 {
655 view -> n_shaders[POLYS][stp] = -1;
656 view -> create_shaders[POLYS] = TRUE;
657 set_old_cmap (img_b, stp, 1);
658 shaders = TRUE;
659 }
660
661 if (img_a -> step != img_b -> step)
662 {
663 if (view -> n_shaders[ATOMS][stp] < 0) view -> create_shaders[ATOMS] = TRUE;
664 if (view -> n_shaders[BONDS][stp] < 0) view -> create_shaders[BONDS] = TRUE;
665 if (view -> n_shaders[POLYS][stp] < 0) view -> create_shaders[POLYS] = TRUE;
666 if (view -> n_shaders[RINGS][stp] < 0) view -> create_shaders[RINGS] = TRUE;
667 if (view -> n_shaders[VOLMS][stp] < 0) view -> create_shaders[VOLMS] = TRUE;
668 if (view -> n_shaders[SELEC][stp] < 0) view -> create_shaders[SELEC] = TRUE;
669 view -> create_shaders[LABEL] = TRUE;
670 view -> create_shaders[MEASU] = TRUE;
671 shaders = TRUE;
672 }
673
674 gboolean do_volms = FALSE;
675 for (i=0; i<FILLED_STYLES; i++)
676 {
677 if (img_a -> show_vol[i] != img_b -> show_vol[i]) do_volms = TRUE;
678 if (img_a -> vol_col[i].red != img_b -> vol_col[i].red) do_volms = TRUE;
679 if (img_a -> vol_col[i].green != img_b -> vol_col[i].green) do_volms = TRUE;
680 if (img_a -> vol_col[i].blue != img_b -> vol_col[i].blue) do_volms = TRUE;
681 for (j=0; j<2; j++)
682 {
683 if (img_a -> fm_show_vol[j][i] == NULL && img_b -> fm_show_vol[j][i] != NULL)
684 {
685 do_volms = TRUE;
686 }
687 else if (img_a -> fm_show_vol[j][i] != NULL && img_b -> fm_show_vol[j][i] == NULL)
688 {
689 do_volms = TRUE;
690 }
691 else if (img_a -> fm_show_vol[j][i] != NULL && img_b -> fm_show_vol[j][i] != NULL)
692 {
693 for (k=0; k<this_coord -> totcoord[j+2]; k++)
694 {
695 if (img_a -> fm_show_vol[j][i][k] != img_b -> fm_show_vol[j][i][k]) do_volms = TRUE;
696 if (img_a -> fm_vol_col[j][i][k].red != img_b -> fm_vol_col[j][i][k].red) do_volms = TRUE;
697 if (img_a -> fm_vol_col[j][i][k].green != img_b -> fm_vol_col[j][i][k].green) do_volms = TRUE;
698 if (img_a -> fm_vol_col[j][i][k].blue != img_b -> fm_vol_col[j][i][k].blue) do_volms = TRUE;
699 }
700 }
701 }
702 }
703 if (do_volms)
704 {
705 view -> create_shaders[VOLMS] = shaders = TRUE;
706 view -> n_shaders[VOLMS][stp] = -1;
707 }
708
709 if (img_a -> box_axis[0] != img_b -> box_axis[0]) view -> create_shaders[MDBOX] = shaders = TRUE;
710 if (img_a -> box_axis_rad[0] != img_b -> box_axis_rad[0]) view -> create_shaders[MDBOX] = shaders = TRUE;
711 if (img_a -> box_axis_line[0] != img_b -> box_axis_line[0]) view -> create_shaders[MDBOX] = shaders = TRUE;
712 if (img_a -> box_color.red != img_b -> box_color.red) view -> create_shaders[MDBOX] = shaders = TRUE;
713 if (img_a -> box_color.green != img_b -> box_color.green) view -> create_shaders[MDBOX] = shaders = TRUE;
714 if (img_a -> box_color.blue != img_b -> box_color.blue) view -> create_shaders[MDBOX] = shaders = TRUE;
715
716 if (img_a -> box_axis[1] != img_b -> box_axis[1]) view -> create_shaders[MAXIS] = shaders = TRUE;
717 if (img_a -> box_axis_rad[1] != img_b -> box_axis_rad[1]) view -> create_shaders[MAXIS] = shaders = TRUE;
718 if (img_a -> box_axis_line[1] != img_b -> box_axis_line[1]) view -> create_shaders[MAXIS] = shaders = TRUE;
719 if (img_a -> axis_length != img_b -> axis_length) view -> create_shaders[MAXIS] = shaders = TRUE;
720 if (img_a -> axispos != img_b -> axispos) view -> create_shaders[MAXIS] = shaders = TRUE;
721 if (img_a -> axis_color == NULL && img_b -> axis_color != NULL)
722 {
723 view -> create_shaders[MAXIS] = shaders = TRUE;
724 }
725 else if (img_a -> axis_color != NULL && img_b -> axis_color == NULL)
726 {
727 view -> create_shaders[MAXIS] = shaders = TRUE;
728 }
729 else if (img_a -> axis_color != NULL && img_b -> axis_color != NULL)
730 {
731 for (i=0; i<3; i++)
732 {
733 if (img_a -> axis_color[i].red != img_b -> axis_color[i].red) view -> create_shaders[MAXIS] = shaders = TRUE;
734 if (img_a -> axis_color[i].green != img_b -> axis_color[i].green) view -> create_shaders[MAXIS] = shaders = TRUE;
735 if (img_a -> axis_color[i].blue != img_b -> axis_color[i].blue) view -> create_shaders[MAXIS] = shaders = TRUE;
736 }
737 }
738 if (img_a -> axis_labels != img_b -> axis_labels) view -> create_shaders[MAXIS] = shaders = TRUE;
739 for (i=0; i<3; i++)
740 {
741 if (g_strcmp0 (img_a -> axis_title[i],img_b -> axis_title[i]) != 0) view -> create_shaders[MAXIS] = shaders = TRUE;
742 if (img_a -> axis_pos[i] != img_b -> axis_pos[i]) view -> create_shaders[MAXIS] = shaders = TRUE;
743 }
744 if (img_a -> labels_format[2] != img_b -> labels_format[2]) view -> create_shaders[MAXIS] = shaders = TRUE;
745 if (g_strcmp0 (img_a -> labels_font[2], img_b -> labels_font[2]) != 0) view -> create_shaders[MAXIS] = shaders = TRUE;
746 if (img_a -> labels_position[2] != img_b -> labels_position[2]) view -> create_shaders[MAXIS] = shaders = TRUE;
747 if (img_a -> labels_scale[2] != img_b -> labels_scale[2]) view -> create_shaders[MAXIS] = shaders = TRUE;
748 if (img_a -> labels_render[2] != img_b -> labels_render[2]) view -> create_shaders[MAXIS] = shaders = TRUE;
749 if (img_a -> labels_color[2] == NULL && img_b -> labels_color[2] != NULL)
750 {
751 view -> create_shaders[MAXIS] = shaders = TRUE;
752 }
753 else if (img_a -> labels_color[2] != NULL && img_b -> labels_color[2] == NULL)
754 {
755 view -> create_shaders[MAXIS] = shaders = TRUE;
756 }
757 else if (img_a -> labels_color[2] != NULL && img_b -> labels_color[2] != NULL)
758 {
759 for (i=0; i<3; i++)
760 {
761 if (img_a -> labels_color[2][i].red != img_b -> labels_color[2][i].red) view -> create_shaders[MAXIS] = shaders = TRUE;
762 if (img_a -> labels_color[2][i].green != img_b -> labels_color[2][i].green) view -> create_shaders[MAXIS] = shaders = TRUE;
763 if (img_a -> labels_color[2][i].blue != img_b -> labels_color[2][i].blue) view -> create_shaders[MAXIS] = shaders = TRUE;
764 }
765 }
766
767 if (img_a -> cloned_poly != img_b -> cloned_poly)
768 {
769 view -> n_shaders[POLYS][stp] = -1;
770 view -> create_shaders[POLYS] = TRUE;
771 view -> n_shaders[RINGS][stp] = -1;
772 view -> create_shaders[RINGS] = TRUE;
773 shaders = TRUE;
774 }
775
776 gboolean dorings = FALSE;
777 for (i=0; i<5; i++)
778 {
779 if (view -> ring_max[i])
780 {
781 if (img_a -> i_rings[i] && img_b -> i_rings[i])
782 {
783 if (img_a -> i_rings[i][0][0] != img_b -> i_rings[i][0][0])
784 {
785 view -> n_shaders[RINGS][stp] = -1;
786 view -> create_shaders[RINGS] = TRUE;
787 dorings = shaders = TRUE;
788 break;
789 }
790 else
791 {
792 for (j=0; j<img_a -> i_rings[i][0][0]; j++)
793 {
794 if ((img_a -> i_rings[i][j+1][0] != img_b -> i_rings[i][j+1][0]) || (img_a -> i_rings[i][j+1][1] != img_b -> i_rings[i][j+1][1]))
795 {
796 view -> n_shaders[RINGS][stp] = -1;
797 view -> create_shaders[RINGS] = TRUE;
798 dorings = shaders = TRUE;
799 break;
800 }
801 }
802 }
803 }
804 else if (img_b -> i_rings[i])
805 {
806 dorings = TRUE;
807 }
808 if (dorings) break;
809 }
810 }
811
812 for (i=0; i<2; i++)
813 {
814 for (j=0; j<tmp_proj -> nspec; j++)
815 {
816 if (img_a -> show_label[i][j] != img_b -> show_label[i][j])
817 {
818 view -> create_shaders[LABEL] = shaders = TRUE;
819 }
820 if (img_a -> show_atom[i][j] != img_b -> show_atom[i][j])
821 {
822 view -> n_shaders[ATOMS][stp] = -1;
823 view -> create_shaders[ATOMS] = TRUE;
824 view -> n_shaders[BONDS][stp] = -1;
825 view -> create_shaders[BONDS] = TRUE;
826 view -> n_shaders[SELEC][stp] = -1;
827 view -> create_shaders[SELEC] = TRUE;
828 view -> create_shaders[LABEL] = TRUE;
829 view -> create_shaders[MEASU] = TRUE;
830 shaders = TRUE;
831 break;
832 }
833 }
834 for (j=0; j<tmp_proj -> natomes; j++)
835 {
836 if (img_a -> at_data[j].show[i] != img_b -> at_data[j].show[i] || img_a -> at_data[j].style != img_b -> at_data[j].style)
837 {
838 view -> n_shaders[ATOMS][stp] = -1;
839 view -> create_shaders[ATOMS] = TRUE;
840 view -> n_shaders[BONDS][stp] = -1;
841 view -> create_shaders[BONDS] = TRUE;
842 view -> n_shaders[SELEC][stp] = -1;
843 view -> create_shaders[SELEC] = TRUE;
844 view -> create_shaders[LABEL] = TRUE;
845 view -> create_shaders[MEASU] = TRUE;
846 shaders = TRUE;
847 break;
848 }
849 if (img_a -> at_data[j].label[i] != img_b -> at_data[j].label[i])
850 {
851 view -> create_shaders[LABEL] = shaders = TRUE;
852 }
853 if (img_a -> at_data[j].pick[0] != img_b -> at_data[j].pick[0])
854 {
855 view -> n_shaders[SELEC][stp] = -1;
856 view -> create_shaders[SELEC] = shaders = TRUE;
857 }
858 if (img_a -> at_data[j].pick[1] != img_b -> at_data[j].pick[1])
859 {
860 view -> n_shaders[SELEC][stp] = -1;
861 view -> create_shaders[SELEC] = shaders = TRUE;
862 }
863 }
864 }
865
866 for (i=0; i<2*tmp_proj -> nspec; i++)
867 {
868 if ((img_a -> sphererad[i] != img_b -> sphererad[i])
869 || (img_a -> pointrad[i] != img_b -> pointrad[i])
870 || (img_a -> atomicrad[i] != img_b -> atomicrad[i]))
871 {
872 view -> n_shaders[ATOMS][stp] = -1;
873 view -> create_shaders[ATOMS] = TRUE;
874 view -> n_shaders[SELEC][stp] = -1;
875 view -> create_shaders[SELEC] = TRUE;
876 view -> create_shaders[LABEL] = TRUE;
877 shaders = TRUE;
878 }
879 for (j=0; j<2*tmp_proj -> nspec; j++)
880 {
881 if ((img_a -> bondrad[i][j] != img_b -> bondrad[i][j])
882 || (img_a -> linerad[i][j] != img_b -> linerad[i][j]))
883 {
884 view -> n_shaders[BONDS][stp] = -1;
885 view -> create_shaders[BONDS] = TRUE;
886 view -> n_shaders[SELEC][stp] = -1;
887 view -> create_shaders[SELEC] = TRUE;
888 view -> create_shaders[LABEL] = TRUE;
889 shaders = TRUE;
890 }
891 }
892 }
893
894 for (i=0; i<2; i++)
895 {
896 if (img_a -> labels_format[i] != img_b -> labels_format[i]) view -> create_shaders[LABEL] = shaders = TRUE;
897 if (g_strcmp0 (img_a -> labels_font[i], img_b -> labels_font[i]) != 0) view -> create_shaders[LABEL] = shaders = TRUE;
898 if (img_a -> labels_position[i] != img_b -> labels_position[i]) view -> create_shaders[LABEL] = shaders = TRUE;
899 if (img_a -> labels_scale[i] != img_b -> labels_scale[i]) view -> create_shaders[LABEL] = shaders = TRUE;
900 if (img_a -> labels_render[i] != img_b -> labels_render[i]) view -> create_shaders[LABEL] = shaders = TRUE;
901 for (j=0; j<3; j++)
902 {
903 if (img_a -> labels_shift[i][j] != img_b -> labels_shift[i][j]) view -> create_shaders[LABEL] = shaders = TRUE;
904 }
905 if (img_a -> labels_color[i] == NULL && img_b -> labels_color[i] != NULL)
906 {
907 view -> create_shaders[LABEL] = shaders = TRUE;
908 }
909 else if (img_a -> labels_color[i] != NULL && img_b -> labels_color[i] == NULL)
910 {
911 view -> create_shaders[LABEL] = shaders = TRUE;
912 }
913 else if (img_a -> labels_color[i] != NULL && img_b -> labels_color[i] != NULL)
914 {
915 for (j=0; j<tmp_proj -> nspec; j++)
916 {
917 if (img_a -> labels_color[i][j].red != img_b -> labels_color[i][j].red) view -> create_shaders[LABEL] = shaders = TRUE;
918 if (img_a -> labels_color[i][j].green != img_b -> labels_color[i][j].green) view -> create_shaders[LABEL] = shaders = TRUE;
919 if (img_a -> labels_color[i][j].blue != img_b -> labels_color[i][j].blue) view -> create_shaders[LABEL] = shaders = TRUE;
920 }
921 }
922
923 if (img_a -> radall[i] != img_b -> radall[i])
924 {
925 view -> n_shaders[ATOMS][stp] = -1;
926 view -> create_shaders[ATOMS] = TRUE;
927 view -> n_shaders[BONDS][stp] = -1;
928 view -> create_shaders[BONDS] = TRUE;
929 view -> n_shaders[SELEC][stp] = -1;
930 view -> create_shaders[SELEC] = TRUE;
931 view -> create_shaders[LABEL] = TRUE;
932 shaders = TRUE;
933 }
934 }
935
936 if (img_a -> render != img_b -> render)
937 {
938 view -> n_shaders[ATOMS][stp] = -1;
939 view -> create_shaders[ATOMS] = TRUE;
940 view -> n_shaders[BONDS][stp] = -1;
941 view -> create_shaders[BONDS] = TRUE;
942 view -> n_shaders[SELEC][stp] = -1;
943 view -> create_shaders[SELEC] = TRUE;
944 shaders = TRUE;
945 }
946 if (img_a -> style != img_b -> style)
947 {
948 view -> n_shaders[ATOMS][stp] = -1;
949 view -> create_shaders[ATOMS] = TRUE;
950 view -> n_shaders[BONDS][stp] = -1;
951 view -> create_shaders[BONDS] = TRUE;
952 view -> n_shaders[SELEC][stp] = -1;
953 view -> create_shaders[SELEC] = TRUE;
954 view -> create_shaders[LABEL] = TRUE;
955 shaders = TRUE;
956 }
957
958 if (img_a -> m_is_pressed != img_b -> m_is_pressed) view -> create_shaders[MEASU] = shaders = TRUE;
959 if (img_a -> mtilt != img_b -> mtilt) view -> create_shaders[MEASU] = shaders = TRUE;
960 if (img_a -> mpattern != img_b -> mpattern) view -> create_shaders[MEASU] = shaders = TRUE;
961 if (img_a -> mfactor != img_b -> mfactor) view -> create_shaders[MEASU] = shaders = TRUE;
962 if (img_a -> mwidth != img_b -> mwidth) view -> create_shaders[MEASU] = shaders = TRUE;
963 for (i=0; i<2; i++)
964 {
965 if (g_strcmp0 (img_a -> labels_font[3+i], img_b -> labels_font[3+i]) != 0) view -> create_shaders[MEASU] = shaders = TRUE;
966 if (img_a -> labels_position[3+i] != img_b -> labels_position[3+i]) view -> create_shaders[MEASU] = shaders = TRUE;
967 if (img_a -> labels_scale[3+i] != img_b -> labels_scale[3+i]) view -> create_shaders[MEASU] = shaders = TRUE;
968 if (img_a -> labels_render[3+i] != img_b -> labels_render[3+i]) view -> create_shaders[MEASU] = shaders = TRUE;
969 if (img_a -> labels_color[3+i][0].red != img_b -> labels_color[3+i][0].red) view -> create_shaders[MEASU] = shaders = TRUE;
970 if (img_a -> labels_color[3+i][0].green != img_b -> labels_color[3+i][0].green) view -> create_shaders[MEASU] = shaders = TRUE;
971 if (img_a -> labels_color[3+i][0].blue != img_b -> labels_color[3+i][0].blue) view -> create_shaders[MEASU] = shaders = TRUE;
972 for (j=0; j<3; j++)
973 {
974 if (img_a -> labels_shift[3+i][j] != img_b -> labels_shift[3+i][j]) view -> create_shaders[MEASU] = shaders = TRUE;
975 }
976 }
977
978 return shaders;
979}
980
981extern GtkWidget * encoding_pb;
982
983/*
984typedef struct{
985 int framesec; // frame(s) per second
986 int extraframes; // extra frame(s) per second
987 int codec; // video codec
988 int oglquality; // OpenGL quality
989 int bitrate; // bitrate
990 int video_res[2]; // video resolution (x, y)
991} video_options;
992*/
993
1003gboolean create_movie (glwin * view, video_options * vopts, gchar * videofile)
1004{
1005 int q;
1006 const AVOutputFormat * output_format = NULL;
1007 AVFormatContext * format_context = NULL;
1008 VideoStream * video_stream = NULL;
1009 const AVCodec * video_codec = NULL;
1010
1011 int error;
1012
1013#ifdef DEBUG
1014 g_debug ("VIDEO ENCODING:: frames per seconds:: %d", vopts -> framesec);
1015 g_debug ("VIDEO ENCODING:: extra frames every:: %d frame(s)", vopts -> extraframes);
1016 g_debug ("VIDEO ENCODING:: bitrate:: %d", vopts -> bitrate);
1017 g_debug ("VIDEO ENCODING:: video_x = %d , video_y = %d", vopts -> video_res[0], vopts -> video_res[1]);
1018 g_debug ("VIDEO ENCODING:: codec:: %d, name= %s, ext= %s", vopts -> codec, codec_name[vopts -> codec], codec_list[vopts -> codec]);
1019#endif // DEBUG
1020
1021 num_frames = view -> anim -> frames;
1022#if LIBAVCODEC_VERSION_MAJOR < 57
1023 av_register_all ();
1024 avcodec_register_all ();
1025#endif
1026
1027 if (! (format_context = avformat_alloc_context()))
1028 {
1029 g_warning ("MOVIE_ENCODING:: Could not allocate AV format context");
1030 return FALSE;
1031 }
1032
1033 // Guess the desired container format based on file extension
1034 if (! (format_context -> oformat = av_guess_format (NULL, videofile, NULL)))
1035 {
1036 g_warning ("MOVIE_ENCODING:: Could not deduce container format: please change file name");
1037 return FALSE;
1038 }
1039
1040 output_format = format_context -> oformat;
1041
1042 video_stream = add_video_stream (format_context, video_codec, vopts);
1043 if (video_stream == NULL)
1044 {
1045 g_warning ("MOVIE_ENCODING:: Could not create video stream");
1046 return FALSE;
1047 }
1048
1049 /* open the codec */
1050 if ((error = avcodec_open2 (video_stream -> cc, video_codec, NULL)) < 0)
1051 {
1052 // Can not open codec
1053 g_warning ("MOVIE_ENCODING:: could not open codec, error= %s", av_err2str(error));
1054 return FALSE;
1055 }
1056
1057 avcodec_parameters_from_context (video_stream -> st -> codecpar, video_stream -> cc);
1058#if LIBAVCODEC_VERSION_MAJOR > 52
1059 av_dump_format (format_context, 0, videofile, 1);
1060#else
1061 dump_format (av_format_context, 0, videofile, 1);
1062#endif
1063
1064#if LIBAVCODEC_VERSION_MAJOR > 52
1065 if (avio_open (& format_context -> pb, videofile, AVIO_FLAG_WRITE) < 0)
1066#else
1067 if (url_fopen (& av_format_context -> pb, videofile, URL_WRONLY) < 0)
1068#endif
1069 {
1070 // error impossible to open output file
1071 g_warning ("MOVIE_ENCODING:: Impossible to open the video file '%s'", videofile);
1072 return FALSE;
1073 }
1074
1075#if LIBAVCODEC_VERSION_MAJOR > 52
1076 if (avformat_write_header (format_context, NULL) < 0)
1077#else
1078 if (av_set_parameters (av_format_context, NULL) < 0)
1079#endif
1080 {
1081 g_warning ("MOVIE_ENCODING:: Impossible to write the AV format header");
1082 return FALSE;
1083 }
1084
1085 view -> anim -> last = view -> anim -> first;
1086 if (vopts -> oglquality != 0)
1087 {
1088 q = view -> anim -> last -> img -> quality;
1089 view -> anim -> last -> img -> quality = vopts -> oglquality;
1090 }
1091
1092 int frame_id;
1093 frame_start = 0;
1094 if (vopts -> codec == 0)
1095 {
1096 frame_start = 1;
1097 write_video_frame (format_context, video_stream, 0, view);
1098 }
1099 else if (vopts -> codec == 2)
1100 {
1101 frame_start = 24;
1102 for (frame_id = 0; frame_id < frame_start; frame_id ++)
1103 {
1104 write_video_frame (format_context, video_stream, frame_id, view);
1105 }
1106 }
1108 recreate_all_shaders (view);
1109 for (frame_id=0; frame_id<2; frame_id++)
1110 {
1111 old_cmap[frame_id] = allocint(get_project_by_id(view -> proj) -> steps);
1112 set_old_cmap (view -> anim -> last -> img, 0, frame_id);
1113 }
1114 double fraction;
1115#ifdef GTK4
1116 // GMainContext * context = g_main_loop_get_context (Event_loop[dialog_id]);
1117#endif // GTK4
1118 for (frame_id = frame_start; frame_id < num_frames+frame_start; frame_id ++)
1119 {
1120 //g_debug ("Rendering frame: %d, id= %d", frame_id-frame_start, view -> anim -> last -> img -> id);
1121 if (vopts -> oglquality != 0)
1122 {
1123 view -> anim -> last -> img -> quality = vopts -> oglquality;
1124 }
1125 write_video_frame (format_context, video_stream, frame_id, view);
1126 if (frame_id-frame_start > 0 && frame_id-frame_start - 10*((frame_id-frame_start)/10) == 0)
1127 {
1128 fraction = (double)(frame_id-frame_start+1)/num_frames;
1129 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(encoding_pb), fraction);
1130#ifdef GTK3
1131 while (gtk_events_pending()) gtk_main_iteration();
1132#else
1133 // while (g_main_context_pending (context)) g_main_context_iteration (context, TRUE);
1134#endif
1135 }
1136 if (frame_id-frame_start < num_frames-1)
1137 {
1139 view -> anim -> last -> img,
1140 view -> anim -> last -> next -> img,
1141 vopts -> oglquality);
1142 view -> anim -> last = view -> anim -> last -> next;
1143 }
1144 }
1145 if (vopts -> oglquality != 0)
1146 {
1147 view -> anim -> last -> img -> quality = q;
1148 }
1149
1150 av_write_trailer (format_context);
1151
1152 if (!(output_format -> flags & AVFMT_NOFILE))
1153 {
1154 /* close the output file */
1155#if LIBAVCODEC_VERSION_MAJOR > 52
1156 avio_closep (& format_context -> pb);
1157#else
1158 url_fclose (av_format_context -> pb);
1159#endif
1160 }
1161
1162 close_stream (format_context, video_stream);
1163
1164 return TRUE;
1165}
1166
1167static GLuint fbo;
1168static GLuint rbo_color;
1169static GLuint rbo_depth;
1178void init_frame_buffer (int x, int y)
1179{
1180 glGenFramebuffers (1, & fbo);
1181 glBindFramebuffer (GL_FRAMEBUFFER, fbo);
1182
1183 /* Color renderbuffer. */
1184 glGenRenderbuffers (1, & rbo_color);
1185 glBindRenderbuffer (GL_RENDERBUFFER, rbo_color);
1186
1187 /* Storage */
1188 // glRenderbufferStorage (GL_RENDERBUFFER, GL_RGB32F, x, y);
1189 // glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA4, x, y);
1190 glRenderbufferStorage (GL_RENDERBUFFER, GL_RGB, x, y);
1191 glFramebufferRenderbuffer (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo_color);
1192 /* Depth renderbuffer. */
1193 glGenRenderbuffers (1, & rbo_depth);
1194 glBindRenderbuffer (GL_RENDERBUFFER, rbo_depth);
1195 glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, x, y);
1196 glFramebufferRenderbuffer (GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
1197
1198 glReadBuffer (GL_COLOR_ATTACHMENT0);
1199}
1200
1207{
1208 glDeleteFramebuffers (1, &fbo);
1209 glDeleteRenderbuffers (1, &rbo_color);
1210 glDeleteRenderbuffers (1, &rbo_depth);
1211}
1212
1213#ifdef GTK4
1223G_MODULE_EXPORT void run_save_movie (GtkNativeDialog * info, gint response_id, gpointer data)
1224{
1225 GtkFileChooser * chooser = GTK_FILE_CHOOSER((GtkFileChooserNative *)info);
1226#else
1236G_MODULE_EXPORT void run_save_movie (GtkDialog * info, gint response_id, gpointer data)
1237{
1238 GtkFileChooser * chooser = GTK_FILE_CHOOSER((GtkWidget *)info);
1239#endif
1240 if (response_id == GTK_RESPONSE_ACCEPT)
1241 {
1242 gchar * videofile = file_chooser_get_file_name (chooser);
1243#ifdef GTK4
1245#else
1246 destroy_this_dialog (info);
1247#endif
1248 video_options * vopts = (video_options *)data;
1249 glwin * view = get_project_by_id (vopts -> proj) -> modelgl;
1250 int x = view -> pixels[0];
1251 int y = view -> pixels[1];
1252 int i;
1253 for (i=0; i<2; i++) tmp_pixels[i] = view -> pixels[i];
1254 view -> pixels[0] = vopts -> video_res[0];
1255 view -> pixels[1] = vopts -> video_res[1];
1256 init_frame_buffer (vopts -> video_res[0], vopts -> video_res[1]);
1257 init_opengl ();
1259 recreate_all_shaders (view);
1260 in_movie_encoding = TRUE;
1261 gboolean res = create_movie (view, vopts, videofile);
1262 if (! res)
1263 {
1264 show_warning ("An error occurred when encoding movie\nyou might want to try again\nsorry for the trouble", view -> win);
1265 }
1267 in_movie_encoding = FALSE;
1269 recreate_all_shaders (view);
1270 reshape (view, x, y, TRUE);
1271 update (view);
1272 }
1273 else
1274 {
1275#ifdef GTK4
1277#else
1278 destroy_this_dialog (info);
1279#endif
1280 }
1281}
1282
1291void save_movie (glwin * view, video_options * vopts)
1292{
1293 GtkFileFilter * filter;
1294 gchar * str;
1295#ifdef GTK4
1296 GtkFileChooserNative * info;
1297#else
1298 GtkWidget * info;
1299#endif
1300 info = create_file_chooser ("Render Movie",
1301 GTK_WINDOW(view -> win),
1302 GTK_FILE_CHOOSER_ACTION_SAVE,
1303 "Save");
1304 GtkFileChooser * chooser = GTK_FILE_CHOOSER(info);
1305#ifdef GTK3
1306 gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
1307#endif
1309 str = g_strdup_printf ("%s.%s", prepare_for_title(get_project_by_id(view -> proj) -> name), codec_list[vopts -> codec]);
1310 gtk_file_chooser_set_current_name (chooser, str);
1311 g_free (str);
1312
1313 filter = gtk_file_filter_new ();
1314 str = g_strdup_printf ("%s file (*.%s)", codec_name[vopts -> codec], codec_list[vopts -> codec]);
1315 gtk_file_filter_set_name (GTK_FILE_FILTER(filter), str);
1316 g_free (str);
1317 str = g_strdup_printf ("*.%s", codec_list[vopts -> codec]);
1318 gtk_file_filter_add_pattern (GTK_FILE_FILTER(filter), str);
1319 g_free (str);
1320 gtk_file_chooser_add_filter (chooser, filter);
1321#ifdef GTK4
1322 run_this_gtk_native_dialog ((GtkNativeDialog *)info, G_CALLBACK(run_save_movie), vopts);
1323#else
1324 run_this_gtk_dialog (info, G_CALLBACK(run_save_movie), vopts);
1325#endif
1326}
GtkFileFilter * filter[NCFORMATS+1]
Definition callbacks.c:1405
void label(cairo_t *cr, double val, int axe, int p, project *this_proj)
draw axis label
Definition labels.c:56
project * tmp_proj
Definition dlp_field.c:953
gboolean in_movie_encoding
Definition global.c:180
int * allocint(int val)
allocate an int * pointer
Definition global.c:314
int tmp_pixels[2]
Definition global.c:173
Global variable declarations Global convenience function declarations Global data structure defin...
GdkPixbuf * convert_to_pixbuf(cairo_surface_t *surf)
convert cairo surface to GdkPixbuf
Definition gtk-misc.c:1264
void run_this_gtk_dialog(GtkWidget *dial, GCallback handler, gpointer data)
run a GTK (3 and 4) basic GtkDialog
Definition gtk-misc.c:492
void recreate_all_shaders(glwin *view)
re-initialize all OpenGL shaders
void file_chooser_set_current_folder(GtkFileChooser *chooser)
set current folder in a GtkFilechooser
Definition gtk-misc.c:2188
project * proj
gchar * file_chooser_get_file_name(GtkFileChooser *chooser)
get a file name from a GtkFileChooser (single file selected)
Definition gtk-misc.c:2136
void destroy_this_dialog(GtkDialog *dialog)
destroy a GtkDialog
Definition gtk-misc.c:2065
gchar * prepare_for_title(gchar *init)
prepare a string for a window title, getting rid of all markup
Definition tools.c:71
GtkWidget * create_file_chooser(const gchar *title, GtkWindow *parent, GtkFileChooserAction act, const gchar *act_name)
create a GtkFileChooser, utility to select file(s)
Definition gtk-misc.c:2223
void destroy_this_native_dialog(GtkNativeDialog *dialog)
destroy a GtkNativeDialog
Definition gtk-misc.c:2084
project * get_project_by_id(int p)
get project pointer using id number
Definition project.c:120
void update(glwin *view)
update the rendering of the OpenGL window
Definition glview.c:439
void reshape(glwin *view, int width, int height, gboolean use_ratio)
reshape (resize) the OpenGL window
Definition glview.c:516
void init_opengl()
initialize OpenGL rendering parameters
Definition glview.c:1390
Variable declarations related to the OpenGL window Function declarations related to the OpenGL wind...
void re_create_all_md_shaders(glwin *view)
re-initialize all MD dependent OpenGL shaders
void draw(glwin *view)
main drawing subroutine for the OpenGL window
Definition ogl_draw.c:461
gboolean pick
render
Definition glview.h:182
int step
Definition ogl_draw.c:70
#define FILLED_STYLES
Definition glwin.h:105
shaders
The different types of shaders in the atomes program.
Definition glwin.h:88
@ BONDS
Definition glwin.h:90
@ LABEL
Definition glwin.h:98
@ VOLMS
Definition glwin.h:102
@ POLYS
Definition glwin.h:92
@ MAXIS
Definition glwin.h:94
@ SELEC
Definition glwin.h:91
@ MDBOX
Definition glwin.h:93
@ MEASU
Definition glwin.h:99
@ ATOMS
Definition glwin.h:89
@ RINGS
Definition glwin.h:96
Function declarations for the creation of the OpenGL window.
void show_warning(char *warning, GtkWidget *win)
show warning
Definition interface.c:260
Messaging function declarations.
G_MODULE_EXPORT void cloned_poly(GtkWidget *widg, gpointer data)
cloned polyehdra callback - GTK3
Definition m_poly.c:181
G_MODULE_EXPORT void run_save_movie(GtkDialog *info, gint response_id, gpointer data)
saving a movie - running the dialog
Definition movie.c:1236
#define PIXEL_FORMAT
Definition movie.c:67
void close_frame_buffer()
close the frame buffer
Definition movie.c:1206
void init_frame_buffer(int x, int y)
init a frame buffer
Definition movie.c:1178
GdkPixbuf * pixbuf
Definition movie.c:122
gboolean check_to_update_shaders(glwin *view, image *img_a, image *img_b, int ogl_q)
test if it is required to update the OpenGL shaders, and which one(s)
Definition movie.c:519
int frame_start
Definition movie.c:126
char * codec_list[VIDEO_CODECS]
Definition movie.c:96
#define AVIO_FLAG_WRITE
Definition movie.c:79
int video_outbuf_size
Definition movie.c:124
#define RGB_TO_V(pixels, loc)
Definition movie.c:76
gboolean create_movie(glwin *view, video_options *vopts, gchar *videofile)
render a movie from the saved animation parameters
Definition movie.c:1003
void set_old_cmap(image *img, int stp, int id)
preserve color map information
Definition movie.c:504
void save_movie(glwin *view, video_options *vopts)
saving a movie - prepare the dialog
Definition movie.c:1291
VideoStream * add_video_stream(AVFormatContext *fc, const AVCodec *vc, video_options *vopts)
create video stream and the associated data buffers
Definition movie.c:451
char * codec_name[VIDEO_CODECS]
Definition movie.c:90
#define RGB_TO_U(pixels, loc)
Definition movie.c:75
void fill_image(VideoStream *vs, int width, int height, glwin *view)
render an image from an OpenGL rendering
Definition movie.c:273
#define URL_WRONLY
Definition movie.c:87
void convert_rgb_pixbuf_to_yuv(GdkPixbuf *pixbuf, AVFrame *picture, int w, int h)
convert an RGB pixbuf to an YUV picture frame
Definition movie.c:138
int codec_id[VIDEO_CODECS]
Definition movie.c:109
#define RGB_TO_Y(pixels, loc)
Definition movie.c:74
int * old_cmap[2]
Definition movie.c:493
uint8_t * video_outbuf
Definition movie.c:123
int num_frames
Definition movie.c:125
GtkWidget * encoding_pb
Definition w_encode.c:266
AVCodecContext * add_codec_context(AVFormatContext *fc, const AVCodec *vc, video_options *vopts)
create a video codec context
Definition movie.c:396
Data structure declarations for movie encoding Function declarations for movie encoding.
#define VIDEO_CODECS
Definition movie.h:36
double y
Definition ogl_draw.c:57
double x
Definition ogl_draw.c:57
Function declarations for reading atomes project file Function declarations for saving atomes proje...
Definition glwin.h:875
Definition glwin.h:277
GtkWidget * frame[11]
Definition tab-1.c:87
GtkWidget * axis_title
Definition tab-4.c:101
int oglquality
Definition w_encode.c:57
GtkWidget * res[2]
Definition w_encode.c:212
int codec
Definition w_encode.c:56
int extraframes
Definition w_encode.c:55
int video_res[2]
Definition w_encode.c:53
int bitrate
Definition w_encode.c:58
int framesec
Definition w_encode.c:54
GtkWidget * img
Definition workspace.c:70