Merged changes in the trunk up to revision 26856.
[blender-staging.git] / source / blender / render / intern / source / pipeline.c
index 298cf30fa5ad040b33c6859f0408cf3331e12f41..72b147e992762f21d71feac1d6a16cf23d373abc 100644 (file)
@@ -14,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2006 Blender Foundation.
  * All rights reserved.
@@ -36,6 +36,7 @@
 #include "DNA_node_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
 #include "DNA_userdef_types.h"
 
 #include "BKE_utildefines.h"
 #include "BKE_main.h"
 #include "BKE_node.h"
 #include "BKE_object.h"
+#include "BKE_report.h"
 #include "BKE_scene.h"
 #include "BKE_writeavi.h"      /* <------ should be replaced once with generic movie module */
+#include "BKE_sequencer.h"
+#include "BKE_pointcache.h"
+#include "BKE_animsys.h"       /* <------ should this be here?, needed for sequencer update */
 
 #include "MEM_guardedalloc.h"
 
-#include "BLI_arithb.h"
+#include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_rand.h"
 #include "BLI_threads.h"
 #include "intern/openexr/openexr_multi.h"
 
 #include "RE_pipeline.h"
-#include "radio.h"
-
-#include "BSE_sequence.h"  /* <----------------- bad!!! */
-
-#ifndef DISABLE_YAFRAY
-/* yafray: include for yafray export/render */
-#include "YafRay_Api.h"
-
-#endif /* disable yafray */
 
 #include "FRS_freestyle.h"
 #include "FRS_freestyle_config.h"
 - tiles, rect, baking
 - layers/tiles optionally to disk or directly in Render Result
 
-4) Composit Render Result
+4) Composite Render Result
 - also read external files etc
 
 5) Image Files
 /* ********* globals ******** */
 
 /* here we store all renders */
-static struct ListBase RenderList= {NULL, NULL};
+static struct {
+       ListBase renderlist;
+
+       /* render slots */
+       int viewslot, renderingslot;
+
+       /* commandline thread override */
+       int threads;
+} RenderGlobal = {{NULL, NULL}, 0, 0, -1}; 
 
 /* hardcopy of current render, used while rendering for speed */
 Render R;
 
-/* commandline thread override */
-static int commandline_threads= -1;
-
 /* ********* alloc and free ******** */
 
 
 static volatile int g_break= 0;
-static int thread_break(void)
+static int thread_break(void *unused)
 {
        return g_break;
 }
 
 /* default callbacks, set in each new render */
-static void result_nothing(RenderResult *rr) {}
-static void result_rcti_nothing(RenderResult *rr, volatile struct rcti *rect) {}
-static void stats_nothing(RenderStats *rs) {}
-static void int_nothing(int val) {}
-static int void_nothing(void) {return 0;}
-static void print_error(char *str) {printf("ERROR: %s\n", str);}
+static void result_nothing(void *unused, RenderResult *rr) {}
+static void result_rcti_nothing(void *unused, RenderResult *rr, volatile struct rcti *rect) {}
+static void stats_nothing(void *unused, RenderStats *rs) {}
+static void int_nothing(void *unused, int val) {}
+static void print_error(void *unused, char *str) {printf("ERROR: %s\n", str);}
+static int default_break(void *unused) {return G.afbreek == 1;}
 
-static void stats_background(RenderStats *rs)
+int RE_RenderInProgress(Render *re)
+{
+       return re->result_ok==0;
+}
+
+static void stats_background(void *unused, RenderStats *rs)
 {
        uintptr_t mem_in_use= MEM_get_memory_in_use();
        float megs_used_memory= mem_in_use/(1024.0*1024.0);
        char str[400], *spos= str;
        
-       spos+= sprintf(spos, "Fra:%d Mem:%.2fM ", G.scene->r.cfra, megs_used_memory);
+       spos+= sprintf(spos, "Fra:%d Mem:%.2fM ", rs->cfra, megs_used_memory);
        
        if(rs->curfield)
                spos+= sprintf(spos, "Field %d ", rs->curfield);
@@ -158,11 +164,11 @@ static void stats_background(RenderStats *rs)
        }
        else {
                if(rs->tothalo)
-                       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);
+                       spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d Ha:%d La:%d", rs->scenename, rs->totvert, rs->totface, rs->tothalo, rs->totlamp);
                else 
-                       spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->totlamp);
+                       spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d La:%d", rs->scenename, rs->totvert, rs->totface, rs->totlamp);
        }
-       printf(str); printf("\n");
+       printf("%s\n", str);
 }
 
 void RE_FreeRenderResult(RenderResult *res)
@@ -216,22 +222,28 @@ static void free_render_result(ListBase *lb, RenderResult *rr)
 /* all layers except the active one get temporally pushed away */
 static void push_render_result(Render *re)
 {
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
        /* officially pushed result should be NULL... error can happen with do_seq */
        RE_FreeRenderResult(re->pushedresult);
        
        re->pushedresult= re->result;
        re->result= NULL;
+
+       BLI_rw_mutex_unlock(&re->resultmutex);
 }
 
 /* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
 static void pop_render_result(Render *re)
 {
-       
        if(re->result==NULL) {
                printf("pop render result error; no current result!\n");
                return;
        }
+
        if(re->pushedresult) {
+               BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
                if(re->pushedresult->rectx==re->result->rectx && re->pushedresult->recty==re->result->recty) {
                        /* find which layer in pushedresult should be replaced */
                        SceneRenderLayer *srl;
@@ -258,6 +270,8 @@ static void pop_render_result(Render *re)
                
                RE_FreeRenderResult(re->pushedresult);
                re->pushedresult= NULL;
+
+               BLI_rw_mutex_unlock(&re->resultmutex);
        }
 }
 
@@ -303,6 +317,12 @@ static char *get_pass_name(int passtype, int channel)
                if(channel==2) return "Color.B";
                return "Color.A";
        }
+       if(passtype == SCE_PASS_EMIT) {
+               if(channel==-1) return "Emit";
+               if(channel==0) return "Emit.R";
+               if(channel==1) return "Emit.G";
+               return "Emit.B";
+       }
        if(passtype == SCE_PASS_DIFFUSE) {
                if(channel==-1) return "Diffuse";
                if(channel==0) return "Diffuse.R";
@@ -327,6 +347,18 @@ static char *get_pass_name(int passtype, int channel)
                if(channel==1) return "AO.G";
                return "AO.B";
        }
+       if(passtype == SCE_PASS_ENVIRONMENT) {
+               if(channel==-1) return "Environment";
+               if(channel==0) return "Environment.R";
+               if(channel==1) return "Environment.G";
+               return "Environment.B";
+       }
+       if(passtype == SCE_PASS_INDIRECT) {
+               if(channel==-1) return "Indirect";
+               if(channel==0) return "Indirect.R";
+               if(channel==1) return "Indirect.G";
+               return "Indirect.B";
+       }
        if(passtype == SCE_PASS_REFLECT) {
                if(channel==-1) return "Reflect";
                if(channel==0) return "Reflect.R";
@@ -353,6 +385,13 @@ static char *get_pass_name(int passtype, int channel)
                if(channel==-1) return "Mist";
                return "Mist.Z";
        }
+       if(passtype == SCE_PASS_RAYHITS)
+       {
+               if(channel==-1) return "Rayhits";
+               if(channel==0) return "Rayhits.R";
+               if(channel==1) return "Rayhits.G";
+               return "Rayhits.B";
+       }
        return "Unknown";
 }
 
@@ -377,6 +416,9 @@ static int passtype_from_name(char *str)
        if(strcmp(str, "Color")==0)
                return SCE_PASS_RGBA;
 
+       if(strcmp(str, "Emit")==0)
+               return SCE_PASS_EMIT;
+
        if(strcmp(str, "Diffuse")==0)
                return SCE_PASS_DIFFUSE;
 
@@ -389,6 +431,12 @@ static int passtype_from_name(char *str)
        if(strcmp(str, "AO")==0)
                return SCE_PASS_AO;
 
+       if(strcmp(str, "Environment")==0)
+               return SCE_PASS_ENVIRONMENT;
+
+       if(strcmp(str, "Indirect")==0)
+               return SCE_PASS_INDIRECT;
+
        if(strcmp(str, "Reflect")==0)
                return SCE_PASS_REFLECT;
 
@@ -404,12 +452,14 @@ static int passtype_from_name(char *str)
        if(strcmp(str, "Mist")==0)
                return SCE_PASS_MIST;
        
+       if(strcmp(str, "RayHits")==0)
+               return SCE_PASS_RAYHITS;
        return 0;
 }
 
 static void render_unique_exr_name(Render *re, char *str, int sample)
 {
-       char di[FILE_MAX], name[FILE_MAXFILE], fi[FILE_MAXFILE];
+       char di[FILE_MAX], name[FILE_MAXFILE+MAX_ID_NAME+100], fi[FILE_MAXFILE];
        
        BLI_strncpy(di, G.sce, FILE_MAX);
        BLI_splitdirstring(di, fi);
@@ -431,6 +481,8 @@ static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channel
        BLI_addtail(&rl->passes, rpass);
        rpass->passtype= passtype;
        rpass->channels= channels;
+       rpass->rectx= rl->rectx;
+       rpass->recty= rl->recty;
        
        if(rr->exrhandle) {
                int a;
@@ -529,10 +581,12 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int
                rl->lay= srl->lay;
                rl->lay_zmask= srl->lay_zmask;
                rl->layflag= srl->layflag;
-               rl->passflag= srl->passflag;
+               rl->passflag= srl->passflag; // for debugging: srl->passflag|SCE_PASS_RAYHITS;
                rl->pass_xor= srl->pass_xor;
                rl->light_override= srl->light_override;
                rl->mat_override= srl->mat_override;
+               rl->rectx= rectx;
+               rl->recty= recty;
                
                if(rr->exrhandle) {
                        IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
@@ -553,12 +607,18 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int
                        render_layer_add_pass(rr, rl, 3, SCE_PASS_UV);
                if(srl->passflag  & SCE_PASS_RGBA)
                        render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA);
+               if(srl->passflag  & SCE_PASS_EMIT)
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT);
                if(srl->passflag  & SCE_PASS_DIFFUSE)
                        render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE);
                if(srl->passflag  & SCE_PASS_SPEC)
                        render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC);
                if(srl->passflag  & SCE_PASS_AO)
                        render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
