Work in progress commit on saving OpenEXR with all render-layers and
authorTon Roosendaal <ton@blender.org>
Thu, 23 Feb 2006 20:57:31 +0000 (20:57 +0000)
committerTon Roosendaal <ton@blender.org>
Thu, 23 Feb 2006 20:57:31 +0000 (20:57 +0000)
passes in single file. Code is currently disabled, commit is mainly to
have a nicer method of excluding OpenEXR dependency from render module.
This should compile with disabled WITH_OPENEXR too.

Reason why EXR is great to include by default in Blender is its feature
to store unlimited layers and channels, and write this tile based. I
need the feature for saving memory; while rendering tiles, all full-size
buffers for all layers and passes are kept in memory now, which can go
into 100s of MB easily.
The code I commit now doesn't allocate these buffers while rendering, but
saves the tiles to disk. In the end is it read back. Overhead for large
renders (like 300 meg buffers) is 10-15 seconds, not bad.

Two more interesting aspects:
- Blender can save such multi-layer files in the temp directory, storing
it with .blend file name and scene name. That way, on each restart of Blender,
or on switching scenes, these buffers can be read. So you always see what was
rendered last. Also great for compositing work.
- This can also become an output image type for rendering. There's plenty of
cases where you want specific layers or passes saved to disk for later use.

Anyhoo, finishing it is another days of work, and I got more urgent stuff
now!

source/blender/imbuf/intern/openexr/openexr_api.cpp
source/blender/imbuf/intern/openexr/openexr_api.h
source/blender/imbuf/intern/openexr/openexr_multi.h [new file with mode: 0644]
source/blender/render/extern/include/RE_pipeline.h
source/blender/render/intern/include/render_types.h
source/blender/render/intern/source/pipeline.c
source/blender/src/sequence.c

index 13ac8b14edfcccba72de7d3d51a746c9d7e7aa06..8c0bbb66911822258a1393e7db635d0f144757fa 100644 (file)
@@ -42,6 +42,9 @@ extern "C"
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 #include "IMB_allocimbuf.h"
+
+#define WITH_OPENEXR
+#include "openexr_multi.h"
 }
 
 #include <iostream>
@@ -333,103 +336,213 @@ short imb_save_openexr(struct ImBuf *ibuf, char *name, int flags)
 
 /* ********************* Tile file support ************************************ */
 
-typedef struct ExrTileHandle {
-       TiledOutputFile *file;
+typedef struct ExrHandle {
+       InputFile *ifile;
+       TiledOutputFile *tofile;
+       OutputFile *ofile;
        int tilex, tiley;
        int width, height;
        ListBase channels;
-} ExrTileHandle;
+} ExrHandle;
 
-typedef struct ExrTileChannel {
-       struct ExrTileChannel *next, *prev;
-       char *name;
+#define CHANMAXNAME 64
+typedef struct ExrChannel {
+       struct ExrChannel *next, *prev;
+       char name[2*CHANMAXNAME + 1];
        int xstride, ystride;
        float *rect;
-} ExrTileChannel;
+} ExrChannel;
 
 /* not threaded! write one tiled file at a time */
-void *imb_exrtile_get_handle(void)
+void *IMB_exr_get_handle(void)
 {
-       static ExrTileHandle data;
+       static ExrHandle data;
+       
+       memset(&data, sizeof(ExrHandle), 0);
        
-       data.channels.first= data.channels.last= NULL;
        return &data;
 }
 
