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