Giant commit!
[blender.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_object_types.h"
36 #include "DNA_scene_types.h"
37
38 #include "BKE_global.h"
39 #include "BKE_image.h"
40 #include "BKE_scene.h"
41 #include "BKE_writeavi.h"       /* <------ should be replaced once with generic movie module */
42
43 #include "MEM_guardedalloc.h"
44
45 #include "BLI_arithb.h"
46 #include "BLI_blenlib.h"
47
48 #include "PIL_time.h"
49 #include "IMB_imbuf.h"
50 #include "IMB_imbuf_types.h"
51
52 #include "RE_pipeline.h"
53 #include "radio.h"
54
55 #include "BSE_sequence.h"  /* <----------------- bad!!! */
56
57 /* internal */
58 #include "render_types.h"
59 #include "renderpipeline.h"
60 #include "renderdatabase.h"
61 #include "rendercore.h"
62 #include "envmap.h"
63 #include "initrender.h"
64 #include "shadbuf.h"
65 #include "zbuf.h"
66
67 #include "SDL_thread.h"
68
69 /* render flow
70
71 1) Initialize state
72 - state data, tables
73 - movie/image file init
74 - everything that doesn't change during animation
75
76 2) Initialize data
77 - camera, world, matrices
78 - make render verts, faces, halos, strands
79 - everything can change per frame/field
80
81 3) Render Processor
82 - multiple layers
83 - tiles, rect, baking
84 - layers/tiles optionally to disk or directly in Render Result
85
86 4) Composit Render Result
87 - also read external files etc
88
89 5) Image Files
90 - save file or append in movie
91
92 */
93
94
95 /* ********* globals ******** */
96
97 /* here we store all renders */
98 static struct ListBase RenderList= {NULL, NULL};
99
100 /* hardcopy of current render, used while rendering for speed */
101 Render R;
102
103 /* ********* alloc and free ******** */
104
105
106 static SDL_mutex *malloc_lock= NULL;
107
108 void *RE_mallocN(int len, char *name)
109 {
110         void *mem;
111         if(malloc_lock) SDL_mutexP(malloc_lock);
112         mem= MEM_mallocN(len, name);
113         if(malloc_lock) SDL_mutexV(malloc_lock);
114         return mem;
115 }
116 void *RE_callocN(int len, char *name)
117 {
118         void *mem;
119         if(malloc_lock) SDL_mutexP(malloc_lock);
120         mem= MEM_callocN(len, name);
121         if(malloc_lock) SDL_mutexV(malloc_lock);
122         return mem;
123 }
124 void RE_freeN(void *poin)
125 {
126         if(malloc_lock) SDL_mutexP(malloc_lock);
127         MEM_freeN(poin);
128         if(malloc_lock) SDL_mutexV(malloc_lock);
129 }
130
131 /* ********************** */
132
133
134 /* default callbacks, set in each new render */
135 static void result_nothing(RenderResult *rr) {}
136 static void result_rcti_nothing(RenderResult *rr, rcti *rect) {}
137 static void stats_nothing(RenderStats *rs) {}
138 static void int_nothing(int val) {}
139 static int void_nothing(void) {return 0;}
140 static void print_error(const char *str) {printf("ERROR: %s\n", str);}
141
142 static void free_render_result(RenderResult *res)
143 {
144         if(res==NULL) return;
145
146         while(res->layers.first) {
147                 RenderLayer *rl= res->layers.first;
148                 if(rl->rectf) RE_freeN(rl->rectf);
149                 if(rl->rectz) RE_freeN(rl->rectz);
150                 BLI_remlink(&res->layers, rl);
151                 RE_freeN(rl);
152         }
153         
154         if(res->rect32)
155                 MEM_freeN(res->rect32);
156         
157         RE_freeN(res);
158 }
159
160 /* called by main render as well for parts */
161 /* will read info from Render *re to define layers */
162 /* called in threads */
163 /* winrct is coordinate rect of entire image, partrct the part within */
164 static RenderResult *new_render_result(Render *re, rcti *partrct, int crop)
165 {
166         RenderResult *rr;
167         RenderLayer *rl;
168         int rectx, recty;
169         
170         rectx= partrct->xmax - partrct->xmin;
171         recty= partrct->ymax - partrct->ymin;
172         
173         if(rectx<=0 || recty<=0)
174                 return NULL;
175         
176         rr= RE_callocN(sizeof(RenderResult), "new render result");
177         rr->rectx= rectx;
178         rr->recty= recty;
179         /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */
180         rr->crop= crop;
181         
182         /* tilerect is relative coordinates within render disprect. do not subtract crop yet */
183         rr->tilerect.xmin= partrct->xmin - re->disprect.xmin;
184         rr->tilerect.xmax= partrct->xmax - re->disprect.xmax;
185         rr->tilerect.ymin= partrct->ymin - re->disprect.ymin;
186         rr->tilerect.ymax= partrct->ymax - re->disprect.ymax;
187         
188         /* check renderdata for amount of layers */
189         /* for now just one */
190         rl= RE_callocN(sizeof(RenderLayer), "new render layer");
191         BLI_addtail(&rr->layers, rl);
192         
193         rl->rectf= RE_callocN(rectx*recty*sizeof(float)*4, "layer float rgba");
194         rl->rectz= RE_callocN(rectx*recty*sizeof(float), "layer float Z");
195         
196         return rr;
197 }
198
199 #define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
200 /* caller is responsible for allocating rect in correct size! */
201 void RE_ResultGet32(Render *re, unsigned int *rect)
202 {
203         if(re->result) {
204                 RenderLayer *rl= re->result->layers.first;
205                 float *fp= rl->rectf;
206                 if(fp) {
207                         int tot= re->rectx*re->recty;
208                         char *cp= (char *)rect;
209                         
210                         for(;tot>0; tot--, cp+=4, fp+=4) {
211                                 cp[0] = FTOCHAR(fp[0]);
212                                 cp[1] = FTOCHAR(fp[1]);
213                                 cp[2] = FTOCHAR(fp[2]);
214                                 cp[3] = FTOCHAR(fp[3]);
215                         }
216                         return;
217                 }
218         }
219         /* else fill with black */
220         memset(rect, sizeof(int)*re->rectx*re->recty, 0);
221 }
222
223 /* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
224 /* no test happens here if it fits... */
225 /* is used within threads */
226 static void merge_render_result(RenderResult *rr, RenderResult *rrpart)
227 {
228         RenderLayer *rl= rr->layers.first;
229         RenderLayer *rlp= rrpart->layers.first;
230         float *rf, *rfp;
231         int *rz=NULL, *rzp;
232         int y, height, len, copylen;
233         
234         if(rlp->rectf==NULL) return;
235         if(rl->rectf==NULL) return;
236         
237         rzp= NULL; //rlp->rectz;
238         rfp= rlp->rectf;
239         
240         copylen=len= rrpart->rectx;
241         height= rrpart->recty;
242         
243         if(rrpart->crop) {      /* filters add pixel extra */
244                 
245                 if(rzp) rzp+= rrpart->crop + rrpart->crop*len;
246                 if(rfp) rfp+= 4*(rrpart->crop + rrpart->crop*len);
247                 
248                 copylen= len-2*rrpart->crop;
249                 height -= 2*rrpart->crop;
250                 
251                 //              rz= re->rectz+ (pa->miny + rrpart->crop)*rr->rectx+ (pa->minx+rrpart->crop);
252                 rf= rl->rectf+ ( (rrpart->tilerect.ymin + rrpart->crop)*rr->rectx + (rrpart->tilerect.xmin+rrpart->crop) )*4;
253         }
254         else {
255                 //              rz= re->rectz +  (pa->disprect.ymin*rr->rectx + pa->disprect.xmin);
256                 rf= rl->rectf+ (rrpart->tilerect.ymin*rr->rectx + rrpart->tilerect.xmin)*4;
257         }
258
259         for(y=0; y<height; y++) {
260                 if(rzp) {
261                         memcpy(rz, rzp, 4*copylen);
262                         rz+= rr->rectx;
263                         rzp+= len;
264                 }
265                 if(rfp) {
266                         memcpy(rf, rfp, 16*copylen);
267                         rf+= 4*rr->rectx;
268                         rfp+= 4*len;
269                 }
270         }
271 }
272
273
274 /* *************************************************** */
275
276 Render *RE_GetRender(const char *name)
277 {
278         Render *re;
279         
280         /* search for existing renders */
281         for(re= RenderList.first; re; re= re->next) {
282                 if(strncmp(re->name, name, RE_MAXNAME)==0) {
283                         break;
284                 }
285         }
286         return re;
287 }
288
289 RenderResult *RE_GetResult(Render *re)
290 {
291         if(re)
292                 return re->result;
293         return NULL;
294 }
295
296 RenderStats *RE_GetStats(Render *re)
297 {
298         return &re->i;
299 }
300
301 Render *RE_NewRender(const char *name)
302 {
303         Render *re;
304         
305         /* only one render per name exists */
306         re= RE_GetRender(name);
307         if(re) {
308                 BLI_remlink(&RenderList, re);
309                 RE_FreeRender(re);
310         }
311         
312         /* new render data struct */
313         re= RE_callocN(sizeof(Render), "new render");
314         BLI_addtail(&RenderList, re);
315         strncpy(re->name, name, RE_MAXNAME);
316         
317         /* set default empty callbacks */
318         re->display_init= result_nothing;
319         re->display_clear= result_nothing;
320         re->display_draw= result_rcti_nothing;
321         re->timecursor= int_nothing;
322         re->test_break= void_nothing;
323         re->test_return= void_nothing;
324         re->error= print_error; 
325         re->stats_draw= stats_nothing;
326         
327         /* init some variables */
328         re->ycor= 1.0f;
329         
330         return re;
331 }
332
333 /* only call this while you know it will remove the link too */
334 void RE_FreeRender(Render *re)
335 {
336         
337         free_renderdata_tables(re);
338         free_sample_tables(re);
339         
340         free_render_result(re->result);
341         
342         BLI_remlink(&RenderList, re);
343         RE_freeN(re);
344 }
345
346 /* exit blender */
347 void RE_FreeAllRender(void)
348 {
349         while(RenderList.first) {
350                 RE_FreeRender(RenderList.first);
351         }
352 }
353
354 /* ********* initialize state ******** */
355
356
357 /* what doesn't change during entire render sequence */
358 /* disprect is optional, if NULL it assumes full window render */
359 void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect)
360 {
361         re->ok= TRUE;   /* maybe flag */
362         
363         re->i.starttime= PIL_check_seconds_timer();
364         re->r= *rd;             /* hardcopy */
365         
366         re->winx= winx;
367         re->winy= winy;
368         if(disprect) {
369                 re->disprect= *disprect;
370                 re->rectx= disprect->xmax-disprect->xmin;
371                 re->recty= disprect->ymax-disprect->ymin;
372         }
373         else {
374                 re->disprect.xmin= re->disprect.xmax= 0;
375                 re->disprect.xmax= winx;
376                 re->disprect.ymax= winy;
377                 re->rectx= winx;
378                 re->recty= winy;
379         }
380         
381         if(re->rectx < 2 || re->recty < 2) {
382                 re->error("Image too small");
383                 re->ok= 0;
384         }
385         else {
386                 /* check state variables, osa? */
387                 if(re->r.mode & (R_OSA|R_MBLUR)) {
388                         re->osa= re->r.osa;
389                         if(re->osa>16) re->osa= 16;
390                 }
391                 else re->osa= 0;
392                 
393                 /* always call, checks for gamma, gamma tables and jitter too */
394                 make_sample_tables(re); 
395                 
396                 /* initialize render result */
397                 free_render_result(re->result);
398                 re->result= new_render_result(re, &re->disprect, 0);
399
400         }
401 }
402
403 void RE_SetDispRect (struct Render *re, rcti *disprect)
404 {
405         re->disprect= *disprect;
406         re->rectx= disprect->xmax-disprect->xmin;
407         re->recty= disprect->ymax-disprect->ymin;
408         
409         /* initialize render result */
410         free_render_result(re->result);
411         re->result= new_render_result(re, &re->disprect, 0);
412 }
413
414 void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
415 {
416         /* re->ok flag? */
417         
418         re->viewplane= *viewplane;
419         re->clipsta= clipsta;
420         re->clipend= clipend;
421
422         i_window(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat);
423 }
424
425 void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend)
426 {
427         /* re->ok flag? */
428         
429         re->viewplane= *viewplane;
430         re->clipsta= clipsta;
431         re->clipend= clipend;
432         re->r.mode |= R_ORTHO;
433
434         i_ortho(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat);
435 }
436
437 void RE_SetView(Render *re, float mat[][4])
438 {
439         /* re->ok flag? */
440         Mat4CpyMat4(re->viewmat, mat);
441         Mat4Invert(re->viewinv, re->viewmat);
442 }
443
444 /* image and movie output has to move to either imbuf or kernel */
445
446 void RE_display_init_cb(Render *re, void (*f)(RenderResult *rr))
447 {
448         re->display_init= f;
449 }
450 void RE_display_clear_cb(Render *re, void (*f)(RenderResult *rr))
451 {
452         re->display_clear= f;
453 }
454 void RE_display_draw_cb(Render *re, void (*f)(RenderResult *rr, rcti *rect))
455 {
456         re->display_draw= f;
457 }
458
459 void RE_stats_draw_cb(Render *re, void (*f)(RenderStats *rs))
460 {
461         re->stats_draw= f;
462 }
463 void RE_timecursor_cb(Render *re, void (*f)(int))
464 {
465         re->timecursor= f;
466 }
467
468 void RE_test_break_cb(Render *re, int (*f)(void))
469 {
470         re->test_break= f;
471 }
472 void RE_test_return_cb(Render *re, int (*f)(void))
473 {
474         re->test_return= f;
475 }
476 void RE_error_cb(Render *re, void (*f)(const char *str))
477 {
478         re->error= f;
479 }
480
481
482 /* ********* add object data (later) ******** */
483
484 /* object is considered fully prepared on correct time etc */
485 /* includes lights */
486 void RE_AddObject(Render *re, Object *ob)
487 {
488         
489 }
490
491 /* ********** basic thread control API ************ */
492
493 #define RE_MAX_THREAD 4
494
495 typedef struct ThreadSlot {
496         RenderPart *part;
497         int avail;
498 } ThreadSlot;
499
500 static ThreadSlot threadslots[RE_MAX_THREAD];
501
502 static void init_threadslots(int tot)
503 {
504         int a;
505         
506         if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD;
507         else if(tot<1) tot= 1;
508         
509         for(a=0; a< RE_MAX_THREAD; a++) {
510                 threadslots[a].part= NULL;
511                 if(a<tot)
512                         threadslots[a].avail= 1;
513                 else
514                         threadslots[a].avail= 0;
515         }
516 }
517
518 static int available_threadslots(void)
519 {
520         int a, counter=0;
521         for(a=0; a< RE_MAX_THREAD; a++)
522                 if(threadslots[a].avail)
523                         counter++;
524         return counter;
525 }
526
527 static void insert_threadslot(RenderPart *pa)
528 {
529         int a;
530         for(a=0; a< RE_MAX_THREAD; a++) {
531                 if(threadslots[a].avail) {
532                         threadslots[a].avail= 0;
533                         threadslots[a].part= pa;
534                         pa->thread= a;
535                         break;
536                 }
537         }
538 }
539
540 static void remove_threadslot(RenderPart *pa)
541 {
542         int a;
543         for(a=0; a< RE_MAX_THREAD; a++) {
544                 if(threadslots[a].part==pa) {
545                         threadslots[a].avail= 1;
546                         threadslots[a].part= NULL;
547                 }
548         }
549 }
550
551 /* ********** basic thread control API ************ */
552
553 static int do_part_thread(void *pa_v)
554 {
555         RenderPart *pa= pa_v;
556         
557         /* need to return nicely all parts on esc */
558         if(R.test_break()==0) {
559                 
560                 pa->result= new_render_result(&R, &pa->disprect, pa->crop);
561                 
562                 if(R.osa)
563                         zbufshadeDA_tile(pa);
564                 else
565                         zbufshade_tile(pa);
566                         
567                 if(!R.test_break())
568                         merge_render_result(R.result, pa->result);
569         }
570         
571         pa->ready= 1;
572         remove_threadslot(pa);
573         
574         return 0;
575 }
576
577 /* returns with render result filled, not threaded */
578 static void render_tile_processor(Render *re)
579 {
580         RenderPart *pa;
581         
582         if(re->test_break())
583                 return;
584         
585         re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
586         re->stats_draw(&re->i);
587         re->i.starttime= PIL_check_seconds_timer();
588  
589         if(re->result==NULL)
590                 return;
591         
592         initparts(re);
593         
594         /* assuming no new data gets added to dbase... */
595         R= *re;
596         
597         for(pa= re->parts.first; pa; pa= pa->next) {
598                 do_part_thread(pa);
599                 
600                 if(pa->result) {
601                         if(!re->test_break()) {
602                                 re->display_draw(pa->result, NULL);
603                                 re->i.partsdone++;
604                         }
605                         free_render_result(pa->result);
606                         pa->result= NULL;
607                 }               
608                 if(re->test_break())
609                         break;
610         }
611         
612         re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
613         re->stats_draw(&re->i);
614
615         freeparts(re);
616 }
617
618 static RenderPart *find_nicest_part(Render *re)
619 {
620         RenderPart *pa, *best= NULL;
621         int centx=re->winx/2, centy=re->winy/2, tot=1;
622         int mindist, distx, disty;
623         
624         /* find center of rendered parts, image center counts for 1 too */
625         for(pa= re->parts.first; pa; pa= pa->next) {
626                 if(pa->ready) {
627                         centx+= (pa->disprect.xmin+pa->disprect.xmax)/2;
628                         centy+= (pa->disprect.ymin+pa->disprect.ymax)/2;
629                         tot++;
630                 }
631         }
632         centx/=tot;
633         centy/=tot;
634         
635         /* closest of the non-rendering parts */
636         mindist= re->winx*re->winy;
637         for(pa= re->parts.first; pa; pa= pa->next) {
638                 if(pa->ready==0 && pa->nr==0) {
639                         distx= centx - (pa->disprect.xmin+pa->disprect.xmax)/2;
640                         disty= centy - (pa->disprect.ymin+pa->disprect.ymax)/2;
641                         distx= (int)sqrt(distx*distx + disty*disty);
642                         if(distx<mindist) {
643                                 best= pa;
644                                 mindist= distx;
645                         }
646                 }
647         }
648         return best;
649 }
650
651 static void threaded_tile_processor(Render *re)
652 {
653         RenderPart *pa;
654         int maxthreads=2, rendering=1, counter= 1;
655         
656         if(re->result==NULL)
657                 return;
658         if(re->test_break())
659                 return;
660         
661         initparts(re);
662         init_threadslots(maxthreads);
663         
664         /* assuming no new data gets added to dbase... */
665         R= *re;
666         
667         malloc_lock = SDL_CreateMutex();
668         
669         while(rendering) {
670                 
671                 /* I noted that test_break() in a thread doesn't make ghost send ESC */
672                 if(available_threadslots() && !re->test_break()) {
673                         pa= find_nicest_part(re);
674                         if(pa) {
675                                 insert_threadslot(pa);
676                                 pa->nr= counter++;      /* only for stats */
677                                 SDL_CreateThread(do_part_thread, pa);
678                         }
679                 }
680                 else
681                         PIL_sleep_ms(50);
682                 
683                 /* check for ready ones to display, and if we need to continue */
684                 rendering= 0;
685                 for(pa= re->parts.first; pa; pa= pa->next) {
686                         if(pa->ready) {
687                                 if(pa->result) {
688                                         re->display_draw(pa->result, NULL);
689                                         free_render_result(pa->result);
690                                         pa->result= NULL;
691                                         re->i.partsdone++;
692                                 }
693                         }
694                         else rendering= 1;
695                 }
696                 
697                 /* on break, wait for all slots to get freed */
698                 if(re->test_break() && available_threadslots()==maxthreads)
699                         rendering= 0;
700                 
701         }
702         
703         if(malloc_lock) SDL_DestroyMutex(malloc_lock); malloc_lock= NULL;
704         
705         freeparts(re);
706 }
707
708 void RE_TileProcessor(Render *re)
709 {
710         if(re->r.mode & R_THREADS) 
711                 threaded_tile_processor(re);
712         else
713                 render_tile_processor(re);      
714 }
715
716
717 /* ************  This part uses API, for rendering Blender scenes ********** */
718
719 void render_one_frame(Render *re)
720 {
721         
722 //      re->cfra= cfra; /* <- unused! */
723         
724         /* make render verts/faces/halos/lamps */
725         RE_Database_FromScene(re, re->scene, 1);
726
727         RE_TileProcessor(re);
728         
729         /* free all render verts etc */
730         RE_Database_Free(re);
731 }
732
733 /* accumulates osa frames */
734 static void do_render_blurred(Render *re, float frame)
735 {
736         
737 }
738
739 /* interleaves 2 frames */
740 static void do_render_fields(Render *re)
741 {
742         
743 }
744
745 static void do_render_final(Render *re, Scene *scene)
746 {
747         if(re->r.scemode & R_DOSEQ) {
748                 re->result->rect32= MEM_callocN(sizeof(int)*re->rectx*re->recty, "rectot");
749                 if(!re->test_break()) 
750                         do_render_seq(re->result);
751         }
752         else {
753                 
754                 re->scene= scene;
755                 
756                 /* now use renderdata and camera to set viewplane */
757                 RE_SetCamera(re, re->scene->camera);
758                 
759                 if(re->r.mode & R_FIELDS)
760                         do_render_fields(re);
761                 else if(re->r.mode & R_MBLUR)
762                         do_render_blurred(re, re->scene->r.cfra);
763                 else
764                         render_one_frame(re);
765         }
766         
767
768         re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
769         re->stats_draw(&re->i);
770         
771         re->display_draw(re->result, NULL);
772         
773 }
774
775
776 static int is_rendering_allowed(Render *re)
777 {
778         
779         /* forbidden combinations */
780         if(re->r.mode & R_PANORAMA) {
781                 if(re->r.mode & R_BORDER) {
782                         re->error("No border supported for Panorama");
783                         return 0;
784                 }
785                 if(re->r.yparts>1) {
786                         re->error("No Y-Parts supported for Panorama");
787                         return 0;
788                 }
789                 if(re->r.mode & R_ORTHO) {
790                         re->error("No Ortho render possible for Panorama");
791                         return 0;
792                 }
793         }
794         
795         if(re->r.mode & R_BORDER) {
796                 if(re->r.border.xmax <= re->r.border.xmin || 
797                    re->r.border.ymax <= re->r.border.ymin) {
798                         re->error("No border area selected.");
799                         return 0;
800                 }
801         }
802         
803         if(re->r.xparts*re->r.yparts>=2 && (re->r.mode & R_MOVIECROP) && (re->r.mode & R_BORDER)) {
804                 re->error("Combination of border, crop and parts not allowed");
805                 return 0;
806         }
807         
808         if(re->r.xparts*re->r.yparts>64) {
809                 re->error("No more than 64 parts supported");
810                 return 0;
811         }
812         
813         if(re->r.yparts>1 && (re->r.mode & R_PANORAMA)) {
814                 re->error("No Y-Parts supported for Panorama");
815                 return 0;
816         }
817         
818         /* check valid camera */
819         if(re->scene->camera==NULL)
820                 re->scene->camera= scene_find_camera(re->scene);
821         if(re->scene->camera==NULL) {
822                 re->error("No camera");
823                 return 0;
824         }
825         
826         
827         return 1;
828 }
829
830 /* evaluating scene options for general Blender render */
831 static int render_initialize_from_scene(Render *re, Scene *scene)
832 {
833         int winx, winy;
834         rcti disprect;
835         
836         /* r.xsch and r.ysch has the actual view window size
837                 r.border is the clipping rect */
838         
839         /* calculate actual render result and display size */
840         winx= (scene->r.size*scene->r.xsch)/100;
841         winy= (scene->r.size*scene->r.ysch)/100;
842         //      if(scene->r.mode & R_PANORAMA)
843         //              winx*= scene->r.xparts;
844         
845         /* only in movie case we render smaller part */
846         if(scene->r.mode & R_BORDER) {
847                 disprect.xmin= scene->r.border.xmin*winx;
848                 disprect.xmax= scene->r.border.xmax*winx;
849                 
850                 disprect.ymin= scene->r.border.ymin*winy;
851                 disprect.ymax= scene->r.border.ymax*winy;
852         }
853         else {
854                 disprect.xmin= disprect.ymin= 0;
855                 disprect.xmax= winx;
856                 disprect.ymax= winy;
857         }
858         
859         RE_InitState(re, &scene->r, winx, winy, &disprect);
860         
861         re->scene= scene;
862         if(!is_rendering_allowed(re))
863                 return 0;
864         
865         re->display_init(re->result);
866         re->display_clear(re->result);
867         
868         return 1;
869 }
870
871 /* general Blender frame render call */
872 /* should return 1 when all is OK, otherwise it throws up errors */
873 void RE_BlenderFrame(Render *re, Scene *scene, int frame)
874 {
875         /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
876         /* is also set by caller renderwin.c */
877         G.rendering= 1;
878         
879         if(render_initialize_from_scene(re, scene)) {
880                 do_render_final(re, scene);
881         }
882 }
883
884
885 /* saves images to disk */
886 void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra)
887 {
888         bMovieHandle *mh= BKE_get_movie_handle(scene->r.imtype);
889         int cfrao= scene->r.cfra;
890         char name[FILE_MAXDIR+FILE_MAXFILE];
891         
892         /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
893         /* is also set by caller renderwin.c */
894         G.rendering= 1;
895         
896         if(!render_initialize_from_scene(re, scene))
897            return;
898         
899         if(BKE_imtype_is_movie(scene->r.imtype))
900                 mh->start_movie(&G.scene->r, re->rectx, re->recty);
901         
902         for(scene->r.cfra= sfra; scene->r.cfra<=efra; G.scene->r.cfra++) {
903                 
904                 do_render_final(re, scene);
905                 
906                 /* write image or movie */
907                 if(re->test_break()==0) {
908                         RenderResult *rr= re->result;
909                         RenderLayer *rl= rr->layers.first;
910
911                         /* write movie or image */
912                         if(BKE_imtype_is_movie(scene->r.imtype)) {
913                                 if(rr->rect32==NULL) {
914                                         rr->rect32= MEM_mallocN(sizeof(int)*rr->rectx*rr->recty, "temp 32 bits rect");
915                                 }
916                                 RE_ResultGet32(re, rr->rect32);
917                                 mh->append_movie(scene->r.cfra, rr->rect32, rr->rectx, rr->recty);
918                                 printf("Append frame %d", scene->r.cfra);
919                         }
920                         else {
921                                 ImBuf *ibuf= IMB_allocImBuf(rr->rectx, rr->recty, scene->r.planes, 0, 0);
922                                 int ok;
923                                 
924                                 BKE_makepicstring(name, (scene->r.cfra));
925                                 ibuf->rect= rr->rect32;         /* if not exists, BKE_write_ibuf makes one */
926                                 ibuf->rect_float= rl->rectf;
927                                 ibuf->zbuf_float= rl->rectz;
928                                 ok= BKE_write_ibuf(ibuf, name, scene->r.imtype, scene->r.subimtype, scene->r.quality);
929                                 IMB_freeImBuf(ibuf);    /* imbuf knows which rects are not part of ibuf */
930
931                                 if(ok==0) {
932                                         printf("Render error: cannot save %s\n", name);
933                                         break;
934                                 }
935                                 else printf("Saved: %s", name);
936                         }
937                         
938                         BLI_timestr(re->i.lastframetime, name);
939                         printf(" Time: %s\n", name);
940                         fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */
941                 }
942                 
943                 if(G.afbreek==1) break;
944         }
945         
946         /* end movie */
947         if(BKE_imtype_is_movie(scene->r.imtype))
948                 mh->end_movie();
949
950         scene->r.cfra= cfrao;
951 }
952
953
954