-void imb_exrtile_add_channel(void *handle, char *channame)
+/* still clumsy name handling, layers/channels can be ordered as list in list later */
+void IMB_exr_add_channel(void *handle, const char *layname, const char *channame)
 {
-       ExrTileHandle *data= (ExrTileHandle *)handle;
-       ExrTileChannel *echan;
+       ExrHandle *data= (ExrHandle *)handle;
+       ExrChannel *echan;
        
-       echan= (ExrTileChannel *)MEM_callocN(sizeof(ExrTileChannel), "exr tile channel");
-       echan->name= channame;
+       echan= (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
+       
+       if(layname) {
+               char lay[CHANMAXNAME], chan[CHANMAXNAME];
+               strncpy(lay, layname, CHANMAXNAME-1);
+               strncpy(chan, channame, CHANMAXNAME-1);
+
+               sprintf(echan->name, "%s.%s", lay, chan);
+       }
+       else
+               strncpy(echan->name, channame, 2*CHANMAXNAME);
+       printf("added channel %s\n", echan->name);
        BLI_addtail(&data->channels, echan);
 }
 
-void imb_exrtile_begin_write(void *handle, char *filename, int width, int height, int tilex, int tiley)
+void IMB_exr_begin_write(void *handle, char *filename, int width, int height)
 {
-       ExrTileHandle *data= (ExrTileHandle *)handle;
+       ExrHandle *data= (ExrHandle *)handle;
        Header header (width, height);
-       ExrTileChannel *echan;
+       ExrChannel *echan;
+       
+       data->width= width;
+       data->height= height;
+       
+       for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
+               header.channels().insert (echan->name, Channel (FLOAT));
+       
+       header.insert ("comments", StringAttribute ("Blender MultiChannel"));
+       
+       data->ofile = new OutputFile(filename, header);
+}
+
+void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height, int tilex, int tiley)
+{
+       ExrHandle *data= (ExrHandle *)handle;
+       Header header (width, height);
+       ExrChannel *echan;
        
        data->tilex= tilex;
        data->tiley= tiley;
        data->width= width;
        data->height= height;
        
-       for(echan= (ExrTileChannel *)data->channels.first; echan; echan= echan->next)
+       for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
                header.channels().insert (echan->name, Channel (FLOAT));
        
        header.setTileDescription (TileDescription (tilex, tiley, ONE_LEVEL));
+       header.lineOrder() = RANDOM_Y,
+       header.compression() = NO_COMPRESSION;
        
-       header.insert ("comments", StringAttribute ("Blender RenderResult"));
+       header.insert ("comments", StringAttribute ("Blender MultiChannel"));
        
-       data->file = new TiledOutputFile(filename, header);
+       data->tofile = new TiledOutputFile(filename, header);
 }
 
+int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height)
+{
+       ExrHandle *data= (ExrHandle *)handle;
+       
+       data->ifile = new InputFile(filename);
+       if(data->ifile) {
+               Box2i dw = data->ifile->header().dataWindow();
+               data->width= *width  = dw.max.x - dw.min.x + 1;
+               data->height= *height = dw.max.y - dw.min.y + 1;
+               
+               const ChannelList &channels = data->ifile->header().channels();
+               
+               for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
+                       IMB_exr_add_channel(data, NULL, i.name());
+               
+               return 1;
+       }
+       return 0;
+}
 
-void imb_exrtile_set_channel(void *handle, char *channame, int xstride, int ystride, float *rect)
+/* still clumsy name handling, layers/channels can be ordered as list in list later */
+void IMB_exr_set_channel(void *handle, char *layname, char *channame, int xstride, int ystride, float *rect)
 {
-       ExrTileHandle *data= (ExrTileHandle *)handle;
-       ExrTileChannel *echan;
+       ExrHandle *data= (ExrHandle *)handle;
+       ExrChannel *echan;
+       char name[2*CHANMAXNAME + 1];
        
-       for(echan= (ExrTileChannel *)data->channels.first; echan; echan= echan->next)
-               if(strcmp(echan->name, channame)==0)
+       if(layname) {
+               char lay[CHANMAXNAME], chan[CHANMAXNAME];
+               strncpy(lay, layname, CHANMAXNAME-1);
+               strncpy(chan, channame, CHANMAXNAME-1);
+               
+               sprintf(name, "%s.%s", lay, chan);
+       }
+       else
+               strncpy(name, channame, 2*CHANMAXNAME);
+       
+       
+       for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
+               if(strcmp(echan->name, name)==0)
                        break;
+       
        if(echan) {
                echan->xstride= xstride;
                echan->ystride= ystride;
                echan->rect= rect;
        }
        else
-               printf("imb_exrtile_set_channel error\n");
+               printf("IMB_exrtile_set_channel error %s\n", name);
 }
 
 
-void imb_exrtile_write_channels(void *handle, int partx, int party)
+void IMB_exrtile_write_channels(void *handle, int partx, int party)
 {
-       ExrTileHandle *data= (ExrTileHandle *)handle;
+       ExrHandle *data= (ExrHandle *)handle;
        FrameBuffer frameBuffer;
-       ExrTileChannel *echan;
+       ExrChannel *echan;
        
-       for(echan= (ExrTileChannel *)data->channels.first; echan; echan= echan->next) {
+       for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
                float *rect= echan->rect - echan->xstride*partx - echan->ystride*party;
 
                frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)rect, 
                                                        echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
        }
        