+               if(srl->passflag  & SCE_PASS_ENVIRONMENT)
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT);
+               if(srl->passflag  & SCE_PASS_INDIRECT)
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT);
                if(srl->passflag  & SCE_PASS_SHADOW)
                        render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
                if(srl->passflag  & SCE_PASS_REFLECT)
@@ -571,6 +631,8 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int
                        render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB);
                if(srl->passflag  & SCE_PASS_MIST)
                        render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST);
+               if(rl->passflag & SCE_PASS_RAYHITS)
+                       render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS);
                
        }
        /* sss, previewrender and envmap don't do layers, so we make a default one */
@@ -578,6 +640,9 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int
                rl= MEM_callocN(sizeof(RenderLayer), "new render layer");
                BLI_addtail(&rr->layers, rl);
                
+               rl->rectx= rectx;
+               rl->recty= recty;
+
                /* duplicate code... */
                if(rr->exrhandle) {
                        IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
@@ -816,7 +881,7 @@ static void ml_addpass_cb(void *base, void *lay, char *str, float *rect, int tot
        
        BLI_addtail(&rl->passes, rpass);
        rpass->channels= totchan;
-       
+
        rpass->passtype= passtype_from_name(str);
        if(rpass->passtype==0) printf("unknown pass %s\n", str);
        rl->passflag |= rpass->passtype;
@@ -833,11 +898,23 @@ static void ml_addpass_cb(void *base, void *lay, char *str, float *rect, int tot
 RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty)
 {
        RenderResult *rr= MEM_callocN(sizeof(RenderResult), "loaded render result");
+       RenderLayer *rl;
+       RenderPass *rpass;
        
        rr->rectx= rectx;
        rr->recty= recty;
        
        IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb);
+
+       for(rl=rr->layers.first; rl; rl=rl->next) {
+               rl->rectx= rectx;
+               rl->recty= recty;
+
+               for(rpass=rl->passes.first; rpass; rpass=rpass->next) {
+                       rpass->rectx= rectx;
+                       rpass->recty= recty;
+               }
+       }
        
        return rr;
 }
@@ -853,33 +930,26 @@ static void renderresult_add_names(RenderResult *rr)
                        strcpy(rpass->name, get_pass_name(rpass->passtype, -1));
 }
 
