fix [#27015] RNA Bug: Unpacking sounds with a long ID name fails: sound ID length...
[blender.git] / source / blender / editors / render / render_internal.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/render/render_internal.c
28  *  \ingroup edrend
29  */
30
31
32 #include <math.h>
33 #include <string.h>
34 #include <stddef.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math.h"
40 #include "BLI_threads.h"
41 #include "BLI_rand.h"
42 #include "BLI_utildefines.h"
43
44 #include "DNA_scene_types.h"
45
46 #include "BKE_blender.h"
47 #include "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_image.h"
50 #include "BKE_library.h"
51 #include "BKE_main.h"
52 #include "BKE_node.h"
53 #include "BKE_multires.h"
54 #include "BKE_report.h"
55 #include "BKE_sequencer.h"
56 #include "BKE_screen.h"
57
58 #include "WM_api.h"
59 #include "WM_types.h"
60
61 #include "ED_screen.h"
62 #include "ED_object.h"
63
64 #include "RE_pipeline.h"
65 #include "IMB_imbuf.h"
66 #include "IMB_imbuf_types.h"
67
68 #include "RNA_access.h"
69 #include "RNA_define.h"
70
71 #include "wm_window.h"
72
73 #include "render_intern.h"
74
75 static ScrArea *biggest_area(bContext *C);
76 static ScrArea *biggest_non_image_area(bContext *C);
77 static ScrArea *find_area_showing_r_result(bContext *C, wmWindow **win);
78 static ScrArea *find_area_image_empty(bContext *C);
79
80 /* called inside thread! */
81 void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect)
82 {
83         float x1, y1, *rectf= NULL;
84         int ymin, ymax, xmin, xmax;
85         int rymin, rxmin;
86         char *rectc;
87
88         /* if renrect argument, we only refresh scanlines */
89         if(renrect) {
90                 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
91                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
92                         return;
93
94                 /* xmin here is first subrect x coord, xmax defines subrect width */
95                 xmin = renrect->xmin + rr->crop;
96                 xmax = renrect->xmax - xmin + rr->crop;
97                 if (xmax<2) return;
98
99                 ymin= renrect->ymin + rr->crop;
100                 ymax= renrect->ymax - ymin + rr->crop;
101                 if(ymax<2)
102                         return;
103                 renrect->ymin= renrect->ymax;
104
105         }
106         else {
107                 xmin = ymin = rr->crop;
108                 xmax = rr->rectx - 2*rr->crop;
109                 ymax = rr->recty - 2*rr->crop;
110         }
111
112         /* xmin ymin is in tile coords. transform to ibuf */
113         rxmin= rr->tilerect.xmin + xmin;
114         if(rxmin >= ibuf->x) return;
115         rymin= rr->tilerect.ymin + ymin;
116         if(rymin >= ibuf->y) return;
117
118         if(rxmin + xmax > ibuf->x)
119                 xmax= ibuf->x - rxmin;
120         if(rymin + ymax > ibuf->y)
121                 ymax= ibuf->y - rymin;
122
123         if(xmax < 1 || ymax < 1) return;
124
125         /* find current float rect for display, first case is after composit... still weak */
126         if(rr->rectf)
127                 rectf= rr->rectf;
128         else {
129                 if(rr->rect32)
130                         return;
131                 else {
132                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
133                         rectf= rr->renlay->rectf;
134                 }
135         }
136         if(rectf==NULL) return;
137
138         if(ibuf->rect==NULL)
139                 imb_addrectImBuf(ibuf);
140         
141         rectf+= 4*(rr->rectx*ymin + xmin);
142         rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
143         
144         /* XXX make nice consistent functions for this */
145         if (scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)) {
146                 for(y1= 0; y1<ymax; y1++) {
147                         float *rf= rectf;
148                         float srgb[3];
149                         char *rc= rectc;
150                         const float dither = ibuf->dither / 255.0f;
151
152                         /* XXX temp. because crop offset */
153                         if( rectc >= (char *)(ibuf->rect)) {
154                                 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
155                                         const float d = (BLI_frand()-0.5f)*dither;
156                                         srgb[0]= d + linearrgb_to_srgb(rf[0]);
157                                         srgb[1]= d + linearrgb_to_srgb(rf[1]);
158                                         srgb[2]= d + linearrgb_to_srgb(rf[2]);
159
160                                         rc[0]= FTOCHAR(srgb[0]);
161                                         rc[1]= FTOCHAR(srgb[1]);
162                                         rc[2]= FTOCHAR(srgb[2]);
163                                         rc[3]= FTOCHAR(rf[3]);
164                                 }
165                         }
166                         rectf += 4*rr->rectx;
167                         rectc += 4*ibuf->x;
168                 }
169         } else {
170                 for(y1= 0; y1<ymax; y1++) {
171                         float *rf= rectf;
172                         char *rc= rectc;
173                         float rgb[3];
174                         const float dither = ibuf->dither / 255.0f;
175
176                         /* XXX temp. because crop offset */
177                         if( rectc >= (char *)(ibuf->rect)) {
178                                 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
179                                         const float d = (BLI_frand()-0.5f)*dither;
180                                         
181                                         rgb[0] = d + rf[0];
182                                         rgb[1] = d + rf[1];
183                                         rgb[2] = d + rf[2];
184                                         
185                                         rc[0]= FTOCHAR(rgb[0]);
186                                         rc[1]= FTOCHAR(rgb[1]);
187                                         rc[2]= FTOCHAR(rgb[2]);
188                                         rc[3]= FTOCHAR(rf[3]);
189                                 }
190                         }
191                         rectf += 4*rr->rectx;
192                         rectc += 4*ibuf->x;
193                 }
194         }       
195 }
196
197 /* new window uses x,y to set position */
198 void screen_set_image_output(bContext *C, int mx, int my)
199 {
200         wmWindow *win= CTX_wm_window(C);
201         Scene *scene= CTX_data_scene(C);
202         ScrArea *sa= NULL;
203         SpaceImage *sima;
204         int area_was_image=0;
205
206         if(scene->r.displaymode==R_OUTPUT_NONE)
207                 return;
208         
209         if(scene->r.displaymode==R_OUTPUT_WINDOW) {
210                 rcti rect;
211                 int sizex, sizey;
212
213                 sizex= 10 + (scene->r.xsch*scene->r.size)/100;
214                 sizey= 40 + (scene->r.ysch*scene->r.size)/100;
215
216                 /* arbitrary... miniature image window views don't make much sense */
217                 if(sizex < 320) sizex= 320;
218                 if(sizey < 256) sizey= 256;
219
220                 /* XXX some magic to calculate postition */
221                 rect.xmin= mx + win->posx - sizex/2;
222                 rect.ymin= my + win->posy - sizey/2;
223                 rect.xmax= rect.xmin + sizex;
224                 rect.ymax= rect.ymin + sizey;
225
226                 /* changes context! */
227                 WM_window_open_temp(C, &rect, WM_WINDOW_RENDER);
228
229                 sa= CTX_wm_area(C);
230         }
231         else if(scene->r.displaymode==R_OUTPUT_SCREEN) {
232                 if (CTX_wm_area(C) && CTX_wm_area(C)->spacetype == SPACE_IMAGE)
233                         area_was_image = 1;
234
235                 /* this function returns with changed context */
236                 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
237                 sa= CTX_wm_area(C);
238         }
239
240         if(!sa) {
241                 sa= find_area_showing_r_result(C, &win); 
242                 if(sa==NULL)
243                         sa= find_area_image_empty(C);
244                 
245                 /* if area found in other window, we make that one show in front */
246                 if(win && win!=CTX_wm_window(C))
247                         wm_window_raise(win);
248
249                 if(sa==NULL) {
250                         /* find largest open non-image area */
251                         sa= biggest_non_image_area(C);
252                         if(sa) {
253                                 ED_area_newspace(C, sa, SPACE_IMAGE);
254                                 sima= sa->spacedata.first;
255
256                                 /* makes ESC go back to prev space */
257                                 sima->flag |= SI_PREVSPACE;
258                         }
259                         else {
260                                 /* use any area of decent size */
261                                 sa= biggest_area(C);
262                                 if(sa->spacetype!=SPACE_IMAGE) {
263                                         // XXX newspace(sa, SPACE_IMAGE);
264                                         sima= sa->spacedata.first;
265
266                                         /* makes ESC go back to prev space */
267                                         sima->flag |= SI_PREVSPACE;
268                                 }
269                         }
270                 }
271         }
272         sima= sa->spacedata.first;
273
274         /* get the correct image, and scale it */
275         sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
276
277
278         /* if we're rendering to full screen, set appropriate hints on image editor
279          * so it can restore properly on pressing esc */
280         if(sa->full) {
281                 sima->flag |= SI_FULLWINDOW;
282
283                 /* Tell the image editor to revert to previous space in space list on close
284                  * _only_ if it wasn't already an image editor when the render was invoked */
285                 if (area_was_image == 0)
286                         sima->flag |= SI_PREVSPACE;
287                 else {
288                         /* Leave it alone so the image editor will just go back from
289                          * full screen to the original tiled setup */
290                         ;
291                 }
292
293         }
294
295 }
296
297
298 /* ****************************** render invoking ***************** */
299
300 /* set callbacks, exported to sequence render too.
301  Only call in foreground (UI) renders. */
302
303 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
304 /* window as the last possible alternative.                                                                        */
305 static ScrArea *biggest_non_image_area(bContext *C)
306 {
307         bScreen *sc= CTX_wm_screen(C);
308         ScrArea *sa, *big= NULL;
309         int size, maxsize= 0, bwmaxsize= 0;
310         short foundwin= 0;
311
312         for(sa= sc->areabase.first; sa; sa= sa->next) {
313                 if(sa->winx > 30 && sa->winy > 30) {
314                         size= sa->winx*sa->winy;
315                         if(sa->spacetype == SPACE_BUTS) {
316                                 if(foundwin == 0 && size > bwmaxsize) {
317                                         bwmaxsize= size;
318                                         big= sa;
319                                 }
320                         }
321                         else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
322                                 maxsize= size;
323                                 big= sa;
324                                 foundwin= 1;
325                         }
326                 }
327         }
328
329         return big;
330 }
331
332 static ScrArea *biggest_area(bContext *C)
333 {
334         bScreen *sc= CTX_wm_screen(C);
335         ScrArea *sa, *big= NULL;
336         int size, maxsize= 0;
337
338         for(sa= sc->areabase.first; sa; sa= sa->next) {
339                 size= sa->winx*sa->winy;
340                 if(size > maxsize) {
341                         maxsize= size;
342                         big= sa;
343                 }
344         }
345         return big;
346 }
347
348
349 static ScrArea *find_area_showing_r_result(bContext *C, wmWindow **win)
350 {
351         wmWindowManager *wm= CTX_wm_manager(C);
352         ScrArea *sa = NULL;
353         SpaceImage *sima;
354
355         /* find an imagewindow showing render result */
356         for(*win=wm->windows.first; *win; *win= (*win)->next) {
357                 for(sa= (*win)->screen->areabase.first; sa; sa= sa->next) {
358                         if(sa->spacetype==SPACE_IMAGE) {
359                                 sima= sa->spacedata.first;
360                                 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
361                                         break;
362                         }
363                 }
364                 if(sa)
365                         break;
366         }
367         
368         return sa;
369 }
370
371 static ScrArea *find_area_image_empty(bContext *C)
372 {
373         bScreen *sc= CTX_wm_screen(C);
374         ScrArea *sa;
375         SpaceImage *sima;
376
377         /* find an imagewindow showing render result */
378         for(sa=sc->areabase.first; sa; sa= sa->next) {
379                 if(sa->spacetype==SPACE_IMAGE) {
380                         sima= sa->spacedata.first;
381                         if(!sima->image)
382                                 break;
383                 }
384         }
385         return sa;
386 }
387
388 #if 0 // XXX not used
389 static ScrArea *find_empty_image_area(bContext *C)
390 {
391         bScreen *sc= CTX_wm_screen(C);
392         ScrArea *sa;
393         SpaceImage *sima;
394
395         /* find an imagewindow showing render result */
396         for(sa=sc->areabase.first; sa; sa= sa->next) {
397                 if(sa->spacetype==SPACE_IMAGE) {
398                         sima= sa->spacedata.first;
399                         if(!sima->image)
400                                 break;
401                 }
402         }
403         return sa;
404 }
405 #endif // XXX not used
406
407 static void render_error_reports(void *reports, const char *str)
408 {
409         BKE_report(reports, RPT_ERROR, str);
410 }
411
412 /* executes blocking render */
413 static int screen_render_exec(bContext *C, wmOperator *op)
414 {
415         Scene *scene= CTX_data_scene(C);
416         Render *re= RE_NewRender(scene->id.name);
417         Image *ima;
418         View3D *v3d= CTX_wm_view3d(C);
419         Main *mainp= CTX_data_main(C);
420         unsigned int lay= (v3d)? v3d->lay: scene->lay;
421         const short is_animation= RNA_boolean_get(op->ptr, "animation");
422         const short is_write_still= RNA_boolean_get(op->ptr, "write_still");
423
424         if(!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.imtype)) {
425                 BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected.");
426                 return OPERATOR_CANCELLED;
427         }
428
429         if(re==NULL) {
430                 re= RE_NewRender(scene->id.name);
431         }
432         
433         G.afbreek= 0;
434         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
435         RE_error_cb(re, op->reports, render_error_reports);
436
437         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
438         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
439         BKE_image_backup_render(scene, ima);
440
441         /* cleanup sequencer caches before starting user triggered render.
442            otherwise, invalidated cache entries can make their way into
443            the output rendering. We can't put that into RE_BlenderFrame,
444            since sequence rendering can call that recursively... (peter) */
445         seq_stripelem_cache_cleanup();
446
447         if(is_animation)
448                 RE_BlenderAnim(re, mainp, scene, lay, scene->r.sfra, scene->r.efra, scene->r.frame_step, op->reports);
449         else
450                 RE_BlenderFrame(re, mainp, scene, NULL, lay, scene->r.cfra, is_write_still);
451
452         // no redraw needed, we leave state as we entered it
453         ED_update_for_newframe(mainp, scene, CTX_wm_screen(C), 1);
454
455         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
456
457         return OPERATOR_FINISHED;
458 }
459
460 typedef struct RenderJob {
461         Main *main;
462         Scene *scene;
463         Render *re;
464         wmWindow *win;
465         SceneRenderLayer *srl;
466         int lay;
467         short anim, write_still;
468         Image *image;
469         ImageUser iuser;
470         short *stop;
471         short *do_update;
472         float *progress;
473         ReportList *reports;
474 } RenderJob;
475
476 static void render_freejob(void *rjv)
477 {
478         RenderJob *rj= rjv;
479
480         MEM_freeN(rj);
481 }
482
483 /* str is IMA_MAX_RENDER_TEXT in size */
484 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
485 {
486         char info_time_str[32]; // used to be extern to header_info.c
487         uintptr_t mem_in_use, mmap_in_use, peak_memory;
488         float megs_used_memory, mmap_used_memory, megs_peak_memory;
489         char *spos= str;
490
491         mem_in_use= MEM_get_memory_in_use();
492         mmap_in_use= MEM_get_mapped_memory_in_use();
493         peak_memory = MEM_get_peak_memory();
494
495         megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
496         mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
497         megs_peak_memory = (peak_memory)/(1024.0*1024.0);
498
499         if(scene->lay & 0xFF000000)
500                 spos+= sprintf(spos, "Localview | ");
501         else if(scene->r.scemode & R_SINGLE_LAYER)
502                 spos+= sprintf(spos, "Single Layer | ");
503
504         if(rs->statstr) {
505                 spos+= sprintf(spos, "%s ", rs->statstr);
506         }
507         else {
508                 spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
509                 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
510                 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
511                 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM, peak %.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory, megs_peak_memory);
512
513                 if(rs->curfield)
514                         spos+= sprintf(spos, "Field %d ", rs->curfield);
515                 if(rs->curblur)
516                         spos+= sprintf(spos, "Blur %d ", rs->curblur);
517         }
518
519         BLI_timestr(rs->lastframetime, info_time_str);
520         spos+= sprintf(spos, "Time:%s ", info_time_str);
521
522         if(rs->infostr && rs->infostr[0])
523                 spos+= sprintf(spos, "| %s ", rs->infostr);
524
525         /* very weak... but 512 characters is quite safe */
526         if(spos >= str+IMA_MAX_RENDER_TEXT)
527                 if (G.f & G_DEBUG)
528                         printf("WARNING! renderwin text beyond limit \n");
529
530 }
531
532 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
533 {
534         RenderJob *rj= rjv;
535         RenderResult *rr;
536
537         rr= RE_AcquireResultRead(rj->re);
538
539         if(rr) {
540                 /* malloc OK here, stats_draw is not in tile threads */
541                 if(rr->text==NULL)
542                         rr->text= MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
543
544                 make_renderinfo_string(rs, rj->scene, rr->text);
545         }
546
547         RE_ReleaseResult(rj->re);
548
549         /* make jobs timer to send notifier */
550         *(rj->do_update)= 1;
551
552 }
553
554 static void render_progress_update(void *rjv, float progress)
555 {
556         RenderJob *rj= rjv;
557         
558         if (rj->progress)
559                 *rj->progress = progress;
560 }
561
562 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
563 {
564         RenderJob *rj= rjv;
565         Image *ima= rj->image;
566         ImBuf *ibuf;
567         void *lock;
568
569         /* only update if we are displaying the slot being rendered */
570         if(ima->render_slot != ima->last_render_slot)
571                 return;
572
573         ibuf= BKE_image_acquire_ibuf(ima, &rj->iuser, &lock);
574         if(ibuf) {
575                 image_buffer_rect_update(rj->scene, rr, ibuf, renrect);
576
577                 /* make jobs timer to send notifier */
578                 *(rj->do_update)= 1;
579         }
580         BKE_image_release_ibuf(ima, lock);
581 }
582
583 static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
584 {
585         RenderJob *rj= rjv;
586
587         rj->stop= stop;
588         rj->do_update= do_update;
589         rj->progress= progress;
590
591         if(rj->anim)
592                 RE_BlenderAnim(rj->re, rj->main, rj->scene, rj->lay, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step, rj->reports);
593         else
594                 RE_BlenderFrame(rj->re, rj->main, rj->scene, rj->srl, rj->lay, rj->scene->r.cfra, rj->write_still);
595 }
596
597 static void render_endjob(void *rjv)
598 {
599         RenderJob *rj= rjv;     
600
601         /* this render may be used again by the sequencer without the active 'Render' where the callbacks
602          * would be re-assigned. assign dummy callbacks to avoid referencing freed renderjobs bug [#24508] */
603         RE_InitRenderCB(rj->re);
604
605         if(rj->main != G.main)
606                 free_main(rj->main);
607
608         /* else the frame will not update for the original value */
609         if(!(rj->scene->r.scemode & R_NO_FRAME_UPDATE))
610                 ED_update_for_newframe(G.main, rj->scene, rj->win->screen, 1);
611         
612         /* XXX above function sets all tags in nodes */
613         ntreeClearTags(rj->scene->nodetree);
614         
615         /* potentially set by caller */
616         rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE;
617         
618         if(rj->srl) {
619                 NodeTagIDChanged(rj->scene->nodetree, &rj->scene->id);
620                 WM_main_add_notifier(NC_NODE|NA_EDITED, rj->scene);
621         }
622         
623         /* XXX render stability hack */
624         G.rendering = 0;
625         WM_main_add_notifier(NC_WINDOW, NULL);
626 }
627
628 /* called by render, check job 'stop' value or the global */
629 static int render_breakjob(void *rjv)
630 {
631         RenderJob *rj= rjv;
632
633         if(G.afbreek)
634                 return 1;
635         if(rj->stop && *(rj->stop))
636                 return 1;
637         return 0;
638 }
639
640 /* runs in thread, no cursor setting here works. careful with notifiers too (malloc conflicts) */
641 /* maybe need a way to get job send notifer? */
642 static void render_drawlock(void *UNUSED(rjv), int lock)
643 {
644         BKE_spacedata_draw_locks(lock);
645         
646 }
647
648 /* catch esc */
649 static int screen_render_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
650 {
651         /* no running blender, remove handler and pass through */
652         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C))) {
653                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
654         }
655
656         /* running render */
657         switch (event->type) {
658                 case ESCKEY:
659                         return OPERATOR_RUNNING_MODAL;
660                         break;
661         }
662         return OPERATOR_PASS_THROUGH;
663 }
664
665 /* using context, starts job */
666 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
667 {
668         /* new render clears all callbacks */
669         Main *mainp;
670         Scene *scene= CTX_data_scene(C);
671         SceneRenderLayer *srl=NULL;
672         bScreen *screen= CTX_wm_screen(C);
673         View3D *v3d= CTX_wm_view3d(C);
674         Render *re;
675         wmJob *steve;
676         RenderJob *rj;
677         Image *ima;
678         int jobflag;
679         const short is_animation= RNA_boolean_get(op->ptr, "animation");
680         const short is_write_still= RNA_boolean_get(op->ptr, "write_still");
681         
682         /* only one render job at a time */
683         if(WM_jobs_test(CTX_wm_manager(C), scene))
684                 return OPERATOR_CANCELLED;
685
686         if(!RE_is_rendering_allowed(scene, op->reports, render_error_reports)) {
687                 return OPERATOR_CANCELLED;
688         }
689
690         if(!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.imtype)) {
691                 BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected.");
692                 return OPERATOR_CANCELLED;
693         }       
694         
695         /* stop all running jobs, currently previews frustrate Render */
696         WM_jobs_stop_all(CTX_wm_manager(C));
697
698         /* get main */
699         if(G.rt == 101) {
700                 /* thread-safety experiment, copy main from the undo buffer */
701                 mainp= BKE_undo_get_main(&scene);
702         }
703         else
704                 mainp= CTX_data_main(C);
705
706         /* cancel animation playback */
707         if (screen->animtimer)
708                 ED_screen_animation_play(C, 0, 0);
709         
710         /* handle UI stuff */
711         WM_cursor_wait(1);
712
713         /* flush multires changes (for sculpt) */
714         multires_force_render_update(CTX_data_active_object(C));
715
716         /* cleanup sequencer caches before starting user triggered render.
717            otherwise, invalidated cache entries can make their way into
718            the output rendering. We can't put that into RE_BlenderFrame,
719            since sequence rendering can call that recursively... (peter) */
720         seq_stripelem_cache_cleanup();
721
722         /* get editmode results */
723         ED_object_exit_editmode(C, 0);  /* 0 = does not exit editmode */
724
725         // store spare
726         // get view3d layer, local layer, make this nice api call to render
727         // store spare
728
729         /* ensure at least 1 area shows result */
730         screen_set_image_output(C, event->x, event->y);
731
732         jobflag= WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS;
733         
734         /* single layer re-render */
735         if(RNA_property_is_set(op->ptr, "layer")) {
736                 SceneRenderLayer *rl;
737                 Scene *scn;
738                 char scene_name[19], rl_name[RE_MAXNAME];
739
740                 RNA_string_get(op->ptr, "layer", rl_name);
741                 RNA_string_get(op->ptr, "scene", scene_name);
742
743                 scn = (Scene *)BLI_findstring(&mainp->scene, scene_name, offsetof(ID, name) + 2);
744                 rl = (SceneRenderLayer *)BLI_findstring(&scene->r.layers, rl_name, offsetof(SceneRenderLayer, name));
745                 
746                 if (scn && rl) {
747                         scene = scn;
748                         srl = rl;
749                 }
750                 jobflag |= WM_JOB_SUSPEND;
751         }
752
753         /* job custom data */
754         rj= MEM_callocN(sizeof(RenderJob), "render job");
755         rj->main= mainp;
756         rj->scene= scene;
757         rj->win= CTX_wm_window(C);
758         rj->srl = srl;
759         rj->lay = (v3d)? v3d->lay: scene->lay;
760         rj->anim= is_animation;
761         rj->write_still= is_write_still && !is_animation;
762         rj->iuser.scene= scene;
763         rj->iuser.ok= 1;
764         rj->reports= op->reports;
765
766         /* setup job */
767         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Render", jobflag);
768         WM_jobs_customdata(steve, rj, render_freejob);
769         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
770         WM_jobs_callbacks(steve, render_startjob, NULL, NULL, render_endjob);
771
772         /* get a render result image, and make sure it is empty */
773         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
774         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
775         BKE_image_backup_render(rj->scene, ima);
776         rj->image= ima;
777
778         /* setup new render */
779         re= RE_NewRender(scene->id.name);
780         RE_test_break_cb(re, rj, render_breakjob);
781         RE_draw_lock_cb(re, rj, render_drawlock);
782         RE_display_draw_cb(re, rj, image_rect_update);
783         RE_stats_draw_cb(re, rj, image_renderinfo_cb);
784         RE_progress_cb(re, rj, render_progress_update);
785
786         rj->re= re;
787         G.afbreek= 0;
788
789         RE_error_cb(re, op->reports, render_error_reports);
790
791         WM_jobs_start(CTX_wm_manager(C), steve);
792
793         WM_cursor_wait(0);
794         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
795
796         /* we set G.rendering here already instead of only in the job, this ensure
797            main loop or other scene updates are disabled in time, since they may
798            have started before the job thread */
799         G.rendering = 1;
800
801         /* add modal handler for ESC */
802         WM_event_add_modal_handler(C, op);
803
804         return OPERATOR_RUNNING_MODAL;
805 }
806
807
808 /* contextual render, using current scene, view3d? */
809 void RENDER_OT_render(wmOperatorType *ot)
810 {
811         /* identifiers */
812         ot->name= "Render";
813         ot->description= "Render active scene";
814         ot->idname= "RENDER_OT_render";
815
816         /* api callbacks */
817         ot->invoke= screen_render_invoke;
818         ot->modal= screen_render_modal;
819         ot->exec= screen_render_exec;
820
821         /*ot->poll= ED_operator_screenactive;*/ /* this isnt needed, causes failer in background mode */
822
823         RNA_def_boolean(ot->srna, "animation", 0, "Animation", "Render files from the animation range of this scene");
824         RNA_def_boolean(ot->srna, "write_still", 0, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)");
825         RNA_def_string(ot->srna, "layer", "", RE_MAXNAME, "Render Layer", "Single render layer to re-render");
826         RNA_def_string(ot->srna, "scene", "", sizeof(((ID *)NULL)->name)-2, "Scene", "Re-render single layer in this scene");
827 }
828
829 /* ****************************** opengl render *************************** */
830
831
832 /* *********************** cancel render viewer *************** */
833
834 static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
835 {
836         wmWindow *win= CTX_wm_window(C);
837         ScrArea *sa= CTX_wm_area(C);
838         SpaceImage *sima= sa->spacedata.first;
839
840         /* test if we have a temp screen in front */
841         if(CTX_wm_window(C)->screen->temp) {
842                 wm_window_lower(CTX_wm_window(C));
843                 return OPERATOR_FINISHED;
844         }
845         /* determine if render already shows */
846         else if(sima->flag & SI_PREVSPACE) {
847                 sima->flag &= ~SI_PREVSPACE;
848
849                 if(sima->flag & SI_FULLWINDOW) {
850                         sima->flag &= ~SI_FULLWINDOW;
851                         ED_screen_full_prevspace(C, sa);
852                 }
853                 else
854                         ED_area_prevspace(C, sa);
855
856                 return OPERATOR_FINISHED;
857         }
858         else if(sima->flag & SI_FULLWINDOW) {
859                 sima->flag &= ~SI_FULLWINDOW;
860                 ED_screen_full_toggle(C, win, sa);
861                 return OPERATOR_FINISHED;
862         }
863
864         return OPERATOR_PASS_THROUGH;
865 }
866
867 void RENDER_OT_view_cancel(struct wmOperatorType *ot)
868 {
869         /* identifiers */
870         ot->name= "Cancel Render View";
871         ot->description= "Cancel show render view";
872         ot->idname= "RENDER_OT_view_cancel";
873
874         /* api callbacks */
875         ot->exec= render_view_cancel_exec;
876         ot->poll= ED_operator_image_active;
877 }
878
879 /* *********************** show render viewer *************** */
880
881 static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(unused), wmEvent *event)
882 {
883         wmWindow *wincur = CTX_wm_window(C);
884         
885         /* test if we have currently a temp screen active */
886         if(wincur->screen->temp) {
887                 wm_window_lower(wincur);
888         }
889         else { 
890                 wmWindow *win, *winshow;
891                 ScrArea *sa= find_area_showing_r_result(C, &winshow);
892                 
893                 /* is there another window showing result? */
894                 for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
895                         if(win->screen->temp || (win==winshow && winshow!=wincur)) {
896                                 wm_window_raise(win);
897                                 return OPERATOR_FINISHED;
898                         }
899                 }
900                 
901                 /* determine if render already shows */
902                 if(sa) {
903                         /* but don't close it when rendering */
904                         if(!G.rendering) {
905                                 SpaceImage *sima= sa->spacedata.first;
906
907                                 if(sima->flag & SI_PREVSPACE) {
908                                         sima->flag &= ~SI_PREVSPACE;
909
910                                         if(sima->flag & SI_FULLWINDOW) {
911                                                 sima->flag &= ~SI_FULLWINDOW;
912                                                 ED_screen_full_prevspace(C, sa);
913                                         }
914                                         else if(sima->next) {
915                                                 /* workaround for case of double prevspace, render window
916                                                    with a file browser on top of it (same as in ED_area_prevspace) */
917                                                 if(sima->next->spacetype == SPACE_FILE && sima->next->next)
918                                                         ED_area_newspace(C, sa, sima->next->next->spacetype);
919                                                 else
920                                                         ED_area_newspace(C, sa, sima->next->spacetype);
921                                                 ED_area_tag_redraw(sa);
922                                         }
923                                 }
924                         }
925                 }
926                 else {
927                         screen_set_image_output(C, event->x, event->y);
928                 }
929         }
930
931         return OPERATOR_FINISHED;
932 }
933
934 void RENDER_OT_view_show(struct wmOperatorType *ot)
935 {
936         /* identifiers */
937         ot->name= "Show/Hide Render View";
938         ot->description= "Toggle show render view";
939         ot->idname= "RENDER_OT_view_show";
940
941         /* api callbacks */
942         ot->invoke= render_view_show_invoke;
943         ot->poll= ED_operator_screenactive;
944 }