-       data->file->setFrameBuffer (frameBuffer);
+       data->tofile->setFrameBuffer (frameBuffer);
        printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
-       data->file->writeTile (partx/data->tilex, party/data->tiley);   
+       data->tofile->writeTile (partx/data->tilex, party/data->tiley); 
        
 }
 
-void imb_exrtile_close(void *handle)
+void IMB_exr_write_channels(void *handle)
 {
-       ExrTileHandle *data= (ExrTileHandle *)handle;
+       ExrHandle *data= (ExrHandle *)handle;
+       FrameBuffer frameBuffer;
+       ExrChannel *echan;
        
-       delete data->file;
+       for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
+               frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)echan->rect, 
+                                                                                               echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
+       
+       data->ofile->setFrameBuffer (frameBuffer);
+       data->ofile->writePixels (data->height);        
+       
+}
+
+void IMB_exr_read_channels(void *handle)
+{
+       ExrHandle *data= (ExrHandle *)handle;
+       FrameBuffer frameBuffer;
+       ExrChannel *echan;
+       
+       for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
+               /* no datawindow correction needed */
+               if(echan->rect)
+                       frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)echan->rect, 
+                                                                                               echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
+       }
+       
+       data->ifile->setFrameBuffer (frameBuffer);
+       data->ifile->readPixels (0, data->height-1);    
+}
+
+
+void IMB_exr_close(void *handle)
+{
+       ExrHandle *data= (ExrHandle *)handle;
+       ExrChannel *echan;
+       
+       if(data->ifile)
+               delete data->ifile;
+       else if(data->ofile)
+               delete data->ofile;
+       else if(data->tofile)
+               delete data->tofile;
+       
+       data->ifile= NULL;
+       data->ofile= NULL;
+       data->tofile= NULL;
        
        BLI_freelistN(&data->channels);
 }
@@ -473,11 +586,9 @@ static int exr_has_zbuffer(InputFile *file)
 static int exr_is_renderresult(InputFile *file)
 {
        const StringAttribute *comments= file->header().findTypedAttribute<StringAttribute>("comments");
-       if(comments) {
-       
-               if(comments->value() == "Blender RenderResult")
+       if(comments)
+               if(comments->value() == "Blender MultiChannel")
                        return 1;
-       }
        return 0;
 }
 
@@ -529,7 +640,8 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags)
                                                                                                                                                /* 1.0 is fill value */
                                frameBuffer.insert ("A", Slice (FLOAT,  (char *) (first+3), xstride, ystride, 1, 1, 1.0f));
 
