atomes 1.3.1
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-2026 by CNRS and University of Strasbourg */
15
21
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_malloc0(nvals * sizeof(GLubyte));
251 GLubyte * rgb = g_malloc0(nvals * sizeof(GLubyte));
252 // On macOS, OpenGL runs over Metal with asynchronous command submission.
253 // glFinish() ensures all GPU rendering commands from draw() have completed
254 // before we read the framebuffer, preventing partial image captures.
255 // This is harmless on Linux and Windows where the driver synchronizes implicitly.
256 glFinish ();
257 glReadPixels (0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
258 // Flip data vertically
259 for (i = 0; i < height; i++)
260 {
261 memcpy (rgb + 4 * width * i, pixels + 4 * width * (height - i - 1), 4 * width);
262 }
263 g_free (pixels);
264 return rgb;
265}
266//#endif
267
278void fill_image (VideoStream * vs, int width, int height, glwin * view)
279{
280 // opengl call is here !!!
281 reshape (view, width, height, FALSE);
282 draw (view);
283 // Might need some correction(s) here for HiDPI screens
284 GLubyte * image = capture_opengl_image (width, height);
285 if (vs != NULL)
286 {
287 //if (movie) convert_rgb_pixbuf_to_yuv (pixbuf, frame, width, height);
288 ffmpeg_encoder_set_frame_yuv_from_rgb (image, vs);
289 }
290 else
291 {
292 cairo_surface_t * surf = cairo_image_surface_create_for_data ((guchar *)image, CAIRO_FORMAT_ARGB32,
293 width, height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
294 pixbuf = convert_to_pixbuf (surf);
295 cairo_surface_destroy (surf);
296 }
297 g_free (image);
298}
299
310static void write_video_frame (AVFormatContext * f_context, VideoStream * vs, int frame_id, glwin * view)
311{
312 int out_size = 0;
313
314 fill_image (vs, vs -> cc -> width, vs -> cc -> height, view);
315
316 AVPacket packet;
317#if LIBAVCODEC_VERSION_MAJOR > 57
318 out_size = av_new_packet (& packet, 0);
319 if (out_size != 0)
320 {
321 // "Error while encoding video frame"
322 g_warning (_("Error in movie encoding : video frame - error : %s"), av_err2str(out_size));
323 }
324 // get_packet_defaults (& packet);
325#else
326 av_init_packet (& packet);
327#endif
328
329 if (! out_size)
330 {
331 packet.dts = packet.pts = AV_NOPTS_VALUE;
332 packet.data = NULL;
333 packet.size = 0;
334
335 vs -> frame -> pts = frame_id + 1;
336 out_size = avcodec_send_frame (vs -> cc, vs -> frame);
337 if (out_size < 0)
338 {
339 // "Error while encoding video frame"
340 g_warning (_("Error in movie encoding : video frame - error : %s"), av_err2str (out_size));
341 }
342 else
343 {
344 if (avcodec_receive_packet (vs -> cc, & packet) < 0)
345 {
346 // "Error while encoding video frame"
347 if (frame_id + 1 > frame_start) g_warning (_("Error in movie encoding : video frame - warning : packet empty, ignoring frame= %d"), frame_id);
348 }
349 else
350 {
351 av_packet_rescale_ts (& packet, vs -> cc -> time_base, vs -> st -> time_base);
352
353 packet.stream_index = vs -> st -> index;
354 packet.flags |= AV_PKT_FLAG_KEY;
355 out_size = av_interleaved_write_frame (f_context, & packet);
356 if (out_size != 0)
357 {
358 // "Error while encoding video frame"
359 g_warning (_("Error in movie encoding : video frame - error : %s"), av_err2str(out_size));
360 }
361 av_packet_unref(& packet);
362 }
363 }
364 }
365}
366
374static AVFrame * alloc_video_frame (AVCodecContext * cc)
375{
376 AVFrame * frame;
377 frame = av_frame_alloc ();
378 if (! frame)
379 {
380 return NULL;
381 }
382 frame -> format = cc -> pix_fmt;
383 frame -> width = cc -> width;
384 frame -> height = cc -> height;
385 if (av_frame_get_buffer (frame, 32) < 0)
386 {
387 return NULL;
388 }
389 return frame;
390}
391
401AVCodecContext * add_codec_context (AVFormatContext * fc, const AVCodec * vc, video_options * vopts)
402{
403 AVCodecContext * cc;
404 if (! (vc = avcodec_find_encoder (codec_id[vopts -> codec])))
405 {
406 // Codec not found
407 g_warning (_("Error in movie encoding : impossible to find codec %s"), codec_name[vopts -> codec]);
408 return NULL;
409 }
410 if (! (cc = avcodec_alloc_context3(vc)))
411 {
412 g_warning (_("Error in movie encoding : impossible to allocate encoding context"));
413 return NULL;
414 }
415 //g_debug ("Codec_id= %d", cc -> codec_id);
416 cc -> codec_id = codec_id[vopts -> codec];
417 //g_debug ("Codec_id= %d", cc -> codec_id);
418 /* put sample parameters */
419 cc -> bit_rate_tolerance = vopts -> bitrate*1000;
420 cc -> bit_rate = vopts -> bitrate*1000;
421
422 /* resolution must be a multiple of two */
423 cc -> width = vopts -> video_res[0];
424 cc -> height = vopts -> video_res[1];
425
426 cc -> time_base = (AVRational){1, vopts -> framesec};
427 cc -> framerate = (AVRational){vopts -> framesec, 1};
428
429 if (vopts -> codec != 1 && vopts -> codec != 4) cc -> max_b_frames = 1;
430
431 cc -> gop_size = vopts -> extraframes; /* emit one intra frame every n frames */
432 cc -> pix_fmt = PIXEL_FORMAT;
433
434 if (vopts -> codec == 2) av_opt_set (cc -> priv_data, "preset", "slow", 0);
435 /*
436 Some container formats (like MP4) require global headers to be present
437 Mark the encoder so that it behaves accordingly.
438 */
439#if LIBAVCODEC_VERSION_MAJOR > 57
440 if (fc -> oformat -> flags & AVFMT_GLOBALHEADER) cc -> flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
441#else
442 if (fc -> oformat -> flags & AVFMT_GLOBALHEADER) cc -> flags |= CODEC_FLAG_GLOBAL_HEADER;
443#endif
444 return cc;
445}
446
456VideoStream * add_video_stream (AVFormatContext * fc, const AVCodec * vc, video_options * vopts)
457{
458 VideoStream * stream = g_malloc0(sizeof*stream);
459 stream -> cc = add_codec_context (fc, vc, vopts);
460 if (stream -> cc == NULL) return NULL;
461
462#if LIBAVCODEC_VERSION_MAJOR > 53
463 stream -> st = avformat_new_stream (fc, vc);
464#else
465 st = av_new_stream (fc, vc);
466#endif
467 if (! stream -> st)
468 {
469 g_warning (_("Error in movie encoding : impossible to allocate video stream"));
470 return NULL;
471 }
472 stream -> st -> time_base = stream -> cc -> time_base;
473 stream -> frame = alloc_video_frame (stream -> cc);
474 if (stream -> frame == NULL)
475 {
476 g_warning (_("Error in movie encoding : impossible to allocate raw frame buffer"));
477 return NULL;
478 }
479 return stream;
480}
481
490static void close_stream (AVFormatContext * fc, VideoStream * vs)
491{
492 avcodec_free_context (& vs -> cc);
493 av_frame_free (& vs -> frame);
494 sws_freeContext (vs -> sws_ctx);
495 avformat_free_context (fc);
496}
497
498int * old_cmap[2];
499
509void set_old_cmap (image * img, int stp, int id)
510{
511 old_cmap[id][stp] = img -> color_map[id];
512}
513
524gboolean check_to_update_shaders (glwin * view, image * img_a, image * img_b, int ogl_q)
525{
526 gboolean shaders = FALSE;
527 int i, j, k;
528 int stp = img_b -> step;
529
530 if ((img_a -> ray_tracing != img_b -> ray_tracing) || (ogl_q == 0 && img_a -> quality != img_b -> quality))
531 {
532 view -> create_shaders[MDBOX] = TRUE;
533 view -> create_shaders[MAXIS] = TRUE;
534 view -> n_shaders[ATOMS][stp] = -1;
535 view -> create_shaders[ATOMS] = TRUE;
536 view -> n_shaders[BONDS][stp] = -1;
537 view -> create_shaders[BONDS] = TRUE;
538 view -> n_shaders[POLYS][stp] = -1;
539 view -> create_shaders[POLYS] = TRUE;
540 view -> n_shaders[RINGS][stp] = -1;
541 view -> create_shaders[RINGS] = TRUE;
542 view -> n_shaders[VOLMS][stp] = -1;
543 view -> create_shaders[VOLMS] = TRUE;
544 view -> n_shaders[SELEC][stp] = -1;
545 view -> create_shaders[SELEC] = TRUE;
546 view -> create_shaders[LABEL] = TRUE;
547 view -> create_shaders[MEASU] = TRUE;
548 for (i=0; i<2; i++) set_old_cmap (img_b, stp, i);
549 return TRUE;
550 }
551
552 for (i=0; i<3; i++)
553 {
554 if (img_a -> abc -> extra_cell[i] != img_b -> abc -> extra_cell[i])
555 {
556 view -> create_shaders[MDBOX] = TRUE;
557 view -> create_shaders[MAXIS] = TRUE;
558 view -> n_shaders[ATOMS][stp] = -1;
559 view -> create_shaders[ATOMS] = TRUE;
560 view -> n_shaders[BONDS][stp] = -1;
561 view -> create_shaders[BONDS] = TRUE;
562 view -> n_shaders[POLYS][stp] = -1;
563 view -> create_shaders[POLYS] = TRUE;
564 view -> n_shaders[RINGS][stp] = -1;
565 view -> create_shaders[RINGS] = TRUE;
566 view -> n_shaders[VOLMS][stp] = -1;
567 view -> create_shaders[VOLMS] = TRUE;
568 view -> n_shaders[SELEC][stp] = -1;
569 view -> create_shaders[SELEC] = TRUE;
570 view -> create_shaders[LABEL] = TRUE;
571 view -> create_shaders[MEASU] = TRUE;
572 for (i=0; i<2; i++) set_old_cmap (img_b, stp, i);
573 return TRUE;
574 }
575 }
576
578 coord_info * this_coord = tmp_proj -> coord;
579 for (i=0; i<9; i++)
580 {
581 for (j=0; j<this_coord -> totcoord[i]; j++)
582 {
583 if (img_a -> show_coord[i][j] != img_b -> show_coord[i][j])
584 {
585 view -> n_shaders[ATOMS][stp] = -1;
586 view -> create_shaders[ATOMS] = TRUE;
587 view -> n_shaders[BONDS][stp] = -1;
588 view -> create_shaders[BONDS] = TRUE;
589 view -> n_shaders[SELEC][stp] = -1;
590 view -> create_shaders[SELEC] = TRUE;
591 view -> create_shaders[LABEL] = TRUE;
592 view -> create_shaders[MEASU] = TRUE;
593 }
594 }
595 if (i < 2)
596 {
597 for (j=0; j<this_coord -> totcoord[i]; j++)
598 {
599 if (img_a -> show_poly[i][j] != img_b -> show_poly[i][j])
600 {
601 view -> n_shaders[POLYS][stp] = -1;
602 view -> create_shaders[POLYS] = TRUE;
603 }
604 }
605 }
606 else if (i > 3)
607 {
608 for (j=0; j<this_coord -> totcoord[i]; j++)
609 {
610 if (img_a -> show_poly[i][j] != img_b -> show_poly[i][j])
611 {
612 view -> n_shaders[RINGS][stp] = -1;
613 view -> create_shaders[RINGS] = TRUE;
614 }
615 }
616 }
617 }
618 for (j=0; j<this_coord -> totcoord[9]; j++)
619 {
620 if (img_a -> show_coord[9][j] != img_b -> show_coord[9][j])
621 {
622 view -> n_shaders[ATOMS][stp] = -1;
623 view -> create_shaders[ATOMS] = TRUE;
624 view -> n_shaders[BONDS][stp] = -1;
625 view -> create_shaders[BONDS] = TRUE;
626 view -> create_shaders[LABEL] = TRUE;
627 view -> create_shaders[MEASU] = TRUE;
628 }
629 }
630
631 if (img_a -> draw_clones != img_b -> draw_clones)
632 {
633 view -> n_shaders[ATOMS][stp] = -1;
634 view -> create_shaders[ATOMS] = TRUE;
635 view -> n_shaders[BONDS][stp] = -1;
636 view -> create_shaders[BONDS] = TRUE;
637 view -> n_shaders[POLYS][stp] = -1;
638 view -> create_shaders[POLYS] = TRUE;
639 view -> n_shaders[RINGS][stp] = -1;
640 view -> create_shaders[RINGS] = TRUE;
641 view -> n_shaders[SELEC][stp] = -1;
642 view -> create_shaders[SELEC] = TRUE;
643 view -> create_shaders[LABEL] = TRUE;
644 shaders = TRUE;
645 }
646
647 if (img_a -> color_map[0] != img_b -> color_map[0] || img_b -> color_map[0] != old_cmap[0][stp])
648 {
649 view -> n_shaders[ATOMS][stp] = -1;
650 view -> create_shaders[ATOMS] = TRUE;
651 view -> n_shaders[BONDS][stp] = -1;
652 view -> create_shaders[BONDS] = TRUE;
653 view -> create_shaders[LABEL] = TRUE;
654 set_old_cmap (img_b, stp, 0);
655 shaders = TRUE;
656 }
657
658 if (img_a -> color_map[1] != img_b -> color_map[1] || img_b -> color_map[1] != old_cmap[1][stp])
659 {
660 view -> n_shaders[POLYS][stp] = -1;
661 view -> create_shaders[POLYS] = TRUE;
662 set_old_cmap (img_b, stp, 1);
663 shaders = TRUE;
664 }
665
666 if (img_a -> step != img_b -> step)
667 {
668 if (view -> n_shaders[ATOMS][stp] < 0) view -> create_shaders[ATOMS] = TRUE;
669 if (view -> n_shaders[BONDS][stp] < 0) view -> create_shaders[BONDS] = TRUE;
670 if (view -> n_shaders[POLYS][stp] < 0) view -> create_shaders[POLYS] = TRUE;
671 if (view -> n_shaders[RINGS][stp] < 0) view -> create_shaders[RINGS] = TRUE;
672 if (view -> n_shaders[VOLMS][stp] < 0) view -> create_shaders[VOLMS] = TRUE;
673 if (view -> n_shaders[SELEC][stp] < 0) view -> create_shaders[SELEC] = TRUE;
674 view -> create_shaders[LABEL] = TRUE;
675 view -> create_shaders[MEASU] = TRUE;
676 shaders = TRUE;
677 }
678
679 gboolean do_volms = FALSE;
680 for (i=0; i<FILLED_STYLES; i++)
681 {
682 if (img_a -> show_vol[i] != img_b -> show_vol[i]) do_volms = TRUE;
683 if (img_a -> vol_col[i].red != img_b -> vol_col[i].red) do_volms = TRUE;
684 if (img_a -> vol_col[i].green != img_b -> vol_col[i].green) do_volms = TRUE;
685 if (img_a -> vol_col[i].blue != img_b -> vol_col[i].blue) do_volms = TRUE;
686 for (j=0; j<2; j++)
687 {
688 if (img_a -> fm_show_vol[j][i] == NULL && img_b -> fm_show_vol[j][i] != NULL)
689 {
690 do_volms = TRUE;
691 }
692 else if (img_a -> fm_show_vol[j][i] != NULL && img_b -> fm_show_vol[j][i] == NULL)
693 {
694 do_volms = TRUE;
695 }
696 else if (img_a -> fm_show_vol[j][i] != NULL && img_b -> fm_show_vol[j][i] != NULL)
697 {
698 for (k=0; k<this_coord -> totcoord[j+2]; k++)
699 {
700 if (img_a -> fm_show_vol[j][i][k] != img_b -> fm_show_vol[j][i][k]) do_volms = TRUE;
701 if (img_a -> fm_vol_col[j][i][k].red != img_b -> fm_vol_col[j][i][k].red) do_volms = TRUE;
702 if (img_a -> fm_vol_col[j][i][k].green != img_b -> fm_vol_col[j][i][k].green) do_volms = TRUE;
703 if (img_a -> fm_vol_col[j][i][k].blue != img_b -> fm_vol_col[j][i][k].blue) do_volms = TRUE;
704 }
705 }
706 }
707 }
708 if (do_volms)
709 {
710 view -> create_shaders[VOLMS] = shaders = TRUE;
711 view -> n_shaders[VOLMS][stp] = -1;
712 }
713
714 if (img_a -> abc -> box != img_b -> abc -> box) view -> create_shaders[MDBOX] = shaders = TRUE;
715 if (img_a -> abc -> rad != img_b -> abc -> rad) view -> create_shaders[MDBOX] = shaders = TRUE;
716 if (img_a -> abc -> line != img_b -> abc -> line) view -> create_shaders[MDBOX] = shaders = TRUE;
717 if (img_a -> abc -> color.red != img_b -> abc -> color.red) view -> create_shaders[MDBOX] = shaders = TRUE;
718 if (img_a -> abc -> color.green != img_b -> abc -> color.green) view -> create_shaders[MDBOX] = shaders = TRUE;
719 if (img_a -> abc -> color.blue != img_b -> abc -> color.blue) view -> create_shaders[MDBOX] = shaders = TRUE;
720
721 if (img_a -> xyz -> axis != img_b -> xyz -> axis) view -> create_shaders[MAXIS] = shaders = TRUE;
722 if (img_a -> xyz -> rad != img_b -> xyz -> rad) view -> create_shaders[MAXIS] = shaders = TRUE;
723 if (img_a -> xyz -> line != img_b -> xyz -> line) view -> create_shaders[MAXIS] = shaders = TRUE;
724 if (img_a -> xyz -> length != img_b -> xyz -> length) view -> create_shaders[MAXIS] = shaders = TRUE;
725 if (img_a -> xyz -> t_pos != img_b -> xyz -> t_pos) view -> create_shaders[MAXIS] = shaders = TRUE;
726 if (img_a -> xyz -> color == NULL && img_b -> xyz -> color != NULL)
727 {
728 view -> create_shaders[MAXIS] = shaders = TRUE;
729 }
730 else if (img_a -> xyz -> color != NULL && img_b -> xyz -> color == NULL)
731 {
732 view -> create_shaders[MAXIS] = shaders = TRUE;
733 }
734 else if (img_a -> xyz -> color != NULL && img_b -> xyz -> color != NULL)
735 {
736 for (i=0; i<3; i++)
737 {
738 if (img_a -> xyz -> color[i].red != img_b -> xyz -> color[i].red) view -> create_shaders[MAXIS] = shaders = TRUE;
739 if (img_a -> xyz -> color[i].green != img_b -> xyz -> color[i].green) view -> create_shaders[MAXIS] = shaders = TRUE;
740 if (img_a -> xyz -> color[i].blue != img_b -> xyz -> color[i].blue) view -> create_shaders[MAXIS] = shaders = TRUE;
741 }
742 }
743 if (img_a -> xyz -> labels != img_b -> xyz -> labels) view -> create_shaders[MAXIS] = shaders = TRUE;
744 for (i=0; i<3; i++)
745 {
746 if (g_strcmp0 (img_a -> xyz -> title[i], img_b -> xyz -> title[i]) != 0) view -> create_shaders[MAXIS] = shaders = TRUE;
747 if (img_a -> xyz -> c_pos[i] != img_b -> xyz -> c_pos[i]) view -> create_shaders[MAXIS] = shaders = TRUE;
748 }
749 if (g_strcmp0 (img_a -> labels[2].font, img_b -> labels[2].font) != 0) view -> create_shaders[MAXIS] = shaders = TRUE;
750 if (img_a -> labels[2].position != img_b -> labels[2].position) view -> create_shaders[MAXIS] = shaders = TRUE;
751 if (img_a -> labels[2].scale != img_b -> labels[2].scale) view -> create_shaders[MAXIS] = shaders = TRUE;
752 if (img_a -> labels[2].render != img_b -> labels[2].render) view -> create_shaders[MAXIS] = shaders = TRUE;
753 if (img_a -> labels[2].color == NULL && img_b -> labels[2].color != NULL)
754 {
755 view -> create_shaders[MAXIS] = shaders = TRUE;
756 }
757 else if (img_a -> labels[2].color != NULL && img_b -> labels[2].color == NULL)
758 {
759 view -> create_shaders[MAXIS] = shaders = TRUE;
760 }
761 else if (img_a -> labels[2].color != NULL && img_b -> labels[2].color != NULL)
762 {
763 for (i=0; i<3; i++)
764 {
765 if (img_a -> labels[2].color[i].red != img_b -> labels[2].color[i].red) view -> create_shaders[MAXIS] = shaders = TRUE;
766 if (img_a -> labels[2].color[i].green != img_b -> labels[2].color[i].green) view -> create_shaders[MAXIS] = shaders = TRUE;
767 if (img_a -> labels[2].color[i].blue != img_b -> labels[2].color[i].blue) view -> create_shaders[MAXIS] = shaders = TRUE;
768 }
769 }
770
771 if (img_a -> cloned_poly != img_b -> cloned_poly)
772 {
773 view -> n_shaders[POLYS][stp] = -1;
774 view -> create_shaders[POLYS] = TRUE;
775 view -> n_shaders[RINGS][stp] = -1;
776 view -> create_shaders[RINGS] = TRUE;
777 shaders = TRUE;
778 }
779
780 gboolean dorings = FALSE;
781 for (i=0; i<5; i++)
782 {
783 if (view -> ring_max[i])
784 {
785 if (img_a -> i_rings[i] && img_b -> i_rings[i])
786 {
787 if (img_a -> i_rings[i][0][0] != img_b -> i_rings[i][0][0])
788 {
789 view -> n_shaders[RINGS][stp] = -1;
790 view -> create_shaders[RINGS] = TRUE;
791 dorings = shaders = TRUE;
792 break;
793 }
794 else
795 {
796 for (j=0; j<img_a -> i_rings[i][0][0]; j++)
797 {
798 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]))
799 {
800 view -> n_shaders[RINGS][stp] = -1;
801 view -> create_shaders[RINGS] = TRUE;
802 dorings = shaders = TRUE;
803 break;
804 }
805 }
806 }
807 }
808 else if (img_b -> i_rings[i])
809 {
810 dorings = TRUE;
811 }
812 if (dorings) break;
813 }
814 }
815
816 for (i=0; i<2; i++)
817 {
818 for (j=0; j<tmp_proj -> nspec; j++)
819 {
820 if (img_a -> show_label[i][j] != img_b -> show_label[i][j])
821 {
822 view -> create_shaders[LABEL] = shaders = TRUE;
823 }
824 if (img_a -> show_atom[i][j] != img_b -> show_atom[i][j])
825 {
826 view -> n_shaders[ATOMS][stp] = -1;
827 view -> create_shaders[ATOMS] = TRUE;
828 view -> n_shaders[BONDS][stp] = -1;
829 view -> create_shaders[BONDS] = TRUE;
830 view -> n_shaders[SELEC][stp] = -1;
831 view -> create_shaders[SELEC] = TRUE;
832 view -> create_shaders[LABEL] = TRUE;
833 view -> create_shaders[MEASU] = TRUE;
834 shaders = TRUE;
835 break;
836 }
837 }
838 for (j=0; j<tmp_proj -> natomes; j++)
839 {
840 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)
841 {
842 view -> n_shaders[ATOMS][stp] = -1;
843 view -> create_shaders[ATOMS] = TRUE;
844 view -> n_shaders[BONDS][stp] = -1;
845 view -> create_shaders[BONDS] = TRUE;
846 view -> n_shaders[SELEC][stp] = -1;
847 view -> create_shaders[SELEC] = TRUE;
848 view -> create_shaders[LABEL] = TRUE;
849 view -> create_shaders[MEASU] = TRUE;
850 shaders = TRUE;
851 break;
852 }
853 if (img_a -> at_data[j].label[i] != img_b -> at_data[j].label[i])
854 {
855 view -> create_shaders[LABEL] = shaders = TRUE;
856 }
857 if (img_a -> at_data[j].pick[0] != img_b -> at_data[j].pick[0])
858 {
859 view -> n_shaders[SELEC][stp] = -1;
860 view -> create_shaders[SELEC] = shaders = TRUE;
861 }
862 if (img_a -> at_data[j].pick[1] != img_b -> at_data[j].pick[1])
863 {
864 view -> n_shaders[SELEC][stp] = -1;
865 view -> create_shaders[SELEC] = shaders = TRUE;
866 }
867 }
868 }
869
870 for (i=0; i<2*tmp_proj -> nspec; i++)
871 {
872 if ((img_a -> sphererad[i] != img_b -> sphererad[i])
873 || (img_a -> pointrad[i] != img_b -> pointrad[i])
874 || (img_a -> atomicrad[i] != img_b -> atomicrad[i]))
875 {
876 view -> n_shaders[ATOMS][stp] = -1;
877 view -> create_shaders[ATOMS] = TRUE;
878 view -> n_shaders[SELEC][stp] = -1;
879 view -> create_shaders[SELEC] = TRUE;
880 view -> create_shaders[LABEL] = TRUE;
881 shaders = TRUE;
882 }
883 for (j=0; j<2*tmp_proj -> nspec; j++)
884 {
885 if ((img_a -> bondrad[i][j] != img_b -> bondrad[i][j])
886 || (img_a -> linerad[i][j] != img_b -> linerad[i][j]))
887 {
888 view -> n_shaders[BONDS][stp] = -1;
889 view -> create_shaders[BONDS] = TRUE;
890 view -> n_shaders[SELEC][stp] = -1;
891 view -> create_shaders[SELEC] = TRUE;
892 view -> create_shaders[LABEL] = TRUE;
893 shaders = TRUE;
894 }
895 }
896 }
897
898 for (i=0; i<2; i++)
899 {
900 if (img_a -> acl_format[i] != img_b -> acl_format[i]) view -> create_shaders[LABEL] = shaders = TRUE;
901 if (g_strcmp0 (img_a -> labels[i].font, img_b -> labels[i].font) != 0) view -> create_shaders[LABEL] = shaders = TRUE;
902 if (img_a -> labels[i].position != img_b -> labels[i].position) view -> create_shaders[LABEL] = shaders = TRUE;
903 if (img_a -> labels[i].scale != img_b -> labels[i].scale) view -> create_shaders[LABEL] = shaders = TRUE;
904 if (img_a -> labels[i].render != img_b -> labels[i].render) view -> create_shaders[LABEL] = shaders = TRUE;
905 for (j=0; j<3; j++)
906 {
907 if (img_a -> labels[i].shift[j] != img_b -> labels[i].shift[j]) view -> create_shaders[LABEL] = shaders = TRUE;
908 }
909 if (img_a -> labels[i].color == NULL && img_b -> labels[i].color != NULL)
910 {
911 view -> create_shaders[LABEL] = shaders = TRUE;
912 }
913 else if (img_a -> labels[i].color != NULL && img_b -> labels[i].color == NULL)
914 {
915 view -> create_shaders[LABEL] = shaders = TRUE;
916 }
917 else if (img_a -> labels[i].color != NULL && img_b -> labels[i].color != NULL)
918 {
919 for (j=0; j<tmp_proj -> nspec; j++)
920 {
921 if (img_a -> labels[i].color[j].red != img_b -> labels[i].color[j].red) view -> create_shaders[LABEL] = shaders = TRUE;
922 if (img_a -> labels[i].color[j].green != img_b -> labels[i].color[j].green) view -> create_shaders[LABEL] = shaders = TRUE;
923 if (img_a -> labels[i].color[j].blue != img_b -> labels[i].color[j].blue) view -> create_shaders[LABEL] = shaders = TRUE;
924 }
925 }
926
927 if (img_a -> radall[i] != img_b -> radall[i])
928 {
929 view -> n_shaders[ATOMS][stp] = -1;
930 view -> create_shaders[ATOMS] = TRUE;
931 view -> n_shaders[BONDS][stp] = -1;
932 view -> create_shaders[BONDS] = TRUE;
933 view -> n_shaders[SELEC][stp] = -1;
934 view -> create_shaders[SELEC] = TRUE;
935 view -> create_shaders[LABEL] = TRUE;
936 shaders = TRUE;
937 }
938 }
939
940 if (img_a -> render != img_b -> render)
941 {
942 view -> n_shaders[ATOMS][stp] = -1;
943 view -> create_shaders[ATOMS] = TRUE;
944 view -> n_shaders[BONDS][stp] = -1;
945 view -> create_shaders[BONDS] = TRUE;
946 view -> n_shaders[SELEC][stp] = -1;
947 view -> create_shaders[SELEC] = TRUE;
948 shaders = TRUE;
949 }
950 if (img_a -> style != img_b -> style)
951 {
952 view -> n_shaders[ATOMS][stp] = -1;
953 view -> create_shaders[ATOMS] = TRUE;
954 view -> n_shaders[BONDS][stp] = -1;
955 view -> create_shaders[BONDS] = TRUE;
956 view -> n_shaders[SELEC][stp] = -1;
957 view -> create_shaders[SELEC] = TRUE;
958 view -> create_shaders[LABEL] = TRUE;
959 shaders = TRUE;
960 }
961
962 if (img_a -> m_is_pressed != img_b -> m_is_pressed) view -> create_shaders[MEASU] = shaders = TRUE;
963 for (i=0; i<2; i++)
964 {
965 if (img_a -> mtilt[i] != img_b -> mtilt[i]) view -> create_shaders[MEASU] = shaders = TRUE;
966 if (img_a -> mpattern[i] != img_b -> mpattern[i]) view -> create_shaders[MEASU] = shaders = TRUE;
967 if (img_a -> mfactor[i] != img_b -> mfactor[i]) view -> create_shaders[MEASU] = shaders = TRUE;
968 if (img_a -> mwidth[i] != img_b -> mwidth[i]) view -> create_shaders[MEASU] = shaders = TRUE;
969 if (g_strcmp0 (img_a -> labels[3+i].font, img_b -> labels[3+i].font) != 0) view -> create_shaders[MEASU] = shaders = TRUE;
970 if (img_a -> labels[3+i].position != img_b -> labels[3+i].position) view -> create_shaders[MEASU] = shaders = TRUE;
971 if (img_a -> labels[3+i].scale != img_b -> labels[3+i].scale) view -> create_shaders[MEASU] = shaders = TRUE;
972 if (img_a -> labels[3+i].render != img_b -> labels[3+i].render) view -> create_shaders[MEASU] = shaders = TRUE;
973 if (img_a -> labels[3+i].color[0].red != img_b -> labels[3+i].color[0].red) view -> create_shaders[MEASU] = shaders = TRUE;
974 if (img_a -> labels[3+i].color[0].green != img_b -> labels[3+i].color[0].green) view -> create_shaders[MEASU] = shaders = TRUE;
975 if (img_a -> labels[3+i].color[0].blue != img_b -> labels[3+i].color[0].blue) view -> create_shaders[MEASU] = shaders = TRUE;
976 for (j=0; j<3; j++)
977 {
978 if (img_a -> labels[3+i].shift[j] != img_b -> labels[3+i].shift[j]) view -> create_shaders[MEASU] = shaders = TRUE;
979 }
980 }
981
982 return shaders;
983}
984
985extern GtkWidget * encoding_pb;
986
987/*
988typedef struct{
989 int framesec; // frame(s) per second
990 int extraframes; // extra frame(s) per second
991 int codec; // video codec
992 int oglquality; // OpenGL quality
993 int bitrate; // bitrate
994 int video_res[2]; // video resolution (x, y)
995} video_options;
996*/
997
1007gboolean create_movie (glwin * view, video_options * vopts, gchar * videofile)
1008{
1009 int q;
1010 const AVOutputFormat * output_format = NULL;
1011 AVFormatContext * format_context = NULL;
1012 VideoStream * video_stream = NULL;
1013 const AVCodec * video_codec = NULL;
1014
1015 int error;
1016
1017#ifdef DEBUG
1018 g_debug ("VIDEO ENCODING:: frames per seconds:: %d", vopts -> framesec);
1019 g_debug ("VIDEO ENCODING:: extra frames every:: %d frame(s)", vopts -> extraframes);
1020 g_debug ("VIDEO ENCODING:: bitrate:: %d", vopts -> bitrate);
1021 g_debug ("VIDEO ENCODING:: video_x = %d , video_y = %d", vopts -> video_res[0], vopts -> video_res[1]);
1022 g_debug ("VIDEO ENCODING:: codec:: %d, name= %s, ext= %s", vopts -> codec, codec_name[vopts -> codec], codec_list[vopts -> codec]);
1023#endif // DEBUG
1024
1025 num_frames = view -> anim -> frames;
1026#if LIBAVCODEC_VERSION_MAJOR < 57
1027 av_register_all ();
1028 avcodec_register_all ();
1029#endif
1030
1031 if (! (format_context = avformat_alloc_context()))
1032 {
1033 g_warning (_("Error in movie encoding : impossible to allocate AV format context"));
1034 return FALSE;
1035 }
1036
1037 // Guess the desired container format based on file extension
1038 if (! (format_context -> oformat = av_guess_format (NULL, videofile, NULL)))
1039 {
1040 g_warning (_("Error in movie encoding : impossible to guess container format : change file name"));
1041 return FALSE;
1042 }
1043
1044 output_format = format_context -> oformat;
1045
1046 video_stream = add_video_stream (format_context, video_codec, vopts);
1047 if (video_stream == NULL)
1048 {
1049 g_warning (_("Error in movie encoding : impossible to create video stream"));
1050 return FALSE;
1051 }
1052
1053 /* open the codec */
1054 if ((error = avcodec_open2 (video_stream -> cc, video_codec, NULL)) < 0)
1055 {
1056 // Can not open codec
1057 g_warning (_("Error in movie encoding : impossible to open codec, error= %s"), av_err2str(error));
1058 return FALSE;
1059 }
1060
1061 avcodec_parameters_from_context (video_stream -> st -> codecpar, video_stream -> cc);
1062#if LIBAVCODEC_VERSION_MAJOR > 52
1063 av_dump_format (format_context, 0, videofile, 1);
1064#else
1065 dump_format (av_format_context, 0, videofile, 1);
1066#endif
1067
1068#if LIBAVCODEC_VERSION_MAJOR > 52
1069 if (avio_open (& format_context -> pb, videofile, AVIO_FLAG_WRITE) < 0)
1070#else
1071 if (url_fopen (& av_format_context -> pb, videofile, URL_WRONLY) < 0)
1072#endif
1073 {
1074 // error impossible to open output file
1075 g_warning (_("Error in movie encoding : impossible to open video file '%s'"), videofile);
1076 return FALSE;
1077 }
1078
1079#if LIBAVCODEC_VERSION_MAJOR > 52
1080 if (avformat_write_header (format_context, NULL) < 0)
1081#else
1082 if (av_set_parameters (av_format_context, NULL) < 0)
1083#endif
1084 {
1085 g_warning (_("Error in movie encoding : impossible to write the AV format header"));
1086 return FALSE;
1087 }
1088
1089 view -> anim -> last = view -> anim -> first;
1090 if (vopts -> oglquality != 0)
1091 {
1092 q = view -> anim -> last -> img -> quality;
1093 view -> anim -> last -> img -> quality = vopts -> oglquality;
1094 }
1095
1096 int frame_id;
1097 frame_start = 0;
1098 if (vopts -> codec == 0)
1099 {
1100 frame_start = 1;
1101 write_video_frame (format_context, video_stream, 0, view);
1102 }
1103 else if (vopts -> codec == 2)
1104 {
1105 frame_start = 24;
1106 for (frame_id = 0; frame_id < frame_start; frame_id ++)
1107 {
1108 write_video_frame (format_context, video_stream, frame_id, view);
1109 }
1110 }
1112 recreate_all_shaders (view);
1113 for (frame_id=0; frame_id<2; frame_id++)
1114 {
1115 old_cmap[frame_id] = allocint (get_project_by_id(view -> proj) -> steps);
1116 set_old_cmap (view -> anim -> last -> img, 0, frame_id);
1117 }
1118 double fraction;
1119#ifdef GTK4
1120 // GMainContext * context = g_main_loop_get_context (Event_loop[dialog_id]);
1121#endif // GTK4
1122 for (frame_id = frame_start; frame_id < num_frames+frame_start; frame_id ++)
1123 {
1124 //g_debug ("Rendering frame: %d, id= %d", frame_id-frame_start, view -> anim -> last -> img -> id);
1125 if (vopts -> oglquality != 0)
1126 {
1127 view -> anim -> last -> img -> quality = vopts -> oglquality;
1128 }
1129 write_video_frame (format_context, video_stream, frame_id, view);
1130 if (frame_id-frame_start > 0 && frame_id-frame_start - 10*((frame_id-frame_start)/10) == 0)
1131 {
1132 fraction = (double)(frame_id-frame_start+1)/num_frames;
1133 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(encoding_pb), fraction);
1134#ifdef GTK3
1135 while (gtk_events_pending()) gtk_main_iteration();
1136#else
1137 // while (g_main_context_pending (context)) g_main_context_iteration (context, TRUE);
1138#endif
1139 }
1140 if (frame_id-frame_start < num_frames-1)
1141 {
1143 view -> anim -> last -> img,
1144 view -> anim -> last -> next -> img,
1145 vopts -> oglquality);
1146 view -> anim -> last = view -> anim -> last -> next;
1147 }
1148 }
1149 if (vopts -> oglquality != 0)
1150 {
1151 view -> anim -> last -> img -> quality = q;
1152 }
1153
1154 av_write_trailer (format_context);
1155
1156 if (!(output_format -> flags & AVFMT_NOFILE))
1157 {
1158 /* close the output file */
1159#if LIBAVCODEC_VERSION_MAJOR > 52
1160 avio_closep (& format_context -> pb);
1161#else
1162 url_fclose (av_format_context -> pb);
1163#endif
1164 }
1165
1166 close_stream (format_context, video_stream);
1167
1168 return TRUE;
1169}
1170
1171static GLuint fbo;
1172static GLuint rbo_color;
1173static GLuint rbo_depth;
1182void init_frame_buffer (int x, int y)
1183{
1184 glGenFramebuffers (1, & fbo);
1185 glBindFramebuffer (GL_FRAMEBUFFER, fbo);
1186
1187 /* Color renderbuffer. */
1188 glGenRenderbuffers (1, & rbo_color);
1189 glBindRenderbuffer (GL_RENDERBUFFER, rbo_color);
1190
1191 /* Storage */
1192 // glRenderbufferStorage (GL_RENDERBUFFER, GL_RGB32F, x, y);
1193 // glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA4, x, y);
1194 glRenderbufferStorage (GL_RENDERBUFFER, GL_RGB, x, y);
1195 glFramebufferRenderbuffer (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo_color);
1196 /* Depth renderbuffer. */
1197 glGenRenderbuffers (1, & rbo_depth);
1198 glBindRenderbuffer (GL_RENDERBUFFER, rbo_depth);
1199 glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, x, y);
1200 glFramebufferRenderbuffer (GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
1201
1202 glReadBuffer (GL_COLOR_ATTACHMENT0);
1203}
1204
1211{
1212 glDeleteFramebuffers (1, &fbo);
1213 glDeleteRenderbuffers (1, &rbo_color);
1214 glDeleteRenderbuffers (1, &rbo_depth);
1215}
1216
1217#ifdef GTK4
1227G_MODULE_EXPORT void run_save_movie (GtkNativeDialog * info, gint response_id, gpointer data)
1228{
1229 GtkFileChooser * chooser = GTK_FILE_CHOOSER((GtkFileChooserNative *)info);
1230#else
1240G_MODULE_EXPORT void run_save_movie (GtkDialog * info, gint response_id, gpointer data)
1241{
1242 GtkFileChooser * chooser = GTK_FILE_CHOOSER((GtkWidget *)info);
1243#endif
1244 if (response_id == GTK_RESPONSE_ACCEPT)
1245 {
1246 gchar * videofile = file_chooser_get_file_name (chooser);
1247#ifdef GTK4
1249#else
1250 destroy_this_dialog (info);
1251#endif
1252 video_options * vopts = (video_options *)data;
1253 glwin * view = get_project_by_id (vopts -> proj) -> modelgl;
1254 int x = view -> pixels[0];
1255 int y = view -> pixels[1];
1256 int i;
1257 for (i=0; i<2; i++) tmp_pixels[i] = view -> pixels[i];
1258 view -> pixels[0] = vopts -> video_res[0];
1259 view -> pixels[1] = vopts -> video_res[1];
1260 // On macOS, the CoreAnimation layer may invalidate the current GL context
1261 // between the file dialog callback and our OpenGL calls.
1262 gtk_gl_area_make_current ((GtkGLArea *)view -> plot);
1263 init_frame_buffer (vopts -> video_res[0], vopts -> video_res[1]);
1264 init_opengl ();
1266 recreate_all_shaders (view);
1267 in_movie_encoding = TRUE;
1268 gboolean res = create_movie (view, vopts, videofile);
1269 if (! res)
1270 {
1271 show_warning (_("An error occurred when encoding movie\nyou might want to try again\nsorry for the trouble"), view -> win);
1272 }
1274 in_movie_encoding = FALSE;
1276 recreate_all_shaders (view);
1277 reshape (view, x, y, TRUE);
1278 update (view);
1279 }
1280 else
1281 {
1282#ifdef GTK4
1284#else
1285 destroy_this_dialog (info);
1286#endif
1287 }
1288}
1289
1298void save_movie (glwin * view, video_options * vopts)
1299{
1300 GtkFileFilter * filter;
1301 gchar * str;
1302#ifdef GTK4
1303 GtkFileChooserNative * info;
1304#else
1305 GtkWidget * info;
1306#endif
1307 info = create_file_chooser (_("Render Movie"),
1308 GTK_WINDOW(view -> win),
1309 GTK_FILE_CHOOSER_ACTION_SAVE,
1310 _("Save"));
1311 GtkFileChooser * chooser = GTK_FILE_CHOOSER(info);
1312#ifdef GTK3
1313 gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
1314#endif
1316 str = g_strdup_printf ("%s.%s", prepare_for_title(get_project_by_id(view -> proj) -> name), codec_list[vopts -> codec]);
1317 gtk_file_chooser_set_current_name (chooser, str);
1318 g_free (str);
1319
1320 filter = gtk_file_filter_new ();
1321 str = g_strdup_printf (_("%s file (*.%s)"), codec_name[vopts -> codec], codec_list[vopts -> codec]);
1322 gtk_file_filter_set_name (GTK_FILE_FILTER(filter), str);
1323 g_free (str);
1324 str = g_strdup_printf ("*.%s", codec_list[vopts -> codec]);
1325 gtk_file_filter_add_pattern (GTK_FILE_FILTER(filter), str);
1326 g_free (str);
1327 gtk_file_chooser_add_filter (chooser, filter);
1328#ifdef GTK4
1329 run_this_gtk_native_dialog ((GtkNativeDialog *)info, G_CALLBACK(run_save_movie), vopts);
1330#else
1331 run_this_gtk_dialog (info, G_CALLBACK(run_save_movie), vopts);
1332#endif
1333}
GtkFileFilter * filter[NCFORMATS+1]
Definition callbacks.c:1557
double scale(double axe)
find appropriate major tick spacing based on axis length
Definition curve.c:205
int * shift
Definition d_measures.c:72
project * tmp_proj
Definition dlp_field.c:1043
gboolean in_movie_encoding
Definition global.c:184
int * allocint(int val)
allocate an int * pointer
Definition global.c:301
int tmp_pixels[2]
Definition global.c:177
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:1351
void run_this_gtk_dialog(GtkWidget *dial, GCallback handler, gpointer data)
run a GTK (3 and 4) basic GtkDialog
Definition gtk-misc.c:533
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:2358
project * proj
gchar * file_chooser_get_file_name(GtkFileChooser *chooser)
get a file name from a GtkFileChooser (single file selected)
Definition gtk-misc.c:2306
void destroy_this_dialog(GtkDialog *dialog)
destroy a GtkDialog
Definition gtk-misc.c:2235
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:2393
void destroy_this_native_dialog(GtkNativeDialog *dialog)
destroy a GtkNativeDialog
Definition gtk-misc.c:2254
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:461
void reshape(glwin *view, int width, int height, gboolean use_ratio)
reshape (resize) the OpenGL window
Definition glview.c:538
void init_opengl()
initialize OpenGL rendering parameters
Definition glview.c:1440
Variable declarations related to the OpenGL window Function declarations related to the OpenGL wind...
image * plot
Definition ogl_draw.c:72
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:528
gboolean pick
render
Definition glview.h:191
int step
Definition ogl_draw.c:76
labels
Definition glview.h:223
#define FILLED_STYLES
Definition glwin.h:106
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.
GdkPixbuf * pixbuf
Definition movie.c:122
void show_warning(char *warning, GtkWidget *win)
show warning
Definition interface.c:266
Messaging function declarations.
G_MODULE_EXPORT void cloned_poly(GtkWidget *widg, gpointer data)
cloned polyehdra callback - GTK3
Definition m_poly.c:181
position
Definition m_proj.c:48
G_MODULE_EXPORT void run_save_movie(GtkDialog *info, gint response_id, gpointer data)
saving a movie - running the dialog
Definition movie.c:1240
#define PIXEL_FORMAT
Definition movie.c:67
void close_frame_buffer()
close the frame buffer
Definition movie.c:1210
void init_frame_buffer(int x, int y)
init a frame buffer
Definition movie.c:1182
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:524
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:1007
void set_old_cmap(image *img, int stp, int id)
preserve color map information
Definition movie.c:509
void save_movie(glwin *view, video_options *vopts)
saving a movie - prepare the dialog
Definition movie.c:1298
VideoStream * add_video_stream(AVFormatContext *fc, const AVCodec *vc, video_options *vopts)
create video stream and the associated data buffers
Definition movie.c:456
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:278
#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:498
uint8_t * video_outbuf
Definition movie.c:123
int num_frames
Definition movie.c:125
GtkWidget * encoding_pb
Definition w_encode.c:396
AVCodecContext * add_codec_context(AVFormatContext *fc, const AVCodec *vc, video_options *vopts)
create a video codec context
Definition movie.c:401
Data structure declarations for movie encoding Function declarations for movie encoding.
#define VIDEO_CODECS
Definition movie.h:36
double y
Definition ogl_draw.c:63
double x
Definition ogl_draw.c:63
Function declarations for reading atomes project file Function declarations for saving atomes proje...
Definition glwin.h:332
Definition glwin.h:350
double green
Definition color_box.h:35
double red
Definition color_box.h:34
double blue
Definition color_box.h:36
Definition glwin.h:967
Definition glwin.h:364
int oglquality
Definition w_encode.c:59
GtkWidget * res[2]
Definition w_encode.c:342
int codec
Definition w_encode.c:58
int extraframes
Definition w_encode.c:57
int video_res[2]
Definition w_encode.c:55
int bitrate
Definition w_encode.c:60
int framesec
Definition w_encode.c:56
GtkWidget * img
Definition workspace.c:70