b5392f6dede3d1a042a8bb94d9f86668560ed0ed
[blender-staging.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         Main *mainp= G.main; //BKE_undo_get_main(&scene);
407         int lay= (v3d)? v3d->lay: scene->lay;
408
409         if(re==NULL) {
410                 re= RE_NewRender(scene->id.name);
411         }
412         
413         G.afbreek= 0;
414         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
415         RE_error_cb(re, op->reports, render_error_reports);
416
417         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
418         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
419         BKE_image_backup_render(scene, ima);
420
421         if(RNA_boolean_get(op->ptr, "animation"))
422                 RE_BlenderAnim(re, mainp, scene, lay, scene->r.sfra, scene->r.efra, scene->r.frame_step, op->reports);
423         else
424                 RE_BlenderFrame(re, mainp, scene, NULL, lay, scene->r.cfra);
425
426         //free_main(mainp);
427
428         // no redraw needed, we leave state as we entered it
429         ED_update_for_newframe(C, 1);
430
431         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
432
433         return OPERATOR_FINISHED;
434 }
435
436 typedef struct RenderJob {
437         Scene *scene;
438         Render *re;
439         wmWindow *win;
440         SceneRenderLayer *srl;
441         int lay;
442         int anim;
443         Image *image;
444         ImageUser iuser;
445         short *stop;
446         short *do_update;
447         float *progress;
448         ReportList *reports;
449 } RenderJob;
450
451 static void render_freejob(void *rjv)
452 {
453         RenderJob *rj= rjv;
454
455         MEM_freeN(rj);
456 }
457
458 /* str is IMA_MAX_RENDER_TEXT in size */
459 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
460 {
461         char info_time_str[32]; // used to be extern to header_info.c
462         uintptr_t mem_in_use, mmap_in_use, peak_memory;
463         float megs_used_memory, mmap_used_memory, megs_peak_memory;
464         char *spos= str;
465
466         mem_in_use= MEM_get_memory_in_use();
467         mmap_in_use= MEM_get_mapped_memory_in_use();
468         peak_memory = MEM_get_peak_memory();
469
470         megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
471         mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
472         megs_peak_memory = (peak_memory)/(1024.0*1024.0);
473
474         if(scene->lay & 0xFF000000)
475                 spos+= sprintf(spos, "Localview | ");
476         else if(scene->r.scemode & R_SINGLE_LAYER)
477                 spos+= sprintf(spos, "Single Layer | ");
478
479         if(rs->statstr) {
480                 spos+= sprintf(spos, "%s ", rs->statstr);
481         }
482         else {
483                 spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
484                 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
485                 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
486                 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM, peak %.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory, megs_peak_memory);
487
488                 if(rs->curfield)
489                         spos+= sprintf(spos, "Field %d ", rs->curfield);
490                 if(rs->curblur)
491                         spos+= sprintf(spos, "Blur %d ", rs->curblur);
492         }
493
494         BLI_timestr(rs->lastframetime, info_time_str);
495         spos+= sprintf(spos, "Time:%s ", info_time_str);
496
497         if(rs->infostr && rs->infostr[0])
498                 spos+= sprintf(spos, "| %s ", rs->infostr);
499
500         /* very weak... but 512 characters is quite safe */
501         if(spos >= str+IMA_MAX_RENDER_TEXT)
502                 if (G.f & G_DEBUG)
503                         printf("WARNING! renderwin text beyond limit \n");
504
505 }
506
507 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
508 {
509         RenderJob *rj= rjv;
510         RenderResult *rr;
511
512         rr= RE_AcquireResultRead(rj->re);
513
514         if(rr) {
515                 /* malloc OK here, stats_draw is not in tile threads */
516                 if(rr->text==NULL)
517                         rr->text= MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
518
519                 make_renderinfo_string(rs, rj->scene, rr->text);
520         }
521
522         RE_ReleaseResult(rj->re);
523
524         /* make jobs timer to send notifier */
525         *(rj->do_update)= 1;
526
527 }
528
529 static void render_progress_update(void *rjv, float progress)
530 {
531         RenderJob *rj= rjv;
532         
533         if (rj->progress)
534                 *rj->progress = progress;
535 }
536
537 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
538 {
539         RenderJob *rj= rjv;
540         Image *ima= rj->image;
541         ImBuf *ibuf;
542         void *lock;
543
544         /* only update if we are displaying the slot being rendered */
545         if(ima->render_slot != ima->last_render_slot)
546                 return;
547
548         ibuf= BKE_image_acquire_ibuf(ima, &rj->iuser, &lock);
549         if(ibuf) {
550                 image_buffer_rect_update(rj->scene, rr, ibuf, renrect);
551
552                 /* make jobs timer to send notifier */
553                 *(rj->do_update)= 1;
554         }
555         BKE_image_release_ibuf(ima, lock);
556 }
557
558 static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
559 {
560         RenderJob *rj= rjv;
561         Main *mainp= G.main; //BKE_undo_get_main(&rj->scene);
562
563         rj->stop= stop;
564         rj->do_update= do_update;
565         rj->progress= progress;
566
567         if(rj->anim)
568                 RE_BlenderAnim(rj->re, mainp, rj->scene, rj->lay, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step, rj->reports);
569         else
570                 RE_BlenderFrame(rj->re, mainp, rj->scene, rj->srl, rj->lay, rj->scene->r.cfra);
571
572         //free_main(mainp);
573 }
574
575 static void render_endjob(void *rjv)
576 {
577         /* XXX render stability hack */
578         G.rendering = 0;
579         WM_main_add_notifier(NC_WINDOW, NULL);
580 }
581
582 /* called by render, check job 'stop' value or the global */
583 static int render_breakjob(void *rjv)
584 {
585         RenderJob *rj= rjv;
586
587         if(G.afbreek)
588                 return 1;
589         if(rj->stop && *(rj->stop))
590                 return 1;
591         return 0;
592 }
593
594 /* catch esc */
595 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
596 {
597         /* no running blender, remove handler and pass through */
598         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C))) {
599                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
600         }
601
602         /* running render */
603         switch (event->type) {
604                 case ESCKEY:
605                         return OPERATOR_RUNNING_MODAL;
606                         break;
607         }
608         return OPERATOR_PASS_THROUGH;
609 }
610
611 /* using context, starts job */
612 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
613 {
614         /* new render clears all callbacks */
615         Scene *scene= CTX_data_scene(C);
616         SceneRenderLayer *srl=NULL;
617         bScreen *screen= CTX_wm_screen(C);
618         View3D *v3d= CTX_wm_view3d(C);
619         Render *re;
620         wmJob *steve;
621         RenderJob *rj;
622         Image *ima;
623
624         /* only one render job at a time */
625         if(WM_jobs_test(CTX_wm_manager(C), scene))
626                 return OPERATOR_CANCELLED;
627
628         /* stop all running jobs, currently previews frustrate Render */
629         WM_jobs_stop_all(CTX_wm_manager(C));
630
631         /* cancel animation playback */
632         if (screen->animtimer)
633                 ED_screen_animation_play(C, 0, 0);
634         
635         /* handle UI stuff */
636         WM_cursor_wait(1);
637
638         /* flush multires changes (for sculpt) */
639         multires_force_render_update(CTX_data_active_object(C));
640
641         /* get editmode results */
642         ED_object_exit_editmode(C, 0);  /* 0 = does not exit editmode */
643
644         // store spare
645         // get view3d layer, local layer, make this nice api call to render
646         // store spare
647
648         /* ensure at least 1 area shows result */
649         screen_set_image_output(C, event->x, event->y);
650
651         /* single layer re-render */
652         if(RNA_property_is_set(op->ptr, "layer")) {
653                 SceneRenderLayer *rl;
654                 Scene *scn;
655                 char scene_name[19], rl_name[RE_MAXNAME];
656
657                 RNA_string_get(op->ptr, "layer", rl_name);
658                 RNA_string_get(op->ptr, "scene", scene_name);
659
660                 scn = (Scene *)BLI_findstring(&CTX_data_main(C)->scene, scene_name, offsetof(ID, name) + 2);
661                 rl = (SceneRenderLayer *)BLI_findstring(&scene->r.layers, rl_name, offsetof(SceneRenderLayer, name));
662
663                 if (scn && rl) {
664                         scene = scn;
665                         srl = rl;
666                 }
667         }
668
669         /* job custom data */
670         rj= MEM_callocN(sizeof(RenderJob), "render job");
671         rj->scene= scene;
672         rj->win= CTX_wm_window(C);
673         rj->srl = srl;
674         rj->lay = (v3d)? v3d->lay: scene->lay;
675         rj->anim= RNA_boolean_get(op->ptr, "animation");
676         rj->iuser.scene= scene;
677         rj->iuser.ok= 1;
678         rj->reports= op->reports;
679
680         /* setup job */
681         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Render", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS);
682         WM_jobs_customdata(steve, rj, render_freejob);
683         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
684         WM_jobs_callbacks(steve, render_startjob, NULL, NULL, render_endjob);
685
686         /* get a render result image, and make sure it is empty */
687         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
688         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
689         BKE_image_backup_render(rj->scene, ima);
690         rj->image= ima;
691
692         /* setup new render */
693         re= RE_NewRender(scene->id.name);
694         RE_test_break_cb(re, rj, render_breakjob);
695         RE_display_draw_cb(re, rj, image_rect_update);
696         RE_stats_draw_cb(re, rj, image_renderinfo_cb);
697         RE_progress_cb(re, rj, render_progress_update);
698
699         rj->re= re;
700         G.afbreek= 0;
701
702         RE_error_cb(re, op->reports, render_error_reports);
703
704         WM_jobs_start(CTX_wm_manager(C), steve);
705
706         WM_cursor_wait(0);
707         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
708
709         /* we set G.rendering here already instead of only in the job, this ensure
710            main loop or other scene updates are disabled in time, since they may
711            have started before the job thread */
712         G.rendering = 1;
713
714         /* add modal handler for ESC */
715         WM_event_add_modal_handler(C, op);
716
717         return OPERATOR_RUNNING_MODAL;
718 }
719
720
721 /* contextual render, using current scene, view3d? */
722 void RENDER_OT_render(wmOperatorType *ot)
723 {
724         /* identifiers */
725         ot->name= "Render";
726         ot->description= "Render active scene";
727         ot->idname= "RENDER_OT_render";
728
729         /* api callbacks */
730         ot->invoke= screen_render_invoke;
731         ot->modal= screen_render_modal;
732         ot->exec= screen_render_exec;
733
734         ot->poll= ED_operator_screenactive;
735
736         RNA_def_boolean(ot->srna, "animation", 0, "Animation", "");
737         RNA_def_string(ot->srna, "layer", "", RE_MAXNAME, "Render Layer", "Single render layer to re-render");
738         RNA_def_string(ot->srna, "scene", "", 19, "Scene", "Re-render single layer in this scene");
739 }
740
741 /* ****************************** opengl render *************************** */
742
743
744 /* *********************** cancel render viewer *************** */
745
746 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
747 {
748         wmWindow *win= CTX_wm_window(C);
749         ScrArea *sa= CTX_wm_area(C);
750         SpaceImage *sima= sa->spacedata.first;
751
752         /* test if we have a temp screen in front */
753         if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
754                 wm_window_lower(CTX_wm_window(C));
755                 return OPERATOR_FINISHED;
756         }
757         /* determine if render already shows */
758         else if(sima->flag & SI_PREVSPACE) {
759                 sima->flag &= ~SI_PREVSPACE;
760
761                 if(sima->flag & SI_FULLWINDOW) {
762                         sima->flag &= ~SI_FULLWINDOW;
763                         ED_screen_full_prevspace(C, sa);
764                 }
765                 else
766                         ED_area_prevspace(C, sa);
767
768                 return OPERATOR_FINISHED;
769         }
770         else if(sima->flag & SI_FULLWINDOW) {
771                 sima->flag &= ~SI_FULLWINDOW;
772                 ED_screen_full_toggle(C, win, sa);
773                 return OPERATOR_FINISHED;
774         }
775
776         return OPERATOR_PASS_THROUGH;
777 }
778
779 void RENDER_OT_view_cancel(struct wmOperatorType *ot)
780 {
781         /* identifiers */
782         ot->name= "Cancel Render View";
783         ot->description= "Cancel show render view";
784         ot->idname= "RENDER_OT_view_cancel";
785
786         /* api callbacks */
787         ot->exec= render_view_cancel_exec;
788         ot->poll= ED_operator_image_active;
789 }
790
791 /* *********************** show render viewer *************** */
792
793 static int render_view_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
794 {
795         ScrArea *sa= find_area_showing_r_result(C);
796
797         /* test if we have a temp screen in front */
798         if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
799                 wm_window_lower(CTX_wm_window(C));
800         }
801         /* determine if render already shows */
802         else if(sa) {
803                 SpaceImage *sima= sa->spacedata.first;
804
805                 if(sima->flag & SI_PREVSPACE) {
806                         sima->flag &= ~SI_PREVSPACE;
807
808                         if(sima->flag & SI_FULLWINDOW) {
809                                 sima->flag &= ~SI_FULLWINDOW;
810                                 ED_screen_full_prevspace(C, sa);
811                         }
812                         else if(sima->next) {
813                                 ED_area_newspace(C, sa, sima->next->spacetype);
814                                 ED_area_tag_redraw(sa);
815                         }
816                 }
817         }
818         else {
819                 screen_set_image_output(C, event->x, event->y);
820         }
821
822         return OPERATOR_FINISHED;
823 }
824
825 void RENDER_OT_view_show(struct wmOperatorType *ot)
826 {
827         /* identifiers */
828         ot->name= "Show/Hide Render View";
829         ot->description= "Toggle show render view";
830         ot->idname= "RENDER_OT_view_show";
831
832         /* api callbacks */
833         ot->invoke= render_view_show_invoke;
834         ot->poll= ED_operator_screenactive;
835 }