-                               if(exr_has_zbuffer(file)) {
+                               if(exr_has_zbuffer(file)) 
+                               {
                                        float *firstz;
                                        
                                        addzbuffloatImBuf(ibuf);
index a82713b65955dda434f7d1980e254922732fc5ce..7572dbcb292e3e4e3736ca3af1916ee03219c592 100644 (file)
@@ -1,15 +1,12 @@
 /**
  * $Id$ 
  *
- * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version. The Blender
- * Foundation also sells licenses for use in proprietary software under
- * the Blender License.  See http://www.blender.org/BL/ for information
- * about this.
+ * of the License, or (at your option) any later version. 
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * The Original Code is Copyright (C) 2005 Blender Foundation
  * All rights reserved.
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s): Austin Benesh.
+ * Contributor(s): Austin Benesh. Ton Roosendaal.
  *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * ***** END GPL LICENSE BLOCK *****
  */
 
 #ifndef _OPENEXR_API_H
@@ -37,8 +34,8 @@
 extern "C" {
 #endif
 
-#define OPENEXR_FLOATRGB 0x1
-#define OPENEXR_ZBUF 0x2
+#define OPENEXR_FLOATRGB       0x1
+#define OPENEXR_ZBUF           0x2
   
 #include <stdio.h>
   
@@ -53,15 +50,6 @@ short        imb_save_openexr                        (struct ImBuf *ibuf, char *name, int flags);
 
 struct ImBuf *imb_load_openexr         (unsigned char *mem, int size, int flags);
 
-
-void * imb_exrtile_get_handle          (void);
-void   imb_exrtile_add_channel         (void *handle, char *channame);
-void   imb_exrtile_begin_write         (void *handle, char *filename, int width, int height, int tilex, int tiley);
-void   imb_exrtile_set_channel         (void *handle, char *channame, int xstride, int ystride, float *rect);
-void   imb_exrtile_write_channels      (void *handle, int partx, int party);
-void   imb_exrtile_close                       (void *handle);
-
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
new file mode 100644 (file)
index 0000000..ff71aab
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * $Id$ 
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Ton Roosendaal.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _OPENEXR_MULTI_H
+#define _OPENEXR_MULTI_H
+
+/* experiment with more advanced exr api */
+
+#ifdef WITH_OPENEXR
+void * IMB_exr_get_handle                      (void);
+void   IMB_exr_add_channel                     (void *handle, const char *layname, const char *channame);
+
+int            IMB_exr_begin_read                      (void *handle, char *filename, int *width, int *height);
+void   IMB_exr_begin_write                     (void *handle, char *filename, int width, int height);
+void   IMB_exrtile_begin_write         (void *handle, char *filename, int width, int height, int tilex, int tiley);
+
+void   IMB_exr_set_channel                     (void *handle, char *layname, char *channame, int xstride, int ystride, float *rect);
+
+void   IMB_exr_read_channels           (void *handle);
+void   IMB_exr_write_channels          (void *handle);
+void   IMB_exrtile_write_channels      (void *handle, int partx, int party);
+
+void   IMB_exr_close                           (void *handle);
+
+#else
+
+/* ugly... but we only use it on pipeline.c, render module, now */
+
+void * IMB_exr_get_handle                      (void) {return NULL;}
+void   IMB_exr_add_channel                     (void *handle, const char *layname, const char *channame) {}
+
+int            IMB_exr_begin_read                      (void *handle, char *filename, int *width, int *height) {return 0;}
+void   IMB_exr_begin_write                     (void *handle, char *filename, int width, int height) {}
+void   IMB_exrtile_begin_write         (void *handle, char *filename, int width, int height, int tilex, int tiley) {}
+
+void   IMB_exr_set_channel                     (void *handle, char *layname, char *channame, int xstride, int ystride, float *rect) {}
+
+void   IMB_exr_read_channels           (void *handle) {}
+void   IMB_exr_write_channels          (void *handle) {}
+void   IMB_exrtile_write_channels      (void *handle, int partx, int party) {}
+
+void   IMB_exr_close                           (void *handle) {}
+
+#endif
+
+
+
+#endif /* __OPENEXR_MULTI_H */
index b1dfb53e357e30cec94b3615d596ae2150bfa1d0..ad3d93cd908228d54bd365010cbfc7fdd9918812 100644 (file)
@@ -58,7 +58,7 @@ typedef struct Render Render;
 
 typedef struct RenderPass {
        struct RenderPass *next, *prev;
-       int passtype;
+       int passtype, channels;
        float *rect;
 } RenderPass;
 
index b76e5343dfd322cb8f26a65b7b9c4d8227461e0b..64780b1b831958de5f8a4e66357fa107c7f461a1 100644 (file)
@@ -332,15 +332,14 @@ typedef struct LampRen
 
 /* **************** defines ********************* */
 
-/* mode flag is same as for renderdata */
-/* flag */
+/* R.r.mode flag is same as for renderdata */
+
+/* R.flag */
 #define R_ZTRA                 1
 #define R_HALO                 2
 #define R_SEC_FIELD            4
 #define R_LAMPHALO             8
-#define R_RENDERING            16
-#define R_ANIMRENDER   32
-#define R_REDRAW_PRV   64
+#define R_FILEBUFFER   16
 
 /* vlakren->flag (vlak = face in dutch) char!!! */
 #define R_SMOOTH               1
index c95442fc97d3bc30aa7aceceecaaca362ff1e6c7..a1e5108d3d603ad5fcefad6ea03809219d5790b9 100644 (file)
 #include "PIL_time.h"
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
-#include "intern/openexr/openexr_api.h"
+
+#include "intern/openexr/openexr_multi.h"
 
 #include "RE_pipeline.h"
 #include "radio.h"
 
 #include "BSE_sequence.h"  /* <----------------- bad!!! */
 
+#include "SDL_thread.h"
+
 /* internal */
 #include "render_types.h"
 #include "renderpipeline.h"
@@ -68,9 +71,6 @@
 #include "shadbuf.h"
 #include "zbuf.h"
 
-#include "SDL_thread.h"
-#include "SDL_mutex.h"
-
 /* render flow
 
 1) Initialize state
@@ -105,7 +105,8 @@ static struct ListBase RenderList= {NULL, NULL};
 /* hardcopy of current render, used while rendering for speed */
 Render R;
 
-void *exrhandle= NULL;
+static SDL_mutex *exrtile_lock= NULL;
+
 /* ********* alloc and free ******** */
 
 
@@ -156,7 +157,7 @@ static void free_render_result(RenderResult *res)
                if(rl->rectf) MEM_freeT(rl->rectf);
                while(rl->passes.first) {
                        RenderPass *rpass= rl->passes.first;
-                       MEM_freeT(rpass->rect);
+                       if(rpass->rect) MEM_freeT(rpass->rect);
                        BLI_remlink(&rl->passes, rpass);
                        MEM_freeT(rpass);
                }
@@ -174,23 +175,90 @@ static void free_render_result(RenderResult *res)
        MEM_freeT(res);
 }
 
-static void render_layer_add_pass(RenderLayer *rl, int rectsize, int passtype, char *mallocstr)
+static char *get_pass_name(int passtype, int channel)
+{
+       
+       if(passtype == SCE_PASS_COMBINED) {
+               if(channel==0) return "Combined.R";
+               else if(channel==1) return "Combined.G";
+               else if(channel==2) return "Combined.B";
+               else return "Combined.A";
+       }
+       if(passtype == SCE_PASS_Z)
+               return "Z";
+       if(passtype == SCE_PASS_VECTOR) {
+               if(channel==0) return "Vector.X";
+               else if(channel==1) return "Vector.Y";
+               else if(channel==2) return "Vector.Z";
+               else return "Vector.W";
+       }
+       if(passtype == SCE_PASS_NORMAL) {
+               if(channel==0) return "Normal.X";
+               else if(channel==1) return "Normal.Y";
+               else return "Normal.Z";
+       }
+       if(passtype == SCE_PASS_RGBA) {
+               if(channel==0) return "Color.R";
+               else if(channel==1) return "Color.G";
+               else if(channel==2) return "Color.B";
+               else return "Color.A";
+       }
+       if(passtype == SCE_PASS_DIFFUSE) {
+               if(channel==0) return "Diffuse.R";
+               else if(channel==1) return "Diffuse.G";
+               else return "Diffuse.B";
+       }
+       if(passtype == SCE_PASS_SPEC) {
+               if(channel==0) return "Spec.R";
+               else if(channel==1) return "Spec.G";
+               else return "Spec.B";
+       }
+       if(passtype == SCE_PASS_SHADOW) {
+               if(channel==0) return "Shadow.R";
+               else if(channel==1) return "Shadow.G";
+               else return "Shadow.B";
+       }
+       if(passtype == SCE_PASS_AO) {
+               if(channel==0) return "AO.R";
+               else if(channel==1) return "AO.G";
+               else return "AO.B";
+       }
+       if(passtype == SCE_PASS_RAY) {
+               if(channel==0) return "Ray.R";
+               else if(channel==1) return "Ray.G";
+               else return "Ray.B";
+       }
+       return "Unknown";
+}
+
+static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
 {
-       RenderPass *rpass= MEM_mallocT(sizeof(RenderPass), mallocstr);
+       char *typestr= get_pass_name(passtype, 0);
+       RenderPass *rpass= MEM_callocT(sizeof(RenderPass), typestr);
+       int rectsize= rr->rectx*rr->recty*channels;
        
        BLI_addtail(&rl->passes, rpass);
        rpass->passtype= passtype;
-       if(passtype==SCE_PASS_VECTOR) {
-               float *rect;
-               int x;
-               
-               /* initialize to max speed */
-               rect= rpass->rect= MEM_mapallocT(sizeof(float)*rectsize, mallocstr);
-               for(x= rectsize-1; x>=0; x--)
-                       rect[x]= PASS_VECTOR_MAX;
+       rpass->channels= channels;
+       
+       if(rr->exrhandle) {
+               int a;
+               for(a=0; a<channels; a++)
+                       IMB_exr_add_channel(rr->exrhandle, rl->name, get_pass_name(passtype, a));
+       }
+       else {
+               if(passtype==SCE_PASS_VECTOR) {
+                       float *rect;
+                       int x;
+                       
+                       /* initialize to max speed */
+                       rect= rpass->rect= MEM_mapallocT(sizeof(float)*rectsize, typestr);
+                       for(x= rectsize-1; x>=0; x--)
+                               rect[x]= PASS_VECTOR_MAX;
+               }
+               else
+                       rpass->rect= MEM_mapallocT(sizeof(float)*rectsize, typestr);
        }
-       else
-               rpass->rect= MEM_mapallocT(sizeof(float)*rectsize, mallocstr);
 }
 
 float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype)
@@ -203,10 +271,11 @@ float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype)
        return NULL;
 }
 
