Two in one:
[blender.git] / source / blender / src / renderwin.c
index 921048ff3b0955ea4b5511b62f79926d89eb3cfc..8ca96f89936090edb891d19bfb1e88366ce115ea 100644 (file)
 #include <limits.h>
 
 #include "BLI_blenlib.h"
+#include "BLI_threads.h"
 
 #include "MEM_guardedalloc.h"
 
 #include "BMF_Api.h"
 
-#include "DNA_view3d_types.h"
+#include "DNA_image_types.h"
+#include "DNA_space_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
 #include "DNA_vec_types.h"
 
 #include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
 #include "BKE_scene.h"
 #include "BKE_utildefines.h"
 #include "BKE_writeavi.h"      /* movie handle */
 
+#include "BIF_drawimage.h"
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 #include "BIF_graphics.h"
 #include "BIF_renderwin.h"
 #include "BIF_resources.h"
 #include "BIF_toets.h"
+#include "BIF_toolbox.h"
 #include "BIF_writeimage.h"
 
+#include "BDR_sculptmode.h"
 #include "BDR_editobject.h"
 #include "BPY_extern.h" /* for BPY_do_all_scripts */
 
 
 #include "RE_pipeline.h"
 
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
 #include "blendef.h"
 #include "mydevice.h"
 #include "winlay.h"
 /* forces draw of alpha */
 #define RW_FLAGS_ALPHA         (1<<4)
 
-/* space for info text */
-#define RW_HEADERY             18
 
 typedef struct {
        Window *win;
 
        int rectx, recty;       /* size of image */
+       
+       int sparex, sparey;     /* spare rect size */
+       unsigned int *rectspare;
+       float *rectsparef;
+       
        float zoom, zoomofs[2];
        int active;
+       short storespare, showspare;
        
-       int mbut[3];
+       int mbut[5];
        int lmouse[2];
        
        unsigned int flags;
@@ -150,17 +165,18 @@ static RenderWin *render_win= NULL;
 /* only called in function open_renderwin */
 static RenderWin *renderwin_alloc(Window *win)
 {
-       RenderWin *rw= MEM_mallocN(sizeof(*rw), "RenderWin");
+       RenderWin *rw= MEM_callocN(sizeof(*rw), "RenderWin");
        rw->win= win;
        rw->zoom= 1.0;
        rw->active= 0;
        rw->flags= 0;
        rw->zoomofs[0]= rw->zoomofs[1]= 0;
        rw->info_text= NULL;
-       rw->render_text= rw->render_text_spare= NULL;
+       rw->render_text= MEM_callocN(RW_MAXTEXT, "rendertext");
+       rw->render_text_spare= MEM_callocN(RW_MAXTEXT, "rendertext spare");
 
        rw->lmouse[0]= rw->lmouse[1]= 0;
-       rw->mbut[0]= rw->mbut[1]= rw->mbut[2]= 0;
+       rw->mbut[0]= rw->mbut[1]= rw->mbut[2]= rw->mbut[3] = rw->mbut[4] = 0;
 
        return rw;
 }
@@ -261,6 +277,7 @@ static void renderwin_draw_render_info(RenderWin *rw)
        if(RW_HEADERY) {
                float colf[3];
                rcti rect;
+               char *str;
                
                window_get_size(rw->win, &rect.xmax, &rect.ymax);
                rect.xmin= 0;
@@ -274,10 +291,15 @@ static void renderwin_draw_render_info(RenderWin *rw)
                glClearColor(colf[0], colf[1], colf[2], 1.0); 
                glClear(GL_COLOR_BUFFER_BIT);
                
-               if(rw->render_text) {
+               if(rw->showspare)
+                       str= rw->render_text_spare;
+               else
+                       str= rw->render_text;
+               
+               if(str) {
                        BIF_ThemeColor(TH_TEXT);
                        glRasterPos2i(12, 5);
-                       BMF_DrawString(G.fonts, rw->render_text);
+                       BMF_DrawString(G.fonts, str);
                }
                
                BIF_SetTheme(curarea);  // restore theme
@@ -318,21 +340,42 @@ static void renderwin_draw(RenderWin *rw, int just_clear)
        } else {
                RenderResult rres;
                
-               RE_GetResultImage(RE_GetRender("Render"), &rres);
-               if(rres.rectf) {
+               if(rw->showspare) {
+                       rres.rectx= rw->sparex;
+                       rres.recty= rw->sparey;
+                       rres.rect32= rw->rectspare;
+                       rres.rectf= rw->rectsparef;
+               }
+               else
+                       RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+               
+               if(rres.rectf || rres.rect32) {
                        
                        glPixelZoom(rw->zoom, rw->zoom);
                        if(rw->flags & RW_FLAGS_ALPHA) {
-                               /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
-       //                              glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
-       //                              glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rr->rectx, rr->recty, GL_LUMINANCE, GL_UNSIGNED_INT, R.rectot);
-       //                              glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
+                               if(rres.rect32) {
+                                       /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
+                                       if(G.order==B_ENDIAN)
+                                               glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+                                       glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_LUMINANCE, GL_UNSIGNED_INT, rres.rect32);
+                                       glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
+                               }
+                               else {
+                                       float *trectf= MEM_mallocN(rres.rectx*rres.recty*4, "temp");
+                                       int a, b;
+                                       
+                                       for(a= rres.rectx*rres.recty -1, b= 4*a+3; a>=0; a--, b-=4)
+                                               trectf[a]= rres.rectf[b];
+                                       
+                                       glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_LUMINANCE, GL_FLOAT, trectf);
+                                       MEM_freeN(trectf);
+                               }
                        }
                        else {
                                if(rres.rect32)
                                        glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rres.rect32);
                                else if(rres.rectf)
-                                       glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_FLOAT, rres.rectf);
+                                       glaDrawPixelsSafe_to32(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, rres.rectf);
                        }
                        glPixelZoom(1.0, 1.0);
                }