-
-/* only for temp buffer files, makes exact copy of render result */
-static void read_render_result(Render *re, int sample)
+/* called for reading temp files, and for external engines */
+static int read_render_result_from_file(char *filename, RenderResult *rr)
 {
        RenderLayer *rl;
        RenderPass *rpass;
        void *exrhandle= IMB_exr_get_handle();
        int rectx, recty;
-       char str[FILE_MAX];
-       
-       RE_FreeRenderResult(re->result);
-       re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
 
-       render_unique_exr_name(re, str, sample);
-       if(IMB_exr_begin_read(exrhandle, str, &rectx, &recty)==0) {
+       if(IMB_exr_begin_read(exrhandle, filename, &rectx, &recty)==0) {
                IMB_exr_close(exrhandle);
-               printf("cannot read: %s\n", str);
-               return;
+               return 0;
        }
        
-       printf("read exr tmp file: %s\n", str);
-       
-       if(re->result == NULL || rectx!=re->result->rectx || recty!=re->result->recty) {
+       if(rr == NULL || rectx!=rr->rectx || recty!=rr->recty) {
                printf("error in reading render result\n");
+               IMB_exr_close(exrhandle);
+               return 0;
        }
        else {
-               for(rl= re->result->layers.first; rl; rl= rl->next) {
+               for(rl= rr->layers.first; rl; rl= rl->next) {
                        
                        /* combined */
                        if(rl->rectf) {
@@ -899,21 +969,64 @@ static void read_render_result(Render *re, int sample)
                        
                }
                IMB_exr_read_channels(exrhandle);
-               renderresult_add_names(re->result);
+               renderresult_add_names(rr);
        }
        
        IMB_exr_close(exrhandle);
+
+       return 1;
+}
+
+/* only for temp buffer files, makes exact copy of render result */
+static void read_render_result(Render *re, int sample)
+{
+       char str[FILE_MAX];
+
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
+       RE_FreeRenderResult(re->result);
+       re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+
+       render_unique_exr_name(re, str, sample);
+       printf("read exr tmp file: %s\n", str);
+
+       if(!read_render_result_from_file(str, re->result))
+               printf("cannot read: %s\n", str);
+
+       BLI_rw_mutex_unlock(&re->resultmutex);
 }
 
 /* *************************************************** */
 
-Render *RE_GetRender(const char *name)
+void RE_SetViewSlot(int slot)
+{
+       RenderGlobal.viewslot = slot;
+}
+
+int RE_GetViewSlot(void)
+{
+       return RenderGlobal.viewslot;
+}
+
+static int re_get_slot(int slot)
+{
+       if(slot == RE_SLOT_VIEW)
+               return RenderGlobal.viewslot;
+       else if(slot == RE_SLOT_RENDERING)
+               return (G.rendering)? RenderGlobal.renderingslot: RenderGlobal.viewslot;
+
+       return slot;
+}
+
+Render *RE_GetRender(const char *name, int slot)
 {
        Render *re;
+
+       slot= re_get_slot(slot);
        
        /* search for existing renders */
-       for(re= RenderList.first; re; re= re->next) {
-               if(strncmp(re->name, name, RE_MAXNAME)==0) {
+       for(re= RenderGlobal.renderlist.first; re; re= re->next) {
+               if(strncmp(re->name, name, RE_MAXNAME)==0 && re->slot==slot) {
                        break;
                }
        }
@@ -921,10 +1034,37 @@ Render *RE_GetRender(const char *name)
 }
 
 /* if you want to know exactly what has been done */
-RenderResult *RE_GetResult(Render *re)
+RenderResult *RE_AcquireResultRead(Render *re)
 {
-       if(re)
+       if(re) {
+               BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ);
                return re->result;
+       }
+
+       return NULL;
+}
+
+RenderResult *RE_AcquireResultWrite(Render *re)
+{
+       if(re) {
+               BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+               return re->result;
+       }
+
+       return NULL;
+}
+
+void RE_ReleaseResult(Render *re)
+{
+       if(re)
+               BLI_rw_mutex_unlock(&re->resultmutex);
+}
+
+/* displist.c util.... */
+Scene *RE_GetScene(Render *re)
+{
+       if(re)
+               return re->scene;
        return NULL;
 }
 
@@ -940,38 +1080,49 @@ RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
 
 
 /* fill provided result struct with what's currently active or done */
-void RE_GetResultImage(Render *re, RenderResult *rr)
+void RE_AcquireResultImage(Render *re, RenderResult *rr)
 {
        memset(rr, 0, sizeof(RenderResult));
 
-       if(re && re->result) {
-               RenderLayer *rl;
-               
-               rr->rectx= re->result->rectx;
-               rr->recty= re->result->recty;
-               
-               rr->rectf= re->result->rectf;
-               rr->rectz= re->result->rectz;
-               rr->rect32= re->result->rect32;
-               
-               /* active layer */
-               rl= render_get_active_layer(re, re->result);
+       if(re) {
+               BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ);
 
-               if(rl) {
-                       if(rr->rectf==NULL)
-                               rr->rectf= rl->rectf;
-                       if(rr->rectz==NULL)
-                               rr->rectz= RE_RenderLayerGetPass(rl, SCE_PASS_Z);       
+               if(re->result) {
+                       RenderLayer *rl;
+                       
+                       rr->rectx= re->result->rectx;
+                       rr->recty= re->result->recty;
+                       
+                       rr->rectf= re->result->rectf;
+                       rr->rectz= re->result->rectz;
+                       rr->rect32= re->result->rect32;
+                       
+                       /* active layer */
+                       rl= render_get_active_layer(re, re->result);
+
+                       if(rl) {
+                               if(rr->rectf==NULL)
+                                       rr->rectf= rl->rectf;
+                               if(rr->rectz==NULL)
+                                       rr->rectz= RE_RenderLayerGetPass(rl, SCE_PASS_Z);       
+                       }
                }
        }
 }
 
+void RE_ReleaseResultImage(Render *re)
+{
+       if(re)
+               BLI_rw_mutex_unlock(&re->resultmutex);
+}
+
 /* caller is responsible for allocating rect in correct size! */
 void RE_ResultGet32(Render *re, unsigned int *rect)
 {
        RenderResult rres;
        
-       RE_GetResultImage(re, &rres);
+       RE_AcquireResultImage(re, &rres);
+
        if(rres.rect32) 
                memcpy(rect, rres.rect32, sizeof(int)*rres.rectx*rres.recty);
        else if(rres.rectf) {
@@ -979,37 +1130,54 @@ void RE_ResultGet32(Render *re, unsigned int *rect)
                int tot= rres.rectx*rres.recty;
                char *cp= (char *)rect;
                
-               for(;tot>0; tot--, cp+=4, fp+=4) {
-                       cp[0] = FTOCHAR(fp[0]);
-                       cp[1] = FTOCHAR(fp[1]);
-                       cp[2] = FTOCHAR(fp[2]);
-                       cp[3] = FTOCHAR(fp[3]);
+               if (re->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
+                       /* Finally convert back to sRGB rendered image */ 
+                       for(;tot>0; tot--, cp+=4, fp+=4) {
+                               cp[0] = FTOCHAR(linearrgb_to_srgb(fp[0]));
+                               cp[1] = FTOCHAR(linearrgb_to_srgb(fp[1]));
+                               cp[2] = FTOCHAR(linearrgb_to_srgb(fp[2]));
+                               cp[3] = FTOCHAR(fp[3]);
+                       }
                }
+               else {
+                       /* Color management is off : no conversion necessary */
+                       for(;tot>0; tot--, cp+=4, fp+=4) {
+                               cp[0] = FTOCHAR(fp[0]);
+                               cp[1] = FTOCHAR(fp[1]);
+                               cp[2] = FTOCHAR(fp[2]);
+                               cp[3] = FTOCHAR(fp[3]);
+                       }
+               }
+
        }
        else
                /* else fill with black */
                memset(rect, 0, sizeof(int)*re->rectx*re->recty);
-}
 
+       RE_ReleaseResultImage(re);
+}
 
 RenderStats *RE_GetStats(Render *re)
 {
        return &re->i;
 }
 
-/* Note, when rendering from a scene, ALWAYS use G.scene->id.name, else compositing wont work */
-Render *RE_NewRender(const char *name)
+Render *RE_NewRender(const char *name, int slot)
 {
        Render *re;
+
+       slot= re_get_slot(slot);
        
        /* only one render per name exists */
-       re= RE_GetRender(name);
+       re= RE_GetRender(name, slot);
        if(re==NULL) {
                
                /* new render data struct */
                re= MEM_callocN(sizeof(Render), "new render");
-               BLI_addtail(&RenderList, re);
+               BLI_addtail(&RenderGlobal.renderlist, re);
                strncpy(re->name, name, RE_MAXNAME);
+               re->slot= slot;
+               BLI_rw_mutex_init(&re->resultmutex);
        }
        
        /* set default empty callbacks */
@@ -1017,13 +1185,14 @@ Render *RE_NewRender(const char *name)
        re->display_clear= result_nothing;
        re->display_draw= result_rcti_nothing;
        re->timecursor= int_nothing;
-       re->test_break= void_nothing;
-       re->test_return= void_nothing;
+       re->test_break= default_break;
        re->error= print_error;
        if(G.background)
                re->stats_draw= stats_background;
        else
                re->stats_draw= stats_nothing;
+       /* clear callback handles */
+       re->dih= re->dch= re->ddh= re->sdh= re->tch= re->tbh= re->erh= NULL;
        
        /* init some variables */
        re->ycor= 1.0f;
@@ -1034,6 +1203,7 @@ Render *RE_NewRender(const char *name)
 /* only call this while you know it will remove the link too */
 void RE_FreeRender(Render *re)
 {
+       BLI_rw_mutex_end(&re->resultmutex);
        
        free_renderdata_tables(re);
        free_sample_tables(re);
@@ -1041,15 +1211,15 @@ void RE_FreeRender(Render *re)
        RE_FreeRenderResult(re->result);
        RE_FreeRenderResult(re->pushedresult);
        
-       BLI_remlink(&RenderList, re);
+       BLI_remlink(&RenderGlobal.renderlist, re);
        MEM_freeN(re);
 }
 
 /* exit blender */
 void RE_FreeAllRender(void)
 {
-       while(RenderList.first) {
-               RE_FreeRender(RenderList.first);
+       while(RenderGlobal.renderlist.first) {
+               RE_FreeRender(RenderGlobal.renderlist.first);
        }
 }
 
@@ -1058,7 +1228,7 @@ void RE_FreeAllRender(void)
 
 /* what doesn't change during entire render sequence */
 /* disprect is optional, if NULL it assumes full window render */
-void RE_InitState(Render *re, Render *source, RenderData *rd, int winx, int winy, rcti *disprect)
+void RE_InitState(Render *re, Render *source, RenderData *rd, SceneRenderLayer *srl, int winx, int winy, rcti *disprect)
 {
        re->ok= TRUE;   /* maybe flag */
        
@@ -1082,49 +1252,79 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, int winx, int winy
        
        if(re->rectx < 2 || re->recty < 2 || (BKE_imtype_is_movie(rd->imtype) &&
                                                                                  (re->rectx < 16 || re->recty < 16) )) {
-               re->error("Image too small");
+               re->error(re->erh, "Image too small");
                re->ok= 0;
+               return;
        }
-       else {
-#ifndef WITH_OPENEXR
-               /* can't do this without openexr support */
-               re->r.scemode &= ~R_EXR_TILE_FILE;
+
+#ifdef WITH_OPENEXR
+       if(re->r.scemode & R_FULL_SAMPLE)
+               re->r.scemode |= R_EXR_TILE_FILE;       /* enable automatic */
+
+       /* Until use_border is made compatible with save_buffers/full_sample, render without the later instead of not rendering at all.*/
+       if(re->r.mode & R_BORDER) 
+       {
+               re->r.scemode &= ~(R_EXR_TILE_FILE|R_FULL_SAMPLE);
+       }
+
+#else
+       /* can't do this without openexr support */
+       re->r.scemode &= ~(R_EXR_TILE_FILE|R_FULL_SAMPLE);
 #endif
-               
-               if(!(re->r.scemode & R_EXR_TILE_FILE))
-                       re->r.scemode &= ~R_FULL_SAMPLE;        /* clear, so we can use this flag for test both */
-               
-               /* fullsample wants uniform osa levels */
-               if(source && (re->r.scemode & R_FULL_SAMPLE)) {
-                       /* but, if source has no full sample we disable it */
-                       if((source->r.scemode & R_FULL_SAMPLE)==0)
-                               re->r.scemode &= ~R_FULL_SAMPLE;
-                       else
-                               re->r.osa= re->osa= source->osa;
+       
+       /* fullsample wants uniform osa levels */
+       if(source && (re->r.scemode & R_FULL_SAMPLE)) {
+               /* but, if source has no full sample we disable it */
+               if((source->r.scemode & R_FULL_SAMPLE)==0)
+                       re->r.scemode &= ~R_FULL_SAMPLE;
+               else
+                       re->r.osa= re->osa= source->osa;
+       }
+       else {
+               /* check state variables, osa? */
+               if(re->r.mode & (R_OSA)) {
+                       re->osa= re->r.osa;
+                       if(re->osa>16) re->osa= 16;
                }
-               else {
-                       /* check state variables, osa? */
-                       if(re->r.mode & (R_OSA)) {
-                               re->osa= re->r.osa;
-                               if(re->osa>16) re->osa= 16;
-                       }
-                       else re->osa= 0;
+               else re->osa= 0;
+       }
+       
+       if (srl) {
+               int index = BLI_findindex(&re->r.layers, srl);
+               if (index != -1) {
+                       re->r.actlay = index;
+                       re->r.scemode |= (R_SINGLE_LAYER|R_COMP_RERENDER);
                }
+       }
+               
+       /* always call, checks for gamma, gamma tables and jitter too */
+       make_sample_tables(re); 
+       
+       /* if preview render, we try to keep old result */
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
 
-               /* always call, checks for gamma, gamma tables and jitter too */
-               make_sample_tables(re); 
+       if(re->r.scemode & R_PREVIEWBUTS) {
+               if(re->result && re->result->rectx==re->rectx && re->result->recty==re->recty);
+               else {
+                       RE_FreeRenderResult(re->result);
+                       re->result= NULL;
+               }
+       }
+       else {
                
                /* make empty render result, so display callbacks can initialize */
                RE_FreeRenderResult(re->result);
                re->result= MEM_callocN(sizeof(RenderResult), "new render result");
                re->result->rectx= re->rectx;
                re->result->recty= re->recty;
-               
-               /* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
-               re->clipcrop= 1.0f + 2.0f/(float)(re->winx>re->winy?re->winy:re->winx);
-               
-               RE_init_threadcount(re);
        }
+
+       BLI_rw_mutex_unlock(&re->resultmutex);
+       
+       /* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
+       re->clipcrop= 1.0f + 2.0f/(float)(re->winx>re->winy?re->winy:re->winx);
+       
+       RE_init_threadcount(re);
 }
 
 /* part of external api, not called for regular render pipeline */
@@ -1135,8 +1335,12 @@ void RE_SetDispRect (struct Render *re, rcti *disprect)
        re->recty= disprect->ymax-disprect->ymin;
        
        /* initialize render result */
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
        RE_FreeRenderResult(re->result);
        re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+
+       BLI_rw_mutex_unlock(&re->resultmutex);
 }
 
 void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
@@ -1148,7 +1352,7 @@ void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
        re->clipend= clipend;
        re->r.mode &= ~R_ORTHO;
 
-       i_window(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat);
+       perspective_m4( re->winmat,re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend);
        
 }
 
@@ -1161,50 +1365,52 @@ void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend)
        re->clipend= clipend;
        re->r.mode |= R_ORTHO;
 
-       i_ortho(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat);
+       orthographic_m4( re->winmat,re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend);
 }
 
 void RE_SetView(Render *re, float mat[][4])
 {
        /* re->ok flag? */
-       Mat4CpyMat4(re->viewmat, mat);
-       Mat4Invert(re->viewinv, re->viewmat);
+       copy_m4_m4(re->viewmat, mat);
+       invert_m4_m4(re->viewinv, re->viewmat);
 }
 
 /* image and movie output has to move to either imbuf or kernel */
-void RE_display_init_cb(Render *re, void (*f)(RenderResult *rr))
+void RE_display_init_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr))
 {
        re->display_init= f;
+       re->dih= handle;
 }
-void RE_display_clear_cb(Render *re, void (*f)(RenderResult *rr))
+void RE_display_clear_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr))
 {
        re->display_clear= f;
+       re->dch= handle;
 }
-void RE_display_draw_cb(Render *re, void (*f)(RenderResult *rr, volatile rcti *rect))
+void RE_display_draw_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr, volatile rcti *rect))
 {
        re->display_draw= f;
+       re->ddh= handle;
 }
-
-void RE_stats_draw_cb(Render *re, void (*f)(RenderStats *rs))
+void RE_stats_draw_cb(Render *re, void *handle, void (*f)(void *handle, RenderStats *rs))
 {
        re->stats_draw= f;
+       re->sdh= handle;
 }
-void RE_timecursor_cb(Render *re, void (*f)(int))
+void RE_timecursor_cb(Render *re, void *handle, void (*f)(void *handle, int))
 {
        re->timecursor= f;
+       re->tch= handle;
 }
 
-void RE_test_break_cb(Render *re, int (*f)(void))
+void RE_test_break_cb(Render *re, void *handle, int (*f)(void *handle))
 {
        re->test_break= f;
+       re->tbh= handle;
 }
-void RE_test_return_cb(Render *re, int (*f)(void))
-{
-       re->test_return= f;
-}
-void RE_error_cb(Render *re, void (*f)(char *str))
+void RE_error_cb(Render *re, void *handle, void (*f)(void *handle, char *str))
 {
        re->error= f;
+       re->erh= handle;
 }
 
 
@@ -1252,7 +1458,7 @@ static void *do_part_thread(void *pa_v)
        RenderPart *pa= pa_v;
        
        /* need to return nicely all parts on esc */
-       if(R.test_break()==0) {
+       if(R.test_break(R.tbh)==0) {
                
                if(!R.sss_points && (R.r.scemode & R_FULL_SAMPLE))
                        pa->result= new_full_sample_buffers(&R, &pa->fullresult, &pa->disprect, pa->crop);
@@ -1274,8 +1480,11 @@ static void *do_part_thread(void *pa_v)
                                save_render_result_tile(rr, rrpart);
                        
                }
-               else if(render_display_draw_enabled(&R))
-                       merge_render_result(R.result, pa->result);
+               else if(render_display_draw_enabled(&R)) {
+                       /* on break, don't merge in result for preview renders, looks nicer */
+                       if(R.test_break(R.tbh) && (R.r.scemode & R_PREVIEWBUTS));
+                       else merge_render_result(R.result, pa->result);
+               }
        }
        
        pa->ready= 1;
@@ -1288,22 +1497,26 @@ static void render_tile_processor(Render *re, int firsttile)
 {
        RenderPart *pa;
        
-       if(re->test_break())
+       if(re->test_break(re->tbh))
                return;
 
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
        /* hrmf... exception, this is used for preview render, re-entrant, so render result has to be re-used */
        if(re->result==NULL || re->result->layers.first==NULL) {
                if(re->result) RE_FreeRenderResult(re->result);
                re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
        }
+
+       BLI_rw_mutex_unlock(&re->resultmutex);
        
-       re->stats_draw(&re->i);
+       re->stats_draw(re->sdh, &re->i);
  
        if(re->result==NULL)
                return;
        
        initparts(re);
-       
+
        /* assuming no new data gets added to dbase... */
        R= *re;
        
@@ -1316,21 +1529,21 @@ static void render_tile_processor(Render *re, int firsttile)
                        do_part_thread(pa);
                        
                        if(pa->result) {
-                               if(!re->test_break()) {
+                               if(!re->test_break(re->tbh)) {
                                        if(render_display_draw_enabled(re))
-                                               re->display_draw(pa->result, NULL);
+                                               re->display_draw(re->ddh, pa->result, NULL);
                                        
                                        re->i.partsdone++;
-                                       re->stats_draw(&re->i);
+                                       re->stats_draw(re->sdh, &re->i);
                                }
                                RE_FreeRenderResult(pa->result);
                                pa->result= NULL;
                        }               
-                       if(re->test_break())
+                       if(re->test_break(re->tbh))
                                break;
                }
        }
-       
+
        freeparts(re);
 }
 
@@ -1386,7 +1599,7 @@ static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane)
                R.viewplane.xmin = viewplane->xmin + R.panodxv;
                R.viewplane.xmax = viewplane->xmax + R.panodxv;
                RE_SetWindow(re, &R.viewplane, R.clipsta, R.clipend);
-               Mat4CpyMat4(R.winmat, re->winmat);
+               copy_m4_m4(R.winmat, re->winmat);
                
                /* rotate database according to part coordinates */
                project_renderdata(re, projectverto, 1, -R.panodxp*phi, 1);
@@ -1443,7 +1656,7 @@ static void print_part_stats(Render *re, RenderPart *pa)
        
        sprintf(str, "Part %d-%d", pa->nr, re->i.totpart);
        re->i.infostr= str;
-       re->stats_draw(&re->i);
+       re->stats_draw(re->sdh, &re->i);
        re->i.infostr= NULL;
 }
 
