r870: Merge 2.1:
[cinelerra_cv.git] / cinelerra / render.C
blobdb9ba4dc72b17772d985290cb5b459d73952b71e
1 #include "arender.h"
2 #include "asset.h"
3 #include "auto.h"
4 #include "batchrender.h"
5 #include "bcprogressbox.h"
6 #include "cache.h"
7 #include "clip.h"
8 #include "compresspopup.h"
9 #include "condition.h"
10 #include "confirmsave.h"
11 #include "cwindowgui.h"
12 #include "cwindow.h"
13 #include "bchash.h"
14 #include "edits.h"
15 #include "edl.h"
16 #include "edlsession.h"
17 #include "errorbox.h"
18 #include "file.h"
19 #include "filesystem.h"
20 #include "filexml.h"
21 #include "formatcheck.h"
22 #include "formatpopup.h"
23 #include "formattools.h"
24 #include "labels.h"
25 #include "language.h"
26 #include "loadmode.h"
27 #include "localsession.h"
28 #include "mainprogress.h"
29 #include "mainsession.h"
30 #include "mainundo.h"
31 #include "module.h"
32 #include "mutex.h"
33 #include "mwindowgui.h"
34 #include "mwindow.h"
35 #include "packagedispatcher.h"
36 #include "packagerenderer.h"
37 #include "patchbay.h"
38 #include "playabletracks.h"
39 #include "preferences.h"
40 #include "quicktime.h"
41 #include "renderfarm.h"
42 #include "render.h"
43 #include "statusbar.h"
44 #include "theme.h"
45 #include "timebar.h"
46 #include "tracks.h"
47 #include "transportque.h"
48 #include "vedit.h"
49 #include "vframe.h"
50 #include "videoconfig.h"
51 #include "vrender.h"
53 #include <ctype.h>
54 #include <string.h>
58 RenderItem::RenderItem(MWindow *mwindow)
59  : BC_MenuItem(_("Render..."), "Shift+R", 'R')
61         this->mwindow = mwindow;
62         set_shift(1);
65 int RenderItem::handle_event() 
67         mwindow->render->start_interactive();
68         return 1;
80 RenderProgress::RenderProgress(MWindow *mwindow, Render *render)
81  : Thread()
83         this->mwindow = mwindow;
84         this->render = render;
85         last_value = 0;
86         Thread::set_synchronous(1);
89 RenderProgress::~RenderProgress()
91         Thread::cancel();
92         Thread::join();
96 void RenderProgress::run()
98         Thread::disable_cancel();
99         while(1)
100         {
101                 if(render->total_rendered != last_value)
102                 {
103                         render->progress->update(render->total_rendered);
104                         last_value = render->total_rendered;
105                 }
107                 Thread::enable_cancel();
108                 sleep(1);
109                 Thread::disable_cancel();
110         }
122 MainPackageRenderer::MainPackageRenderer(Render *render)
123  : PackageRenderer()
125         this->render = render;
130 MainPackageRenderer::~MainPackageRenderer()
135 int MainPackageRenderer::get_master()
137         return 1;
140 int MainPackageRenderer::get_result()
142         return render->result;
145 void MainPackageRenderer::set_result(int value)
147         if(value)
148                 render->result = value;
151 void MainPackageRenderer::set_progress(int64_t value)
153         render->counter_lock->lock("MainPackageRenderer::set_progress");
154         render->total_rendered += value;
156 // If non interactive, print progress out
157         if(!render->progress)
158         {
159                 int64_t current_eta = render->progress_timer->get_scaled_difference(1000);
160                 if(current_eta - render->last_eta > 1000)
161                 {
162                         double eta = 0;
165                         if(render->total_rendered)
166                         {
167                                 eta = current_eta /
168                                         1000 *
169                                         render->progress_max /
170                                         render->total_rendered -
171                                         current_eta /
172                                         1000;
173                         }
175                         char string[BCTEXTLEN];
176                         Units::totext(string, 
177                                 eta,
178                                 TIME_HMS2);
180                         printf("\r%d%% ETA: %s      ", (int)(100 * 
181                                 (float)render->total_rendered / 
182                                         render->progress_max),
183                                 string);
184                         fflush(stdout);
185                         render->last_eta = current_eta;
186                 }
187         }
189         render->counter_lock->unlock();
192 int MainPackageRenderer::progress_cancelled()
194         return (render->progress && render->progress->is_cancelled()) || 
195                 render->batch_cancelled;
209 Render::Render(MWindow *mwindow)
210  : Thread(0, 0, 0)
212         this->mwindow = mwindow;
213         if(mwindow) plugindb = mwindow->plugindb;
214         in_progress = 0;
215         progress = 0;
216         preferences = 0;
217         elapsed_time = 0.0;
218         package_lock = new Mutex("Render::package_lock");
219         counter_lock = new Mutex("Render::counter_lock");
220         completion = new Condition(0, "Render::completion");
221         progress_timer = new Timer;
224 Render::~Render()
226         delete package_lock;
227         delete counter_lock;
228         delete completion;
229         if(preferences) delete preferences;
230         delete progress_timer;
233 void Render::start_interactive()
235         if(!Thread::running())
236         {
237                 mode = Render::INTERACTIVE;
238                 this->jobs = 0;
239                 batch_cancelled = 0;
240                 completion->reset();
241                 Thread::start();
242         }
243         else
244         {
245                 // raise the window if rendering hasn't started yet
246                 if (render_window && ! in_progress) {
247                         render_window->raise_window();
248                 }
249                 else {
250                         ErrorBox error_box(PROGRAM_NAME ": Error",
251                                            mwindow->gui->get_abs_cursor_x(1),
252                                            mwindow->gui->get_abs_cursor_y(1));
253                         error_box.create_objects("Already rendering");
254                         error_box.raise_window();
255                         error_box.run_window();
256                 }
257         }
260 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs)
262         batch_cancelled = 0;
263         if(!Thread::running())
264         {
265                 mode = Render::BATCH;
266                 this->jobs = jobs;
267                 completion->reset();
268                 Thread::start();
269         }
270         else
271         {
272                 ErrorBox error_box(PROGRAM_NAME ": Error",
273                         mwindow->gui->get_abs_cursor_x(1),
274                         mwindow->gui->get_abs_cursor_y(1));
275                 error_box.create_objects("Already rendering");
276                 error_box.raise_window();
277                 error_box.run_window();
278         }
281 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs,
282         BC_Hash *boot_defaults,
283         Preferences *preferences,
284         ArrayList<PluginServer*> *plugindb)
286         mode = Render::BATCH;
287         batch_cancelled = 0;
288         this->jobs = jobs;
289         this->preferences = preferences;
290         this->plugindb = plugindb;
292         completion->reset();
293         run();
294         this->preferences = 0;
297 void Render::stop_operation()
299         if(Thread::running())
300         {
301                 batch_cancelled = 1;
302 // Wait for completion
303                 completion->lock("Render::stop_operation");
304                 completion->reset();
305         }
309 void Render::run()
311         int format_error;
314         result = 0;
316         if(mode == Render::INTERACTIVE)
317         {
318 // Fix the asset for rendering
319 printf("Render::run 1\n");
320                 Asset *asset = new Asset;
321                 load_defaults(asset);
322 printf("Render::run 2\n");
323                 check_asset(mwindow->edl, *asset);
324 printf("Render::run 3\n");
326 // Get format from user
327                 if(!result)
328                 {
329 printf("Render::run 4\n");
330                         do
331                         {
332                                 format_error = 0;
333                                 result = 0;
335                                 {
336 printf("Render::run 5\n");
337                                         RenderWindow window(mwindow, this, asset);
338 printf("Render::run 6\n");
339                                         window.create_objects();
340 printf("Render::run 7\n");
341                                         result = window.run_window();
342 printf("Render::run 8\n");
343                                         if (! result) {
344                                                 // add to recentlist only on OK
345                                                 window.format_tools->path_recent->add_item(FILE_FORMAT_PREFIX(asset->format), asset->path);
346                                         }
347                                 }
349                                 if(!result)
350                                 {
351 printf("Render::run 8.1\n");
352 // Check the asset format for errors.
353                                         FormatCheck format_check(asset);
354 printf("Render::run 8.2\n");
355                                         format_error = format_check.check_format();
356 printf("Render::run 8.3\n");
357                                 }
358                         }while(format_error && !result);
359                 }
360 printf("Render::run 9\n");
362                 save_defaults(asset);
363                 mwindow->save_defaults();
364 printf("Render::run 10\n");
366                 if(!result) render(1, asset, mwindow->edl, strategy);
367 printf("Render::run 11\n");
369                 Garbage::delete_object(asset);
370 printf("Render::run 12\n");
371         }
372         else
373         if(mode == Render::BATCH)
374         {
375                 for(int i = 0; i < jobs->total && !result; i++)
376                 {
377                         BatchRenderJob *job = jobs->values[i];
378                         if(job->enabled)
379                         {
380                                 if(mwindow)
381                                 {
382                                         mwindow->batch_render->update_active(i);
383                                 }
384                                 else
385                                 {
386                                         printf("Render::run: %s\n", job->edl_path);
387                                 }
390                                 FileXML *file = new FileXML;
391                                 EDL *edl = new EDL;
392                                 edl->create_objects();
393                                 file->read_from_file(job->edl_path);
394                                 if(!plugindb && mwindow)
395                                         plugindb = mwindow->plugindb;
396                                 edl->load_xml(plugindb, file, LOAD_ALL);
398                                 check_asset(edl, *job->asset);
399                                 render(0, job->asset, edl, job->strategy);
401                                 delete edl;
402                                 delete file;
403                                 if(!result)
404                                 {
405                                         if(mwindow)
406                                                 mwindow->batch_render->update_done(i, 1, elapsed_time);
407                                         else
408                                         {
409                                                 char string[BCTEXTLEN];
410                                                 elapsed_time = 
411                                                         (double)progress_timer->get_scaled_difference(1);
412                                                 Units::totext(string,
413                                                         elapsed_time,
414                                                         TIME_HMS2);
415                                                 printf("Render::run: done in %s\n", string);
416                                         }
417                                 }
418                                 else
419                                 {
420                                         if(mwindow)
421                                                 mwindow->batch_render->update_active(-1);
422                                         else
423                                                 printf("Render::run: failed\n");
424                                 }
425                         }
426                 }
428                 if(mwindow)
429                 {
430                         mwindow->batch_render->update_active(-1);
431                         mwindow->batch_render->update_done(-1, 0, 0);
432                 }
433         }
434 printf("Render::run 100\n");
439 int Render::check_asset(EDL *edl, Asset &asset)
441         if(asset.video_data && 
442                 edl->tracks->playable_video_tracks() &&
443                 File::supports_video(asset.format))
444         {
445                 asset.video_data = 1;
446                 asset.layers = 1;
447                 asset.width = edl->session->output_w;
448                 asset.height = edl->session->output_h;
449                 asset.interlace_mode = edl->session->interlace_mode;
450                 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
451                         edl->local_session->get_selectionstart() *
452                                 edl->session->frame_rate);
453                 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
454                         edl->local_session->get_selectionend() *
455                                 edl->session->frame_rate);
456         }
457         else
458         {
459                 asset.video_data = 0;
460                 asset.layers = 0;
461                 asset.tcstart = 0;
462                 asset.tcend = 0;
463         }
465         if(asset.audio_data && 
466                 edl->tracks->playable_audio_tracks() &&
467                 File::supports_audio(asset.format))
468         {
469                 asset.audio_data = 1;
470                 asset.channels = edl->session->audio_channels;
471                 if(asset.format == FILE_MOV) asset.byte_order = 0;
472                 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
473                         edl->local_session->get_selectionstart() *
474                                 edl->session->sample_rate);
475                 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
476                         edl->local_session->get_selectionend() *
477                                 edl->session->sample_rate);
478         }
479         else
480         {
481                 asset.audio_data = 0;
482                 asset.channels = 0;
483                 asset.tcstart = 0;
484                 asset.tcend = 0;
485         }
487         if(!asset.audio_data &&
488                 !asset.video_data)
489         {
490                 return 1;
491         }
492         return 0;
495 int Render::fix_strategy(int strategy, int use_renderfarm)
497         if(use_renderfarm)
498         {
499                 if(strategy == FILE_PER_LABEL)
500                         strategy = FILE_PER_LABEL_FARM;
501                 else
502                 if(strategy == SINGLE_PASS)
503                         strategy = SINGLE_PASS_FARM;
504         }
505         else
506         {
507                 if(strategy == FILE_PER_LABEL_FARM)
508                         strategy = FILE_PER_LABEL;
509                 else
510                 if(strategy == SINGLE_PASS_FARM)
511                         strategy = SINGLE_PASS;
512         }
513         return strategy;
516 void Render::start_progress()
518         char filename[BCTEXTLEN];
519         char string[BCTEXTLEN];
520         FileSystem fs;
522         progress_max = packages->get_progress_max();
524         progress_timer->update();
525         last_eta = 0;
526         if(mwindow)
527         {
528 // Generate the progress box
529                 fs.extract_name(filename, default_asset->path);
530                 sprintf(string, _("Rendering %s..."), filename);
532 // Don't bother with the filename since renderfarm defeats the meaning
533                 progress = mwindow->mainprogress->start_progress(_("Rendering..."), 
534                         progress_max);
535                 render_progress = new RenderProgress(mwindow, this);
536                 render_progress->start();
537         }
540 void Render::stop_progress()
542         if(progress)
543         {
544                 char string[BCTEXTLEN], string2[BCTEXTLEN];
545                 delete render_progress;
546                 progress->get_time(string);
547                 elapsed_time = progress->get_time();
548                 progress->stop_progress();
549                 delete progress;
551                 sprintf(string2, _("Rendering took %s"), string);
552                 mwindow->gui->lock_window("");
553                 mwindow->gui->show_message(string2);
554                 mwindow->gui->stop_hourglass();
555                 mwindow->gui->unlock_window();
556         }
557         progress = 0;
562 int Render::render(int test_overwrite, 
563         Asset *asset,
564         EDL *edl,
565         int strategy)
567         char string[BCTEXTLEN];
568 // Total length in seconds
569         double total_length;
570         int last_audio_buffer;
571         RenderFarmServer *farm_server = 0;
572         FileSystem fs;
573         int total_digits;      // Total number of digits including padding the user specified.
574         int number_start;      // Character in the filename path at which the number begins
575         int current_number;    // The number the being injected into the filename.
576 // Pointer from file
577 // (VFrame*)(VFrame array [])(Channel [])
578         VFrame ***video_output;
579 // Pointer to output buffers
580         VFrame *video_output_ptr[MAX_CHANNELS];
581         double *audio_output_ptr[MAX_CHANNELS];
582         int done = 0;
583         in_progress = 1;
586         this->default_asset = asset;
587         progress = 0;
588         result = 0;
590         if(mwindow)
591         {
592                 if(!preferences)
593                         preferences = new Preferences;
595                 preferences->copy_from(mwindow->preferences);
596         }
599 // Create rendering command
600         command = new TransportCommand;
601         command->command = NORMAL_FWD;
602         command->get_edl()->copy_all(edl);
603         command->change_type = CHANGE_ALL;
604 // Get highlighted playback range
605         command->set_playback_range();
606 // Adjust playback range with in/out points
607         command->adjust_playback_range();
608         packages = new PackageDispatcher;
611 // Configure preview monitor
612         VideoOutConfig vconfig;
613         PlaybackConfig *playback_config = new PlaybackConfig;
615 // Create caches
616         audio_cache = new CICache(preferences, plugindb);
617         video_cache = new CICache(preferences, plugindb);
619         default_asset->frame_rate = command->get_edl()->session->frame_rate;
620         default_asset->sample_rate = command->get_edl()->session->sample_rate;
622 // Conform asset to EDL.  Find out if any tracks are playable.
623         result = check_asset(command->get_edl(), *default_asset);
625         if(!result)
626         {
627 // Get total range to render
628                 total_start = command->start_position;
629                 total_end = command->end_position;
630                 total_length = total_end - total_start;
632 // Nothing to render
633                 if(EQUIV(total_length, 0))
634                 {
635                         result = 1;
636                 }
637         }
645 // Generate packages
646         if(!result)
647         {
648 // Stop background rendering
649                 if(mwindow) mwindow->stop_brender();
651                 fs.complete_path(default_asset->path);
652                 strategy = Render::fix_strategy(strategy, preferences->use_renderfarm);
654                 result = packages->create_packages(mwindow,
655                         command->get_edl(),
656                         preferences,
657                         strategy, 
658                         default_asset, 
659                         total_start, 
660                         total_end,
661                         test_overwrite);
662         }
673         done = 0;
674         total_rendered = 0;
675         frames_per_second = 0;
677         if(!result)
678         {
679 // Start dispatching external jobs
680                 if(mwindow)
681                 {
682                         mwindow->gui->lock_window("Render::render 1");
683                         mwindow->gui->show_message(_("Starting render farm"));
684                         mwindow->gui->start_hourglass();
685                         mwindow->gui->unlock_window();
686                 }
687                 else
688                 {
689                         printf("Render::render: starting render farm\n");
690                 }
692                 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
693                 {
694                         farm_server = new RenderFarmServer(plugindb, 
695                                 packages,
696                                 preferences, 
697                                 1,
698                                 &result,
699                                 &total_rendered,
700                                 counter_lock,
701                                 default_asset,
702                                 command->get_edl(),
703                                 0);
704                         result = farm_server->start_clients();
706                         if(result)
707                         {
708                                 if(mwindow)
709                                 {
710                                         mwindow->gui->lock_window("Render::render 2");
711                                         mwindow->gui->show_message(_("Failed to start render farm"),
712                                                 mwindow->theme->message_error);
713                                         mwindow->gui->stop_hourglass();
714                                         mwindow->gui->unlock_window();
715                                 }
716                                 else
717                                 {
718                                         printf("Render::render: Failed to start render farm\n");
719                                 }
720                         }
721                 }
722         }
727 // Perform local rendering
730         if(!result)
731         {
732                 start_progress();
733         
737                 MainPackageRenderer package_renderer(this);
738                 result = package_renderer.initialize(mwindow,
739                                 command->get_edl(),   // Copy of master EDL
740                                 preferences, 
741                                 default_asset,
742                                 plugindb);
750                 while(!result)
751                 {
752 // Get unfinished job
753                         RenderPackage *package;
755                         if(strategy == SINGLE_PASS_FARM)
756                         {
757                                 package = packages->get_package(frames_per_second, -1, 1);
758                         }
759                         else
760                         {
761                                 package = packages->get_package(0, -1, 1);
762                         }
764 // Exit point
765                         if(!package) 
766                         {
767                                 done = 1;
768                                 break;
769                         }
773                         Timer timer;
774                         timer.update();
776                         if(package_renderer.render_package(package))
777                                 result = 1;
779 // Result is also set directly by the RenderFarm.
781                         frames_per_second = (double)(package->video_end - package->video_start) / 
782                                 (double)(timer.get_difference() / 1000);
785                 } // file_number
789 printf("Render::run: Session finished.\n");
795                 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
796                 {
797                         farm_server->wait_clients();
798                         result |= packages->packages_are_done();
799                 }
801 printf("Render::render 90\n");
803 // Notify of error
804                 if(result && 
805                         (!progress || !progress->is_cancelled()) &&
806                         !batch_cancelled)
807                 {
808                         if(mwindow)
809                         {
810                                 ErrorBox error_box(PROGRAM_NAME ": Error",
811                                         mwindow->gui->get_abs_cursor_x(1),
812                                         mwindow->gui->get_abs_cursor_y(1));
813                                 error_box.create_objects(_("Error rendering data."));
814                                 error_box.raise_window();
815                                 error_box.run_window();
816                         }
817                         else
818                         {
819                                 printf("Render::render: Error rendering data\n");
820                         }
821                 }
823 // Delete the progress box
824                 stop_progress();
826 //printf("Render::render 100\n");
831         }
834 // Paste all packages into timeline if desired
836         if(!result && 
837                 load_mode != LOAD_NOTHING && 
838                 mwindow &&
839                 mode != Render::BATCH)
840         {
841                 mwindow->gui->lock_window("Render::render 3");
846                 ArrayList<Asset*> *assets = packages->get_asset_list();
847                 if(load_mode == LOAD_PASTE)
848                         mwindow->clear(0);
849                 mwindow->load_assets(assets, 
850                         -1, 
851                         load_mode,
852                         0,
853                         0,
854                         mwindow->edl->session->labels_follow_edits,
855                         mwindow->edl->session->plugins_follow_edits);
856                 delete assets;
859                 mwindow->save_backup();
860                 mwindow->undo->update_undo(_("render"), LOAD_ALL);
861                 mwindow->update_plugin_guis();
862                 mwindow->gui->update(1, 
863                         2,
864                         1,
865                         1,
866                         1,
867                         1,
868                         0);
869                 mwindow->sync_parameters(CHANGE_ALL);
870                 mwindow->gui->unlock_window();
871         }
874 // Disable hourglass
875         if(mwindow)
876         {
877                 mwindow->gui->lock_window("Render::render 3");
878                 mwindow->gui->stop_hourglass();
879                 mwindow->gui->unlock_window();
880         }
882 //printf("Render::render 110\n");
883 // Need to restart because brender always stops before render.
884         if(mwindow)
885                 mwindow->restart_brender();
886         if(farm_server) delete farm_server;
887         delete command;
888         delete playback_config;
889         delete audio_cache;
890         delete video_cache;
891 // Must delete packages after server
892         delete packages;
893         in_progress = 0;
894         completion->unlock();
895 //printf("Render::render 120\n");
897         return result;
901 void Render::create_filename(char *path, 
902         char *default_path, 
903         int current_number,
904         int total_digits,
905         int number_start)
907         int i, j, k;
908         int len = strlen(default_path);
909         char printf_string[BCTEXTLEN];
910         int found_number = 0;
912         for(i = 0, j = 0; i < number_start; i++, j++)
913         {
914                 printf_string[j] = default_path[i];
915         }
917 // Found the number
918         sprintf(&printf_string[j], "%%0%dd", total_digits);
919         j = strlen(printf_string);
920         i += total_digits;
922 // Copy remainder of string
923         for( ; i < len; i++, j++)
924         {
925                 printf_string[j] = default_path[i];
926         }
927         printf_string[j] = 0;
928 // Print the printf argument to the path
929         sprintf(path, printf_string, current_number);
932 void Render::get_starting_number(char *path, 
933         int &current_number,
934         int &number_start, 
935         int &total_digits,
936         int min_digits)
938         int i, j;
939         int len = strlen(path);
940         char number_text[BCTEXTLEN];
941         char *ptr = 0;
942         char *ptr2 = 0;
944         total_digits = 0;
945         number_start = 0;
947 // Search for last /
948         ptr2 = strrchr(path, '/');
950 // Search for first 0 after last /.
951         if(ptr2)
952                 ptr = strchr(ptr2, '0');
954         if(ptr && isdigit(*ptr))
955         {
956                 number_start = ptr - path;
958 // Store the first number
959                 char *ptr2 = number_text;
960                 while(isdigit(*ptr))
961                         *ptr2++ = *ptr++;
962                 *ptr2++ = 0;
963                 current_number = atol(number_text);
964                 total_digits = strlen(number_text);
965         }
968 // No number found or number not long enough
969         if(total_digits < min_digits)
970         {
971                 current_number = 1;
972                 number_start = len;
973                 total_digits = min_digits;
974         }
983 int Render::load_defaults(Asset *asset)
985         strategy = mwindow->defaults->get("RENDER_STRATEGY", SINGLE_PASS);
986         load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOAD_NEW_TRACKS);
989         asset->load_defaults(mwindow->defaults, 
990                 "RENDER_", 
991                 1,
992                 1,
993                 1,
994                 1,
995                 1);
998         return 0;
1001 int Render::save_defaults(Asset *asset)
1003         mwindow->defaults->update("RENDER_STRATEGY", strategy);
1004         mwindow->defaults->update("RENDER_LOADMODE", load_mode);
1009         asset->save_defaults(mwindow->defaults, 
1010                 "RENDER_",
1011                 1,
1012                 1,
1013                 1,
1014                 1,
1015                 1);
1017         return 0;
1023 #define WIDTH 410
1024 #define HEIGHT 360
1027 RenderWindow::RenderWindow(MWindow *mwindow, Render *render, Asset *asset)
1028  : BC_Window(PROGRAM_NAME ": Render", 
1029         mwindow->gui->get_root_w(0, 1) / 2 - WIDTH / 2,
1030         mwindow->gui->get_root_h(1) / 2 - HEIGHT / 2,
1031         WIDTH, 
1032         HEIGHT,
1033         (int)BC_INFINITY,
1034         (int)BC_INFINITY,
1035         0,
1036         0,
1037         1)
1039         this->mwindow = mwindow;
1040         this->render = render;
1041         this->asset = asset;
1044 RenderWindow::~RenderWindow()
1046         delete format_tools;
1047         delete loadmode;
1052 int RenderWindow::create_objects()
1054         int x = 5, y = 5;
1055         add_subwindow(new BC_Title(x, 
1056                 y, 
1057                 (char*)((render->strategy == FILE_PER_LABEL || 
1058                                 render->strategy == FILE_PER_LABEL_FARM) ? 
1059                         _("Select the first file to render to:") : 
1060                         _("Select a file to render to:"))));
1061         y += 25;
1063         format_tools = new FormatTools(mwindow,
1064                                         this, 
1065                                         asset);
1066         format_tools->create_objects(x, 
1067                 y, 
1068                 1, 
1069                 1, 
1070                 1, 
1071                 1, 
1072                 0,
1073                 1,
1074                 0,
1075                 0,
1076                 &render->strategy,
1077                 0);
1079         loadmode = new LoadMode(mwindow, this, x, y, &render->load_mode, 1);
1080         loadmode->create_objects();
1082         add_subwindow(new BC_OKButton(this));
1083         add_subwindow(new BC_CancelButton(this));
1084         show_window();
1085         return 0;