|
Blender
V2.59
|
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