+
 /* called by main render as well for parts */
 /* will read info from Render *re to define layers */
 /* called in threads */
-/* winrct is coordinate rect of entire image, partrct the part within */
+/* re->winx,winy is coordinate space of entire image, partrct the part within */
 static RenderResult *new_render_result(Render *re, rcti *partrct, int crop)
 {
        RenderResult *rr;
@@ -232,6 +301,11 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop)
        rr->tilerect.ymin= partrct->ymin - re->disprect.ymin;
        rr->tilerect.ymax= partrct->ymax - re->disprect.ymax;
        
+       /* this flag needs cleared immediate after result was made */
+       if(re->flag & R_FILEBUFFER) {
+               rr->exrhandle= IMB_exr_get_handle();
+       }
+       
        /* check renderdata for amount of layers */
        for(nr=0, srl= re->r.layers.first; srl; srl= srl->next, nr++) {
                
@@ -246,26 +320,33 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop)
                rl->layflag= srl->layflag;
                rl->passflag= srl->passflag;
                
-               rl->rectf= MEM_mapallocT(rectx*recty*sizeof(float)*4, "layer float rgba");
+               if(rr->exrhandle) {
+                       IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R");
+                       IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G");
+                       IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B");
+                       IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A");
+               }
+               else
+                       rl->rectf= MEM_mapallocT(rectx*recty*sizeof(float)*4, "Combined rgba");
                
                if(srl->passflag  & SCE_PASS_Z)
