Patch 5105 by Joshua Leung (Aligorith), slightly modified by me
[blender-staging.git] / source / blender / render / intern / source / pipeline.c
1 /**  
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. 
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2006 Blender Foundation.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30 #include <limits.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include "DNA_group_types.h"
35 #include "DNA_image_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_userdef_types.h"
40
41 #include "BKE_global.h"
42 #include "BKE_image.h"
43 #include "BKE_node.h"
44 #include "BKE_object.h"
45 #include "BKE_scene.h"
46 #include "BKE_writeavi.h"       /* <------ should be replaced once with generic movie module */
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_arithb.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_rand.h"
53 #include "BLI_threads.h"
54
55 #include "PIL_time.h"
56 #include "IMB_imbuf.h"
57 #include "IMB_imbuf_types.h"
58
59 #include "intern/openexr/openexr_multi.h"
60
61 #include "RE_pipeline.h"
62 #include "radio.h"
63
64 #include "BSE_sequence.h"  /* <----------------- bad!!! */
65
66 #ifndef DISABLE_YAFRAY
67 /* yafray: include for yafray export/render */
68 #include "YafRay_Api.h"
69
70 #endif /* disable yafray */
71
72 /* internal */
73 #include "render_types.h"
74 #include "renderpipeline.h"
75 #include "renderdatabase.h"
76 #include "rendercore.h"
77 #include "envmap.h"
78 #include "initrender.h"
79 #include "shadbuf.h"
80 #include "zbuf.h"
81
82
83 /* render flow
84
85 1) Initialize state
86 - state data, tables
87 - movie/image file init
88 - everything that doesn't change during animation
89
90 2) Initialize data
91 - camera, world, matrices
92 - make render verts, faces, halos, strands
93 - everything can change per frame/field
94
95 3) Render Processor
96 - multiple layers
97 - tiles, rect, baking
98 - layers/tiles optionally to disk or directly in Render Result
99
100 4) Composit Render Result
101 - also read external files etc
102
103 5) Image Files
104 - save file or append in movie
105
106 */
107
108
109 /* ********* globals ******** */
110
111 /* here we store all renders */
112 static struct ListBase RenderList= {NULL, NULL};
113
114 /* hardcopy of current render, used while rendering for speed */
115 Render R;
116
117 /* ********* alloc and free ******** */
118
119
120 static volatile int g_break= 0;
121 static int thread_break(void)
122 {
123         return g_break;
124 }
125
126 /* default callbacks, set in each new render */
127 static void result_nothing(RenderResult *rr) {}
128 static void result_rcti_nothing(RenderResult *rr, volatile struct rcti *rect) {}
129 static void stats_nothing(RenderStats *rs) {}
130 static void int_nothing(int val) {}
131 static int void_nothing(void) {return 0;}
132 static void print_error(char *str) {printf("ERROR: %s\n", str);}
133
134 static void stats_background(RenderStats *rs)
135 {
136         extern unsigned long mem_in_use;
137         float megs_used_memory= mem_in_use/(1024.0*1024.0);
138         char str[400], *spos= str;
139         
140         if(rs->convertdone) {
141                 
142                 spos+= sprintf(spos, "Fra:%d Mem:%.2fM ", G.scene->r.cfra, megs_used_memory);
143                 
144                 if(rs->curfield)
145                         spos+= sprintf(spos, "Field %d ", rs->curfield);
146                 if(rs->curblur)
147                         spos+= sprintf(spos, "Blur %d ", rs->curblur);
148                 
149                 if(rs->infostr) {
150                         spos+= sprintf(spos, "| %s", rs->infostr);
151                 }
152                 else {
153                         if(rs->tothalo)
154                                 spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d Ha:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->tothalo, rs->totlamp);
155                         else 
156                                 spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->totlamp);
157                 }
158                 printf(str); printf("\n");
159         }       
160 }
161
162 static void free_render_result(RenderResult *res)
163 {
164         if(res==NULL) return;
165
166         while(res->layers.first) {
167                 RenderLayer *rl= res->layers.first;
168                 
169                 if(rl->rectf) MEM_freeN(rl->rectf);
170                 /* acolrect is optionally allocated in shade_tile, only free here since it can be used for drawing */
171                 if(rl->acolrect) MEM_freeN(rl->acolrect);
172                 
173                 while(rl->passes.first) {
174                         RenderPass *rpass= rl->passes.first;
175                         if(rpass->rect) MEM_freeN(rpass->rect);
176                         BLI_remlink(&rl->passes, rpass);
177                         MEM_freeN(rpass);
178                 }
179                 BLI_remlink(&res->layers, rl);
180                 MEM_freeN(rl);
181         }
182         
183         if(res->rect32)
184                 MEM_freeN(res->rect32);
185         if(res->rectz)
186                 MEM_freeN(res->rectz);
187         if(res->rectf)
188                 MEM_freeN(res->rectf);
189         
190         MEM_freeN(res);
191 }
192
193 /* all layers except the active one get temporally pushed away */
194 static void push_render_result(Render *re)
195 {
196         /* officially pushed result should be NULL... error can happen with do_seq */
197         free_render_result(re->pushedresult);
198         
199         re->pushedresult= re->result;
200         re->result= NULL;
201 }
202
203 /* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
204 static void pop_render_result(Render *re)
205 {
206         
207         if(re->result==NULL) {
208                 printf("pop render result error; no current result!\n");
209                 return;
210         }
211         if(re->pushedresult) {
212                 if(re->pushedresult->rectx==re->result->rectx && re->pushedresult->recty==re->result->recty) {
213                         /* find which layer in pushedresult should be replaced */
214                         SceneRenderLayer *srl;
215                         RenderLayer *rlpush;
216                         RenderLayer *rl= re->result->layers.first;
217                         int nr;
218                         
219                         /* render result should be empty after this */
220                         BLI_remlink(&re->result->layers, rl);
221                         
222                         /* reconstruct render result layers */
223                         for(nr=0, srl= re->scene->r.layers.first; srl; srl= srl->next, nr++) {
224                                 if(nr==re->r.actlay)
225                                         BLI_addtail(&re->result->layers, rl);
226                                 else {
227                                         rlpush= RE_GetRenderLayer(re->pushedresult, srl->name);
228                                         if(rlpush) {
229                                                 BLI_remlink(&re->pushedresult->layers, rlpush);
230                                                 BLI_addtail(&re->result->layers, rlpush);
231                                         }
232                                 }
233                         }
234                 }
235                 
236                 free_render_result(re->pushedresult);
237                 re->pushedresult= NULL;
238         }
239 }
240
241
242 static char *get_pass_name(int passtype, int channel)
243 {
244         
245         if(passtype == SCE_PASS_COMBINED) {
246                 if(channel==0) return "Combined.R";
247                 else if(channel==1) return "Combined.G";
248                 else if(channel==2) return "Combined.B";
249                 else return "Combined.A";
250         }
251         if(passtype == SCE_PASS_Z)
252                 return "Z";
253         if(passtype == SCE_PASS_VECTOR) {
254                 if(channel==0) return "Vector.X";
255                 else if(channel==1) return "Vector.Y";
256                 else if(channel==2) return "Vector.Z";
257                 else return "Vector.W";
258         }
259         if(passtype == SCE_PASS_NORMAL) {
260                 if(channel==0) return "Normal.X";
261                 else if(channel==1) return "Normal.Y";
262                 else return "Normal.Z";
263         }
264         if(passtype == SCE_PASS_RGBA) {
265                 if(channel==0) return "Color.R";
266                 else if(channel==1) return "Color.G";
267                 else if(channel==2) return "Color.B";
268                 else return "Color.A";
269         }
270         if(passtype == SCE_PASS_DIFFUSE) {
271                 if(channel==0) return "Diffuse.R";
272                 else if(channel==1) return "Diffuse.G";
273                 else return "Diffuse.B";
274         }
275         if(passtype == SCE_PASS_SPEC) {
276                 if(channel==0) return "Spec.R";
277                 else if(channel==1) return "Spec.G";
278                 else return "Spec.B";
279         }
280         if(passtype == SCE_PASS_SHADOW) {
281                 if(channel==0) return "Shadow.R";
282                 else if(channel==1) return "Shadow.G";
283                 else return "Shadow.B";
284         }
285         if(passtype == SCE_PASS_AO) {
286                 if(channel==0) return "AO.R";
287                 else if(channel==1) return "AO.G";
288                 else return "AO.B";
289         }
290         if(passtype == SCE_PASS_RAY) {
291                 if(channel==0) return "Ray.R";
292                 else if(channel==1) return "Ray.G";
293                 else return "Ray.B";
294         }
295         return "Unknown";
296 }
297
298 static void render_unique_exr_name(Render *re, char *str)
299 {
300         char di[FILE_MAXDIR+FILE_MAXFILE], name[FILE_MAXFILE], fi[FILE_MAXFILE];
301         
302         BLI_strncpy(di, G.sce, FILE_MAXDIR+FILE_MAXFILE);
303         BLI_splitdirstring(di, fi);
304         sprintf(name, "%s_%s.exr", fi, re->scene->id.name+2);
305         if(G.background)
306                 BLI_make_file_string("/", str, "/tmp/", name);
307         else
308                 BLI_make_file_string("/", str, U.tempdir, name);
309                 
310 }
311
312 static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
313 {
314         char *typestr= get_pass_name(passtype, 0);
315         RenderPass *rpass= MEM_callocN(sizeof(RenderPass), typestr);
316         int rectsize= rr->rectx*rr->recty*channels;
317         
318         BLI_addtail(&rl->passes, rpass);
319         rpass->passtype= passtype;
320         rpass->channels= channels;
321         
322         if(rr->exrhandle) {
323                 int a;
324                 for(a=0; a<channels; a++)
325                         IMB_exr_add_channel(rr->exrhandle, rl->name, get_pass_name(passtype, a));
326         }
327         else {
328                 if(passtype==SCE_PASS_VECTOR) {
329                         float *rect;
330                         int x;
331                         
332                         /* initialize to max speed */
333                         rect= rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr);
334                         for(x= rectsize-1; x>=0; x--)
335                                 rect[x]= PASS_VECTOR_MAX;
336                 }
337                 else
338                         rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr);
339         }
340 }
341
342 float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype)
343 {
344         RenderPass *rpass;
345         
346         for(rpass=rl->passes.first; rpass; rpass= rpass->next)
347                 if(rpass->passtype== passtype)
348                         return rpass->rect;
349         return NULL;
350 }
351
352 RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
353 {
354         RenderLayer *rl;
355         
356         if(rr==NULL) return NULL;
357         
358         for(rl= rr->layers.first; rl; rl= rl->next)
359                 if(strncmp(rl->name, name, RE_MAXNAME)==0)
360                         return rl;
361         return NULL;
362 }
363
364 #define RR_USEMEM       0
365 /* called by main render as well for parts */
366 /* will read info from Render *re to define layers */
367 /* called in threads */
368 /* re->winx,winy is coordinate space of entire image, partrct the part within */
369 static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int savebuffers)
370 {
371         RenderResult *rr;
372         RenderLayer *rl;
373         SceneRenderLayer *srl;
374         int rectx, recty, nr;
375         
376         rectx= partrct->xmax - partrct->xmin;
377         recty= partrct->ymax - partrct->ymin;
378         
379         if(rectx<=0 || recty<=0)
380                 return NULL;
381         
382         rr= MEM_callocN(sizeof(RenderResult), "new render result");
383         rr->rectx= rectx;
384         rr->recty= recty;
385         rr->renrect.xmin= 0; rr->renrect.xmax= rectx-2*crop;
386         /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */
387         rr->crop= crop;
388         
389         /* tilerect is relative coordinates within render disprect. do not subtract crop yet */
390         rr->tilerect.xmin= partrct->xmin - re->disprect.xmin;
391         rr->tilerect.xmax= partrct->xmax - re->disprect.xmax;
392         rr->tilerect.ymin= partrct->ymin - re->disprect.ymin;
393         rr->tilerect.ymax= partrct->ymax - re->disprect.ymax;
394         
395         if(savebuffers) {
396                 rr->exrhandle= IMB_exr_get_handle();
397         }
398         
399         /* check renderdata for amount of layers */
400         for(nr=0, srl= re->r.layers.first; srl; srl= srl->next, nr++) {
401                 
402                 if((re->r.scemode & R_SINGLE_LAYER) && nr!=re->r.actlay)
403                         continue;
404                 
405                 rl= MEM_callocN(sizeof(RenderLayer), "new render layer");
406                 BLI_addtail(&rr->layers, rl);
407                 
408                 strcpy(rl->name, srl->name);
409                 rl->lay= srl->lay;
410                 rl->layflag= srl->layflag;
411                 rl->passflag= srl->passflag;
412                 
413                 if(rr->exrhandle) {
414                         IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R");
415                         IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G");
416                         IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B");
417                         IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A");
418                 }
419                 else
420                         rl->rectf= MEM_mapallocN(rectx*recty*sizeof(float)*4, "Combined rgba");
421                 
422                 if(srl->passflag  & SCE_PASS_Z)
423                         render_layer_add_pass(rr, rl, 1, SCE_PASS_Z);
424                 if(srl->passflag  & SCE_PASS_VECTOR)
425                         render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR);
426                 if(srl->passflag  & SCE_PASS_NORMAL)
427                         render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL);
428                 if(srl->passflag  & SCE_PASS_RGBA)
429                         render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA);
430                 if(srl->passflag  & SCE_PASS_DIFFUSE)
431                         render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE);
432                 if(srl->passflag  & SCE_PASS_SPEC)
433                         render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC);
434                 if(srl->passflag  & SCE_PASS_SHADOW)
435                         render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
436                 if(srl->passflag  & SCE_PASS_AO)
437                         render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
438                 if(srl->passflag  & SCE_PASS_RAY)
439                         render_layer_add_pass(rr, rl, 3, SCE_PASS_RAY);
440                 
441         }
442         /* previewrender and envmap don't do layers, so we make a default one */
443         if(rr->layers.first==NULL) {
444                 rl= MEM_callocN(sizeof(RenderLayer), "new render layer");
445                 BLI_addtail(&rr->layers, rl);
446                 
447                 rl->rectf= MEM_mapallocN(rectx*recty*sizeof(float)*4, "prev/env float rgba");
448                 
449                 /* note, this has to be in sync with scene.c */
450                 rl->lay= (1<<20) -1;
451                 rl->layflag= 0x7FFF;    /* solid ztra halo strand */
452                 rl->passflag= SCE_PASS_COMBINED;
453                 
454                 re->r.actlay= 0;
455         }
456         
457         /* border render; calculate offset for use in compositor. compo is centralized coords */
458         rr->xof= re->disprect.xmin + (re->disprect.xmax - re->disprect.xmin)/2 - re->winx/2;
459         rr->yof= re->disprect.ymin + (re->disprect.ymax - re->disprect.ymin)/2 - re->winy/2;
460         
461         return rr;
462 }
463
464 static int render_scene_needs_vector(Render *re)
465 {
466         if(re->r.scemode & R_DOCOMP) {
467                 SceneRenderLayer *srl;
468         
469                 for(srl= re->scene->r.layers.first; srl; srl= srl->next)
470                         if(srl->passflag & SCE_PASS_VECTOR)
471                                 return 1;
472         }
473         return 0;
474 }
475
476 static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize)
477 {
478         int y, ofs, copylen, tilex, tiley;
479         
480         copylen= tilex= rrpart->rectx;
481         tiley= rrpart->recty;
482         
483         if(rrpart->crop) {      /* filters add pixel extra */
484                 tile+= pixsize*(rrpart->crop + rrpart->crop*tilex);
485                 
486                 copylen= tilex - 2*rrpart->crop;
487                 tiley -= 2*rrpart->crop;
488                 
489                 ofs= (rrpart->tilerect.ymin + rrpart->crop)*rr->rectx + (rrpart->tilerect.xmin+rrpart->crop);
490                 target+= pixsize*ofs;
491         }
492         else {
493                 ofs= (rrpart->tilerect.ymin*rr->rectx + rrpart->tilerect.xmin);
494                 target+= pixsize*ofs;
495         }
496
497         copylen *= sizeof(float)*pixsize;
498         tilex *= pixsize;
499         ofs= pixsize*rr->rectx;
500
501         for(y=0; y<tiley; y++) {
502                 memcpy(target, tile, copylen);
503                 target+= ofs;
504                 tile+= tilex;
505         }
506 }
507
508 /* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
509 /* no test happens here if it fits... we also assume layers are in sync */
510 /* is used within threads */
511 static void merge_render_result(RenderResult *rr, RenderResult *rrpart)
512 {
513         RenderLayer *rl, *rlp;
514         RenderPass *rpass, *rpassp;
515         
516         for(rl= rr->layers.first, rlp= rrpart->layers.first; rl && rlp; rl= rl->next, rlp= rlp->next) {
517                 
518                 /* combined */
519                 if(rl->rectf && rlp->rectf)
520                         do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4);
521                 
522                 /* passes are allocated in sync */
523                 for(rpass= rl->passes.first, rpassp= rlp->passes.first; rpass && rpassp; rpass= rpass->next, rpassp= rpassp->next) {
524                         do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
525                 }
526         }
527 }
528
529
530 static void save_render_result_tile(Render *re, RenderPart *pa)
531 {
532         RenderResult *rrpart= pa->result;
533         RenderLayer *rlp;
534         RenderPass *rpassp;
535         int offs, partx, party;
536         
537         BLI_lock_thread(LOCK_CUSTOM1);
538         
539         for(rlp= rrpart->layers.first; rlp; rlp= rlp->next) {
540                 
541                 if(rrpart->crop) {      /* filters add pixel extra */
542                         offs= (rrpart->crop + rrpart->crop*rrpart->rectx);
543                 }
544                 else {
545                         offs= 0;
546                 }
547                 
548                 /* combined */
549                 if(rlp->rectf) {
550                         int a, xstride= 4;
551                         for(a=0; a<xstride; a++)
552                                 IMB_exr_set_channel(re->result->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a), 
553                                                                 xstride, xstride*pa->rectx, rlp->rectf+a + xstride*offs);
554                 }
555                 
556                 /* passes are allocated in sync */
557                 for(rpassp= rlp->passes.first; rpassp; rpassp= rpassp->next) {
558                         int a, xstride= rpassp->channels;
559                         for(a=0; a<xstride; a++)
560                                 IMB_exr_set_channel(re->result->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a), 
561                                                                         xstride, xstride*pa->rectx, rpassp->rect+a + xstride*offs);
562                 }
563                 
564         }
565
566         party= rrpart->tilerect.ymin + rrpart->crop;
567         partx= rrpart->tilerect.xmin + rrpart->crop;
568         IMB_exrtile_write_channels(re->result->exrhandle, partx, party);
569
570         BLI_unlock_thread(LOCK_CUSTOM1);
571
572 }
573
574 static void read_render_result(Render *re)
575 {
576         RenderLayer *rl;
577         RenderPass *rpass;
578         void *exrhandle= IMB_exr_get_handle();
579         int rectx, recty;
580         char str[FILE_MAXDIR+FILE_MAXFILE];
581         
582         free_render_result(re->result);
583         re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
584
585         render_unique_exr_name(re, str);
586         if(IMB_exr_begin_read(exrhandle, str, &rectx, &recty)==0) {
587                 printf("cannot read render result\n");
588                 return;
589         }
590         
591         if(rectx!=re->result->rectx || recty!=re->result->recty) {
592                 printf("error in reading render result\n");
593         }
594         else {
595                 for(rl= re->result->layers.first; rl; rl= rl->next) {
596                         
597                         /* combined */
598                         if(rl->rectf) {
599                                 int a, xstride= 4;
600                                 for(a=0; a<xstride; a++)
601                                         IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), 
602                                                                                 xstride, xstride*rectx, rl->rectf+a);
603                         }
604                         
605                         /* passes are allocated in sync */
606                         for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
607                                 int a, xstride= rpass->channels;
608                                 for(a=0; a<xstride; a++)
609                                         IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), 
610                                                                                 xstride, xstride*rectx, rpass->rect+a);
611                         }
612                         
613                 }
614                 IMB_exr_read_channels(exrhandle);
615         }
616         
617         IMB_exr_close(exrhandle);
618 }
619
620 /* *************************************************** */
621
622 Render *RE_GetRender(const char *name)
623 {
624         Render *re;
625         
626         /* search for existing renders */
627         for(re= RenderList.first; re; re= re->next) {
628                 if(strncmp(re->name, name, RE_MAXNAME)==0) {
629                         break;
630                 }
631         }
632         return re;
633 }
634
635 /* if you want to know exactly what has been done */
636 RenderResult *RE_GetResult(Render *re)
637 {
638         if(re)
639                 return re->result;
640         return NULL;
641 }
642
643 RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
644 {
645         RenderLayer *rl= BLI_findlink(&rr->layers, re->r.actlay);
646         
647         if(rl) 
648                 return rl;
649         else 
650                 return rr->layers.first;
651 }
652
653
654 /* fill provided result struct with what's currently active or done */
655 void RE_GetResultImage(Render *re, RenderResult *rr)
656 {
657         memset(rr, 0, sizeof(RenderResult));
658
659         if(re && re->result) {
660                 RenderLayer *rl;
661                 
662                 rr->rectx= re->result->rectx;
663                 rr->recty= re->result->recty;
664                 
665                 rr->rectf= re->result->rectf;
666                 rr->rectz= re->result->rectz;
667                 rr->rect32= re->result->rect32;
668                 
669                 /* active layer */
670                 rl= render_get_active_layer(re, re->result);
671
672                 if(rl) {
673                         if(rr->rectf==NULL)
674                                 rr->rectf= rl->rectf;
675                         if(rr->rectz==NULL)
676                                 rr->rectz= RE_RenderLayerGetPass(rl, SCE_PASS_Z);       
677                 }
678         }
679 }
680
681 #define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
682 /* caller is responsible for allocating rect in correct size! */
683 void RE_ResultGet32(Render *re, unsigned int *rect)
684 {
685         RenderResult rres;
686         
687         RE_GetResultImage(re, &rres);
688         if(rres.rect32) 
689                 memcpy(rect, rres.rect32, sizeof(int)*rres.rectx*rres.recty);
690         else if(rres.rectf) {
691                 float *fp= rres.rectf;
692                 int tot= rres.rectx*rres.recty;
693                 char *cp= (char *)rect;
694                 
695                 for(;tot>0; tot--, cp+=4, fp+=4) {
696                         cp[0] = FTOCHAR(fp[0]);
697                         cp[1] = FTOCHAR(fp[1]);
698                         cp[2] = FTOCHAR(fp[2]);
699                         cp[3] = FTOCHAR(fp[3]);
700                 }
701         }
702         else
703                 /* else fill with black */
704                 memset(rect, 0, sizeof(int)*re->rectx*re->recty);
705 }
706
707
708 RenderStats *RE_GetStats(Render *re)
709 {
710         return &re->i;
711 }
712
713 Render *RE_NewRender(const char *name)
714 {
715         Render *re;
716         
717         /* only one render per name exists */
718         re= RE_GetRender(name);
719         if(re==NULL) {
720                 
721                 /* new render data struct */
722                 re= MEM_callocN(sizeof(Render), "new render");
723                 BLI_addtail(&RenderList, re);
724                 strncpy(re->name, name, RE_MAXNAME);
725         }
726         
727         /* set default empty callbacks */
728         re->display_init= result_nothing;
729         re->display_clear= result_nothing;
730         re->display_draw= result_rcti_nothing;
731         re->timecursor= int_nothing;
732         re->test_break= void_nothing;
733         re->test_return= void_nothing;
734         re->error= print_error;
735         if(G.background)
736                 re->stats_draw= stats_background;
737         else
738                 re->stats_draw= stats_nothing;
739         
740         /* init some variables */
741         re->ycor= 1.0f;
742         
743         return re;
744 }
745
746 /* only call this while you know it will remove the link too */
747 void RE_FreeRender(Render *re)
748 {
749         
750         free_renderdata_tables(re);
751         free_sample_tables(re);
752         
753         free_render_result(re->result);
754         free_render_result(re->pushedresult);
755         
756         BLI_remlink(&RenderList, re);
757         MEM_freeN(re);
758 }
759
760 /* exit blender */
761 void RE_FreeAllRender(void)
762 {
763         while(RenderList.first) {
764                 RE_FreeRender(RenderList.first);
765         }
766 }
767
768 /* ********* initialize state ******** */
769
770
771 /* what doesn't change during entire render sequence */
772 /* disprect is optional, if NULL it assumes full window render */
773 void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect)
774 {
775         re->ok= TRUE;   /* maybe flag */
776         
777         re->i.starttime= PIL_check_seconds_timer();
778         re->r= *rd;             /* hardcopy */
779         
780         re->winx= winx;
781         re->winy= winy;
782         if(disprect) {
783                 re->disprect= *disprect;
784                 re->rectx= disprect->xmax-disprect->xmin;
785                 re->recty= disprect->ymax-disprect->ymin;
786         }
787         else {
788                 re->disprect.xmin= re->disprect.ymin= 0;
789                 re->disprect.xmax= winx;
790                 re->disprect.ymax= winy;
791                 re->rectx= winx;
792                 re->recty= winy;
793         }
794         
795         if(re->rectx < 2 || re->recty < 2) {
796                 re->error("Image too small");
797                 re->ok= 0;
798         }
799         else {
800                 /* check state variables, osa? */
801                 if(re->r.mode & (R_OSA)) {
802                         re->osa= re->r.osa;
803                         if(re->osa>16) re->osa= 16;
804                 }
805                 else re->osa= 0;
806                 
807                 /* always call, checks for gamma, gamma tables and jitter too */
808                 make_sample_tables(re); 
809                 
810                 /* make empty render result, so display callbacks can initialize */
811                 free_render_result(re->result);
812                 re->result= MEM_callocN(sizeof(RenderResult), "new render result");
813                 re->result->rectx= re->rectx;
814                 re->result->recty= re->recty;
815         }
816 }
817
818 void RE_SetDispRect (struct Render *re, rcti *disprect)
819 {
820         re->disprect= *disprect;
821         re->rectx= disprect->xmax-disprect->xmin;
822         re->recty= disprect->ymax-disprect->ymin;
823         
824         /* initialize render result */
825         free_render_result(re->result);
826         re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
827 }
828
829 void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
830 {
831         /* re->ok flag? */
832         
833         re->viewplane= *viewplane;
834         re->clipsta= clipsta;
835         re->clipend= clipend;
836         re->r.mode &= ~R_ORTHO;
837
838         i_window(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat);
839 }
840
841 void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend)
842 {
843         /* re->ok flag? */
844         
845         re->viewplane= *viewplane;
846         re->clipsta= clipsta;
847         re->clipend= clipend;
848         re->r.mode |= R_ORTHO;
849
850         i_ortho(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat);
851 }
852
853 void RE_SetView(Render *re, float mat[][4])
854 {
855         /* re->ok flag? */
856         Mat4CpyMat4(re->viewmat, mat);
857         Mat4Invert(re->viewinv, re->viewmat);
858 }
859
860 /* image and movie output has to move to either imbuf or kernel */
861 void RE_display_init_cb(Render *re, void (*f)(RenderResult *rr))
862 {
863         re->display_init= f;
864 }
865 void RE_display_clear_cb(Render *re, void (*f)(RenderResult *rr))
866 {
867         re->display_clear= f;
868 }
869 void RE_display_draw_cb(Render *re, void (*f)(RenderResult *rr, volatile rcti *rect))
870 {
871         re->display_draw= f;
872 }
873
874 void RE_stats_draw_cb(Render *re, void (*f)(RenderStats *rs))
875 {
876         re->stats_draw= f;
877 }
878 void RE_timecursor_cb(Render *re, void (*f)(int))
879 {
880         re->timecursor= f;
881 }
882
883 void RE_test_break_cb(Render *re, int (*f)(void))
884 {
885         re->test_break= f;
886 }
887 void RE_test_return_cb(Render *re, int (*f)(void))
888 {
889         re->test_return= f;
890 }
891 void RE_error_cb(Render *re, void (*f)(char *str))
892 {
893         re->error= f;
894 }
895
896
897 /* ********* add object data (later) ******** */
898
899 /* object is considered fully prepared on correct time etc */
900 /* includes lights */
901 void RE_AddObject(Render *re, Object *ob)
902 {
903         
904 }
905
906 /* *************************************** */
907
908 static void *do_part_thread(void *pa_v)
909 {
910         RenderPart *pa= pa_v;
911         
912         /* need to return nicely all parts on esc */
913         if(R.test_break()==0) {
914                 
915                 pa->result= new_render_result(&R, &pa->disprect, pa->crop, RR_USEMEM);
916                 
917                 if(R.osa)
918                         zbufshadeDA_tile(pa);
919                 else
920                         zbufshade_tile(pa);
921                 
922                 /* merge too on break! */
923                 if(R.result->exrhandle)
924                         save_render_result_tile(&R, pa);
925                 else
926                         merge_render_result(R.result, pa->result);
927         }
928         
929         pa->ready= 1;
930         
931         return NULL;
932 }
933
934 /* returns with render result filled, not threaded, used for preview now only */
935 static void render_tile_processor(Render *re, int firsttile)
936 {
937         RenderPart *pa;
938         
939         if(re->test_break())
940                 return;
941
942         /* hrmf... exception, this is used for preview render, re-entrant, so render result has to be re-used */
943         if(re->result==NULL || re->result->layers.first==NULL) {
944                 if(re->result) free_render_result(re->result);
945                 re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
946         }
947         
948         re->stats_draw(&re->i);
949  
950         if(re->result==NULL)
951                 return;
952         
953         initparts(re);
954         
955         /* assuming no new data gets added to dbase... */
956         R= *re;
957         
958         for(pa= re->parts.first; pa; pa= pa->next) {
959                 if(firsttile) {
960                         re->i.partsdone++;      /* was reset in initparts */
961                         firsttile--;
962                 }
963                 else {
964                         do_part_thread(pa);
965                         
966                         if(pa->result) {
967                                 if(!re->test_break()) {
968                                         re->display_draw(pa->result, NULL);
969                                         
970                                         re->i.partsdone++;
971                                         re->stats_draw(&re->i);
972                                 }
973                                 free_render_result(pa->result);
974                                 pa->result= NULL;
975                         }               
976                         if(re->test_break())
977                                 break;
978                 }
979         }
980         
981         freeparts(re);
982 }
983
984 /* calculus for how much 1 pixel rendered should rotate the 3d geometry */
985 /* is not that simple, needs to be corrected for errors of larger viewplane sizes */
986 /* called in initrender.c, initparts() and convertblender.c, for speedvectors */
987 float panorama_pixel_rot(Render *re)
988 {
989         float psize, phi, xfac;
990         
991         /* size of 1 pixel mapped to viewplane coords */
992         psize= (re->viewplane.xmax-re->viewplane.xmin)/(float)re->winx;
993         /* angle of a pixel */
994         phi= atan(psize/re->clipsta);
995         
996         /* correction factor for viewplane shifting, first calculate how much the viewplane angle is */
997         xfac= ((re->viewplane.xmax-re->viewplane.xmin))/(float)re->xparts;
998         xfac= atan(0.5f*xfac/re->clipsta); 
999         /* and how much the same viewplane angle is wrapped */
1000         psize= 0.5f*phi*((float)re->partx);
1001         
1002         /* the ratio applied to final per-pixel angle */
1003         phi*= xfac/psize;
1004         
1005         return phi;
1006 }
1007
1008 /* call when all parts stopped rendering, to find the next Y slice */
1009 /* if slice found, it rotates the dbase */
1010 static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane)
1011 {
1012         RenderPart *pa, *best= NULL;
1013         
1014         *minx= re->winx;
1015         
1016         /* most left part of the non-rendering parts */
1017         for(pa= re->parts.first; pa; pa= pa->next) {
1018                 if(pa->ready==0 && pa->nr==0) {
1019                         if(pa->disprect.xmin < *minx) {
1020                                 best= pa;
1021                                 *minx= pa->disprect.xmin;
1022                         }
1023                 }
1024         }
1025                         
1026         if(best) {
1027                 float phi= panorama_pixel_rot(re);
1028
1029                 R.panodxp= (re->winx - (best->disprect.xmin + best->disprect.xmax) )/2;
1030                 R.panodxv= ((viewplane->xmax-viewplane->xmin)*R.panodxp)/(float)R.winx;
1031                 
1032                 /* shift viewplane */
1033                 R.viewplane.xmin = viewplane->xmin + R.panodxv;
1034                 R.viewplane.xmax = viewplane->xmax + R.panodxv;
1035                 RE_SetWindow(re, &R.viewplane, R.clipsta, R.clipend);
1036                 Mat4CpyMat4(R.winmat, re->winmat);
1037                 
1038                 /* rotate database according to part coordinates */
1039                 project_renderdata(re, projectverto, 1, -R.panodxp*phi);
1040                 R.panosi= sin(R.panodxp*phi);
1041                 R.panoco= cos(R.panodxp*phi);
1042         }
1043         return best;
1044 }
1045
1046 static RenderPart *find_next_part(Render *re, int minx)
1047 {
1048         RenderPart *pa, *best= NULL;
1049         int centx=re->winx/2, centy=re->winy/2, tot=1;
1050         int mindist, distx, disty;
1051         
1052         /* find center of rendered parts, image center counts for 1 too */
1053         for(pa= re->parts.first; pa; pa= pa->next) {
1054                 if(pa->ready) {
1055                         centx+= (pa->disprect.xmin+pa->disprect.xmax)/2;
1056                         centy+= (pa->disprect.ymin+pa->disprect.ymax)/2;
1057                         tot++;
1058                 }
1059         }
1060         centx/=tot;
1061         centy/=tot;
1062         
1063         /* closest of the non-rendering parts */
1064         mindist= re->winx*re->winy;
1065         for(pa= re->parts.first; pa; pa= pa->next) {
1066                 if(pa->ready==0 && pa->nr==0) {
1067                         distx= centx - (pa->disprect.xmin+pa->disprect.xmax)/2;
1068                         disty= centy - (pa->disprect.ymin+pa->disprect.ymax)/2;
1069                         distx= (int)sqrt(distx*distx + disty*disty);
1070                         if(distx<mindist) {
1071                                 if(re->r.mode & R_PANORAMA) {
1072                                         if(pa->disprect.xmin==minx) {
1073                                                 best= pa;
1074                                                 mindist= distx;
1075                                         }
1076                                 }
1077                                 else {
1078                                         best= pa;
1079                                         mindist= distx;
1080                                 }
1081                         }
1082                 }
1083         }
1084         return best;
1085 }
1086
1087 static void print_part_stats(Render *re, RenderPart *pa)
1088 {
1089         char str[64];
1090         
1091         sprintf(str, "Part %d-%d", pa->nr, re->i.totpart);
1092         re->i.infostr= str;
1093         re->stats_draw(&re->i);
1094         re->i.infostr= NULL;
1095 }
1096
1097 static void threaded_tile_processor(Render *re)
1098 {
1099         ListBase threads;
1100         RenderPart *pa, *nextpa;
1101         RenderResult *rr;
1102         rctf viewplane= re->viewplane;
1103         int maxthreads, rendering=1, counter= 1, drawtimer=0, hasdrawn, minx=0;
1104         
1105         /* first step; the entire render result, or prepare exr buffer saving */
1106         free_render_result(re->result);
1107         rr= re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & R_EXR_TILE_FILE);
1108         
1109         if(rr==NULL)
1110                 return;
1111         /* warning; no return here without closing exr file */
1112 //      if(re->re->test_break())
1113 //              return;
1114         
1115         initparts(re);
1116         
1117         if(rr->exrhandle) {
1118                 char str[FILE_MAXDIR+FILE_MAXFILE];
1119                 
1120                 render_unique_exr_name(re, str);
1121                 
1122                 printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
1123                 IMB_exrtile_begin_write(rr->exrhandle, str, rr->rectx, rr->recty, rr->rectx/re->xparts, rr->recty/re->yparts);
1124         }
1125         
1126         if(re->r.mode & R_THREADS) 
1127                 maxthreads= RE_MAXTHREAD;       /* should become button value too */
1128         else maxthreads= 1;
1129         
1130         BLI_init_threads(&threads, do_part_thread, maxthreads);
1131         
1132         /* assuming no new data gets added to dbase... */
1133         R= *re;
1134         
1135         /* set threadsafe break */
1136         R.test_break= thread_break;
1137         
1138         /* timer loop demands to sleep when no parts are left, so we enter loop with a part */
1139         if(re->r.mode & R_PANORAMA)
1140                 nextpa= find_next_pano_slice(re, &minx, &viewplane);
1141         else
1142                 nextpa= find_next_part(re, 0);
1143         
1144         while(rendering) {
1145                 
1146                 if(re->test_break())
1147                         PIL_sleep_ms(50);
1148                 else if(nextpa && BLI_available_threads(&threads)) {
1149                         drawtimer= 0;
1150                         nextpa->nr= counter++;  /* for nicest part, and for stats */
1151                         nextpa->thread= BLI_available_thread_index(&threads);   /* sample index */
1152                         BLI_insert_thread(&threads, nextpa);
1153
1154                         nextpa= find_next_part(re, minx);
1155                 }
1156                 else if(re->r.mode & R_PANORAMA) {
1157                         if(nextpa==NULL && BLI_available_threads(&threads)==maxthreads)
1158                                 nextpa= find_next_pano_slice(re, &minx, &viewplane);
1159                         else {
1160                                 PIL_sleep_ms(50);
1161                                 drawtimer++;
1162                         }
1163                 }
1164                 else {
1165                         PIL_sleep_ms(50);
1166                         drawtimer++;
1167                 }
1168                 
1169                 /* check for ready ones to display, and if we need to continue */
1170                 rendering= 0;
1171                 hasdrawn= 0;
1172                 for(pa= re->parts.first; pa; pa= pa->next) {
1173                         if(pa->ready) {
1174                                 if(pa->result) {
1175                                         BLI_remove_thread(&threads, pa);
1176
1177                                         re->display_draw(pa->result, NULL);
1178                                         print_part_stats(re, pa);
1179                                         
1180                                         free_render_result(pa->result);
1181                                         pa->result= NULL;
1182                                         re->i.partsdone++;
1183                                         hasdrawn= 1;
1184                                 }
1185                         }
1186                         else {
1187                                 rendering= 1;
1188                                 if(pa->nr && pa->result && drawtimer>20) {
1189                                         re->display_draw(pa->result, &pa->result->renrect);
1190                                         hasdrawn= 1;
1191                                 }
1192                         }
1193                 }
1194                 if(hasdrawn)
1195                         drawtimer= 0;
1196
1197                 /* on break, wait for all slots to get freed */
1198                 if( (g_break=re->test_break()) && BLI_available_threads(&threads)==maxthreads)
1199                         rendering= 0;
1200                 
1201         }
1202         
1203         if(rr->exrhandle) {
1204                 IMB_exr_close(rr->exrhandle);
1205                 rr->exrhandle= NULL;
1206                 if(!re->test_break())
1207                         read_render_result(re);
1208         }
1209         
1210         /* unset threadsafety */
1211         g_break= 0;
1212         
1213         BLI_end_threads(&threads);
1214         freeparts(re);
1215 }
1216
1217 /* currently only called by preview renders and envmap */
1218 void RE_TileProcessor(Render *re, int firsttile)
1219 {
1220         /* the partsdone variable has to be reset to firsttile, to survive esc before it was set to zero */
1221         
1222         re->i.partsdone= firsttile;
1223
1224         re->i.starttime= PIL_check_seconds_timer();
1225
1226         //if(re->r.mode & R_THREADS) 
1227         //      threaded_tile_processor(re);
1228         //else
1229                 render_tile_processor(re, firsttile);
1230                 
1231         re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
1232         re->stats_draw(&re->i);
1233 }
1234
1235
1236 /* ************  This part uses API, for rendering Blender scenes ********** */
1237
1238 static void do_render_3d(Render *re)
1239 {
1240         
1241 //      re->cfra= cfra; /* <- unused! */
1242         
1243         /* make render verts/faces/halos/lamps */
1244         if(render_scene_needs_vector(re))
1245                 RE_Database_FromScene_Vectors(re, re->scene);
1246         else
1247            RE_Database_FromScene(re, re->scene, 1);
1248         
1249         threaded_tile_processor(re);
1250         
1251         /* do left-over 3d post effects (flares) */
1252         if(re->flag & R_HALO)
1253                 if(!re->test_break())
1254                         add_halo_flare(re);
1255
1256         
1257         /* free all render verts etc */
1258         RE_Database_Free(re);
1259 }
1260
1261 /* called by blur loop, accumulate renderlayers */
1262 static void addblur_rect(RenderResult *rr, float *rectf, float *rectf1, float blurfac, int channels)
1263 {
1264         float mfac= 1.0f - blurfac;
1265         int a, b, stride= channels*rr->rectx;
1266         int len= stride*sizeof(float);
1267         
1268         for(a=0; a<rr->recty; a++) {
1269                 if(blurfac==1.0f) {
1270                         memcpy(rectf, rectf1, len);
1271                 }
1272                 else {
1273                         float *rf= rectf, *rf1= rectf1;
1274                         
1275                         for( b= rr->rectx*channels; b>0; b--, rf++, rf1++) {
1276                                 rf[0]= mfac*rf[0] + blurfac*rf1[0];
1277                         }
1278                 }
1279                 rectf+= stride;
1280                 rectf1+= stride;
1281         }
1282 }
1283
1284 /* called by blur loop, accumulate renderlayers */
1285 static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float blurfac)
1286 {
1287         RenderLayer *rl, *rl1;
1288         RenderPass *rpass, *rpass1;
1289         
1290         rl1= brr->layers.first;
1291         for(rl= rr->layers.first; rl && rl1; rl= rl->next, rl1= rl1->next) {
1292                 
1293                 /* combined */
1294                 if(rl->rectf && rl1->rectf)
1295                         addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4);
1296                 
1297                 /* passes are allocated in sync */
1298                 rpass1= rl1->passes.first;
1299                 for(rpass= rl->passes.first; rpass && rpass1; rpass= rpass->next, rpass1= rpass1->next) {
1300                         addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
1301                 }
1302         }
1303 }
1304
1305 /* main blur loop, can be called by fields too */
1306 static void do_render_blur_3d(Render *re)
1307 {
1308         RenderResult *rres;
1309         float blurfac;
1310         int blur= re->r.osa;
1311         
1312         /* create accumulation render result */
1313         rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
1314         
1315         /* do the blur steps */
1316         while(blur--) {
1317                 set_mblur_offs( re->r.blurfac*((float)(re->r.osa-blur))/(float)re->r.osa );
1318                 
1319                 re->i.curblur= re->r.osa-blur;  /* stats */
1320                 
1321                 do_render_3d(re);
1322                 
1323                 blurfac= 1.0f/(float)(re->r.osa-blur);
1324                 
1325                 merge_renderresult_blur(rres, re->result, blurfac);
1326                 if(re->test_break()) break;
1327         }
1328         
1329         /* swap results */
1330         free_render_result(re->result);
1331         re->result= rres;
1332         
1333         set_mblur_offs(0.0f);
1334         re->i.curblur= 0;       /* stats */
1335         
1336         /* weak... the display callback wants an active renderlayer pointer... */
1337         re->result->renlay= render_get_active_layer(re, re->result);
1338         re->display_draw(re->result, NULL);     
1339 }
1340
1341
1342 /* function assumes rectf1 and rectf2 to be half size of rectf */
1343 static void interleave_rect(RenderResult *rr, float *rectf, float *rectf1, float *rectf2, int channels)
1344 {
1345         int a, stride= channels*rr->rectx;
1346         int len= stride*sizeof(float);
1347         
1348         for(a=0; a<rr->recty; a+=2) {
1349                 memcpy(rectf, rectf1, len);
1350                 rectf+= stride;
1351                 rectf1+= stride;
1352                 memcpy(rectf, rectf2, len);
1353                 rectf+= stride;
1354                 rectf2+= stride;
1355         }
1356 }
1357
1358 /* merge render results of 2 fields */
1359 static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, RenderResult *rr2)
1360 {
1361         RenderLayer *rl, *rl1, *rl2;
1362         RenderPass *rpass, *rpass1, *rpass2;
1363         
1364         rl1= rr1->layers.first;
1365         rl2= rr2->layers.first;
1366         for(rl= rr->layers.first; rl && rl1 && rl2; rl= rl->next, rl1= rl1->next, rl2= rl2->next) {
1367                 
1368                 /* combined */
1369                 if(rl->rectf && rl1->rectf && rl2->rectf)
1370                         interleave_rect(rr, rl->rectf, rl1->rectf, rl2->rectf, 4);
1371                 
1372                 /* passes are allocated in sync */
1373                 rpass1= rl1->passes.first;
1374                 rpass2= rl2->passes.first;
1375                 for(rpass= rl->passes.first; rpass && rpass1 && rpass2; rpass= rpass->next, rpass1= rpass1->next, rpass2= rpass2->next) {
1376                         interleave_rect(rr, rpass->rect, rpass1->rect, rpass2->rect, rpass->channels);
1377                 }
1378         }
1379 }
1380
1381
1382 /* interleaves 2 frames */
1383 static void do_render_fields_3d(Render *re)
1384 {
1385         RenderResult *rr1, *rr2= NULL;
1386         
1387         /* no render result was created, we can safely halve render y */
1388         re->winy /= 2;
1389         re->recty /= 2;
1390         re->disprect.ymin /= 2;
1391         re->disprect.ymax /= 2;
1392         
1393         re->i.curfield= 1;      /* stats */
1394         
1395         /* first field, we have to call camera routine for correct aspect and subpixel offset */
1396         RE_SetCamera(re, re->scene->camera);
1397         if(re->r.mode & R_MBLUR)
1398                 do_render_blur_3d(re);
1399         else
1400                 do_render_3d(re);
1401         rr1= re->result;
1402         re->result= NULL;
1403         
1404         /* second field */
1405         if(!re->test_break()) {
1406                 
1407                 re->i.curfield= 2;      /* stats */
1408                 
1409                 re->flag |= R_SEC_FIELD;
1410                 if((re->r.mode & R_FIELDSTILL)==0) 
1411                         set_field_offs(0.5f);
1412                 RE_SetCamera(re, re->scene->camera);
1413                 if(re->r.mode & R_MBLUR)
1414                         do_render_blur_3d(re);
1415                 else
1416                         do_render_3d(re);
1417                 re->flag &= ~R_SEC_FIELD;
1418                 set_field_offs(0.0f);
1419                 
1420                 rr2= re->result;
1421         }
1422         
1423         /* allocate original height new buffers */
1424         re->winy *= 2;
1425         re->recty *= 2;
1426         re->disprect.ymin *= 2;
1427         re->disprect.ymax *= 2;
1428         re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
1429         
1430         if(rr2) {
1431                 if(re->r.mode & R_ODDFIELD)
1432                         merge_renderresult_fields(re->result, rr2, rr1);
1433                 else
1434                         merge_renderresult_fields(re->result, rr1, rr2);
1435                 
1436                 free_render_result(rr2);
1437         }
1438         free_render_result(rr1);
1439         
1440         re->i.curfield= 0;      /* stats */
1441         
1442         /* weak... the display callback wants an active renderlayer pointer... */
1443         re->result->renlay= render_get_active_layer(re, re->result);
1444         re->display_draw(re->result, NULL);
1445 }
1446
1447 static void load_backbuffer(Render *re)
1448 {
1449         if(re->r.alphamode == R_ADDSKY) {
1450                 Image *bima;
1451                 char name[256];
1452                 
1453                 strcpy(name, re->r.backbuf);
1454                 BLI_convertstringcode(name, G.sce, re->r.cfra);
1455                 
1456                 if(re->backbuf) {
1457                         re->backbuf->id.us--;
1458                         bima= re->backbuf;
1459                 }
1460                 else bima= NULL;
1461                 
1462                 re->backbuf= add_image(name);
1463                 
1464                 if(bima && bima->id.us<1) {
1465                         free_image_buffers(bima);
1466                 }
1467                 
1468                 if(re->backbuf && re->backbuf->ibuf==NULL) {
1469                         re->backbuf->ibuf= IMB_loadiffname(re->backbuf->name, IB_rect);
1470                         if(re->backbuf->ibuf==NULL) 
1471                                 re->backbuf->ok= 0;
1472                         else {
1473                                 re->backbuf->ok= 1;
1474                                 
1475                                 if (re->r.mode & R_FIELDS)
1476                                         image_de_interlace(re->backbuf, re->r.mode & R_ODDFIELD);
1477                         }
1478                 }
1479                 if(re->backbuf==NULL || re->backbuf->ok==0) {
1480                         // error() doesnt work with render window open
1481                         //error("No backbuf there!");
1482                         printf("Error: No backbuf %s\n", name);
1483                 }
1484         }
1485 }
1486
1487 /* main render routine, no compositing */
1488 static void do_render_fields_blur_3d(Render *re)
1489 {
1490         /* also check for camera here */
1491         if(re->scene->camera==NULL) {
1492                 printf("ERROR: Cannot render, no camera\n");
1493                 G.afbreek= 1;
1494                 return;
1495         }
1496         
1497         /* backbuffer initialize */
1498         if(re->r.bufflag & 1)
1499                 load_backbuffer(re);
1500
1501         /* now use renderdata and camera to set viewplane */
1502         RE_SetCamera(re, re->scene->camera);
1503         
1504         if(re->r.mode & R_FIELDS)
1505                 do_render_fields_3d(re);
1506         else if(re->r.mode & R_MBLUR)
1507                 do_render_blur_3d(re);
1508         else
1509                 do_render_3d(re);
1510         
1511         /* when border render, check if we have to insert it in black */
1512         if(re->result) {
1513                 if(re->r.mode & R_BORDER) {
1514                         if((re->r.mode & R_CROP)==0) {
1515                                 RenderResult *rres;
1516                                 
1517                                 /* sub-rect for merge call later on */
1518                                 re->result->tilerect= re->disprect;
1519                                 
1520                                 /* this copying sequence could become function? */
1521                                 re->disprect.xmin= re->disprect.ymin= 0;
1522                                 re->disprect.xmax= re->winx;
1523                                 re->disprect.ymax= re->winy;
1524                                 re->rectx= re->winx;
1525                                 re->recty= re->winy;
1526                                 
1527                                 rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
1528                                 
1529                                 merge_render_result(rres, re->result);
1530                                 free_render_result(re->result);
1531                                 re->result= rres;
1532                                 
1533                                 /* weak... the display callback wants an active renderlayer pointer... */
1534                                 re->result->renlay= render_get_active_layer(re, re->result);
1535                                 
1536                                 re->display_init(re->result);
1537                                 re->display_draw(re->result, NULL);
1538                         }
1539                 }
1540         }
1541 }
1542
1543
1544 /* within context of current Render *re, render another scene.
1545    it uses current render image size and disprect, but doesn't execute composite
1546 */
1547 static void render_scene(Render *re, Scene *sce, int cfra)
1548 {
1549         Render *resc= RE_NewRender(sce->id.name);
1550         
1551         sce->r.cfra= cfra;
1552                 
1553         /* initial setup */
1554         RE_InitState(resc, &sce->r, re->winx, re->winy, &re->disprect);
1555         
1556         /* this to enable this scene to create speed vectors */
1557         resc->r.scemode |= R_DOCOMP;
1558         
1559         /* still unsure entity this... */
1560         resc->scene= sce;
1561         
1562         /* ensure scene has depsgraph, base flags etc OK. Warning... also sets G.scene */
1563         set_scene_bg(sce);
1564
1565         /* copy callbacks */
1566         resc->display_draw= re->display_draw;
1567         resc->test_break= re->test_break;
1568         resc->stats_draw= re->stats_draw;
1569         
1570         do_render_fields_blur_3d(resc);
1571 }
1572
1573 static void ntree_render_scenes(Render *re)
1574 {
1575         bNode *node;
1576         int cfra= re->scene->r.cfra;
1577         
1578         if(re->scene->nodetree==NULL) return;
1579         
1580         /* check for render-layers nodes using other scenes, we tag them LIB_DOIT */
1581         for(node= re->scene->nodetree->nodes.first; node; node= node->next) {
1582                 if(node->type==CMP_NODE_R_LAYERS) {
1583                         if(node->id) {
1584                                 if(node->id != (ID *)re->scene)
1585                                         node->id->flag |= LIB_DOIT;
1586                                 else
1587                                         node->id->flag &= ~LIB_DOIT;
1588                         }
1589                 }
1590         }
1591         
1592         /* now foreach render-result node tagged we do a full render */
1593         /* results are stored in a way compisitor will find it */
1594         for(node= re->scene->nodetree->nodes.first; node; node= node->next) {
1595                 if(node->type==CMP_NODE_R_LAYERS) {
1596                         if(node->id && node->id != (ID *)re->scene) {
1597                                 if(node->id->flag & LIB_DOIT) {
1598                                         render_scene(re, (Scene *)node->id, cfra);
1599                                         node->id->flag &= ~LIB_DOIT;
1600                                 }
1601                         }
1602                 }
1603         }
1604         
1605         /* still the global... */
1606         if(G.scene!=re->scene)
1607                 set_scene_bg(re->scene);
1608         
1609 }
1610
1611 /* helper call to detect if theres a composite with render-result node */
1612 static int composite_needs_render(Scene *sce)
1613 {
1614         bNodeTree *ntree= sce->nodetree;
1615         bNode *node;
1616         
1617         if(ntree==NULL) return 1;
1618         if(sce->use_nodes==0) return 1;
1619         if((sce->r.scemode & R_DOCOMP)==0) return 1;
1620                 
1621         for(node= ntree->nodes.first; node; node= node->next) {
1622                 if(node->type==CMP_NODE_R_LAYERS)
1623                         if(node->id==NULL || node->id==&sce->id)
1624                                 return 1;
1625         }
1626         return 0;
1627 }
1628
1629 /* bad call... need to think over proper method still */
1630 static void render_composit_stats(char *str)
1631 {
1632         R.i.infostr= str;
1633         R.stats_draw(&R.i);
1634         R.i.infostr= NULL;
1635 }
1636
1637 /* returns fully composited render-result on given time step (in RenderData) */
1638 static void do_render_composite_fields_blur_3d(Render *re)
1639 {
1640         bNodeTree *ntree= re->scene->nodetree;
1641         
1642         /* INIT seeding, compositor can use random texture */
1643         BLI_srand(re->r.cfra);
1644         
1645         if(composite_needs_render(re->scene)) {
1646                 /* save memory... free all cached images */
1647                 ntreeFreeCache(ntree);
1648                 
1649                 do_render_fields_blur_3d(re);
1650         }
1651         
1652         /* swap render result */
1653         if(re->r.scemode & R_SINGLE_LAYER)
1654                 pop_render_result(re);
1655         
1656         if(!re->test_break() && ntree) {
1657                 ntreeCompositTagRender(ntree);
1658                 ntreeCompositTagAnimated(ntree);
1659                 
1660                 if(re->r.scemode & R_DOCOMP) {
1661                         /* checks if there are render-result nodes that need scene */
1662                         if((re->r.scemode & R_SINGLE_LAYER)==0)
1663                                 ntree_render_scenes(re);
1664                         
1665                         if(!re->test_break()) {
1666                                 ntree->stats_draw= render_composit_stats;
1667                                 ntree->test_break= re->test_break;
1668                                 /* in case it was never initialized */
1669                                 R.stats_draw= re->stats_draw;
1670                                 
1671                                 ntreeCompositExecTree(ntree, &re->r, G.background==0);
1672                                 ntree->stats_draw= NULL;
1673                                 ntree->test_break= NULL;
1674                         }
1675                 }
1676         }
1677
1678         re->display_draw(re->result, NULL);
1679 }
1680
1681 #ifndef DISABLE_YAFRAY
1682 /* yafray: main yafray render/export call */
1683 static void yafrayRender(Render *re)
1684 {
1685         free_render_result(re->result);
1686         re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
1687         
1688         // need this too, for aspect/ortho/etc info
1689         RE_SetCamera(re, re->scene->camera);
1690
1691         // switch must be done before prepareScene()
1692         if (!re->r.YFexportxml)
1693                 YAF_switchFile();
1694         else
1695                 YAF_switchPlugin();
1696         
1697         printf("Starting scene conversion.\n");
1698         RE_Database_FromScene(re, re->scene, 1);
1699         printf("Scene conversion done.\n");
1700         
1701         re->i.starttime = PIL_check_seconds_timer();
1702         
1703         YAF_exportScene(re);
1704
1705         /* also needed for yafray border render, straight copy from do_render_fields_blur_3d() */
1706         /* when border render, check if we have to insert it in black */
1707         if(re->result) {
1708                 if(re->r.mode & R_BORDER) {
1709                         if((re->r.mode & R_CROP)==0) {
1710                                 RenderResult *rres;
1711                                 
1712                                 /* sub-rect for merge call later on */
1713                                 re->result->tilerect= re->disprect;
1714                                 
1715                                 /* this copying sequence could become function? */
1716                                 re->disprect.xmin= re->disprect.ymin= 0;
1717                                 re->disprect.xmax= re->winx;
1718                                 re->disprect.ymax= re->winy;
1719                                 re->rectx= re->winx;
1720                                 re->recty= re->winy;
1721                                 
1722                                 rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
1723                                 
1724                                 merge_render_result(rres, re->result);
1725                                 free_render_result(re->result);
1726                                 re->result= rres;
1727                                 
1728                                 re->display_init(re->result);
1729                                 re->display_draw(re->result, NULL);
1730                         }
1731                 }
1732         }
1733
1734         re->i.lastframetime = PIL_check_seconds_timer()- re->i.starttime;
1735         re->stats_draw(&re->i);
1736         
1737         RE_Database_Free(re);
1738 }
1739
1740 #endif /* disable yafray */
1741
1742
1743 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
1744
1745
1746 /* main loop: doing sequence + fields + blur + 3d render + compositing */
1747 static void do_render_all_options(Render *re)
1748 {
1749         re->i.starttime= PIL_check_seconds_timer();
1750
1751         if(re->r.scemode & R_DOSEQ) {
1752                 /* note: do_render_seq() frees rect32 when sequencer returns float images */
1753                 if(!re->test_break()) 
1754                         do_render_seq(re->result, re->r.cfra);
1755                 
1756                 re->stats_draw(&re->i);
1757                 re->display_draw(re->result, NULL);
1758                 
1759         }
1760         else {
1761 #ifndef DISABLE_YAFRAY
1762                 if(re->r.renderer==R_YAFRAY)
1763                         yafrayRender(re);
1764                 else
1765                         do_render_composite_fields_blur_3d(re);
1766 #else
1767                 do_render_composite_fields_blur_3d(re);
1768 #endif
1769         }
1770         
1771         re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
1772         re->stats_draw(&re->i);
1773 }
1774
1775 static int is_rendering_allowed(Render *re)
1776 {
1777         
1778         /* forbidden combinations */
1779         if(re->r.mode & R_PANORAMA) {
1780                 if(re->r.mode & R_BORDER) {
1781                         re->error("No border supported for Panorama");
1782                         return 0;
1783                 }
1784                 if(re->r.mode & R_ORTHO) {
1785                         re->error("No Ortho render possible for Panorama");
1786                         return 0;
1787                 }
1788         }
1789         
1790         if(re->r.mode & R_BORDER) {
1791                 if(re->r.border.xmax <= re->r.border.xmin || 
1792                    re->r.border.ymax <= re->r.border.ymin) {
1793                         re->error("No border area selected.");
1794                         return 0;
1795                 }
1796                 if(re->r.scemode & R_EXR_TILE_FILE) {
1797                         re->error("Border render and Buffer-save not supported yet");
1798                         return 0;
1799                 }
1800         }
1801         
1802         if(re->r.scemode & R_EXR_TILE_FILE) {
1803                 char str[FILE_MAXDIR+FILE_MAXFILE];
1804                 
1805                 render_unique_exr_name(re, str);
1806                 
1807                 if (BLI_is_writable(str)==0) {
1808                         re->error("Can not save render buffers, check the temp default path");
1809                         return 0;
1810                 }
1811                 
1812         }
1813         
1814         if(re->r.scemode & R_DOCOMP) {
1815                 if(re->scene->use_nodes) {
1816                         bNodeTree *ntree= re->scene->nodetree;
1817                         bNode *node;
1818                 
1819                         if(ntree==NULL) {
1820                                 re->error("No Nodetree in Scene");
1821                                 return 0;
1822                         }
1823                 
1824                         for(node= ntree->nodes.first; node; node= node->next)
1825                                 if(node->type==CMP_NODE_COMPOSITE)
1826                                         break;
1827                         
1828                         if(node==NULL) {
1829                                 re->error("No Render Output Node in Scene");
1830                                 return 0;
1831                         }
1832                 }
1833         }
1834         
1835         /* check valid camera, without camera render is OK (compo, seq) */
1836         if(re->scene->camera==NULL)
1837                 re->scene->camera= scene_find_camera(re->scene);
1838         
1839         if(!(re->r.scemode & (R_DOSEQ|R_DOCOMP))) {
1840                 if(re->scene->camera==NULL) {
1841                         re->error("No camera");
1842                         return 0;
1843                 }
1844         }
1845         
1846         return 1;
1847 }
1848
1849 /* evaluating scene options for general Blender render */
1850 static int render_initialize_from_scene(Render *re, Scene *scene)
1851 {
1852         int winx, winy;
1853         rcti disprect;
1854         
1855         /* r.xsch and r.ysch has the actual view window size
1856                 r.border is the clipping rect */
1857         
1858         /* calculate actual render result and display size */
1859         winx= (scene->r.size*scene->r.xsch)/100;
1860         winy= (scene->r.size*scene->r.ysch)/100;
1861         
1862         /* we always render smaller part, inserting it in larger image is compositor bizz, it uses disprect for it */
1863         if(scene->r.mode & R_BORDER) {
1864                 disprect.xmin= scene->r.border.xmin*winx;
1865                 disprect.xmax= scene->r.border.xmax*winx;
1866                 
1867                 disprect.ymin= scene->r.border.ymin*winy;
1868                 disprect.ymax= scene->r.border.ymax*winy;
1869         }
1870         else {
1871                 disprect.xmin= disprect.ymin= 0;
1872                 disprect.xmax= winx;
1873                 disprect.ymax= winy;
1874         }
1875         
1876         if(scene->r.scemode & R_EXR_TILE_FILE) {
1877                 int partx= winx/scene->r.xparts, party= winy/scene->r.yparts;
1878                 
1879                 /* stupid exr tiles dont like different sizes */
1880                 if(winx != partx*scene->r.xparts || winy != party*scene->r.yparts) {
1881                         re->error("Sorry... exr tile saving only allowed with equally sized parts");
1882                         return 0;
1883                 }
1884                 if((scene->r.mode & R_FIELDS) && (party & 1)) {
1885                         re->error("Sorry... exr tile saving only allowed with equally sized parts");
1886                         return 0;
1887                 }
1888         }
1889         
1890         if(scene->r.scemode & R_SINGLE_LAYER)
1891                 push_render_result(re);
1892         
1893         RE_InitState(re, &scene->r, winx, winy, &disprect);
1894         
1895         re->scene= scene;
1896         if(!is_rendering_allowed(re))
1897                 return 0;
1898         
1899         re->display_init(re->result);
1900         re->display_clear(re->result);
1901         
1902         return 1;
1903 }
1904
1905 /* general Blender frame render call */
1906 void RE_BlenderFrame(Render *re, Scene *scene, int frame)
1907 {
1908         /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
1909         /* is also set by caller renderwin.c */
1910         G.rendering= 1;
1911         
1912         scene->r.cfra= frame;
1913         
1914         if(render_initialize_from_scene(re, scene)) {
1915                 do_render_all_options(re);
1916         }
1917         
1918         /* UGLY WARNING */
1919         G.rendering= 0;
1920 }
1921
1922 static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
1923 {
1924         char name[FILE_MAXDIR+FILE_MAXFILE];
1925         RenderResult rres;
1926         
1927         RE_GetResultImage(re, &rres);
1928
1929         /* write movie or image */
1930         if(BKE_imtype_is_movie(scene->r.imtype)) {
1931                 int dofree = 0;
1932                 /* note; the way it gets 32 bits rects is weak... */
1933                 if(rres.rect32==NULL) {
1934                         rres.rect32= MEM_mapallocN(sizeof(int)*rres.rectx*rres.recty, "temp 32 bits rect");
1935                         dofree = 1;
1936                 }
1937                 RE_ResultGet32(re, rres.rect32);
1938                 mh->append_movie(scene->r.cfra, rres.rect32, rres.rectx, rres.recty);
1939                 if(dofree) {
1940                         MEM_freeN(rres.rect32);
1941                 }
1942                 printf("Append frame %d", scene->r.cfra);
1943         } else {
1944                 ImBuf *ibuf= IMB_allocImBuf(rres.rectx, rres.recty, scene->r.planes, 0, 0);
1945                 int ok;
1946                 
1947                 BKE_makepicstring(name, scene->r.pic, scene->r.cfra, scene->r.imtype);
1948
1949                 /* if not exists, BKE_write_ibuf makes one */
1950                 ibuf->rect= rres.rect32;    
1951                 ibuf->rect_float= rres.rectf;
1952                 ibuf->zbuf_float= rres.rectz;
1953                 
1954                 /* float factor for random dither, imbuf takes care of it */
1955                 ibuf->dither= scene->r.dither_intensity;
1956
1957                 ok= BKE_write_ibuf(ibuf, name, scene->r.imtype, scene->r.subimtype, scene->r.quality);
1958                 
1959                 if(ok==0) {
1960                         printf("Render error: cannot save %s\n", name);
1961                         G.afbreek=1;
1962                 }
1963                 else printf("Saved: %s", name);
1964                 
1965                 /* optional preview images for exr */
1966                 if(ok && scene->r.imtype==R_OPENEXR && (scene->r.subimtype & R_PREVIEW_JPG)) {
1967                         if(BLI_testextensie(name, ".exr")) 
1968                                 name[strlen(name)-4]= 0;
1969                         BKE_add_image_extension(name, R_JPEG90);
1970                         ibuf->depth= 24; 
1971                         BKE_write_ibuf(ibuf, name, R_JPEG90, scene->r.subimtype, scene->r.quality);
1972                         printf("\nSaved: %s", name);
1973                 }
1974                 
1975                 /* imbuf knows which rects are not part of ibuf */
1976                 IMB_freeImBuf(ibuf);    
1977         }
1978         
1979         BLI_timestr(re->i.lastframetime, name);
1980         printf(" Time: %s\n", name);
1981         fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */
1982 }
1983
1984 /* saves images to disk */
1985 void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra)
1986 {
1987         bMovieHandle *mh= BKE_get_movie_handle(scene->r.imtype);
1988         int cfrao= scene->r.cfra;
1989         
1990         /* do not call for each frame, it initializes & pops output window */
1991         if(!render_initialize_from_scene(re, scene))
1992                 return;
1993         
1994         /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
1995         /* is also set by caller renderwin.c */
1996         G.rendering= 1;
1997         
1998         if(BKE_imtype_is_movie(scene->r.imtype))
1999                 mh->start_movie(&re->r, re->rectx, re->recty);
2000         
2001         if (mh->get_next_frame) {
2002                 while (!(G.afbreek == 1)) {
2003                         int nf = mh->get_next_frame();
2004                         if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) {
2005                                 scene->r.cfra = re->r.cfra = nf;
2006                                 
2007                                 do_render_all_options(re);
2008
2009                                 if(re->test_break() == 0) {
2010                                         do_write_image_or_movie(re, scene, mh);
2011                                 }
2012                         } else {
2013                                 re->test_break();
2014                         }
2015                 }
2016         } else {
2017                 for(scene->r.cfra= sfra; 
2018                     scene->r.cfra<=efra; scene->r.cfra++) {
2019                         re->r.cfra= scene->r.cfra;         /* weak.... */
2020                 
2021                         do_render_all_options(re);
2022
2023                         if(re->test_break() == 0) {
2024                                 do_write_image_or_movie(re, scene, mh);
2025                         }
2026                 
2027                         if(G.afbreek==1) break;
2028                 }
2029         }
2030         
2031         /* end movie */
2032         if(BKE_imtype_is_movie(scene->r.imtype))
2033                 mh->end_movie();
2034
2035         scene->r.cfra= cfrao;
2036         
2037         /* UGLY WARNING */
2038         G.rendering= 0;
2039 }
2040
2041 /* note; repeated win/disprect calc... solve that nicer, also in compo */
2042
2043 void RE_ReadRenderResult(Scene *scene, Scene *scenode)
2044 {
2045         Render *re;
2046         int winx, winy;
2047         rcti disprect;
2048         
2049         /* calculate actual render result and display size */
2050         winx= (scene->r.size*scene->r.xsch)/100;
2051         winy= (scene->r.size*scene->r.ysch)/100;
2052         
2053         /* only in movie case we render smaller part */
2054         if(scene->r.mode & R_BORDER) {
2055                 disprect.xmin= scene->r.border.xmin*winx;
2056                 disprect.xmax= scene->r.border.xmax*winx;
2057                 
2058                 disprect.ymin= scene->r.border.ymin*winy;
2059                 disprect.ymax= scene->r.border.ymax*winy;
2060         }
2061         else {
2062                 disprect.xmin= disprect.ymin= 0;
2063                 disprect.xmax= winx;
2064                 disprect.ymax= winy;
2065         }
2066         
2067         if(scenode)
2068                 scene= scenode;
2069         
2070         re= RE_NewRender(scene->id.name);
2071         RE_InitState(re, &scene->r, winx, winy, &disprect);
2072         re->scene= scene;
2073         
2074         read_render_result(re);
2075 }