Two in one:
[blender.git] / source / blender / src / renderwin.c
index bea32212779d27350487f20bce1d68f79e5cacf9..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;
@@ -136,7 +145,7 @@ typedef struct {
        int active;
        short storespare, showspare;
        
-       int mbut[3];
+       int mbut[5];
        int lmouse[2];
        
        unsigned int flags;
@@ -163,10 +172,11 @@ static RenderWin *renderwin_alloc(Window *win)
        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;
 }
@@ -339,13 +349,14 @@ static void renderwin_draw(RenderWin *rw, int just_clear)
                else
                        RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
                
-               if(rres.rectf) {
+               if(rres.rectf || rres.rect32) {
                        
                        glPixelZoom(rw->zoom, rw->zoom);
                        if(rw->flags & RW_FLAGS_ALPHA) {
                                if(rres.rect32) {
                                        /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
-                                       glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+                                       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);
                                }
@@ -364,7 +375,7 @@ static void renderwin_draw(RenderWin *rw, int just_clear)
                                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);
                }
@@ -389,7 +400,24 @@ 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)
 {
@@ -460,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);
@@ -508,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;
@@ -543,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) {
@@ -569,7 +599,7 @@ static void renderwin_handler(Window *win, void *user_data, short evt, short val
                                mainwindow_make_active();
                                rw->active= 0;
                                areawinset(find_biggest_area()->win);
-                               BIF_save_rendered_image_fs(0);
+                               BIF_save_rendered_image_fs();
                        }
                } 
                else if (evt==F11KEY) {
@@ -590,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 (previous frame)";
-               else title = "Blender:Render (previous frame)";
+               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";
@@ -724,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 */
@@ -756,8 +785,9 @@ static void renderwin_clear_display_cb(RenderResult *rr)
 static void renderwin_progress(RenderWin *rw, RenderResult *rr, volatile rcti *renrect)
 {
        rcti win_rct;
-       float *rectf, fullrect[2][2];
-       int ymin, ymax;
+       float *rectf= NULL, fullrect[2][2];
+       unsigned int *rect32= NULL;
+       int ymin, ymax, xmin, xmax;
        
        /* if renrect argument, we only display scanlines */
        if(renrect) {
@@ -765,15 +795,21 @@ static void renderwin_progress(RenderWin *rw, RenderResult *rr, volatile rcti *r
                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;
+               ymax= renrect->ymax - ymin;
                if(ymax<2)
                        return;
                renrect->ymin= renrect->ymax;
        }
        else {
-               ymin= 0;
-               ymax= rr->recty-2*rr->crop;
+               xmin = ymin = 0;
+               xmax = rr->rectx - 2*rr->crop;
+               ymax = rr->recty - 2*rr->crop;
        }
        
        /* renderwindow cruft */
@@ -786,20 +822,26 @@ static void renderwin_progress(RenderWin *rw, RenderResult *rr, volatile rcti *r
        if(rr->rectf)
                rectf= rr->rectf;
        else {
-               if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
-               rectf= rr->renlay->rectf;
+               if(rr->rect32)
+                       rect32= rr->rect32;
+               else {
+                       if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
+                       rectf= rr->renlay->rectf;
+               }
        }
-       /* if scanline updates... */
-       rectf+= 4*rr->rectx*ymin;
+       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);
+               /* 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 + ymin)*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);
@@ -809,15 +851,18 @@ static void renderwin_progress(RenderWin *rw, RenderResult *rr, volatile rcti *r
        glDrawBuffer(GL_FRONT);
 #endif
        glPixelZoom(rw->zoom, rw->zoom);
-       glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rr->rectx-2*rr->crop, ymax, 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
-       /* no glFlush(); here... threads render hates it! */
-       glFinish();
+       glFlush();
        glDrawBuffer(GL_BACK);
 #endif 
 }
@@ -833,37 +878,52 @@ static void renderwin_progress_display_cb(RenderResult *rr, volatile rcti *rect)
 
 /* -------------- callbacks for render loop: interactivity ----------------------- */
 
-
-/* callback for print info in top header of renderwin */
-static void printrenderinfo_cb(RenderStats *rs)
+/* 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;
-       static float megs_used_memory, mmap_used_memory;
-       char str[300], *spos= str;
-               
+       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(render_win) {
-               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(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");
+       
+}
 
-               BLI_timestr(rs->lastframetime, info_time_str);
-               spos+= sprintf(spos, " Time:%s ", info_time_str);
+/* callback for print info in top header of renderwin */
+static void renderwin_renderinfo_cb(RenderStats *rs)
+{
+       
+       if(render_win) {
                
-               if(rs->infostr)
-                       spos+= sprintf(spos, " | %s", rs->infostr);
+               make_renderinfo_string(rs, render_win->render_text);
                
-               if(render_win->render_text) MEM_freeN(render_win->render_text);
-               render_win->render_text= BLI_strdup(str);
 #ifdef __APPLE__
 #else
                glDrawBuffer(GL_FRONT);
@@ -873,29 +933,11 @@ static void printrenderinfo_cb(RenderStats *rs)
 #ifdef __APPLE__
                window_swap_buffers(render_win->win);
 #else
-               /* no glFlush(); here... threads render hates it! */
-               glFinish();
+               glFlush();
                glDrawBuffer(GL_BACK);
 #endif
        }
 
-       /* temporal render debug printing, needed for testing orange renders atm... will be gone soon (or option) */
-       if(G.rt==7 && rs->convertdone) {
-               spos= str;
-               spos+= sprintf(spos, "Fra:%d Mem:%.2fM (%.2fM)", G.scene->r.cfra, megs_used_memory, mmap_used_memory);
-               
-               if(rs->infostr) {
-                       spos+= sprintf(spos, " | %s", rs->infostr);
-               }
-               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);
-                       else 
-                               spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->totlamp);
-               }
-               printf(str); printf("\n");
-       }       
-       
 }
 
 /* -------------- callback system to allow ESC from rendering ----------------------- */