-                       render_layer_add_pass(rl, rectx*recty, SCE_PASS_Z, "Layer float Z");
+                       render_layer_add_pass(rr, rl, 1, SCE_PASS_Z);
                if(srl->passflag  & SCE_PASS_VECTOR)
-                       render_layer_add_pass(rl, rectx*recty*4, SCE_PASS_VECTOR, "layer float Vector");
+                       render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR);
                if(srl->passflag  & SCE_PASS_NORMAL)
-                       render_layer_add_pass(rl, rectx*recty*3, SCE_PASS_NORMAL, "layer float Normal");
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL);
                if(srl->passflag  & SCE_PASS_RGBA)
-                       render_layer_add_pass(rl, rectx*recty*4, SCE_PASS_RGBA, "layer float Color");
+                       render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA);
                if(srl->passflag  & SCE_PASS_DIFFUSE)
-                       render_layer_add_pass(rl, rectx*recty*3, SCE_PASS_DIFFUSE, "layer float Diffuse");
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE);
                if(srl->passflag  & SCE_PASS_SPEC)
-                       render_layer_add_pass(rl, rectx*recty*3, SCE_PASS_SPEC, "layer float Spec");
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC);
                if(srl->passflag  & SCE_PASS_SHADOW)
-                       render_layer_add_pass(rl, rectx*recty*3, SCE_PASS_SHADOW, "layer float Shadow");
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
                if(srl->passflag  & SCE_PASS_AO)
-                       render_layer_add_pass(rl, rectx*recty*3, SCE_PASS_AO, "layer float AO");
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
                if(srl->passflag  & SCE_PASS_RAY)
-                       render_layer_add_pass(rl, rectx*recty*3, SCE_PASS_RAY, "layer float Mirror");
+                       render_layer_add_pass(rr, rl, 3, SCE_PASS_RAY);
                
        }
        /* previewrender and envmap don't do layers, so we make a default one */
@@ -346,19 +427,7 @@ static void merge_render_result(RenderResult *rr, RenderResult *rrpart)
                
                /* passes are allocated in sync */
                for(rpass= rl->passes.first, rpassp= rlp->passes.first; rpass && rpassp; rpass= rpass->next, rpassp= rpassp->next) {
-                       switch(rpass->passtype) {
-                               case SCE_PASS_Z:
-                                       do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, 1);
-                                       break;
-                               case SCE_PASS_VECTOR:
-                                       do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, 4);
-                                       break;
-                               case SCE_PASS_RGBA:
-                                       do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, 4);
-                                       break;
-                               default:
-                                       do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, 3);
-                       }
+                       do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
                }
        }
 }
