Blender  V2.59
render_internal.c
Go to the documentation of this file.
00001 /*
00002  * $Id: render_internal.c 37916 2011-06-28 16:25:07Z blendix $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2008 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include <math.h>
00033 #include <string.h>
00034 #include <stddef.h>
00035 
00036 #include "MEM_guardedalloc.h"
00037 
00038 #include "BLI_blenlib.h"
00039 #include "BLI_math.h"
00040 #include "BLI_threads.h"
00041 #include "BLI_rand.h"
00042 #include "BLI_utildefines.h"
00043 
00044 #include "DNA_scene_types.h"
00045 
00046 #include "BKE_blender.h"
00047 #include "BKE_context.h"
00048 #include "BKE_global.h"
00049 #include "BKE_image.h"
00050 #include "BKE_library.h"
00051 #include "BKE_main.h"
00052 #include "BKE_node.h"
00053 #include "BKE_multires.h"
00054 #include "BKE_report.h"
00055 #include "BKE_sequencer.h"
00056 #include "BKE_screen.h"
00057 #include "BKE_scene.h"
00058 
00059 #include "WM_api.h"
00060 #include "WM_types.h"
00061 
00062 #include "ED_screen.h"
00063 #include "ED_object.h"
00064 
00065 #include "RE_pipeline.h"
00066 #include "IMB_imbuf.h"
00067 #include "IMB_imbuf_types.h"
00068 
00069 #include "RNA_access.h"
00070 #include "RNA_define.h"
00071 
00072 #include "wm_window.h"
00073 
00074 #include "render_intern.h"
00075 
00076 /* Render Callbacks */
00077 
00078 /* called inside thread! */
00079 void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect)
00080 {
00081         float x1, y1, *rectf= NULL;
00082         int ymin, ymax, xmin, xmax;
00083         int rymin, rxmin, do_color_management;
00084         char *rectc;
00085 
00086         /* if renrect argument, we only refresh scanlines */
00087         if(renrect) {
00088                 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
00089                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
00090                         return;
00091 
00092                 /* xmin here is first subrect x coord, xmax defines subrect width */
00093                 xmin = renrect->xmin + rr->crop;
00094                 xmax = renrect->xmax - xmin + rr->crop;
00095                 if(xmax<2)
00096                         return;
00097 
00098                 ymin= renrect->ymin + rr->crop;
00099                 ymax= renrect->ymax - ymin + rr->crop;
00100                 if(ymax<2)
00101                         return;
00102                 renrect->ymin= renrect->ymax;
00103 
00104         }
00105         else {
00106                 xmin = ymin = rr->crop;
00107                 xmax = rr->rectx - 2*rr->crop;
00108                 ymax = rr->recty - 2*rr->crop;
00109         }
00110 
00111         /* xmin ymin is in tile coords. transform to ibuf */
00112         rxmin= rr->tilerect.xmin + xmin;
00113         if(rxmin >= ibuf->x) return;
00114         rymin= rr->tilerect.ymin + ymin;
00115         if(rymin >= ibuf->y) return;
00116 
00117         if(rxmin + xmax > ibuf->x)
00118                 xmax= ibuf->x - rxmin;
00119         if(rymin + ymax > ibuf->y)
00120                 ymax= ibuf->y - rymin;
00121 
00122         if(xmax < 1 || ymax < 1) return;
00123 
00124         /* find current float rect for display, first case is after composit... still weak */
00125         if(rr->rectf)
00126                 rectf= rr->rectf;
00127         else {
00128                 if(rr->rect32)
00129                         return;
00130                 else {
00131                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
00132                         rectf= rr->renlay->rectf;
00133                 }
00134         }
00135         if(rectf==NULL) return;
00136 
00137         if(ibuf->rect==NULL)
00138                 imb_addrectImBuf(ibuf);
00139         
00140         rectf+= 4*(rr->rectx*ymin + xmin);
00141         rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
00142 
00143         do_color_management = (scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT));
00144         
00145         /* XXX make nice consistent functions for this */
00146         for(y1= 0; y1<ymax; y1++) {
00147                 float *rf= rectf;
00148                 float srgb[3];
00149                 char *rc= rectc;
00150                 const float dither = ibuf->dither / 255.0f;
00151 
00152                 /* XXX temp. because crop offset */
00153                 if(rectc >= (char *)(ibuf->rect)) {
00154                         for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
00155                                 /* color management */
00156                                 if(do_color_management) {
00157                                         srgb[0]= linearrgb_to_srgb(rf[0]);
00158                                         srgb[1]= linearrgb_to_srgb(rf[1]);
00159                                         srgb[2]= linearrgb_to_srgb(rf[2]);
00160                                 }
00161                                 else {
00162                                         copy_v3_v3(srgb, rf);
00163                                 }
00164 
00165                                 /* dither */
00166                                 if(dither != 0.0f) {
00167                                         const float d = (BLI_frand()-0.5f)*dither;
00168 
00169                                         srgb[0] += d;
00170                                         srgb[1] += d;
00171                                         srgb[2] += d;
00172                                 }
00173 
00174                                 /* write */
00175                                 rc[0]= FTOCHAR(srgb[0]);
00176                                 rc[1]= FTOCHAR(srgb[1]);
00177                                 rc[2]= FTOCHAR(srgb[2]);
00178                                 rc[3]= FTOCHAR(rf[3]);
00179                         }
00180                 }
00181 
00182                 rectf += 4*rr->rectx;
00183                 rectc += 4*ibuf->x;
00184         }
00185 }
00186 
00187 /* ****************************** render invoking ***************** */
00188 
00189 /* set callbacks, exported to sequence render too.
00190  Only call in foreground (UI) renders. */
00191 
00192 /* executes blocking render */
00193 static int screen_render_exec(bContext *C, wmOperator *op)
00194 {
00195         Scene *scene= CTX_data_scene(C);
00196         Render *re= RE_NewRender(scene->id.name);
00197         Image *ima;
00198         View3D *v3d= CTX_wm_view3d(C);
00199         Main *mainp= CTX_data_main(C);
00200         unsigned int lay= (v3d)? v3d->lay: scene->lay;
00201         const short is_animation= RNA_boolean_get(op->ptr, "animation");
00202         const short is_write_still= RNA_boolean_get(op->ptr, "write_still");
00203         struct Object *camera_override= v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
00204 
00205         if(!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.imtype)) {
00206                 BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected.");
00207                 return OPERATOR_CANCELLED;
00208         }
00209 
00210         G.afbreek= 0;
00211         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
00212 
00213         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
00214         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
00215         BKE_image_backup_render(scene, ima);
00216 
00217         /* cleanup sequencer caches before starting user triggered render.
00218            otherwise, invalidated cache entries can make their way into
00219            the output rendering. We can't put that into RE_BlenderFrame,
00220            since sequence rendering can call that recursively... (peter) */
00221         seq_stripelem_cache_cleanup();
00222 
00223         RE_SetReports(re, op->reports);
00224 
00225         if(is_animation)
00226                 RE_BlenderAnim(re, mainp, scene, camera_override, lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
00227         else
00228                 RE_BlenderFrame(re, mainp, scene, NULL, camera_override, lay, scene->r.cfra, is_write_still);
00229 
00230         RE_SetReports(re, NULL);
00231 
00232         // no redraw needed, we leave state as we entered it
00233         ED_update_for_newframe(mainp, scene, CTX_wm_screen(C), 1);
00234 
00235         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
00236 
00237         return OPERATOR_FINISHED;
00238 }
00239 
00240 typedef struct RenderJob {
00241         Main *main;
00242         Scene *scene;
00243         Render *re;
00244         wmWindow *win;
00245         SceneRenderLayer *srl;
00246         struct Object *camera_override;
00247         int lay;
00248         short anim, write_still;
00249         Image *image;
00250         ImageUser iuser;
00251         short *stop;
00252         short *do_update;
00253         float *progress;
00254         ReportList *reports;
00255 } RenderJob;
00256 
00257 static void render_freejob(void *rjv)
00258 {
00259         RenderJob *rj= rjv;
00260 
00261         MEM_freeN(rj);
00262 }
00263 
00264 /* str is IMA_MAX_RENDER_TEXT in size */
00265 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
00266 {
00267         char info_time_str[32]; // used to be extern to header_info.c
00268         uintptr_t mem_in_use, mmap_in_use, peak_memory;
00269         float megs_used_memory, mmap_used_memory, megs_peak_memory;
00270         char *spos= str;
00271 
00272         mem_in_use= MEM_get_memory_in_use();
00273         mmap_in_use= MEM_get_mapped_memory_in_use();
00274         peak_memory = MEM_get_peak_memory();
00275 
00276         megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
00277         mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
00278         megs_peak_memory = (peak_memory)/(1024.0*1024.0);
00279 
00280         if(scene->lay & 0xFF000000)
00281                 spos+= sprintf(spos, "Localview | ");
00282         else if(scene->r.scemode & R_SINGLE_LAYER)
00283                 spos+= sprintf(spos, "Single Layer | ");
00284 
00285         if(rs->statstr) {
00286                 spos+= sprintf(spos, "%s ", rs->statstr);
00287         }
00288         else {
00289                 spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
00290                 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
00291                 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
00292                 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM, peak %.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory, megs_peak_memory);
00293 
00294                 if(rs->curfield)
00295                         spos+= sprintf(spos, "Field %d ", rs->curfield);
00296                 if(rs->curblur)
00297                         spos+= sprintf(spos, "Blur %d ", rs->curblur);
00298         }
00299 
00300         BLI_timestr(rs->lastframetime, info_time_str);
00301         spos+= sprintf(spos, "Time:%s ", info_time_str);
00302 
00303         if(rs->curfsa)
00304                 spos+= sprintf(spos, "| Full Sample %d ", rs->curfsa);
00305         
00306         if(rs->infostr && rs->infostr[0])
00307                 spos+= sprintf(spos, "| %s ", rs->infostr);
00308 
00309         /* very weak... but 512 characters is quite safe */
00310         if(spos >= str+IMA_MAX_RENDER_TEXT)
00311                 if (G.f & G_DEBUG)
00312                         printf("WARNING! renderwin text beyond limit \n");
00313 
00314 }
00315 
00316 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
00317 {
00318         RenderJob *rj= rjv;
00319         RenderResult *rr;
00320 
00321         rr= RE_AcquireResultRead(rj->re);
00322 
00323         if(rr) {
00324                 /* malloc OK here, stats_draw is not in tile threads */
00325                 if(rr->text==NULL)
00326                         rr->text= MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
00327 
00328                 make_renderinfo_string(rs, rj->scene, rr->text);
00329         }
00330 
00331         RE_ReleaseResult(rj->re);
00332 
00333         /* make jobs timer to send notifier */
00334         *(rj->do_update)= 1;
00335 
00336 }
00337 
00338 static void render_progress_update(void *rjv, float progress)
00339 {
00340         RenderJob *rj= rjv;
00341         
00342         if(rj->progress)
00343                 *rj->progress = progress;
00344 }
00345 
00346 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
00347 {
00348         RenderJob *rj= rjv;
00349         Image *ima= rj->image;
00350         ImBuf *ibuf;
00351         void *lock;
00352 
00353         /* only update if we are displaying the slot being rendered */
00354         if(ima->render_slot != ima->last_render_slot)
00355                 return;
00356 
00357         ibuf= BKE_image_acquire_ibuf(ima, &rj->iuser, &lock);
00358         if(ibuf) {
00359                 image_buffer_rect_update(rj->scene, rr, ibuf, renrect);
00360 
00361                 /* make jobs timer to send notifier */
00362                 *(rj->do_update)= 1;
00363         }
00364         BKE_image_release_ibuf(ima, lock);
00365 }
00366 
00367 static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
00368 {
00369         RenderJob *rj= rjv;
00370 
00371         rj->stop= stop;
00372         rj->do_update= do_update;
00373         rj->progress= progress;
00374 
00375         RE_SetReports(rj->re, rj->reports);
00376 
00377         if(rj->anim)
00378                 RE_BlenderAnim(rj->re, rj->main, rj->scene, rj->camera_override, rj->lay, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step);
00379         else
00380                 RE_BlenderFrame(rj->re, rj->main, rj->scene, rj->srl, rj->camera_override, rj->lay, rj->scene->r.cfra, rj->write_still);
00381 
00382         RE_SetReports(rj->re, NULL);
00383 }
00384 
00385 static void render_endjob(void *rjv)
00386 {
00387         RenderJob *rj= rjv;     
00388 
00389         /* this render may be used again by the sequencer without the active 'Render' where the callbacks
00390          * would be re-assigned. assign dummy callbacks to avoid referencing freed renderjobs bug [#24508] */
00391         RE_InitRenderCB(rj->re);
00392 
00393         if(rj->main != G.main)
00394                 free_main(rj->main);
00395 
00396         /* else the frame will not update for the original value */
00397         if(!(rj->scene->r.scemode & R_NO_FRAME_UPDATE))
00398                 ED_update_for_newframe(G.main, rj->scene, rj->win->screen, 1);
00399         
00400         /* XXX above function sets all tags in nodes */
00401         ntreeClearTags(rj->scene->nodetree);
00402         
00403         /* potentially set by caller */
00404         rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE;
00405         
00406         if(rj->srl) {
00407                 NodeTagIDChanged(rj->scene->nodetree, &rj->scene->id);
00408                 WM_main_add_notifier(NC_NODE|NA_EDITED, rj->scene);
00409         }
00410         
00411         /* XXX render stability hack */
00412         G.rendering = 0;
00413         WM_main_add_notifier(NC_WINDOW, NULL);
00414 }
00415 
00416 /* called by render, check job 'stop' value or the global */
00417 static int render_breakjob(void *rjv)
00418 {
00419         RenderJob *rj= rjv;
00420 
00421         if(G.afbreek)
00422                 return 1;
00423         if(rj->stop && *(rj->stop))
00424                 return 1;
00425         return 0;
00426 }
00427 
00428 /* runs in thread, no cursor setting here works. careful with notifiers too (malloc conflicts) */
00429 /* maybe need a way to get job send notifer? */
00430 static void render_drawlock(void *UNUSED(rjv), int lock)
00431 {
00432         BKE_spacedata_draw_locks(lock);
00433         
00434 }
00435 
00436 /* catch esc */
00437 static int screen_render_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
00438 {
00439         /* no running blender, remove handler and pass through */
00440         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C))) {
00441                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
00442         }
00443 
00444         /* running render */
00445         switch (event->type) {
00446                 case ESCKEY:
00447                         return OPERATOR_RUNNING_MODAL;
00448                         break;
00449         }
00450         return OPERATOR_PASS_THROUGH;
00451 }
00452 
00453 /* using context, starts job */
00454 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
00455 {
00456         /* new render clears all callbacks */
00457         Main *mainp;
00458         Scene *scene= CTX_data_scene(C);
00459         SceneRenderLayer *srl=NULL;
00460         bScreen *screen= CTX_wm_screen(C);
00461         View3D *v3d= CTX_wm_view3d(C);
00462         Render *re;
00463         wmJob *steve;
00464         RenderJob *rj;
00465         Image *ima;
00466         int jobflag;
00467         const short is_animation= RNA_boolean_get(op->ptr, "animation");
00468         const short is_write_still= RNA_boolean_get(op->ptr, "write_still");
00469         struct Object *camera_override= v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
00470         
00471         /* only one render job at a time */
00472         if(WM_jobs_test(CTX_wm_manager(C), scene))
00473                 return OPERATOR_CANCELLED;
00474 
00475         if(!RE_is_rendering_allowed(scene, camera_override, op->reports)) {
00476                 return OPERATOR_CANCELLED;
00477         }
00478 
00479         if(!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.imtype)) {
00480                 BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected.");
00481                 return OPERATOR_CANCELLED;
00482         }       
00483         
00484         /* stop all running jobs, currently previews frustrate Render */
00485         WM_jobs_stop_all(CTX_wm_manager(C));
00486 
00487         /* get main */
00488         if(G.rt == 101) {
00489                 /* thread-safety experiment, copy main from the undo buffer */
00490                 mainp= BKE_undo_get_main(&scene);
00491         }
00492         else
00493                 mainp= CTX_data_main(C);
00494 
00495         /* cancel animation playback */
00496         if (screen->animtimer)
00497                 ED_screen_animation_play(C, 0, 0);
00498         
00499         /* handle UI stuff */
00500         WM_cursor_wait(1);
00501 
00502         /* flush multires changes (for sculpt) */
00503         multires_force_render_update(CTX_data_active_object(C));
00504 
00505         /* cleanup sequencer caches before starting user triggered render.
00506            otherwise, invalidated cache entries can make their way into
00507            the output rendering. We can't put that into RE_BlenderFrame,
00508            since sequence rendering can call that recursively... (peter) */
00509         seq_stripelem_cache_cleanup();
00510 
00511         /* get editmode results */
00512         ED_object_exit_editmode(C, 0);  /* 0 = does not exit editmode */
00513 
00514         // store spare
00515         // get view3d layer, local layer, make this nice api call to render
00516         // store spare
00517 
00518         /* ensure at least 1 area shows result */
00519         render_view_open(C, event->x, event->y);
00520 
00521         jobflag= WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS;
00522         
00523         /* single layer re-render */
00524         if(RNA_property_is_set(op->ptr, "layer")) {
00525                 SceneRenderLayer *rl;
00526                 Scene *scn;
00527                 char scene_name[MAX_ID_NAME-2], rl_name[RE_MAXNAME];
00528 
00529                 RNA_string_get(op->ptr, "layer", rl_name);
00530                 RNA_string_get(op->ptr, "scene", scene_name);
00531 
00532                 scn = (Scene *)BLI_findstring(&mainp->scene, scene_name, offsetof(ID, name) + 2);
00533                 rl = (SceneRenderLayer *)BLI_findstring(&scene->r.layers, rl_name, offsetof(SceneRenderLayer, name));
00534                 
00535                 if (scn && rl) {
00536                         /* camera switch wont have updated */
00537                         scn->r.cfra= scene->r.cfra;
00538                         scene_camera_switch_update(scn);
00539 
00540                         scene = scn;
00541                         srl = rl;
00542                 }
00543                 jobflag |= WM_JOB_SUSPEND;
00544         }
00545 
00546         /* job custom data */
00547         rj= MEM_callocN(sizeof(RenderJob), "render job");
00548         rj->main= mainp;
00549         rj->scene= scene;
00550         rj->win= CTX_wm_window(C);
00551         rj->srl = srl;
00552         rj->camera_override = camera_override;
00553         rj->lay = (v3d)? v3d->lay: scene->lay;
00554         rj->anim= is_animation;
00555         rj->write_still= is_write_still && !is_animation;
00556         rj->iuser.scene= scene;
00557         rj->iuser.ok= 1;
00558         rj->reports= op->reports;
00559 
00560         /* setup job */
00561         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Render", jobflag);
00562         WM_jobs_customdata(steve, rj, render_freejob);
00563         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
00564         WM_jobs_callbacks(steve, render_startjob, NULL, NULL, render_endjob);
00565 
00566         /* get a render result image, and make sure it is empty */
00567         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
00568         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
00569         BKE_image_backup_render(rj->scene, ima);
00570         rj->image= ima;
00571 
00572         /* setup new render */
00573         re= RE_NewRender(scene->id.name);
00574         RE_test_break_cb(re, rj, render_breakjob);
00575         RE_draw_lock_cb(re, rj, render_drawlock);
00576         RE_display_draw_cb(re, rj, image_rect_update);
00577         RE_stats_draw_cb(re, rj, image_renderinfo_cb);
00578         RE_progress_cb(re, rj, render_progress_update);
00579 
00580         rj->re= re;
00581         G.afbreek= 0;
00582 
00583         WM_jobs_start(CTX_wm_manager(C), steve);
00584 
00585         WM_cursor_wait(0);
00586         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
00587 
00588         /* we set G.rendering here already instead of only in the job, this ensure
00589            main loop or other scene updates are disabled in time, since they may
00590            have started before the job thread */
00591         G.rendering = 1;
00592 
00593         /* add modal handler for ESC */
00594         WM_event_add_modal_handler(C, op);
00595 
00596         return OPERATOR_RUNNING_MODAL;
00597 }
00598 
00599 /* contextual render, using current scene, view3d? */
00600 void RENDER_OT_render(wmOperatorType *ot)
00601 {
00602         /* identifiers */
00603         ot->name= "Render";
00604         ot->description= "Render active scene";
00605         ot->idname= "RENDER_OT_render";
00606 
00607         /* api callbacks */
00608         ot->invoke= screen_render_invoke;
00609         ot->modal= screen_render_modal;
00610         ot->exec= screen_render_exec;
00611 
00612         /*ot->poll= ED_operator_screenactive;*/ /* this isnt needed, causes failer in background mode */
00613 
00614         RNA_def_boolean(ot->srna, "animation", 0, "Animation", "Render files from the animation range of this scene");
00615         RNA_def_boolean(ot->srna, "write_still", 0, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)");
00616         RNA_def_string(ot->srna, "layer", "", RE_MAXNAME, "Render Layer", "Single render layer to re-render");
00617         RNA_def_string(ot->srna, "scene", "", MAX_ID_NAME-2, "Scene", "Re-render single layer in this scene");
00618 }
00619