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