source: synfigstudio/trunk/fuentes/src/gui/render.cpp @ 481

Last change on this file since 481 was 481, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 14.5 KB
Line 
1/* === S Y N F I G ========================================================= */
2/*!     \file gtkmm/render.cpp
3**      \brief Template File
4**
5**      $Id$
6**
7**      \legal
8**      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9**      Copyright (c) 2007, 2008 Chris Moore
10**
11**      This package is free software; you can redistribute it and/or
12**      modify it under the terms of the GNU General Public License as
13**      published by the Free Software Foundation; either version 2 of
14**      the License, or (at your option) any later version.
15**
16**      This package is distributed in the hope that it will be useful,
17**      but WITHOUT ANY WARRANTY; without even the implied warranty of
18**      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19**      General Public License for more details.
20**      \endlegal
21*/
22/* ========================================================================= */
23
24/* === H E A D E R S ======================================================= */
25
26#ifdef USING_PCH
27#       include "pch.h"
28#else
29#ifdef HAVE_CONFIG_H
30#       include <config.h>
31#endif
32
33#include "render.h"
34#include "app.h"
35#include <gtkmm/frame.h>
36#include <gtkmm/alignment.h>
37#include <glibmm.h>
38#include <synfig/target_scanline.h>
39#include <synfig/canvas.h>
40#include "asyncrenderer.h"
41#include "dialogs/dialog_ffmpegparam.h"
42#include "dialogs/dialog_spritesheetparam.h"
43
44#include "general.h"
45
46#include <ETL/stringf>
47#include <errno.h>
48
49#endif
50
51/* === U S I N G =========================================================== */
52
53using namespace std;
54using namespace etl;
55using namespace synfig;
56using namespace studio;
57
58/* === M A C R O S ========================================================= */
59
60/* === G L O B A L S ======================================================= */
61
62/* === P R O C E D U R E S ================================================= */
63
64/* === M E T H O D S ======================================================= */
65
66RenderSettings::RenderSettings(Gtk::Window& parent, etl::handle<synfigapp::CanvasInterface> canvas_interface):
67        Gtk::Dialog(_("Render Settings"),parent),
68        canvas_interface_(canvas_interface),
69        adjustment_quality(Gtk::Adjustment::create(3,0,9)),
70        entry_quality(adjustment_quality,1,0),
71        adjustment_antialias(Gtk::Adjustment::create(1,1,31)),
72        entry_antialias(adjustment_antialias,1,0),
73        toggle_single_frame(_("Render _current frame only"), true),
74        toggle_extract_alpha(_("Extract alpha"), true),
75        tparam("libx264-lossless",2000)
76{
77        tparam.sequence_separator=App::sequence_separator;
78        widget_rend_desc.show();
79        widget_rend_desc.signal_changed().connect(sigc::mem_fun(*this,&studio::RenderSettings::on_rend_desc_changed));
80        widget_rend_desc.set_rend_desc(canvas_interface_->get_canvas()->rend_desc());
81
82        canvas_interface->signal_rend_desc_changed().connect(sigc::mem_fun(*this,&RenderSettings::on_rend_desc_changed));
83
84        comboboxtext_target.append(_("Auto"));
85        target_names.push_back(String());
86        synfig::Target::Book::iterator iter;
87        synfig::Target::Book book(synfig::Target::book());
88        for(iter=book.begin();iter!=book.end();iter++)
89        {
90                comboboxtext_target.append(iter->first);
91                target_names.push_back(iter->first);
92        }
93        comboboxtext_target.set_active(0);
94        comboboxtext_target.signal_changed().connect(sigc::mem_fun(this, &RenderSettings::on_comboboxtext_target_changed));
95
96        Gtk::Alignment *dialogPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
97        dialogPadding->set_padding(12, 12, 12, 12);
98        get_vbox()->pack_start(*dialogPadding, false, false, 0);
99
100        Gtk::VBox *dialogBox = manage(new Gtk::VBox(false, 12));
101        dialogPadding->add(*dialogBox);
102
103        Gtk::Button *choose_button(manage(new class Gtk::Button(Gtk::StockID(_("Choose...")))));
104        choose_button->show();
105        choose_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_choose_pressed));
106
107        tparam_button=manage(new class Gtk::Button(Gtk::StockID(_("Parameters..."))));
108        tparam_button->show();
109        tparam_button->set_sensitive(false);
110        tparam_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_targetparam_pressed));
111
112        Gtk::Frame *target_frame=manage(new Gtk::Frame(_("Target")));
113        target_frame->set_shadow_type(Gtk::SHADOW_NONE);
114        ((Gtk::Label *) target_frame->get_label_widget())->set_markup(_("<b>Target</b>"));
115        dialogBox->pack_start(*target_frame);
116        Gtk::Alignment *targetPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
117        targetPadding->set_padding(6, 0, 24, 0);
118        target_frame->add(*targetPadding);
119
120        Gtk::Table *target_table = manage(new Gtk::Table(2, 3, false));
121        target_table->set_row_spacings(6);
122        target_table->set_col_spacings(12);
123        targetPadding->add(*target_table);
124
125        Gtk::Label *filenameLabel = manage(new Gtk::Label(_("_Filename"), true));
126        filenameLabel->set_alignment(0, 0.5);
127        filenameLabel->set_mnemonic_widget(entry_filename);
128        target_table->attach(*filenameLabel, 0, 1, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
129        target_table->attach(entry_filename, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
130        target_table->attach(*choose_button, 2, 3, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
131
132        Gtk::Label *targetLabel = manage(new Gtk::Label(_("_Target"), true));
133        targetLabel->set_alignment(0, 0.5);
134        targetLabel->set_mnemonic_widget(comboboxtext_target);
135        target_table->attach(*targetLabel, 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
136        target_table->attach(comboboxtext_target, 1, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
137        target_table->attach(*tparam_button, 2, 3, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
138
139        toggle_single_frame.signal_toggled().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_single_frame_toggle));
140
141        Gtk::Frame *settings_frame=manage(new Gtk::Frame(_("Settings")));
142        settings_frame->set_shadow_type(Gtk::SHADOW_NONE);
143        ((Gtk::Label *) settings_frame->get_label_widget())->set_markup(_("<b>Settings</b>"));
144        dialogBox->pack_start(*settings_frame);
145
146        Gtk::Alignment *settingsPadding = manage(new Gtk::Alignment(0, 0, 1, 1));
147        settingsPadding->set_padding(6, 0, 24, 0);
148        settings_frame->add(*settingsPadding);
149
150        Gtk::Table *settings_table=manage(new Gtk::Table(3,2,false));
151        settings_table->set_row_spacings(6);
152        settings_table->set_col_spacings(12);
153        settingsPadding->add(*settings_table);
154
155        Gtk::Label *qualityLabel = manage(new Gtk::Label(_("_Quality"), true));
156        qualityLabel->set_alignment(0, 0.5);
157        qualityLabel->set_mnemonic_widget(entry_quality);
158        settings_table->attach(*qualityLabel, 0, 1, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
159        settings_table->attach(entry_quality, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
160
161        Gtk::Label *antiAliasLabel = manage(new Gtk::Label(_("_Anti-Aliasing"), true));
162        antiAliasLabel->set_alignment(0, 0.5);
163        antiAliasLabel->set_mnemonic_widget(entry_antialias);
164        settings_table->attach(*antiAliasLabel, 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
165        settings_table->attach(entry_antialias, 1, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
166
167        toggle_single_frame.set_alignment(0, 0.5);
168        settings_table->attach(toggle_single_frame, 2, 3, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
169        toggle_single_frame.set_active(false);
170       
171        toggle_extract_alpha.set_alignment(0, 0.5);
172        settings_table->attach(toggle_extract_alpha, 2, 3, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
173        toggle_extract_alpha.set_active(false);
174
175        dialogBox->pack_start(widget_rend_desc);
176
177
178        Gtk::Button *render_button(manage(new class Gtk::Button(Gtk::StockID(_("Render")))));
179        render_button->show();
180        add_action_widget(*render_button,1);
181        render_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_render_pressed));
182
183        Gtk::Button *cancel_button(manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))));
184        cancel_button->show();
185        add_action_widget(*cancel_button,0);
186        cancel_button->signal_clicked().connect(sigc::mem_fun(*this, &studio::RenderSettings::on_cancel_pressed));
187
188        //set_default_response(1);
189
190        set_title(_("Render Settings")+String(" - ")+canvas_interface_->get_canvas()->get_name());
191
192        widget_rend_desc.enable_time_section();
193
194        set_entry_filename();
195
196        get_vbox()->show_all();
197}
198
199RenderSettings::~RenderSettings()
200{
201}
202
203void
204RenderSettings::set_entry_filename()
205{
206        String filename(filename_sans_extension(canvas_interface_->get_canvas()->get_file_name()));
207
208        // if this isn't the root canvas, append (<canvasname>) to the filename
209        etl::handle<synfig::Canvas> canvas = canvas_interface_->get_canvas();
210        if (!canvas->is_root())
211        {
212                if(canvas->get_name().empty())
213                        filename+=" ("+canvas->get_id()+')';
214                else
215                        filename+=" ("+canvas->get_name()+')';
216        }
217
218        filename += ".png";
219
220        try
221        {
222                entry_filename.set_text((filename));
223        }
224        catch(...)
225        {
226                synfig::warning("Averted crash!");
227                entry_filename.set_text("output.png");
228        }
229}
230
231void
232RenderSettings::on_comboboxtext_target_changed()
233{
234        int i = comboboxtext_target.get_active_row_number();
235        if (i < 0 || i >= (int)target_names.size()) return;
236        if (target_name == target_names[i]) return;
237        set_target(target_names[i]);
238}
239
240void
241RenderSettings::on_rend_desc_changed()
242{
243        widget_rend_desc.set_rend_desc(canvas_interface_->get_canvas()->rend_desc());
244}
245
246void
247RenderSettings::set_target(synfig::String name)
248{
249        target_name=name;
250        //TODO: Replace this condition
251        tparam_button->set_sensitive(target_name.compare("ffmpeg") && target_name.compare("png-spritesheet")?false:true);
252}
253
254void
255RenderSettings::on_choose_pressed()
256{
257        String filename=entry_filename.get_text();
258        if(App::dialog_save_file_render("Save Render As", filename, RENDER_DIR_PREFERENCE))
259                entry_filename.set_text(filename);
260}
261
262void
263RenderSettings::on_targetparam_pressed()
264{
265        Dialog_TargetParam * dialogtp;
266        //TODO: Replace this conditions too
267        if (target_name.compare("ffmpeg") == 0)
268                dialogtp = new Dialog_FFmpegParam (*this);
269        else if (target_name.compare("png-spritesheet") == 0)
270                dialogtp = new Dialog_SpriteSheetParam (*this);
271        else
272                return;
273
274        RendDesc rend_desc(widget_rend_desc.get_rend_desc());
275        dialogtp->set_desc(rend_desc);
276        dialogtp->set_tparam(tparam);
277        if(dialogtp->run() == Gtk::RESPONSE_OK)
278                tparam = dialogtp->get_tparam();
279        delete dialogtp;
280}
281
282void
283RenderSettings::on_render_pressed()
284{
285        String filename=entry_filename.get_text();
286        calculated_target_name=target_name;
287
288        if(filename.empty())
289        {
290                canvas_interface_->get_ui_interface()->error(_("You must supply a filename!"));
291                return;
292        }
293
294        // If the target type is not yet defined,
295        // try to figure it out from the outfile.
296        if(calculated_target_name.empty())
297        {
298                try
299                {
300                        String ext(filename_extension(filename));
301                        if (ext.size()) ext=ext.substr(1); // skip initial '.'
302                        synfig::info("render target filename: '%s'; extension: '%s'", filename.c_str(), ext.c_str());
303                        if(Target::ext_book().count(ext))
304                        {
305                                calculated_target_name=Target::ext_book()[ext];
306                                synfig::info("'%s' is a known extension - using target '%s'", ext.c_str(), calculated_target_name.c_str());
307                        }
308                        else
309                        {
310                                calculated_target_name=ext;
311                                synfig::info("unknown extension");
312                        }
313                }
314                catch(std::runtime_error x)
315                {
316                        canvas_interface_->get_ui_interface()->error(_("Unable to determine proper target from filename."));
317                        return;
318                }
319        }
320
321        if(filename.empty() && calculated_target_name!="null")
322        {
323                canvas_interface_->get_ui_interface()->error(_("A filename is required for this target"));
324                return;
325        }
326
327        hide();
328       
329        render_passes.clear();
330        if (toggle_extract_alpha.get_active())
331        {
332                String filename_alpha(filename_sans_extension(filename)+"-alpha"+filename_extension(filename));
333               
334                render_passes.push_back(make_pair(TARGET_ALPHA_MODE_EXTRACT, filename_alpha));
335                render_passes.push_back(make_pair(TARGET_ALPHA_MODE_REDUCE, filename));
336               
337        } else {
338                render_passes.push_back(make_pair(TARGET_ALPHA_MODE_KEEP, filename));
339        }
340       
341        submit_next_render_pass();
342       
343        return;
344}
345       
346void
347RenderSettings::submit_next_render_pass()
348{
349        if (render_passes.size()>0) {
350                pair<TargetAlphaMode,String> pass_info = render_passes.back();
351                render_passes.pop_back();
352               
353                TargetAlphaMode pass_alpha_mode = pass_info.first;
354#ifdef WIN32
355                String pass_filename = Glib::locale_from_utf8(pass_info.second);
356#else
357                String pass_filename = pass_info.second;
358#endif
359               
360                Target::Handle target=Target::create(calculated_target_name,pass_filename, tparam);
361                if(!target)
362                {
363                        canvas_interface_->get_ui_interface()->error(_("Unable to create target for ")+pass_filename);
364                        return;
365                }
366                // Test whether the output file is writable (path exists or has write permit)
367                if (access(dirname(pass_filename).c_str(),W_OK) == -1)
368                {
369                        canvas_interface_->get_ui_interface()->error(_("Unable to create file for ")+pass_filename+": "+strerror( errno ));
370                        return;
371                }
372
373                target->set_canvas(canvas_interface_->get_canvas());
374                RendDesc rend_desc(widget_rend_desc.get_rend_desc());
375                rend_desc.set_antialias((int)adjustment_antialias->get_value());
376                rend_desc.set_render_excluded_contexts(false);
377
378                // If we are to only render the current frame
379                if(toggle_single_frame.get_active())
380                        rend_desc.set_time(canvas_interface_->get_time());
381       
382                target->set_rend_desc(&rend_desc);
383                target->set_quality((int)adjustment_quality->get_value());
384                if( !target->init(canvas_interface_->get_ui_interface().get()) ){
385                        canvas_interface_->get_ui_interface()->error(_("Target initialization failure"));
386                        return;
387                }
388                if(pass_alpha_mode!=TARGET_ALPHA_MODE_KEEP)
389                        target->set_alpha_mode(pass_alpha_mode);
390
391                canvas_interface_->get_ui_interface()->task(_("Rendering ")+pass_filename);
392       
393                /*
394                if(async_renderer)
395                {
396                        async_renderer->stop();
397                        async_renderer.detach();
398                }
399                */
400                async_renderer=new AsyncRenderer(target);
401                async_renderer->signal_finished().connect( sigc::mem_fun(*this,&RenderSettings::on_finished));
402                async_renderer->start();
403                /*
404                if(!target->render(canvas_interface_->get_ui_interface().get()))
405                {
406                        canvas_interface_->get_ui_interface()->error(_("Render Failure"));
407                        canvas_interface_->get_ui_interface()->amount_complete(0,10000);
408                        return;
409                }
410
411                // Success!
412                canvas_interface_->get_ui_interface()->task(pass_filename+_(" rendered successfully"));
413                canvas_interface_->get_ui_interface()->amount_complete(0,10000);
414                */
415        }
416        return;
417}
418
419void
420RenderSettings::on_finished()
421{
422        String text(_("File rendered successfully"));
423        Real execution_time = async_renderer ? async_renderer->get_execution_time() : 0.0;
424        if (execution_time > 0) text += strprintf(" (%f %s)", execution_time, _("sec"));
425
426        canvas_interface_->get_ui_interface()->task(text);
427        canvas_interface_->get_ui_interface()->amount_complete(0,10000);
428       
429        submit_next_render_pass();
430}
431
432void
433RenderSettings::on_cancel_pressed()
434{
435        hide();
436}
437
438void
439RenderSettings::on_single_frame_toggle()
440{
441        if(toggle_single_frame.get_active())
442                widget_rend_desc.disable_time_section();
443        else
444                widget_rend_desc.enable_time_section();
445}
Note: See TracBrowser for help on using the repository browser.