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