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