Two in one:
[blender.git] / source / blender / src / renderwin.c
index 26a232f7a5da11a0f6880d8a36192c288dfa9f65..8ca96f89936090edb891d19bfb1e88366ce115ea 100644 (file)
 
 #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 */
@@ -86,6 +89,7 @@
 #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 */
 
@@ -141,7 +145,7 @@ typedef struct {
        int active;
        short storespare, showspare;
        
-       int mbut[3];
+       int mbut[5];
        int lmouse[2];
        
        unsigned int flags;
@@ -172,7 +176,7 @@ static RenderWin *renderwin_alloc(Window *win)
        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;
 }
@@ -351,7 +355,8 @@ static void renderwin_draw(RenderWin *rw, int just_clear)
                        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);
                                }
@@ -370,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);
                }
@@ -395,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)
 {
@@ -466,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);
@@ -514,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;
@@ -549,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) {
@@ -575,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) {
@@ -730,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 */
@@ -749,35 +772,6 @@ static void renderwin_clear_display_cb(RenderResult *rr)
        }
 }
 
-#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
-static void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int row_w, int format, int type, float *rectf)
-{
-       float *rf;
-       int x, y;
-       char *rect32, *rc;
-       
-       /* copy imgw-imgh to a temporal 32 bits rect */
-       if(img_w<1 || img_h<1) return;
-       
-       /* happens during threaded render... */
-       rc= rect32= MEM_mallocT(img_w*img_h*sizeof(int), "temp 32 bits");
-       
-       for(y=0; y<img_h; y++) {
-               rf= rectf;
-               for(x=0; x<img_w; x++, rf+=4, rc+=4) {
-                       rc[0]= FTOCHAR(rf[0]);
-                       rc[1]= FTOCHAR(rf[1]);
-                       rc[2]= FTOCHAR(rf[2]);
-                       rc[3]= FTOCHAR(rf[3]);
-               }
-               rectf+= 4*row_w;
-       }
-       
-       glaDrawPixelsSafe(fx, fy, img_w, img_h, img_w, GL_RGBA, GL_UNSIGNED_BYTE, rect32);
-               
-       MEM_freeT(rect32);
-}
-
 /* XXX, this is not good, we do this without any regard to state
 * ... better is to make this an optimization of a more clear
 * implementation. the bug shows up when you do something like
@@ -861,15 +855,14 @@ static void renderwin_progress(RenderWin *rw, RenderResult *rr, volatile rcti *r
        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, GL_RGBA, GL_FLOAT, rectf);
+               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 
 }
@@ -890,7 +883,7 @@ 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;
+       float megs_used_memory, mmap_used_memory;
        char *spos= str;
        
        megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
@@ -902,40 +895,25 @@ void make_renderinfo_string(RenderStats *rs, char *str)
                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);
+               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);
+               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);
+       spos+= sprintf(spos, "Time:%s ", info_time_str);
        
        if(rs->infostr)
-               spos+= sprintf(spos, " | %s", 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");
        
-       /* temporal render debug printing, needed for testing orange renders atm... will be gone soon (or option) */
-       if(G.rt==7 && rs->convertdone) {
-               char str[256];
-               
-               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 for print info in top header of renderwin */
@@ -955,8 +933,7 @@ static void renderwin_renderinfo_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
        }
@@ -1058,8 +1035,7 @@ static void end_test_break_callback()
 {
        struct itimerval tmevalue;
 
-       tmevalue.it_value.tv_sec = 0;
-       tmevalue.it_value.tv_usec = 0;
+       memset(&tmevalue, 0, sizeof(struct itimerval));
 
        setitimer(ITIMER_REAL, &tmevalue, 0);
        signal(SIGALRM, SIG_IGN);
@@ -1078,35 +1054,21 @@ static void end_test_break_callback()
    - set callbacks
    - cleanup
 */
-static void error_cb(char *str){error(str);}
 
 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;
        
        /* 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 */
-       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);
-       init_test_break_callback();
-       RE_test_break_cb(re, test_break);
-       RE_timecursor_cb(re, set_timecursor);
+       /* set render callbacks, also starts ESC timer */
+       BIF_init_render_callbacks(re, 1);
        
        waitcursor(1);
        if(render_win) 
@@ -1115,6 +1077,8 @@ static void do_render(int anim)
        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) {
@@ -1138,58 +1102,38 @@ 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
        
+       /* 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);
+       
+       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));
-       }
+       
+       /* 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);
        
@@ -1211,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)
@@ -1237,8 +1226,7 @@ void BIF_do_render(int anim)
                }
        }
        
-       if(render_win && render_win->showspare)
-               renderwin_store_spare();
+       BIF_store_spare();
 
        do_render(anim);
 
@@ -1273,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);
@@ -1285,6 +1276,9 @@ void BIF_do_ogl_render(View3D *v3d, int anim)
                        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);
@@ -1298,7 +1292,7 @@ void BIF_do_ogl_render(View3D *v3d, int anim)
                                char name[FILE_MAXDIR+FILE_MAXFILE];
                                int ok;
                                
-                               BKE_makepicstring(name, (G.scene->r.cfra));
+                               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);
@@ -1329,7 +1323,8 @@ void BIF_do_ogl_render(View3D *v3d, int anim)
                window_swap_buffers(render_win->win);
        }
        
-       renderwin_draw(render_win, 0);
+       if(render_win)
+               renderwin_draw(render_win, 0);
 
        mainwindow_make_active();
        
@@ -1346,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();