@@ -357,13 +400,30 @@ static void renderwin_draw(RenderWin *rw, int just_clear)
        if (set_back_mainwindow) mainwindow_make_active();      
 }
 
+
 /* ------ interactivity calls for RenderWin ------------- */
+static void renderwin_zoom(RenderWin *rw, int ZoomIn) {
+       if (ZoomIn) {
+               if (rw->zoom>0.26) {
+                       if(rw->zoom>1.0 && rw->zoom<2.0) rw->zoom= 1.0;
+                       else rw->zoom*= 0.5;
+               }
+       } else {
+               if (rw->zoom<15.9) {
+                       if(rw->zoom>0.5 && rw->zoom<1.0) rw->zoom= 1.0;
+                       else rw->zoom*= 2.0;
+               }
+       }
+       if (rw->zoom>1.0) rw->flags |= RW_FLAGS_OLDZOOM;
+       if (rw->zoom==1.0) rw->flags &= ~RW_FLAGS_OLDZOOM;
+       renderwin_queue_redraw(rw);
+}
 
 static void renderwin_mouse_moved(RenderWin *rw)
 {
        RenderResult rres;
        
-       RE_GetResultImage(RE_GetRender("Render"), &rres);
+       RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
 
        if (rw->flags & RW_FLAGS_PIXEL_EXAMINING) {
                int imgco[2], ofs=0;
@@ -428,8 +488,13 @@ static void renderwin_mousebut_changed(RenderWin *rw)
                rw->pan_mouse_start[1]= rw->lmouse[1];
                rw->pan_ofs_start[0]= rw->zoomofs[0];
                rw->pan_ofs_start[1]= rw->zoomofs[1];
-       } 
-       else {
+       } else if (rw->mbut[3]) {
+               renderwin_zoom(rw, 0);
+               rw->mbut[3]=0;
+       } else if (rw->mbut[4]) {
+               renderwin_zoom(rw, 1);
+               rw->mbut[4]=0;
+       } else {
                if (rw->flags & RW_FLAGS_PANNING) {
                        rw->flags &= ~RW_FLAGS_PANNING;
                        renderwin_queue_redraw(rw);
@@ -476,6 +541,11 @@ static void renderwin_handler(Window *win, void *user_data, short evt, short val
                rw->lmouse[evt==MOUSEY]= val;
                renderwin_mouse_moved(rw);
        } 
+       else if (ELEM(evt, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
+               int which=(evt==WHEELUPMOUSE?3:4); 
+               rw->mbut[which]=val;
+               renderwin_mousebut_changed(rw);
+       }
        else if (ELEM3(evt, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
                int which= (evt==LEFTMOUSE)?0:(evt==MIDDLEMOUSE)?1:2;
                rw->mbut[which]= val;
@@ -499,7 +569,7 @@ static void renderwin_handler(Window *win, void *user_data, short evt, short val
                        renderwin_queue_redraw(render_win);
                }
                else if (evt==JKEY) {
-//                     if(R.flag==0) BIF_swap_render_rects();
+                       if(G.rendering==0) BIF_swap_render_rects();
                } 
                else if (evt==ZKEY) {
                        if (rw->flags&RW_FLAGS_OLDZOOM) {
@@ -511,19 +581,11 @@ static void renderwin_handler(Window *win, void *user_data, short evt, short val
                                renderwin_mouse_moved(rw);
                        }
                } 
-               else if (evt==PADPLUSKEY) {
-                       if (rw->zoom<15.9) {
-                               if(rw->zoom>0.5 && rw->zoom<1.0) rw->zoom= 1.0;
-                               else rw->zoom*= 2.0;
-                               renderwin_queue_redraw(rw);
-                       }
+               else if (ELEM(evt,PADPLUSKEY,PAGEUPKEY))  {
+                       renderwin_zoom(rw, 0);
                } 
-               else if (evt==PADMINUS) {
-                       if (rw->zoom>0.26) {
-                               if(rw->zoom>1.0 && rw->zoom<2.0) rw->zoom= 1.0;
-                               else rw->zoom*= 0.5;
-                               renderwin_queue_redraw(rw);
-                       }
+               else if (ELEM(evt,PADMINUS,PAGEDOWNKEY)) {
+                       renderwin_zoom(rw, 1);
                } 
                else if (evt==PADENTER || evt==HOMEKEY) {
                        if (rw->flags&RW_FLAGS_OLDZOOM) {
@@ -532,20 +594,20 @@ static void renderwin_handler(Window *win, void *user_data, short evt, short val
                        renderwin_reset_view(rw);
                } 
                else if (evt==F3KEY) {
-//                     if(R.flag==0) {
-//                             mainwindow_raise();
-//                             mainwindow_make_active();
-//                             rw->active= 0;
-//                             areawinset(find_biggest_area()->win);
-//                             BIF_save_rendered_image_fs();
-//                     }
+                       if(G.rendering==0) {
+                               mainwindow_raise();
+                               mainwindow_make_active();
+                               rw->active= 0;
+                               areawinset(find_biggest_area()->win);
+                               BIF_save_rendered_image_fs();
+                       }
                } 
                else if (evt==F11KEY) {
                        BIF_toggle_render_display();
                } 
                else if (evt==F12KEY) {
-                       /* if it's rendering, this flag is set */
-//                     if(R.flag==0) BIF_do_render(0);
+                       if(G.rendering==0) 
+                               BIF_do_render(0);
                }
        }
 }
@@ -558,8 +620,8 @@ static char *renderwin_get_title(int doswap)
        swap+= doswap;
        
        if(swap & 1) {
-               if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render (spare)";
-               else title = "Blender:Render (spare)";
+               if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render (previous)";
+               else title = "Blender:Render (previous)";
        }
        else {
                if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render";
@@ -643,7 +705,7 @@ void calc_renderwin_rectangle(int rectx, int recty, int posmask, int renderpos_r
 /* init renderwin, alloc/open/resize */
 static void renderwin_init_display_cb(RenderResult *rr) 
 {
-       if (G.afbreek == 0) {
+       if (G.afbreek != 1) {
                int rendersize[2], renderpos[2], imagesize[2];
 
                calc_renderwin_rectangle(rr->rectx, rr->recty, G.winpos, renderpos, rendersize);
@@ -692,7 +754,6 @@ static void renderwin_init_display_cb(RenderResult *rr)
                        }
 
                        renderwin_reset_view(render_win);
-                       render_win->flags&= ~RW_FLAGS_ESCAPE;
                        render_win->active= 1;
                }
                /* make sure we are in normal draw again */
@@ -721,10 +782,35 @@ static void renderwin_clear_display_cb(RenderResult *rr)
 */
 
 /* can get as well the full picture, as the parts while rendering */
-static void renderwin_progress(RenderWin *rw, RenderResult *rr, rcti *unused)
+static void renderwin_progress(RenderWin *rw, RenderResult *rr, volatile rcti *renrect)
 {
        rcti win_rct;
-       float *rectf, fullrect[2][2];
+       float *rectf= NULL, fullrect[2][2];
+       unsigned int *rect32= NULL;
+       int ymin, ymax, xmin, xmax;
+       
+       /* if renrect argument, we only display scanlines */
+       if(renrect) {
+                /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
+               if(rr->renlay==NULL || renrect->ymax>=rr->recty)
+                       return;
+               
+               /* xmin here is first subrect x coord, xmax defines subrect width */
+               xmin = renrect->xmin;
+               xmax = renrect->xmax - xmin;
+               if (xmax<2) return;
+               
+               ymin= renrect->ymin;
+               ymax= renrect->ymax - ymin;
+               if(ymax<2)
+                       return;
+               renrect->ymin= renrect->ymax;
+       }
+       else {
+               xmin = ymin = 0;
+               xmax = rr->rectx - 2*rr->crop;
+               ymax = rr->recty - 2*rr->crop;
+       }
        
        /* renderwindow cruft */
        win_rct.xmin= win_rct.ymin= 0;
@@ -736,33 +822,54 @@ static void renderwin_progress(RenderWin *rw, RenderResult *rr, rcti *unused)
        if(rr->rectf)
                rectf= rr->rectf;
        else {
-               RenderLayer *rl= BLI_findlink(&rr->layers, rr->actlay);
-               rectf= rl->rectf;
-       }       
-       /* when rendering more pixels than needed, we crop away cruft */
-       if(rr->crop)
-               rectf+= 4*(rr->crop*rr->rectx + rr->crop);
+               if(rr->rect32)
+                       rect32= rr->rect32;
+               else {
+                       if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
+                       rectf= rr->renlay->rectf;
+               }
+       }
+       if(rectf) {
+               /* if scanline updates... */
+               rectf+= 4*(rr->rectx*ymin + xmin);
+       
+               /* when rendering more pixels than needed, we crop away cruft */
+               if(rr->crop)
+                       rectf+= 4*(rr->crop*rr->rectx + rr->crop);
+       }
        
        /* tilerect defines drawing offset from (0,0) */
        /* however, tilerect (xmin, ymin) is first pixel */
-       fullrect[0][0] += (rr->tilerect.xmin+rr->crop)*rw->zoom;
-       fullrect[0][1] += (rr->tilerect.ymin+rr->crop)*rw->zoom;
+       fullrect[0][0] += (rr->tilerect.xmin + rr->crop + xmin)*rw->zoom;
+       fullrect[0][1] += (rr->tilerect.ymin + rr->crop + ymin)*rw->zoom;
 
        glEnable(GL_SCISSOR_TEST);
        glaDefine2DArea(&win_rct);
 
+#ifdef __APPLE__
+#else
        glDrawBuffer(GL_FRONT);
+#endif
        glPixelZoom(rw->zoom, rw->zoom);
-       glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rr->rectx-2*rr->crop, rr->recty-2*rr->crop, rr->rectx, 
-                                         GL_RGBA, GL_FLOAT, rectf);
+
+       if(rect32)
+               glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], xmax, ymax, rr->rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect32);
+       else
+               glaDrawPixelsSafe_to32(fullrect[0][0], fullrect[0][1], xmax, ymax, rr->rectx, rectf);
+       
        glPixelZoom(1.0, 1.0);
+       
+#ifdef __APPLE__
+       window_swap_buffers(render_win->win);
+#else
        glFlush();
        glDrawBuffer(GL_BACK);
+#endif 
 }
 
 
 /* in render window; display a couple of scanlines of rendered image */
-static void renderwin_progress_display_cb(RenderResult *rr, rcti *rect)
+static void renderwin_progress_display_cb(RenderResult *rr, volatile rcti *rect)
 {
        if (render_win) {
                renderwin_progress(render_win, rr, rect);
@@ -771,35 +878,66 @@ static void renderwin_progress_display_cb(RenderResult *rr, rcti *rect)
 
 /* -------------- callbacks for render loop: interactivity ----------------------- */
 
+/* string is RW_MAXTEXT chars min */
+void make_renderinfo_string(RenderStats *rs, char *str)
+{
+       extern char info_time_str[32];  // header_info.c
+       extern unsigned long mem_in_use, mmap_in_use;
+       float megs_used_memory, mmap_used_memory;
+       char *spos= str;
+       
+       megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
+       mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
+       
+       if(G.scene->lay & 0xFF000000)
+               spos+= sprintf(spos, "Localview | ");
+       else if(G.scene->r.scemode & R_SINGLE_LAYER)
+               spos+= sprintf(spos, "Single Layer | ");
+       
+       if(rs->tothalo)
+               spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d Ha:%d La:%d Mem:%.2fM (%.2fM) ", (G.scene->r.cfra), rs->totvert, rs->totface, rs->tothalo, rs->totlamp, megs_used_memory, mmap_used_memory);
+       else 
+               spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d La:%d Mem:%.2fM (%.2fM) ", (G.scene->r.cfra), rs->totvert, rs->totface, rs->totlamp, megs_used_memory, mmap_used_memory);
+       
+       if(rs->curfield)
+               spos+= sprintf(spos, "Field %d ", rs->curfield);
+       if(rs->curblur)
+               spos+= sprintf(spos, "Blur %d ", rs->curblur);
+       
+       BLI_timestr(rs->lastframetime, info_time_str);
+       spos+= sprintf(spos, "Time:%s ", info_time_str);
+       
+       if(rs->infostr)
+               spos+= sprintf(spos, "| %s ", rs->infostr);
+       
+       /* very weak... but 512 characters is quite safe... we cannot malloc during thread render */
+       if(spos >= str+RW_MAXTEXT)
+               printf("WARNING! renderwin text beyond limit \n");
+       
+}
 
 /* callback for print info in top header of renderwin */
-static void printrenderinfo_cb(RenderStats *rs)
+static void renderwin_renderinfo_cb(RenderStats *rs)
 {
-       extern char info_time_str[32];  // header_info.c
-       extern int mem_in_use;
-       static float megs_used_memory;
-       char str[300], *spos= str;
-               
+       
        if(render_win) {
-               megs_used_memory= mem_in_use/(1024.0*1024.0);
                
-               if(rs->tothalo)
-                       spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d Ha:%d La:%d Mem:%.2fM", (G.scene->r.cfra), rs->totvert, rs->totface, rs->tothalo, rs->totlamp, megs_used_memory);
-               else 
-                       spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d La:%d Mem:%.2fM", (G.scene->r.cfra), rs->totvert, rs->totface, rs->totlamp, megs_used_memory);
-
-               BLI_timestr(rs->lastframetime, info_time_str);
-               spos+= sprintf(spos, " Time:%s ", info_time_str);
+               make_renderinfo_string(rs, render_win->render_text);
                
-               if(render_win) {
-                       if(render_win->render_text) MEM_freeN(render_win->render_text);
-                       render_win->render_text= BLI_strdup(str);
-                       glDrawBuffer(GL_FRONT);
-                       renderwin_draw_render_info(render_win);
-                       glFlush();
-                       glDrawBuffer(GL_BACK);
-               }
+#ifdef __APPLE__
+#else
+               glDrawBuffer(GL_FRONT);
+#endif
+               renderwin_draw_render_info(render_win);
+               
+#ifdef __APPLE__
+               window_swap_buffers(render_win->win);
+#else
+               glFlush();
+               glDrawBuffer(GL_BACK);
+#endif
        }
+
 }
 
 /* -------------- callback system to allow ESC from rendering ----------------------- */
@@ -855,6 +993,17 @@ static void end_test_break_callback()
 #else
 /* all other OS's support signal(SIGVTALRM) */
 
+/* XXX The ESC problem: some unix users reported that ESC doesn't cancel
+ * renders anymore. Most complaints came from linux, but it's not
+ * general, not all linux users have the problem.
+ *
+ * From tests, the systems that do have it are not signalling SIGVTALRM
+ * interrupts (an issue with signals and threads). Using SIGALRM instead
+ * fixes the problem, at least while we investigate better.
+ *
+ * ITIMER_REAL (SIGALRM): timer that counts real system time
+ * ITIMER_VIRTUAL (SIGVTALRM): only counts time spent in its owner process */
+
 /* POSIX: this function goes in the signal() callback */
 static void interruptESC(int sig)
 {
@@ -862,7 +1011,7 @@ static void interruptESC(int sig)
        if(G.afbreek==0) G.afbreek= 2;  /* code for read queue */
 
        /* call again, timer was reset */
-       signal(SIGVTALRM, interruptESC);
+       signal(SIGALRM, interruptESC);
 }
 
 /* POSIX: initialize timer and signal */
@@ -873,13 +1022,12 @@ static void init_test_break_callback()
 
        tmevalue.it_interval.tv_sec = 0;
        tmevalue.it_interval.tv_usec = 250000;
-       /* wanneer de eerste ? */
+       /* when the first ? */
        tmevalue.it_value.tv_sec = 0;
        tmevalue.it_value.tv_usec = 10000;
 
-       signal(SIGVTALRM, interruptESC);
-       setitimer(ITIMER_VIRTUAL, &tmevalue, 0);
-
+       signal(SIGALRM, interruptESC);
+       setitimer(ITIMER_REAL, &tmevalue, 0);
 }
 
 /* POSIX: stop timer and callback */
@@ -887,10 +1035,10 @@ static void end_test_break_callback()
 {
        struct itimerval tmevalue;
 
-       tmevalue.it_value.tv_sec = 0;
-       tmevalue.it_value.tv_usec = 0;
-       setitimer(ITIMER_VIRTUAL, &tmevalue, 0);
-       signal(SIGVTALRM, SIG_IGN);
+       memset(&tmevalue, 0, sizeof(struct itimerval));
+
+       setitimer(ITIMER_REAL, &tmevalue, 0);
+       signal(SIGALRM, SIG_IGN);
 
 }
 
@@ -909,92 +1057,161 @@ static void end_test_break_callback()
 
 static void do_render(int anim)
 {
-       Render *re= RE_NewRender("Render");
+       Image *ima;
+       Render *re= RE_NewRender(G.scene->id.name);
+       unsigned int lay= G.scene->lay;
+       int scemode= G.scene->r.scemode;
+       int sculptmode= G.f & G_SCULPTMODE;
        
-       /* we set this flag to prevent renderwindow queue to execute another render */
+       /* UGLY! we set this flag to prevent renderwindow queue to execute another render */
+       /* is reset in RE_BlenderFrame */
        G.rendering= 1;
-       G.afbreek= 0;
 
-       /* set callbacks */
-       RE_display_init_cb(re, renderwin_init_display_cb);
-       RE_display_draw_cb(re, renderwin_progress_display_cb);
-       RE_display_clear_cb(re, renderwin_clear_display_cb);
-       init_test_break_callback();
-       RE_test_break_cb(re, test_break);
-       RE_timecursor_cb(re, set_timecursor);
-       RE_stats_draw_cb(re, printrenderinfo_cb);
+       /* set render callbacks, also starts ESC timer */
+       BIF_init_render_callbacks(re, 1);
        
-       if(render_win) window_set_cursor(render_win->win, CURSOR_WAIT);
        waitcursor(1);
-
+       if(render_win) 
+               window_set_cursor(render_win->win, CURSOR_WAIT);
+       
        if(G.obedit)
                exit_editmode(0);       /* 0 = no free data */
 
+       if(sculptmode) set_sculptmode();
+
+       /* allow localview render for objects with lights in normal layers */
+       if(curarea->spacetype==SPACE_VIEW3D) {
+               if(G.vd->lay & 0xFF000000) {
+                       G.scene->lay |= G.vd->lay;
+                       G.scene->r.scemode |= R_SINGLE_LAYER;
+               }
+               else G.scene->lay= G.vd->lay;
+       }
+       
        if(anim)
                RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
        else
                RE_BlenderFrame(re, G.scene, G.scene->r.cfra);
 
+       /* restore local view exception */
+       G.scene->lay= lay;
+       G.scene->r.scemode= scemode;
+       
        if(render_win) window_set_cursor(render_win->win, CURSOR_STD);
-
+       
        free_filesel_spec(G.scene->r.pic);
 
        G.afbreek= 0;
-       end_test_break_callback();
-       
-       mainwindow_make_active();
+       BIF_end_render_callbacks();
        
        /* after an envmap creation...  */
 //             if(R.flag & R_REDRAW_PRV) {
 //                     BIF_preview_changed(ID_TE);
 //             }
-       allqueue(REDRAWBUTSSCENE, 0);   // visualize fbuf for example
+               
+       scene_update_for_newframe(G.scene, G.scene->lay);       // no redraw needed, this restores to view as we left it
        
-       // before scene update!
-       G.rendering= 0;
+       /* get a render result image, and make sure it is clean */
+       ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
+       BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
        
-       scene_update_for_newframe(G.scene, G.scene->lay);       // no redraw needed, this restores to view as we left it
+       if(sculptmode) set_sculptmode();
        
-       waitcursor(0);  // waitcursor checks rendering R.flag...
+       waitcursor(0);
 }
 
+/* called before render, store old render in spare buffer */
+static void renderwin_store_spare(void)
+{
+       RenderResult rres;
+       
+       if(render_win==0 || render_win->storespare==0)
+               return;
+       
+       /* only store when it does not show spare */
+       if(render_win->showspare==0)
+               return;
+       
+       render_win->showspare= 0;
+       window_set_title(render_win->win, renderwin_get_title(1));
+       
+       BLI_strncpy(render_win->render_text_spare, render_win->render_text, RW_MAXTEXT);
+       
+       if(render_win->rectspare) MEM_freeN(render_win->rectspare);
+       render_win->rectspare= NULL;
+       if(render_win->rectsparef) MEM_freeN(render_win->rectsparef);
+       render_win->rectsparef= NULL;
+       
+       RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+       
+       if(rres.rect32)
+               render_win->rectspare= MEM_dupallocN(rres.rect32);
+       else if(rres.rectf)
+               render_win->rectsparef= MEM_dupallocN(rres.rectf);
+
+       render_win->sparex= rres.rectx;
+       render_win->sparey= rres.recty;
+}
+
+/* -------------- API: externally called --------------- */
+
+static void error_cb(char *str){error(str);}
+static int esc_timer_set= 0;
 
-/* used for swapping with spare buffer, when images are different size */
-static void scalefastrect(unsigned int *recto, unsigned int *rectn, int oldx, int oldy, int newx, int newy)
+/* set callbacks, exported to sequence render too. 
+   Only call in foreground (UI) renders. */
+
+void BIF_init_render_callbacks(Render *re, int do_display)
 {
-       unsigned int *rect, *newrect;
-       int x, y;
-       int ofsx, ofsy, stepx, stepy;
-
-       stepx = (int)((65536.0 * (oldx - 1.0) / (newx - 1.0)) + 0.5);
-       stepy = (int)((65536.0 * (oldy - 1.0) / (newy - 1.0)) + 0.5);
-       ofsy = 32768;
-       newrect= rectn;
-       
-       for (y = newy; y > 0 ; y--){
-               rect = recto;
-               rect += (ofsy >> 16) * oldx;
-               ofsy += stepy;
-               ofsx = 32768;
-               for (x = newx ; x>0 ; x--){
-                       *newrect++ = rect[ofsx >> 16];
-                       ofsx += stepx;
+       if(do_display) {
+               if(G.displaymode!=R_DISPLAYWIN) {
+                       if(render_win)
+                               BIF_close_render_display();
+                       imagewindow_render_callbacks(re);
+               }
+               else {
+                       RE_display_init_cb(re, renderwin_init_display_cb);
+                       RE_display_draw_cb(re, renderwin_progress_display_cb);
+                       RE_display_clear_cb(re, renderwin_clear_display_cb);
+                       RE_stats_draw_cb(re, renderwin_renderinfo_cb);
                }
        }
-}
+       
+       RE_error_cb(re, error_cb);
+       
+       G.afbreek= 0;
+       if(render_win)
+               render_win->flags &= ~RW_FLAGS_ESCAPE;
 
-/* -------------- API: externally called --------------- */
+       /* start esc timer. ensure it happens once only */
+       if(esc_timer_set==0)
+               init_test_break_callback();
+       esc_timer_set++;
+       
+       RE_test_break_cb(re, test_break);
+       RE_timecursor_cb(re, set_timecursor);
+       
+}
 
-/* not used anywhere ??? */
-#if 0
-void BIF_renderwin_make_active(void)
+/* the init/end callbacks can be called multiple times (sequence render) */
+void BIF_end_render_callbacks(void)
 {
-       if(render_win) {
-               window_make_active(render_win->win);
-               mywinset(2);
+       esc_timer_set--;
+       if(esc_timer_set==0) {
+               end_test_break_callback();
+               
+               if(render_win)
+                       mainwindow_make_active();
        }
 }
-#endif
+
+void BIF_store_spare(void)
+{
+       if(render_win)
+               renderwin_store_spare();
+       else
+               imagewin_store_spare();
+}
 
 /* set up display, render an image or scene */
 void BIF_do_render(int anim)
@@ -1008,29 +1225,15 @@ void BIF_do_render(int anim)
                        slink_flag = 1;
                }
        }
+       
+       BIF_store_spare();
 
-       /* if start render in 3d win, use layer from window (e.g also local view) */
-       if(curarea && curarea->spacetype==SPACE_VIEW3D) {
-               int lay= G.scene->lay;
-               /*
-                * if view is defined (might not be if called form script), check
-                * and set layers
-                */
-               if(G.vd) {
-                       if(G.vd->lay & 0xFF000000)      // localview
-                               G.scene->lay |= G.vd->lay;
-                       else
-                               G.scene->lay= G.vd->lay;
-               }
-               
-               do_render(anim);
-               
-               G.scene->lay= lay;
-       }
-       else do_render(anim);
+       do_render(anim);
 
-       if(G.scene->use_nodes)
+       if(G.scene->use_nodes) {
                allqueue(REDRAWNODE, 1);
+               allqueue(REDRAWIMAGE, 1);
+       }
        if (slink_flag) G.f |= G_DOSCRIPTLINKS;
        if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_POSTRENDER);
 }
@@ -1039,7 +1242,7 @@ void BIF_do_render(int anim)
 /* the RE_Render is only used to make sure we got the picture in the result */
 void BIF_do_ogl_render(View3D *v3d, int anim)
 {
-       Render *re= RE_NewRender("Render");
+       Render *re= RE_NewRender(G.scene->id.name);
        RenderResult *rr;
        int winx, winy;
        
@@ -1058,6 +1261,9 @@ void BIF_do_ogl_render(View3D *v3d, int anim)
        
        /* open window */
        renderwin_init_display_cb(rr);
+       if(render_win)
+               render_win->flags &= ~RW_FLAGS_ESCAPE;
+
        init_gl_stuff();
        
        waitcursor(1);
@@ -1066,17 +1272,49 @@ void BIF_do_ogl_render(View3D *v3d, int anim)
                bMovieHandle *mh= BKE_get_movie_handle(G.scene->r.imtype);
                int cfrao= CFRA;
                
-               mh->start_movie(&G.scene->r, winx, winy);
+               if(BKE_imtype_is_movie(G.scene->r.imtype))
+                       mh->start_movie(&G.scene->r, winx, winy);
                
                for(CFRA= SFRA; CFRA<=EFRA; CFRA++) {
+                       /* user event can close window */
+                       if(render_win==NULL)
+                               break;
                        drawview3d_render(v3d, winx, winy);
                        glReadPixels(0, 0, winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, rr->rect32);
                        window_swap_buffers(render_win->win);
                        
-                       mh->append_movie(CFRA, rr->rect32, winx, winy);
+                       if(BKE_imtype_is_movie(G.scene->r.imtype)) {
+                               mh->append_movie(CFRA, rr->rect32, winx, winy);
+                               printf("Append frame %d", G.scene->r.cfra);
+                       }
+                       else {
+                               ImBuf *ibuf= IMB_allocImBuf(winx, winy, G.scene->r.planes, 0, 0);
+                               char name[FILE_MAXDIR+FILE_MAXFILE];
+                               int ok;
+                               
+                               BKE_makepicstring(name, G.scene->r.pic, G.scene->r.cfra, G.scene->r.imtype);
+
+                               ibuf->rect= rr->rect32;    
+                               ok= BKE_write_ibuf(ibuf, name, G.scene->r.imtype, G.scene->r.subimtype, G.scene->r.quality);
+                               
+                               if(ok==0) {
+                                       printf("Write error: cannot save %s\n", name);
+                                       break;
+                               }
+                               else printf("Saved: %s", name);
+                               
+                /* imbuf knows which rects are not part of ibuf */
+                               IMB_freeImBuf(ibuf);    
+                       }
+                       /* movie stats prints have no line break */
+                       printf("\n");
+                       
                        if(test_break()) break;
                }
-               mh->end_movie();
+               
+               if(BKE_imtype_is_movie(G.scene->r.imtype))
+                       mh->end_movie();
+               
                CFRA= cfrao;
        }
        else {
@@ -1085,6 +1323,9 @@ void BIF_do_ogl_render(View3D *v3d, int anim)
                window_swap_buffers(render_win->win);
        }
        
+       if(render_win)
+               renderwin_draw(render_win, 0);
+
        mainwindow_make_active();
        
        if(anim)
@@ -1100,45 +1341,38 @@ void BIF_redraw_render_rect(void)
        if (render_win) {
                renderwin_queue_redraw(render_win);
        }
+       else {
+               allqueue(REDRAWIMAGE, 0);
+       }
 }      
 
 void BIF_swap_render_rects(void)
 {
-#if 0
-       unsigned int *temp;
-
-       if(R.rectspare==0) {
-               R.rectspare= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot");
-               R.sparex= R.rectx;
-               R.sparey= R.recty;
-       }
-       else if(R.sparex!=R.rectx || R.sparey!=R.recty) {
-               temp= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot");
-                                       
-               scalefastrect(R.rectspare, temp, R.sparex, R.sparey, R.rectx, R.recty);
-               MEM_freeN(R.rectspare);
-               R.rectspare= temp;
-                                       
-               R.sparex= R.rectx;
-               R.sparey= R.recty;
-       }
-       
-       temp= R.rectot;
-       R.rectot= R.rectspare;
-       R.rectspare= temp;
+       RenderResult rres;
        
-       if (render_win) {
-               char *tmp= render_win->render_text_spare;
-               render_win->render_text_spare= render_win->render_text;
-               render_win->render_text= tmp;
+       if(G.displaymode!=R_DISPLAYWIN) {
+               imagewindow_swap_render_rects();
+       }
+       else if(render_win) {
                
-               window_set_title(render_win->win, renderwin_get_title(1));
+               render_win->storespare= 1;
+               render_win->showspare ^= 1;
+                       
+               RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+                       
+               if(render_win->sparex!=rres.rectx || render_win->sparey!=rres.recty) {
+                       if(render_win->rectspare) MEM_freeN(render_win->rectspare);
+                       render_win->rectspare= NULL;
+                       if(render_win->rectsparef) MEM_freeN(render_win->rectsparef);
+                       render_win->rectsparef= NULL;
+               }
                
+               window_set_title(render_win->win, renderwin_get_title(1));
        }
-
+       
        /* redraw */
        BIF_redraw_render_rect();
-#endif
+
 }                              
 
 /* called from usiblender.c too, to free and close renderwin */
@@ -1148,7 +1382,9 @@ void BIF_close_render_display(void)
                if (render_win->info_text) MEM_freeN(render_win->info_text);
                if (render_win->render_text) MEM_freeN(render_win->render_text);
                if (render_win->render_text_spare) MEM_freeN(render_win->render_text_spare);
-
+               if (render_win->rectspare) MEM_freeN(render_win->rectspare);
+               if (render_win->rectsparef) MEM_freeN(render_win->rectsparef);
+                       
                window_destroy(render_win->win); /* ghost close window */
                MEM_freeN(render_win);
 
@@ -1161,21 +1397,26 @@ void BIF_close_render_display(void)
 void BIF_toggle_render_display(void) 
 {
        
-       if (render_win) {
-               if(render_win->active) {
-                       mainwindow_raise();
-                       mainwindow_make_active();
-                       render_win->active= 0;
-               }
+       if (G.displaymode!=R_DISPLAYWIN) {
+               imagewindow_toggle_render();
+       }
+       else {
+               if (render_win) {
+                       if(render_win->active) {
+                               mainwindow_raise();
+                               mainwindow_make_active();
+                               render_win->active= 0;
+                       }
+                       else {
+                               window_raise(render_win->win);
+                               window_make_active(render_win->win);
+                               render_win->active= 1;
+                       }
+               } 
                else {
-                       window_raise(render_win->win);
-                       window_make_active(render_win->win);
-                       render_win->active= 1;
+                       RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name));
+                       if(rr) renderwin_init_display_cb(rr);
                }
-       } 
-       else {
-               RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
-               if(rr) renderwin_init_display_cb(rr);
        }
 }