@@ -1468,15 +1681,21 @@ static void threaded_tile_processor(Render *re)
        rctf viewplane= re->viewplane;
        int rendering=1, counter= 1, drawtimer=0, hasdrawn, minx=0;
        
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
        /* first step; free the entire render result, make new, and/or prepare exr buffer saving */
-       RE_FreeRenderResult(re->result);
+       if(re->result==NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
+               RE_FreeRenderResult(re->result);
        
-       if(re->sss_points)
-               re->result= new_render_result(re, &re->disprect, 0, 0);
-       else if(re->r.scemode & R_FULL_SAMPLE)
-               re->result= new_full_sample_buffers_exr(re);
-       else
-               re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & R_EXR_TILE_FILE);
+               if(re->sss_points && render_display_draw_enabled(re))
+                       re->result= new_render_result(re, &re->disprect, 0, 0);
+               else if(re->r.scemode & R_FULL_SAMPLE)
+                       re->result= new_full_sample_buffers_exr(re);
+               else
+                       re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & (R_EXR_TILE_FILE|R_FULL_SAMPLE));
+       }
+
+       BLI_rw_mutex_unlock(&re->resultmutex);
        
        if(re->result==NULL)
                return;
@@ -1484,7 +1703,7 @@ static void threaded_tile_processor(Render *re)
        /* warning; no return here without closing exr file */
        
        initparts(re);
-       
+
        if(re->result->exrhandle) {
                RenderResult *rr;
                char str[FILE_MAX];
@@ -1513,7 +1732,7 @@ static void threaded_tile_processor(Render *re)
        
        while(rendering) {
                
-               if(re->test_break())
+               if(re->test_break(re->tbh))
                        PIL_sleep_ms(50);
                else if(nextpa && BLI_available_threads(&threads)) {
                        drawtimer= 0;
@@ -1546,7 +1765,7 @@ static void threaded_tile_processor(Render *re)
                                
                                if(pa->result) {
                                        if(render_display_draw_enabled(re))
-                                               re->display_draw(pa->result, NULL);
+                                               re->display_draw(re->ddh, pa->result, NULL);
                                        print_part_stats(re, pa);
                                        
                                        free_render_result(&pa->fullresult, pa->result);
@@ -1559,7 +1778,7 @@ static void threaded_tile_processor(Render *re)
                                rendering= 1;
                                if(pa->nr && pa->result && drawtimer>20) {
                                        if(render_display_draw_enabled(re))
-                                               re->display_draw(pa->result, &pa->result->renrect);
+                                               re->display_draw(re->ddh, pa->result, &pa->result->renrect);
                                        hasdrawn= 1;
                                }
                        }
@@ -1568,7 +1787,7 @@ static void threaded_tile_processor(Render *re)
                        drawtimer= 0;
 
                /* on break, wait for all slots to get freed */
-               if( (g_break=re->test_break()) && BLI_available_threads(&threads)==re->r.threads)
+               if( (g_break=re->test_break(re->tbh)) && BLI_available_threads(&threads)==re->r.threads)
                        rendering= 0;
                
        }
@@ -1576,6 +1795,7 @@ static void threaded_tile_processor(Render *re)
        if(re->result->exrhandle) {
                RenderResult *rr;
 
+               BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
                save_empty_result_tiles(re);
                
                for(rr= re->result; rr; rr= rr->next) {
@@ -1585,6 +1805,8 @@ static void threaded_tile_processor(Render *re)
                
                free_render_result(&re->fullresult, re->result);
                re->result= NULL;
+
+               BLI_rw_mutex_unlock(&re->resultmutex);
                
                read_render_result(re, 0);
        }
@@ -1614,15 +1836,30 @@ void RE_TileProcessor(Render *re, int firsttile, int threaded)
                
        if(!re->sss_points)
                re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
-       re->stats_draw(&re->i);
+       re->stats_draw(re->sdh, &re->i);
 }
 
 
 /* ************  This part uses API, for rendering Blender scenes ********** */
 
+static void external_render_3d(Render *re, RenderEngineType *type);
+
 static void do_render_3d(Render *re)
 {
+       RenderEngineType *type;
 
+       /* try external */
+       for(type=R_engines.first; type; type=type->next)
+               if(strcmp(type->idname, re->r.engine) == 0)
+                       break;
+
+       if(type && type->render) {
+               external_render_3d(re, type);
+               return;
+       }
+
+       /* internal */
+       
 //     re->cfra= cfra; /* <- unused! */
        
        /* make render verts/faces/halos/lamps */
@@ -1635,17 +1872,53 @@ static void do_render_3d(Render *re)
        
        /* do left-over 3d post effects (flares) */
        if(re->flag & R_HALO)
-               if(!re->test_break())
+               if(!re->test_break(re->tbh))
                        add_halo_flare(re);
        
        /* Freestyle  */
        if( re->r.mode & R_EDGE_FRS && re->r.renderer==R_INTERN)
                FRS_add_Freestyle(re);
-       
+               
        /* free all render verts etc */
        RE_Database_Free(re);
 }
 
+/* called by blur loop, accumulate RGBA key alpha */
+static void addblur_rect_key(RenderResult *rr, float *rectf, float *rectf1, float blurfac)
+{
+       float mfac= 1.0f - blurfac;
+       int a, b, stride= 4*rr->rectx;
+       int len= stride*sizeof(float);
+       
+       for(a=0; a<rr->recty; a++) {
+               if(blurfac==1.0f) {
+                       memcpy(rectf, rectf1, len);
+               }
+               else {
+                       float *rf= rectf, *rf1= rectf1;
+                       
+                       for( b= rr->rectx; b>0; b--, rf+=4, rf1+=4) {
+                               if(rf1[3]<0.01f)
+                                       rf[3]= mfac*rf[3];
+                               else if(rf[3]<0.01f) {
+                                       rf[0]= rf1[0];
+                                       rf[1]= rf1[1];
+                                       rf[2]= rf1[2];
+                                       rf[3]= blurfac*rf1[3];
+                               }
+                               else {
+                                       rf[0]= mfac*rf[0] + blurfac*rf1[0];
+                                       rf[1]= mfac*rf[1] + blurfac*rf1[1];
+                                       rf[2]= mfac*rf[2] + blurfac*rf1[2];
+                                       rf[3]= mfac*rf[3] + blurfac*rf1[3];
+                               }                               
+                       }
+               }
+               rectf+= stride;
+               rectf1+= stride;
+       }
+}
+
 /* called by blur loop, accumulate renderlayers */
 static void addblur_rect(RenderResult *rr, float *rectf, float *rectf1, float blurfac, int channels)
 {
@@ -1669,8 +1942,9 @@ static void addblur_rect(RenderResult *rr, float *rectf, float *rectf1, float bl
        }
 }
 
+
 /* called by blur loop, accumulate renderlayers */
-static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float blurfac)
+static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float blurfac, int key_alpha)
 {
        RenderLayer *rl, *rl1;
        RenderPass *rpass, *rpass1;
@@ -1679,8 +1953,12 @@ static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float b
        for(rl= rr->layers.first; rl && rl1; rl= rl->next, rl1= rl1->next) {
                
                /* combined */
-               if(rl->rectf && rl1->rectf)
-                       addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4);
+               if(rl->rectf && rl1->rectf) {
+                       if(key_alpha)
+                               addblur_rect_key(rr, rl->rectf, rl1->rectf, blurfac);
+                       else
+                               addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4);
+               }
                
                /* passes are allocated in sync */
                rpass1= rl1->passes.first;
