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