@@ -366,11 +435,13 @@ static void merge_render_result(RenderResult *rr, RenderResult *rrpart)
 
 static void save_render_result_tile(Render *re, RenderPart *pa)
 {
-#ifdef WITH_OPENEXR
        RenderResult *rrpart= pa->result;
        RenderLayer *rlp;
+       RenderPass *rpassp;
        int offs, partx, party;
        
+       if(exrtile_lock) SDL_mutexP(exrtile_lock);
+       
        for(rlp= rrpart->layers.first; rlp; rlp= rlp->next) {
                
                if(rrpart->crop) {      /* filters add pixel extra */
@@ -384,18 +455,69 @@ static void save_render_result_tile(Render *re, RenderPart *pa)
                
                /* combined */
                if(rlp->rectf) {
-                       int xstride= 4;
-                       imb_exrtile_set_channel(exrhandle, "R", xstride, xstride*pa->rectx, rlp->rectf   + xstride*offs);
-                       imb_exrtile_set_channel(exrhandle, "G", xstride, xstride*pa->rectx, rlp->rectf+1 + xstride*offs);
-                       imb_exrtile_set_channel(exrhandle, "B", xstride, xstride*pa->rectx, rlp->rectf+2 + xstride*offs);
-                       imb_exrtile_set_channel(exrhandle, "A", xstride, xstride*pa->rectx, rlp->rectf+3 + xstride*offs);
-                       
-                       imb_exrtile_write_channels(exrhandle, partx, party);
-               }               
+                       int a, xstride= 4;
+                       for(a=0; a<xstride; a++)
+                               IMB_exr_set_channel(re->result->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a), 
+                                                               xstride, xstride*pa->rectx, rlp->rectf+a + xstride*offs);
+               }
+               
+               /* passes are allocated in sync */
+               for(rpassp= rlp->passes.first; rpassp; rpassp= rpassp->next) {
+                       int a, xstride= rpassp->channels;
+                       for(a=0; a<xstride; a++)
+                               IMB_exr_set_channel(re->result->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a), 
+                                                                       xstride, xstride*pa->rectx, rpassp->rect+a + xstride*offs);
+               }
+               
        }
-#endif
+
+       IMB_exrtile_write_channels(re->result->exrhandle, partx, party);
+
+       if(exrtile_lock) SDL_mutexV(exrtile_lock);
+
 }
 
+static void read_render_result(Render *re)
+{
+       RenderLayer *rl;
+       RenderPass *rpass;
+       void *exrhandle= IMB_exr_get_handle();
+       int rectx, recty;
+       
+       free_render_result(re->result);
+       re->result= new_render_result(re, &re->disprect, 0);
+
+       IMB_exr_begin_read(exrhandle, "/tmp/render.exr", &rectx, &recty);
+       if(rectx!=re->result->rectx || recty!=re->result->recty) {
+               printf("error in reading render result\n");
+       }
+       else {
+               for(rl= re->result->layers.first; rl; rl= rl->next) {
+                       
+                       /* combined */
+                       if(rl->rectf) {
+                               int a, xstride= 4;
+                               for(a=0; a<xstride; a++)
+                                       IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), 
+                                                                               xstride, xstride*rectx, rl->rectf+a);
+                       }
+                       
+                       /* passes are allocated in sync */
+                       for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+                               int a, xstride= rpass->channels;
+                               for(a=0; a<xstride; a++)
+                                       IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), 
+                                                                               xstride, xstride*rectx, rpass->rect+a);
+                       }
+                       
+               }
+               printf("before read\n");
+               IMB_exr_read_channels(exrhandle);
+               printf("after read\n");
+       }
+       
+       IMB_exr_close(exrhandle);
+}
 
 /* *************************************************** */
 
@@ -590,7 +712,7 @@ void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect
                /* initialize render result */
                free_render_result(re->result);
                re->result= new_render_result(re, &re->disprect, 0);
-               
+                       
                /* single layer render disables composit */
                if(re->r.scemode & R_SINGLE_LAYER)
                        re->r.scemode &= ~R_DOCOMP;
@@ -701,8 +823,11 @@ static int do_part_thread(void *pa_v)
                else
                        zbufshade_tile(pa);
                
-               /* merge too on break! */       
-               merge_render_result(R.result, pa->result);
+               /* merge too on break! */
+               if(R.result->exrhandle)
+                       save_render_result_tile(&R, pa);
+               else
+                       merge_render_result(R.result, pa->result);
        }
        
        pa->ready= 1;