@@ -1695,35 +1973,37 @@ static void do_render_blur_3d(Render *re)
 {
        RenderResult *rres;
        float blurfac;
-       int blur= re->r.osa;
+       int blur= re->r.mblur_samples;
        
        /* create accumulation render result */
        rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
        
        /* do the blur steps */
        while(blur--) {
-               set_mblur_offs( re->r.blurfac*((float)(re->r.osa-blur))/(float)re->r.osa );
+               set_mblur_offs( re->r.blurfac*((float)(re->r.mblur_samples-blur))/(float)re->r.mblur_samples );
                
-               re->i.curblur= re->r.osa-blur;  /* stats */
+               re->i.curblur= re->r.mblur_samples-blur;        /* stats */
                
                do_render_3d(re);
                
-               blurfac= 1.0f/(float)(re->r.osa-blur);
+               blurfac= 1.0f/(float)(re->r.mblur_samples-blur);
                
-               merge_renderresult_blur(rres, re->result, blurfac);
-               if(re->test_break()) break;
+               merge_renderresult_blur(rres, re->result, blurfac, re->r.alphamode & R_ALPHAKEY);
+               if(re->test_break(re->tbh)) break;
        }
        
        /* swap results */
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
        RE_FreeRenderResult(re->result);
        re->result= rres;
+       BLI_rw_mutex_unlock(&re->resultmutex);
        
        set_mblur_offs(0.0f);
        re->i.curblur= 0;       /* stats */
        
        /* weak... the display callback wants an active renderlayer pointer... */
        re->result->renlay= render_get_active_layer(re, re->result);
-       re->display_draw(re->result, NULL);     
+       re->display_draw(re->ddh, re->result, NULL);    
 }
 
 
@@ -1786,11 +2066,14 @@ static void do_render_fields_3d(Render *re)
                do_render_blur_3d(re);
        else
                do_render_3d(re);
+
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
        rr1= re->result;
        re->result= NULL;
+       BLI_rw_mutex_unlock(&re->resultmutex);
        
        /* second field */
-       if(!re->test_break()) {
+       if(!re->test_break(re->tbh)) {
                
                re->i.curfield= 2;      /* stats */
                
@@ -1813,8 +2096,10 @@ static void do_render_fields_3d(Render *re)
        re->recty *= 2;
        re->disprect.ymin *= 2;
        re->disprect.ymax *= 2;
+
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
        re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
-       
+
        if(rr2) {
                if(re->r.mode & R_ODDFIELD)
                        merge_renderresult_fields(re->result, rr2, rr1);
@@ -1823,13 +2108,17 @@ static void do_render_fields_3d(Render *re)
                
                RE_FreeRenderResult(rr2);
        }
+
        RE_FreeRenderResult(rr1);
        
        re->i.curfield= 0;      /* stats */
        
        /* weak... the display callback wants an active renderlayer pointer... */
        re->result->renlay= render_get_active_layer(re, re->result);
-       re->display_draw(re->result, NULL);
+
+       BLI_rw_mutex_unlock(&re->resultmutex);
+
+       re->display_draw(re->ddh, re->result, NULL);
 }
 
 static void load_backbuffer(Render *re)
@@ -1840,7 +2129,7 @@ static void load_backbuffer(Render *re)
                
                strcpy(name, re->r.backbuf);
                BLI_convertstringcode(name, G.sce);
-               BLI_convertstringframe(name, re->r.cfra);
+               BLI_convertstringframe(name, re->r.cfra, 0);
                
                if(re->backbuf) {
                        re->backbuf->id.us--;
@@ -1848,7 +2137,7 @@ static void load_backbuffer(Render *re)
                                BKE_image_signal(re->backbuf, NULL, IMA_SIGNAL_RELOAD);
                }
                
-               re->backbuf= BKE_add_image_file(name);
+               re->backbuf= BKE_add_image_file(name, re->r.cfra);
                ibuf= BKE_image_get_ibuf(re->backbuf, NULL);
                if(ibuf==NULL) {
                        // error() doesnt work with render window open
@@ -1892,6 +2181,8 @@ static void do_render_fields_blur_3d(Render *re)
                        if((re->r.mode & R_CROP)==0) {
                                RenderResult *rres;
                                
+                               BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
                                /* sub-rect for merge call later on */
                                re->result->tilerect= re->disprect;
                                
@@ -1912,8 +2203,15 @@ static void do_render_fields_blur_3d(Render *re)
                                /* weak... the display callback wants an active renderlayer pointer... */
                                re->result->renlay= render_get_active_layer(re, re->result);
                                
-                               re->display_init(re->result);
-                               re->display_draw(re->result, NULL);
+                               BLI_rw_mutex_unlock(&re->resultmutex);
+               
+                               re->display_init(re->dih, re->result);
+                               re->display_draw(re->ddh, re->result, NULL);
+                       }
+                       else {
+                               /* set offset (again) for use in compositor, disprect was manipulated. */
+                               re->result->xof= 0;
+                               re->result->yof= 0;
                        }
                }
        }
@@ -1925,7 +2223,7 @@ static void do_render_fields_blur_3d(Render *re)
 */
 static void render_scene(Render *re, Scene *sce, int cfra)
 {
-       Render *resc= RE_NewRender(sce->id.name);
+       Render *resc= RE_NewRender(sce->id.name, RE_SLOT_RENDERING);
        int winx= re->winx, winy= re->winy;
        
        sce->r.cfra= cfra;
@@ -1937,18 +2235,21 @@ static void render_scene(Render *re, Scene *sce, int cfra)
        }
        
        /* initial setup */
-       RE_InitState(resc, re, &sce->r, winx, winy, &re->disprect);
+       RE_InitState(resc, re, &sce->r, NULL, winx, winy, &re->disprect);
        
        /* still unsure entity this... */
        resc->scene= sce;
        
-       /* ensure scene has depsgraph, base flags etc OK. Warning... also sets G.scene */
+       /* ensure scene has depsgraph, base flags etc OK */
        set_scene_bg(sce);
 
        /* copy callbacks */
        resc->display_draw= re->display_draw;
+       resc->ddh= re->ddh;
        resc->test_break= re->test_break;
+       resc->tbh= re->tbh;
        resc->stats_draw= re->stats_draw;
+       resc->sdh= re->sdh;
        
        do_render_fields_blur_3d(resc);
 }
@@ -1998,11 +2299,6 @@ static void ntree_render_scenes(Render *re)
                        }
                }
        }
-       
-       /* still the global... */
-       if(G.scene!=re->scene)
-               set_scene_bg(re->scene);
-       
 }
 
 /* helper call to detect if theres a composite with render-result node */
@@ -2024,10 +2320,10 @@ static int composite_needs_render(Scene *sce)
 }
 
 /* bad call... need to think over proper method still */
-static void render_composit_stats(char *str)
+static void render_composit_stats(void *unused, char *str)
 {
        R.i.infostr= str;
-       R.stats_draw(&R.i);
+       R.stats_draw(R.sdh, &R.i);
        R.i.infostr= NULL;
 }
 
@@ -2054,7 +2350,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
                        Render *re1;
                        
                        tag_scenes_for_render(re);
-                       for(re1= RenderList.first; re1; re1= re1->next) {
+                       for(re1= RenderGlobal.renderlist.first; re1; re1= re1->next) {
                                if(re1->scene->id.flag & LIB_DOIT)
                                        if(re1->r.scemode & R_FULL_SAMPLE)
                                                read_render_result(re1, sample);
@@ -2070,7 +2366,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
                }
                
                /* ensure we get either composited result or the active layer */
-               RE_GetResultImage(re, &rres);
+               RE_AcquireResultImage(re, &rres);
                
                /* accumulate with filter, and clip */
                mask= (1<<sample);
@@ -2081,6 +2377,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
                        float *col= rres.rectf + 4*y*re->rectx;
                                
                        for(x=0; x<re->rectx; x++, rf+=4, col+=4) {
+                               /* clamping to 1.0 is needed for correct AA */
                                if(col[0]<0.0f) col[0]=0.0f; else if(col[0] > 1.0f) col[0]= 1.0f;
                                if(col[1]<0.0f) col[1]=0.0f; else if(col[1] > 1.0f) col[1]= 1.0f;
                                if(col[2]<0.0f) col[2]=0.0f; else if(col[2] > 1.0f) col[2]= 1.0f;
@@ -2089,20 +2386,24 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
                        }
                }
                
+               RE_ReleaseResultImage(re);
+
                /* show stuff */
                if(sample!=re->osa-1) {
                        /* weak... the display callback wants an active renderlayer pointer... */
                        re->result->renlay= render_get_active_layer(re, re->result);
-                       re->display_draw(re->result, NULL);
+                       re->display_draw(re->ddh, re->result, NULL);
                }
                
-               if(re->test_break())
+               if(re->test_break(re->tbh))
                        break;
        }
        
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
        if(re->result->rectf) 
                MEM_freeN(re->result->rectf);
        re->result->rectf= rectf;
+       BLI_rw_mutex_unlock(&re->resultmutex);
 }
 
 void RE_MergeFullSample(Render *re, Scene *sce, bNodeTree *ntree)
@@ -2130,12 +2431,12 @@ void RE_MergeFullSample(Render *re, Scene *sce, bNodeTree *ntree)
        }
        
        /* own render result should be read/allocated */
-       if(G.scene->id.flag & LIB_DOIT)
-               RE_ReadRenderResult(G.scene, G.scene);
+       if(re->scene->id.flag & LIB_DOIT)
+               RE_ReadRenderResult(re->scene, re->scene);
        
        /* and now we can draw (result is there) */
-       re->display_init(re->result);
-       re->display_clear(re->result);
+       re->display_init(re->dih, re->result);
+       re->display_clear(re->dch, re->result);
        
        do_merge_fullsample(re, ntree);
 }
@@ -2144,6 +2445,7 @@ void RE_MergeFullSample(Render *re, Scene *sce, bNodeTree *ntree)
 static void do_render_composite_fields_blur_3d(Render *re)
 {
        bNodeTree *ntree= re->scene->nodetree;
+       int update_newframe=0;
        
        /* INIT seeding, compositor can use random texture */
        BLI_srandom(re->r.cfra);
@@ -2153,13 +2455,16 @@ static void do_render_composite_fields_blur_3d(Render *re)
                ntreeFreeCache(ntree);
                
                do_render_fields_blur_3d(re);
+       } else {
+               /* scene render process already updates animsys */
+               update_newframe = 1;
        }
        
        /* swap render result */
        if(re->r.scemode & R_SINGLE_LAYER)
                pop_render_result(re);
        