@@ -951,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)
 {
@@ -958,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 */
@@ -969,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 */
@@ -983,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);
 
 }
 
@@ -1005,28 +1057,28 @@ static void end_test_break_callback()
 
 static void do_render(int anim)
 {
+       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);
+       
+       waitcursor(1);
+       if(render_win) 
+               window_set_cursor(render_win->win, CURSOR_WAIT);
        
-       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) {
@@ -1050,65 +1102,40 @@ static void do_render(int anim)
        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);
 }
 
-#if 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)
-{
-       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;
-               }
-       }
-}
-#endif
-
+/* 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;
-
-       if(render_win->showspare) {
-               render_win->showspare= 0;
-               window_set_title(render_win->win, renderwin_get_title(1));
-       }
        
-       if(render_win->render_text_spare) MEM_freeN(render_win->render_text_spare);
-       render_win->render_text_spare= render_win->render_text;
-       render_win->render_text= NULL;
+       /* 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;
@@ -1128,18 +1155,63 @@ static void renderwin_store_spare(void)
 
 /* -------------- API: externally called --------------- */
 
-/* not used anywhere ??? */
-#if 0
-void BIF_renderwin_make_active(void)
+static void error_cb(char *str){error(str);}
+static int esc_timer_set= 0;
+
+/* set callbacks, exported to sequence render too. 
+   Only call in foreground (UI) renders. */
+
+void BIF_init_render_callbacks(Render *re, int do_display)
 {
-       if(render_win) {
-               window_make_active(render_win->win);
-               mywinset(2);
+       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;
+
+       /* 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);
+       
 }
-#endif
 
+/* the init/end callbacks can be called multiple times (sequence render) */
+void BIF_end_render_callbacks(void)
+{
+       esc_timer_set--;
+       if(esc_timer_set==0) {
+               end_test_break_callback();
+               
+               if(render_win)
+                       mainwindow_make_active();
+       }
+}
 
+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)
@@ -1154,7 +1226,7 @@ void BIF_do_render(int anim)
                }
        }
        
-       renderwin_store_spare();
+       BIF_store_spare();
 
        do_render(anim);
 
@@ -1189,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);
@@ -1197,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 {
@@ -1216,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)
@@ -1231,28 +1341,35 @@ void BIF_redraw_render_rect(void)
        if (render_win) {
                renderwin_queue_redraw(render_win);
        }
+       else {
+               allqueue(REDRAWIMAGE, 0);
+       }
 }      
 
 void BIF_swap_render_rects(void)
 {
        RenderResult rres;
        
-       if (render_win==NULL) return;
-       
-       render_win->storespare= 1;
-       render_win->showspare ^= 1;
+       if(G.displaymode!=R_DISPLAYWIN) {
+               imagewindow_swap_render_rects();
+       }
+       else if(render_win) {
                
-       RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+               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;
+               }
                
-       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));
        }
        
-       window_set_title(render_win->win, renderwin_get_title(1));
-
        /* redraw */
        BIF_redraw_render_rect();
 
@@ -1280,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(G.scene->id.name));
-               if(rr) renderwin_init_display_cb(rr);
        }
 }