@@ -805,13 +930,19 @@ static void threaded_tile_processor(Render *re)
 {
        ListBase threads;
        RenderPart *pa, *nextpa;
-       int maxthreads, rendering=1, counter= 1, drawtimer=0;
+       RenderResult *rr= re->result;
+       int maxthreads, rendering=1, counter= 1, drawtimer=0, hasdrawn;
        
-       if(re->result==NULL)
+       if(rr==NULL)
                return;
        if(re->test_break())
                return;
        
+       if(rr->exrhandle) {
+               IMB_exrtile_begin_write(rr->exrhandle, "/tmp/render.exr", rr->rectx, rr->recty, rr->rectx/re->r.xparts, rr->recty/re->r.yparts);
+               exrtile_lock = SDL_CreateMutex();
+       }
+       
        if(re->r.mode & R_THREADS) maxthreads= 2;
        else maxthreads= 1;
        
@@ -844,37 +975,45 @@ static void threaded_tile_processor(Render *re)
                
                /* check for ready ones to display, and if we need to continue */
                rendering= 0;
+               hasdrawn= 0;
                for(pa= re->parts.first; pa; pa= pa->next) {
                        if(pa->ready) {
                                if(pa->result) {
                                        BLI_remove_thread(&threads, pa);
+
                                        re->display_draw(pa->result, NULL);
                                        print_part_stats(re, pa);
                                        
-                                       if(exrhandle) save_render_result_tile(re, pa);
-                                       
                                        free_render_result(pa->result);
                                        pa->result= NULL;
                                        re->i.partsdone++;
-                                       drawtimer= 0;
+                                       hasdrawn= 1;
                                }
                        }
                        else {
                                rendering= 1;
                                if(pa->nr && pa->result && drawtimer>20) {
                                        re->display_draw(pa->result, &pa->result->renrect);
-                                       drawtimer= 0;
+                                       hasdrawn= 1;
                                }
                        }
                }
-               
+               if(hasdrawn)
+                       drawtimer= 0;
+
                /* on break, wait for all slots to get freed */
                if( (g_break=re->test_break()) && BLI_available_threads(&threads)==maxthreads)
                        rendering= 0;
                
        }
        
-       /* restore threadsafety */
+       if(rr->exrhandle) {
+               if(exrtile_lock) SDL_DestroyMutex(exrtile_lock); 
+               IMB_exr_close(rr->exrhandle);
+               read_render_result(re);
+       }
+       
+       /* unset threadsafety */
        g_break= 0;
        
        BLI_end_threads(&threads);
@@ -1158,7 +1297,9 @@ static int render_initialize_from_scene(Render *re, Scene *scene)
                disprect.ymax= winy;
        }
        
+/*     if(G.rt) re->flag |= R_FILEBUFFER; */
        RE_InitState(re, &scene->r, winx, winy, &disprect);
+       re->flag &= ~R_FILEBUFFER;
        
        re->scene= scene;
        if(!is_rendering_allowed(re))
@@ -1167,15 +1308,6 @@ static int render_initialize_from_scene(Render *re, Scene *scene)
        re->display_init(re->result);
        re->display_clear(re->result);
        
-       if(0) {
-               exrhandle= imb_exrtile_get_handle();
-               imb_exrtile_add_channel(exrhandle, "R");
-               imb_exrtile_add_channel(exrhandle, "G");
-               imb_exrtile_add_channel(exrhandle, "B");
-               imb_exrtile_add_channel(exrhandle, "A");
-               imb_exrtile_begin_write(exrhandle, "/tmp/render.exr", winx, winy, winx/scene->r.xparts, winy/scene->r.yparts);
-       }
-       
        return 1;
 }
 
@@ -1189,11 +1321,6 @@ void RE_BlenderFrame(Render *re, Scene *scene, int frame)
        if(render_initialize_from_scene(re, scene)) {
                do_render_final(re);
                
-#ifdef WITH_OPENEXR
-               if(exrhandle)
-                       imb_exrtile_close(exrhandle);
-#endif
-               exrhandle= NULL;
        }
 }
 
index 1333e1f177f70e307897902710f6f19d806b1de9..dd54d014c5ce143e4b86afba17708973e1587e49 100644 (file)
@@ -2182,7 +2182,7 @@ static void do_build_seq_ibuf(Sequence * seq, int cfra)
                                Scene *oldsce;
                                unsigned int *rectot;
                                int oldcfra, doseq;
-                               int redisplay= (!G.background && !(R.flag & R_RENDERING));
+                               int redisplay= (!G.background && !G.rendering);
                                
                                oldsce= G.scene;
                                if(seq->scene!=G.scene) set_scene_bg(seq->scene);