-       if(!re->test_break()) {
+       if(!re->test_break(re->tbh)) {
                
                if(ntree) {
                        ntreeCompositTagRender(re->scene);
@@ -2172,19 +2477,27 @@ static void do_render_composite_fields_blur_3d(Render *re)
                                if((re->r.scemode & R_SINGLE_LAYER)==0)
                                        ntree_render_scenes(re);
                                
-                               if(!re->test_break()) {
+                               if(!re->test_break(re->tbh)) {
                                        ntree->stats_draw= render_composit_stats;
                                        ntree->test_break= re->test_break;
+                                       ntree->sdh= re->sdh;
+                                       ntree->tbh= re->tbh;
                                        /* in case it was never initialized */
+                                       R.sdh= re->sdh;
                                        R.stats_draw= re->stats_draw;
                                        
+                                       if (update_newframe)
+                                               scene_update_for_newframe(re->scene, re->scene->lay);
+                                       
                                        if(re->r.scemode & R_FULL_SAMPLE) 
                                                do_merge_fullsample(re, ntree);
-                                       else
+                                       else {
                                                ntreeCompositExecTree(ntree, &re->r, G.background==0);
+                                       }
                                        
                                        ntree->stats_draw= NULL;
                                        ntree->test_break= NULL;
+                                       ntree->tbh= ntree->sdh= NULL;
                                }
                        }
                        else if(re->r.scemode & R_FULL_SAMPLE)
@@ -2194,78 +2507,84 @@ static void do_render_composite_fields_blur_3d(Render *re)
 
        /* weak... the display callback wants an active renderlayer pointer... */
        re->result->renlay= render_get_active_layer(re, re->result);
-       re->display_draw(re->result, NULL);
+       re->display_draw(re->ddh, re->result, NULL);
 }
 
-#ifndef DISABLE_YAFRAY
-/* yafray: main yafray render/export call */
-static void yafrayRender(Render *re)
+static void renderresult_stampinfo(Scene *scene)
 {
-       RE_FreeRenderResult(re->result);
-       re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
-       
-       // need this too, for aspect/ortho/etc info
-       RE_SetCamera(re, re->scene->camera);
+       RenderResult rres;
+       Render *re= RE_GetRender(scene->id.name, RE_SLOT_RENDERING);
 
-       // switch must be done before prepareScene()
-       if (!re->r.YFexportxml)
-               YAF_switchFile();
-       else
-               YAF_switchPlugin();
-       
-       printf("Starting scene conversion.\n");
-       RE_Database_FromScene(re, re->scene, 1);
-       printf("Scene conversion done.\n");
-       
-       re->i.starttime = PIL_check_seconds_timer();
-       
-       YAF_exportScene(re);
+       /* this is the basic trick to get the displayed float or char rect from render result */
+       RE_AcquireResultImage(re, &rres);
+       BKE_stamp_buf(scene, (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
+       RE_ReleaseResultImage(re);
+}
 
-       /* also needed for yafray border render, straight copy from do_render_fields_blur_3d() */
-       /* when border render, check if we have to insert it in black */
-       if(re->result) {
-               if(re->r.mode & R_BORDER) {
-                       if((re->r.mode & R_CROP)==0) {
-                               RenderResult *rres;
-                               
-                               /* sub-rect for merge call later on */
-                               re->result->tilerect= re->disprect;
-                               
-                               /* this copying sequence could become function? */
-                               re->disprect.xmin= re->disprect.ymin= 0;
-                               re->disprect.xmax= re->winx;
-                               re->disprect.ymax= re->winy;
-                               re->rectx= re->winx;
-                               re->recty= re->winy;
-                               
-                               rres = new_render_result(re, &re->disprect, 0, RR_USEMEM);
-                               
-                               merge_render_result(rres, re->result);
-                               RE_FreeRenderResult(re->result);
-                               re->result= rres;
-                               
-                               re->display_init(re->result);
-                               re->display_draw(re->result, NULL);
-                       }
-               }
+static void do_render_seq(Render * re)
+{
+       static int recurs_depth = 0;
+       struct ImBuf *ibuf;
+       RenderResult *rr = re->result;
+       int cfra = re->r.cfra;
+
+       if(recurs_depth==0) {
+               /* otherwise sequencer animation isnt updated */
+               BKE_animsys_evaluate_all_animation(G.main, (float)cfra); // XXX, was frame_to_float(re->scene, cfra)
        }
 
-       re->i.lastframetime = PIL_check_seconds_timer()- re->i.starttime;
-       re->stats_draw(&re->i);
+       recurs_depth++;
+
+       ibuf= give_ibuf_seq(re->scene, rr->rectx, rr->recty, cfra, 0, 100.0);
+
+       recurs_depth--;
        
-       RE_Database_Free(re);
-}
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
 
+       if(ibuf) {
+               if(ibuf->rect_float) {
+                       if (!rr->rectf)
+                               rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf");
+                       
+                       memcpy(rr->rectf, ibuf->rect_float, 4*sizeof(float)*rr->rectx*rr->recty);
+                       
+                       /* TSK! Since sequence render doesn't free the *rr render result, the old rect32
+                          can hang around when sequence render has rendered a 32 bits one before */
+                       if(rr->rect32) {
+                               MEM_freeN(rr->rect32);
+                               rr->rect32= NULL;
+                       }
+               }
+               else if(ibuf->rect) {
+                       if (!rr->rect32)
+                               rr->rect32= MEM_mallocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect");
 
+                       memcpy(rr->rect32, ibuf->rect, 4*rr->rectx*rr->recty);
 
-#endif /* disable yafray */
+                       /* if (ibuf->zbuf) { */
+                       /*      if (R.rectz) freeN(R.rectz); */
+                       /*      R.rectz = BLI_dupallocN(ibuf->zbuf); */
+                       /* } */
+               }
+               
+               if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */
+                       Editing * ed = re->scene->ed;
+                       if (ed) {
+                               free_imbuf_seq(re->scene, &ed->seqbase, TRUE);
+                       }
+               }
+       }
+       else {
+               /* render result is delivered empty in most cases, nevertheless we handle all cases */
+               if (rr->rectf)
+                       memset(rr->rectf, 0, 4*sizeof(float)*rr->rectx*rr->recty);
+               else if (rr->rect32)
+                       memset(rr->rect32, 0, 4*rr->rectx*rr->recty);
+               else
+                       rr->rect32= MEM_callocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect");
+       }
 
-static void renderresult_stampinfo()
-{
-       RenderResult rres;
-       /* this is the basic trick to get the displayed float or char rect from render result */
-       RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
-       BKE_stamp_buf((unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
+       BLI_rw_mutex_unlock(&re->resultmutex);
 }
 
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -2273,42 +2592,42 @@ static void renderresult_stampinfo()
 /* main loop: doing sequence + fields + blur + 3d render + compositing */
 static void do_render_all_options(Render *re)
 {
+#ifdef DURIAN_CAMERA_SWITCH
+       Object *camera= scene_find_camera_switch(re->scene);
+       if(camera)
+               re->scene->camera= camera;
+#endif
+
        re->i.starttime= PIL_check_seconds_timer();
 
        /* ensure no images are in memory from previous animated sequences */
        BKE_image_all_free_anim_ibufs(re->r.cfra);
        
-       if(re->r.scemode & R_DOSEQ) {
+       if((re->r.scemode & R_DOSEQ) && re->scene->ed && re->scene->ed->seqbase.first) {
                /* note: do_render_seq() frees rect32 when sequencer returns float images */
-               if(!re->test_break()) 
-                       do_render_seq(re->result, re->r.cfra);
-               
-               re->stats_draw(&re->i);
-               re->display_draw(re->result, NULL);
+               if(!re->test_break(re->tbh)) 
+                       do_render_seq(re);
                
+               re->stats_draw(re->sdh, &re->i);
+               re->display_draw(re->ddh, re->result, NULL);
        }
        else {
-#ifndef DISABLE_YAFRAY
-               if(re->r.renderer==R_YAFRAY)
-                       yafrayRender(re);
-               else
-                       do_render_composite_fields_blur_3d(re);
-#else
                do_render_composite_fields_blur_3d(re);
-#endif
        }
        
        /* for UI only */
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
        renderresult_add_names(re->result);
+       BLI_rw_mutex_unlock(&re->resultmutex);
        
        re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
        
-       re->stats_draw(&re->i);
+       re->stats_draw(re->sdh, &re->i);
        
        /* stamp image info here */
-       if((G.scene->r.scemode & R_STAMP_INFO) && (G.scene->r.stamp & R_STAMP_DRAW)) {
-               renderresult_stampinfo();
-               re->display_draw(re->result, NULL);
+       if((re->r.stamp & R_STAMP_ALL) && (re->r.stamp & R_STAMP_DRAW)) {
+               renderresult_stampinfo(re->scene);
+               re->display_draw(re->ddh, re->result, NULL);
        }
 }
 
@@ -2319,11 +2638,11 @@ static int is_rendering_allowed(Render *re)
        /* forbidden combinations */
        if(re->r.mode & R_PANORAMA) {
                if(re->r.mode & R_BORDER) {
-                       re->error("No border supported for Panorama");
+                       re->error(re->erh, "No border supported for Panorama");
                        return 0;
                }
                if(re->r.mode & R_ORTHO) {
-                       re->error("No Ortho render possible for Panorama");
+                       re->error(re->erh, "No Ortho render possible for Panorama");
                        return 0;
                }
        }
@@ -2331,22 +2650,18 @@ static int is_rendering_allowed(Render *re)
        if(re->r.mode & R_BORDER) {
                if(re->r.border.xmax <= re->r.border.xmin || 
                   re->r.border.ymax <= re->r.border.ymin) {
-                       re->error("No border area selected.");
-                       return 0;
-               }
-               if(re->r.scemode & R_EXR_TILE_FILE) {
-                       re->error("Border render and Buffer-save not supported yet");
+                       re->error(re->erh, "No border area selected.");
                        return 0;
                }
        }
        
-       if(re->r.scemode & R_EXR_TILE_FILE) {
+       if(re->r.scemode & (R_EXR_TILE_FILE|R_FULL_SAMPLE)) {
                char str[FILE_MAX];
                
                render_unique_exr_name(re, str, 0);
                
                if (BLI_is_writable(str)==0) {
-                       re->error("Can not save render buffers, check the temp default path");
+                       re->error(re->erh, "Can not save render buffers, check the temp default path");
                        return 0;
                }
                
@@ -2356,7 +2671,7 @@ static int is_rendering_allowed(Render *re)
                
                /* no fullsample and edge */
                if((re->r.scemode & R_FULL_SAMPLE) && (re->r.mode & R_EDGE)) {
-                       re->error("Full Sample doesn't support Edge Enhance");
+                       re->error(re->erh, "Full Sample doesn't support Edge Enhance");
                        return 0;
                }
                
@@ -2370,7 +2685,7 @@ static int is_rendering_allowed(Render *re)
                        bNode *node;
                
                        if(ntree==NULL) {
-                               re->error("No Nodetree in Scene");
+                               re->error(re->erh, "No Nodetree in Scene");
                                return 0;
                        }
                        
@@ -2380,7 +2695,7 @@ static int is_rendering_allowed(Render *re)
                        
                        
                        if(node==NULL) {
-                               re->error("No Render Output Node in Scene");
+                               re->error(re->erh, "No Render Output Node in Scene");
                                return 0;
                        }
                }
@@ -2392,7 +2707,7 @@ static int is_rendering_allowed(Render *re)
        
        if(!(re->r.scemode & (R_DOSEQ|R_DOCOMP))) {
                if(re->scene->camera==NULL) {
-                       re->error("No camera");
+                       re->error(re->erh, "No camera");
                        return 0;
                }
        }
@@ -2408,20 +2723,36 @@ static int is_rendering_allowed(Render *re)
                if(!(srl->layflag & SCE_LAY_DISABLE))
                        break;
        if(srl==NULL) {
-               re->error("All RenderLayers are disabled");
+               re->error(re->erh, "All RenderLayers are disabled");
                return 0;
        }
        
        /* renderer */
        if(!ELEM(re->r.renderer, R_INTERN, R_YAFRAY)) {
-               re->error("Unknown render engine set");
+               re->error(re->erh, "Unknown render engine set");
                return 0;
        }
        return 1;
 }
 
+static void update_physics_cache(Render *re, Scene *scene, int anim_init)
+{
+       PTCacheBaker baker;
+
+       baker.scene = scene;
+       baker.pid = NULL;
+       baker.bake = 0;
+       baker.render = 1;
+       baker.anim_init = 1;
+       baker.quick_step = 1;
+       baker.break_test = re->test_break;
+       baker.break_data = re->tbh;
+       baker.progressbar = NULL;
+
+       BKE_ptcache_make_cache(&baker);
+}
 /* evaluating scene options for general Blender render */
-static int render_initialize_from_scene(Render *re, Scene *scene, int anim)
+static int render_initialize_from_scene(Render *re, Scene *scene, SceneRenderLayer *srl, int anim, int anim_init)
 {
        int winx, winy;
        rcti disprect;
@@ -2457,11 +2788,21 @@ static int render_initialize_from_scene(Render *re, Scene *scene, int anim)
        
        /* check all scenes involved */
        tag_scenes_for_render(re);
+
+       /*
+        * Disabled completely for now,
+        * can be later set as render profile option
+        * and default for background render.
+       */
+       if(0) {
+               /* make sure dynamics are up to date */
+               update_physics_cache(re, scene, anim_init);
+       }
        
-       if(scene->r.scemode & R_SINGLE_LAYER)
+       if(srl || scene->r.scemode & R_SINGLE_LAYER)
                push_render_result(re);
        
-       RE_InitState(re, NULL, &scene->r, winx, winy, &disprect);
+       RE_InitState(re, NULL, &scene->r, srl, winx, winy, &disprect);
        if(!re->ok)  /* if an error was printed, abort */
                return 0;
        
@@ -2471,35 +2812,39 @@ static int render_initialize_from_scene(Render *re, Scene *scene, int anim)
        if(!is_rendering_allowed(re))
                return 0;
        
-       re->display_init(re->result);
-       re->display_clear(re->result);
+       re->display_init(re->dih, re->result);
+       re->display_clear(re->dch, re->result);
        
        return 1;
 }
 
 /* general Blender frame render call */
-void RE_BlenderFrame(Render *re, Scene *scene, int frame)
+void RE_BlenderFrame(Render *re, Scene *scene, SceneRenderLayer *srl, int frame)
 {
-       /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
-       /* is also set by caller renderwin.c */
+       /* ugly global still... is to prevent preview events and signal subsurfs etc to make full resol */
+       RenderGlobal.renderingslot= re->slot;
+       re->result_ok= 0;
        G.rendering= 1;
        
        scene->r.cfra= frame;
        
-       if(render_initialize_from_scene(re, scene, 0)) {
+       if(render_initialize_from_scene(re, scene, srl, 0, 0)) {
                do_render_all_options(re);
        }
        
        /* UGLY WARNING */
+       re->result_ok= 1;
        G.rendering= 0;
+       RenderGlobal.renderingslot= RenderGlobal.viewslot;
 }
 
-static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
+static int do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh, ReportList *reports)
 {
        char name[FILE_MAX];
        RenderResult rres;
+       int ok= 1;
        
-       RE_GetResultImage(re, &rres);
+       RE_AcquireResultImage(re, &rres);
 
        /* write movie or image */
        if(BKE_imtype_is_movie(scene->r.imtype)) {
@@ -2510,14 +2855,14 @@ static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
                        dofree = 1;
                }
                RE_ResultGet32(re, (unsigned int *)rres.rect32);
-               mh->append_movie(scene->r.cfra, rres.rect32, rres.rectx, rres.recty);
+               ok= mh->append_movie(&re->r, scene->r.cfra, rres.rect32, rres.rectx, rres.recty, reports);
                if(dofree) {
                        MEM_freeN(rres.rect32);
                }
                printf("Append frame %d", scene->r.cfra);
        } 
        else {
-               BKE_makepicstring(name, scene->r.pic, scene->r.cfra, scene->r.imtype);
+               BKE_makepicstring(name, scene->r.pic, scene->r.cfra, scene->r.imtype, scene->r.scemode & R_EXTENSION);
                
                if(re->r.imtype==R_MULTILAYER) {
                        if(re->result) {
@@ -2527,21 +2872,31 @@ static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
                }
                else {
                        ImBuf *ibuf= IMB_allocImBuf(rres.rectx, rres.recty, scene->r.planes, 0, 0);
-                       int ok;
                        
-                                       /* if not exists, BKE_write_ibuf makes one */
+                       /* if not exists, BKE_write_ibuf makes one */
                        ibuf->rect= (unsigned int *)rres.rect32;    
                        ibuf->rect_float= rres.rectf;
                        ibuf->zbuf_float= rres.rectz;
                        
                        /* float factor for random dither, imbuf takes care of it */
                        ibuf->dither= scene->r.dither_intensity;
+                       
+                       /* prepare to gamma correct to sRGB color space */
+                       if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
+                               /* sequence editor can generate 8bpc render buffers */
+                               if (ibuf->rect) {
+                                       ibuf->profile = IB_PROFILE_SRGB;
+                                       if (ELEM(scene->r.imtype, R_OPENEXR, R_RADHDR))
+                                               IMB_float_from_rect(ibuf);
+                               } else {                                
+                                       ibuf->profile = IB_PROFILE_LINEAR_RGB;
+                               }
+                       }
 
-                       ok= BKE_write_ibuf(ibuf, name, scene->r.imtype, scene->r.subimtype, scene->r.quality);
+                       ok= BKE_write_ibuf(scene, ibuf, name, scene->r.imtype, scene->r.subimtype, scene->r.quality);
                        
                        if(ok==0) {
                                printf("Render error: cannot save %s\n", name);
-                               G.afbreek=1;
                        }
                        else printf("Saved: %s", name);
                        
@@ -2551,7 +2906,7 @@ static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
                                        name[strlen(name)-4]= 0;
                                BKE_add_image_extension(name, R_JPEG90);
                                ibuf->depth= 24; 
-                               BKE_write_ibuf(ibuf, name, R_JPEG90, scene->r.subimtype, scene->r.quality);
+                               BKE_write_ibuf(scene, ibuf, name, R_JPEG90, scene->r.subimtype, scene->r.quality);
                                printf("\nSaved: %s", name);
                        }
                        
@@ -2560,13 +2915,17 @@ static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
                }
        }
        
+       RE_ReleaseResultImage(re);
+
        BLI_timestr(re->i.lastframetime, name);
        printf(" Time: %s\n", name);
        fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */
+
+       return ok;
 }
 
 /* saves images to disk */
-void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra)
+void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra, ReportList *reports)
 {
        bMovieHandle *mh= BKE_get_movie_handle(scene->r.imtype);
        unsigned int lay;
@@ -2574,29 +2933,34 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra)
        int nfra;
        
        /* do not fully call for each frame, it initializes & pops output window */
-       if(!render_initialize_from_scene(re, scene, 0))
+       if(!render_initialize_from_scene(re, scene, NULL, 0, 1))
                return;
        
        /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
        /* is also set by caller renderwin.c */
        G.rendering= 1;
+       RenderGlobal.renderingslot= re->slot;
+       re->result_ok= 0;
        
        if(BKE_imtype_is_movie(scene->r.imtype))
-               mh->start_movie(&re->r, re->rectx, re->recty);
-       
+               if(!mh->start_movie(scene, &re->r, re->rectx, re->recty, reports))
+                       G.afbreek= 1;
+
        if (mh->get_next_frame) {
                while (!(G.afbreek == 1)) {
-                       int nf = mh->get_next_frame();
+                       int nf = mh->get_next_frame(&re->r, reports);
                        if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) {
                                scene->r.cfra = re->r.cfra = nf;
                                
                                do_render_all_options(re);
 
-                               if(re->test_break() == 0) {
-                                       do_write_image_or_movie(re, scene, mh);
+                               if(re->test_break(re->tbh) == 0) {
+                                       if(!do_write_image_or_movie(re, scene, mh, reports))
+                                               G.afbreek= 1;
                                }
                        } else {
-                               re->test_break();
+                               if(re->test_break(re->tbh))
+                                       G.afbreek= 1;
                        }
                }
        } else {
@@ -2604,7 +2968,7 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra)
                        char name[FILE_MAX];
                        
                        /* only border now, todo: camera lens. (ton) */
-                       render_initialize_from_scene(re, scene, 1);
+                       render_initialize_from_scene(re, scene, NULL, 1, 0);
 
                        if(nfra!=scene->r.cfra) {
                                /*
@@ -2623,31 +2987,39 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra)
                        else
                                nfra+= tfra;
 
-                       if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH) ) {
-                               BKE_makepicstring(name, scene->r.pic, scene->r.cfra, scene->r.imtype);
-                       }
-                       
-                       if (scene->r.mode & R_NO_OVERWRITE && BLI_exist(name)) {
-                               printf("skipping existing frame \"%s\"\n", name);
-                               continue;
-                       }
-                       if (scene->r.mode & R_TOUCH && !BLI_exist(name)) {
-                               BLI_make_existing_file(name); /* makes the dir if its not there */
-                               BLI_touch(name);
+                       /* Touch/NoOverwrite options are only valid for image's */
+                       if(BKE_imtype_is_movie(scene->r.imtype) == 0) {
+                               if(scene->r.mode & (R_NO_OVERWRITE | R_TOUCH))
+                                       BKE_makepicstring(name, scene->r.pic, scene->r.cfra, scene->r.imtype, scene->r.scemode & R_EXTENSION);
+
+                               if(scene->r.mode & R_NO_OVERWRITE && BLI_exist(name)) {
+                                       printf("skipping existing frame \"%s\"\n", name);
+                                       continue;
+                               }
+                               if(scene->r.mode & R_TOUCH && !BLI_exist(name)) {
+                                       BLI_make_existing_file(name); /* makes the dir if its not there */
+                                       BLI_touch(name);
+                               }
                        }
 
                        re->r.cfra= scene->r.cfra;         /* weak.... */
                        
                        do_render_all_options(re);
                        
-                       if(re->test_break() == 0) {
-                               do_write_image_or_movie(re, scene, mh);
+                       if(re->test_break(re->tbh) == 0) {
+                               if(!G.afbreek)
+                                       if(!do_write_image_or_movie(re, scene, mh, reports))
+                                               G.afbreek= 1;
                        }
+                       else
+                               G.afbreek= 1;
                
                        if(G.afbreek==1) {
                                /* remove touched file */
-                               if (scene->r.mode & R_TOUCH && BLI_exist(name) && BLI_filepathsize(name) == 0) {
-                                       BLI_delete(name, 0, 0);
+                               if(BKE_imtype_is_movie(scene->r.imtype) == 0) {
+                                       if (scene->r.mode & R_TOUCH && BLI_exist(name) && BLI_filepathsize(name) == 0) {
+                                               BLI_delete(name, 0, 0);
+                                       }
                                }
                                
                                break;
@@ -2663,6 +3035,8 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra)
        
        /* UGLY WARNING */
        G.rendering= 0;
+       re->result_ok= 1;
+       RenderGlobal.renderingslot= RenderGlobal.viewslot;
 }
 
 /* note; repeated win/disprect calc... solve that nicer, also in compo */
@@ -2696,10 +3070,10 @@ void RE_ReadRenderResult(Scene *scene, Scene *scenode)
                scene= scenode;
        
        /* get render: it can be called from UI with draw callbacks */
-       re= RE_GetRender(scene->id.name);
+       re= RE_GetRender(scene->id.name, RE_SLOT_VIEW);
        if(re==NULL)
-               re= RE_NewRender(scene->id.name);
-       RE_InitState(re, NULL, &scene->r, winx, winy, &disprect);
+               re= RE_NewRender(scene->id.name, RE_SLOT_VIEW);
+       RE_InitState(re, NULL, &scene->r, NULL, winx, winy, &disprect);
        re->scene= scene;
        
        read_render_result(re, 0);
@@ -2708,19 +3082,211 @@ void RE_ReadRenderResult(Scene *scene, Scene *scenode)
 void RE_set_max_threads(int threads)
 {
        if (threads==0) {
-               commandline_threads = BLI_system_thread_count();
+               RenderGlobal.threads = BLI_system_thread_count();
        } else if(threads>=1 && threads<=BLENDER_MAX_THREADS) {
-               commandline_threads= threads;
+               RenderGlobal.threads= threads;
        } else {
-               printf("Error, threads has to be in range 1-%d\n", BLENDER_MAX_THREADS);
+               printf("Error, threads has to be in range 0-%d\n", BLENDER_MAX_THREADS);
        }
 }
 
 void RE_init_threadcount(Render *re) 
 {
-        if(commandline_threads >= 1) { /* only set as an arg in background mode */
-               re->r.threads= MIN2(commandline_threads, BLENDER_MAX_THREADS);
-       } else if ((re->r.mode & R_FIXED_THREADS)==0 || commandline_threads == 0) { /* Automatic threads */
+       if(RenderGlobal.threads >= 1) { /* only set as an arg in background mode */
+               re->r.threads= MIN2(RenderGlobal.threads, BLENDER_MAX_THREADS);
+       } else if ((re->r.mode & R_FIXED_THREADS)==0 || RenderGlobal.threads == 0) { /* Automatic threads */
                re->r.threads = BLI_system_thread_count();
        }
 }
+
+/************************** External Engines ***************************/
+
+RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h)
+{
+       Render *re= engine->re;
+       RenderResult *result;
+       rcti disprect;
+
+       /* ensure the coordinates are within the right limits */
+       CLAMP(x, 0, re->result->rectx);
+       CLAMP(y, 0, re->result->recty);
+       CLAMP(w, 0, re->result->rectx);
+       CLAMP(h, 0, re->result->recty);
+
+       if(x + w > re->result->rectx)
+               w= re->result->rectx - x;
+       if(y + h > re->result->recty)
+               h= re->result->recty - y;
+
+       /* allocate a render result */
+       disprect.xmin= x;
+       disprect.xmax= x+w;
+       disprect.ymin= y;
+       disprect.ymax= y+h;
+
+       if(0) { // XXX (re->r.scemode & R_FULL_SAMPLE)) {
+               result= new_full_sample_buffers(re, &engine->fullresult, &disprect, 0);
+       }
+       else {
+               result= new_render_result(re, &disprect, 0, RR_USEMEM);
+               BLI_addtail(&engine->fullresult, result);
+       }
+
+       return result;
+}
+
+void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
+{
+       Render *re= engine->re;
+
+       if(result && render_display_draw_enabled(re)) {
+               result->renlay= result->layers.first; // weak
+               re->display_draw(re->ddh, result, NULL);
+       }
+}
+
+void RE_engine_end_result(RenderEngine *engine, RenderResult *result)
+{
+       Render *re= engine->re;
+
+       if(!result)
+               return;
+
+       /* merge */
+       if(re->result->exrhandle) {
+               RenderResult *rr, *rrpart;
+               
+               // XXX crashes, exr expects very particular part sizes
+               for(rr= re->result, rrpart= result; rr && rrpart; rr= rr->next, rrpart= rrpart->next)
+                       save_render_result_tile(rr, rrpart);
+       }
+       else if(render_display_draw_enabled(re)) {
+               /* on break, don't merge in result for preview renders, looks nicer */
+               if(re->test_break(re->tbh) && (re->r.scemode & R_PREVIEWBUTS));
+               else merge_render_result(re->result, result);
+       }
+
+       /* draw */
+       if(!re->test_break(re->tbh) && render_display_draw_enabled(re)) {
+               result->renlay= result->layers.first; // weak
+               re->display_draw(re->ddh, result, NULL);
+       }
+
+       /* free */
+       free_render_result(&engine->fullresult, result);
+}
+
+int RE_engine_test_break(RenderEngine *engine)
+{
+       Render *re= engine->re;
+
+       return re->test_break(re->tbh);
+}
+
+void RE_engine_update_stats(RenderEngine *engine, char *stats, char *info)
+{
+       Render *re= engine->re;
+
+       re->i.statstr= stats;
+       re->i.infostr= info;
+       re->stats_draw(re->sdh, &re->i);
+       re->i.infostr= NULL;
+       re->i.statstr= NULL;
+}
+
+/* loads in image into a result, size must match
+ * x/y offsets are only used on a partial copy when dimensions dont match */
+void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, char *filename)
+{
+       ImBuf *ibuf = IMB_loadiffname(filename, IB_rect);
+
+       if(ibuf  && (ibuf->rect || ibuf->rect_float)) {
+               if (ibuf->x == layer->rectx && ibuf->y == layer->recty) {
+                       if(ibuf->rect_float==NULL)
+                               IMB_float_from_rect(ibuf);
+
+                       memcpy(layer->rectf, ibuf->rect_float, sizeof(float)*4*layer->rectx*layer->recty);
+               } else {
+                       if ((ibuf->x >= layer->rectx) && (ibuf->y >= layer->recty)) {
+                               ImBuf *ibuf_clip;
+
+                               if(ibuf->rect_float==NULL)
+                                       IMB_float_from_rect(ibuf);
+
+                               ibuf_clip = IMB_allocImBuf(layer->rectx, layer->recty, 32, IB_rectfloat, 0);
+                               if(ibuf_clip) {
+                                       IMB_rectcpy(ibuf_clip, ibuf, 0,0, 0,0, layer->rectx, layer->recty);
+
+                                       memcpy(layer->rectf, ibuf_clip->rect_float, sizeof(float)*4*layer->rectx*layer->recty);
+                                       IMB_freeImBuf(ibuf_clip);
+                               }
+                               else {
+                                       BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to allocate clip buffer '%s'\n", filename);
+                               }
+                       }
+                       else {
+                               BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: incorrect dimensions for partial copy '%s'\n", filename);
+                       }
+               }
+
+               IMB_freeImBuf(ibuf);
+       }
+       else {
+               BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'\n", filename);
+       }
+}
+
+void RE_result_load_from_file(RenderResult *result, ReportList *reports, char *filename)
+{
+       if(!read_render_result_from_file(filename, result)) {
+               BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'\n", filename);
+               return;
+       }
+}
+
+static void external_render_3d(Render *re, RenderEngineType *type)
+{
+       RenderEngine engine;
+
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+       if(re->result==NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
+               RE_FreeRenderResult(re->result);
+       
+               if(0) // XXX re->r.scemode & R_FULL_SAMPLE)
+                       re->result= new_full_sample_buffers_exr(re);
+               else
+                       re->result= new_render_result(re, &re->disprect, 0, 0); // XXX re->r.scemode & (R_EXR_TILE_FILE|R_FULL_SAMPLE));
+       }
+       BLI_rw_mutex_unlock(&re->resultmutex);
+       
+       if(re->result==NULL)
+               return;
+
+       /* external */
+       memset(&engine, 0, sizeof(engine));
+       engine.type= type;
+       engine.re= re;
+
+       type->render(&engine, re->scene);
+
+       free_render_result(&engine.fullresult, engine.fullresult.first);
+
+       BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+       if(re->result->exrhandle) {
+               RenderResult *rr;
+
+               save_empty_result_tiles(re);
+               
+               for(rr= re->result; rr; rr= rr->next) {
+                       IMB_exr_close(rr->exrhandle);
+                       rr->exrhandle= NULL;
+               }
+               
+               free_render_result(&re->fullresult, re->result);
+               re->result= NULL;
+               
+               read_render_result(re, 0);
+       }
+       BLI_rw_mutex_unlock(&re->resultmutex);
+}
+