7699de4138160b4283ba8b1d4d57bbfc54c0e7b7
[blender.git] / source / blender / src / renderwin.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29  
30 #ifdef WIN32
31 /* for the multimedia timer */
32 #include <windows.h>
33 #include <mmsystem.h>
34 #endif
35
36 #include <string.h>
37 #include <stdarg.h>
38 #include <math.h>
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #ifdef WIN32
45 #include "BLI_winstuff.h"
46 #else
47  /* for signal callback, not (fully) supported at windows */
48 #include <sys/time.h>
49 #include <signal.h>
50
51 #endif
52
53 #include <limits.h>
54
55 #include "BLI_blenlib.h"
56 #include "BLI_threads.h"
57
58 #include "MEM_guardedalloc.h"
59
60 #include "BMF_Api.h"
61
62 #include "DNA_image_types.h"
63 #include "DNA_space_types.h"
64 #include "DNA_screen_types.h"
65 #include "DNA_scene_types.h"
66 #include "DNA_view3d_types.h"
67 #include "DNA_vec_types.h"
68
69 #include "BKE_global.h"
70 #include "BKE_image.h"
71 #include "BKE_library.h"
72 #include "BKE_scene.h"
73 #include "BKE_utildefines.h"
74 #include "BKE_writeavi.h"       /* movie handle */
75
76 #include "BIF_drawimage.h"
77 #include "BIF_gl.h"
78 #include "BIF_glutil.h"
79 #include "BIF_graphics.h"
80 #include "BIF_screen.h"
81 #include "BIF_space.h"
82 #include "BIF_mywindow.h"
83 #include "BIF_renderwin.h"
84 #include "BIF_resources.h"
85 #include "BIF_toets.h"
86 #include "BIF_toolbox.h"
87 #include "BIF_writeimage.h"
88
89 #include "BDR_sculptmode.h"
90 #include "BDR_editobject.h"
91 #include "BPY_extern.h" /* for BPY_do_all_scripts */
92
93 #include "BSE_view.h"
94 #include "BSE_drawview.h"
95 #include "BSE_filesel.h"
96 #include "BSE_headerbuttons.h"
97
98 #include "RE_pipeline.h"
99
100 #include "IMB_imbuf.h"
101 #include "IMB_imbuf_types.h"
102
103 #include "blendef.h"
104 #include "mydevice.h"
105 #include "winlay.h"
106
107 /* ------------ renderwin struct, to prevent too much global vars --------- */
108 /* ------------ only used for display in a 2nd window  --------- */
109
110
111 /* flags escape presses during event handling
112 * so we can test for user break later.
113 */
114 #define RW_FLAGS_ESCAPE         (1<<0)
115 /* old zoom style (2x, locked to mouse, exits
116 * when mouse leaves window), to be removed
117 * at some point.
118 */
119 #define RW_FLAGS_OLDZOOM                (1<<1)
120 /* on when image is being panned with middlemouse
121 */
122 #define RW_FLAGS_PANNING                (1<<2)
123 /* on when the mouse is dragging over the image
124 * to examine pixel values.
125 */
126 #define RW_FLAGS_PIXEL_EXAMINING        (1<<3)
127
128 /* forces draw of alpha */
129 #define RW_FLAGS_ALPHA          (1<<4)
130
131
132 typedef struct {
133         Window *win;
134
135         int rectx, recty;       /* size of image */
136         
137         float zoom, zoomofs[2];
138         int active;
139         
140         int mbut[5];
141         int lmouse[2];
142         
143         unsigned int flags;
144         
145         float pan_mouse_start[2], pan_ofs_start[2];
146
147         char *info_text;
148         
149 } RenderWin;
150
151 typedef struct RenderSpare {
152         ImBuf *ibuf;
153         
154         short storespare, showspare;
155         char *render_text_spare;
156 } RenderSpare;
157
158 static RenderWin *render_win= NULL;
159 static RenderSpare *render_spare= NULL;
160 static char *render_text= NULL;
161
162 /* --------------- help functions for RenderWin struct ---------------------------- */
163
164 static RenderSpare *renderspare_alloc()
165 {
166         RenderSpare *rspare= MEM_callocN(sizeof(*rspare), "RenderSpare");
167         rspare->render_text_spare= MEM_callocN(RW_MAXTEXT, "rendertext spare");
168
169         return rspare;
170 }
171
172 /* only called in function open_renderwin */
173 static RenderWin *renderwin_alloc(Window *win)
174 {
175         RenderWin *rw= MEM_callocN(sizeof(*rw), "RenderWin");
176         rw->win= win;
177         rw->zoom= 1.0;
178         rw->active= 0;
179         rw->flags= 0;
180         rw->zoomofs[0]= rw->zoomofs[1]= 0;
181         rw->info_text= NULL;
182
183         rw->lmouse[0]= rw->lmouse[1]= 0;
184         rw->mbut[0]= rw->mbut[1]= rw->mbut[2]= rw->mbut[3] = rw->mbut[4] = 0;
185
186         return rw;
187 }
188
189
190 static void renderwin_queue_redraw(RenderWin *rw)
191 {
192         window_queue_redraw(rw->win); // to ghost
193 }
194
195 static void renderwin_reshape(RenderWin *rw)
196 {
197         ;
198 }
199
200 static void renderwin_get_fullrect(RenderWin *rw, float fullrect_r[2][2])
201 {
202         float display_w, display_h;
203         float cent_x, cent_y;
204         int w, h;
205
206         window_get_size(rw->win, &w, &h);
207         h-= RW_HEADERY;
208
209         display_w= rw->rectx*rw->zoom;
210         display_h= rw->recty*rw->zoom;
211         cent_x= (rw->zoomofs[0] + rw->rectx/2)*rw->zoom;
212         cent_y= (rw->zoomofs[1] + rw->recty/2)*rw->zoom;
213         
214         fullrect_r[0][0]= w/2 - cent_x;
215         fullrect_r[0][1]= h/2 - cent_y;
216         fullrect_r[1][0]= fullrect_r[0][0] + display_w;
217         fullrect_r[1][1]= fullrect_r[0][1] + display_h;
218 }
219
220         /** 
221          * Project window coordinate to image pixel coordinate.
222          * Returns true if resulting coordinate is within image.
223          */
224 static int renderwin_win_to_image_co(RenderWin *rw, int winco[2], int imgco_r[2])
225 {
226         float fullrect[2][2];
227         
228         renderwin_get_fullrect(rw, fullrect);
229         
230         imgco_r[0]= (int) ((winco[0]-fullrect[0][0])/rw->zoom);
231         imgco_r[1]= (int) ((winco[1]-fullrect[0][1])/rw->zoom);
232         
233         return (imgco_r[0]>=0 && imgco_r[1]>=0 && imgco_r[0]<rw->rectx && imgco_r[1]<rw->recty);
234 }
235
236         /**
237          * Project window coordinates to normalized device coordinates
238          * Returns true if resulting coordinate is within window.
239          */
240 static int renderwin_win_to_ndc(RenderWin *rw, int win_co[2], float ndc_r[2])
241 {
242         int w, h;
243
244         window_get_size(rw->win, &w, &h);
245         h-= RW_HEADERY;
246
247         ndc_r[0]=  ((float)(win_co[0]*2)/(w-1) - 1.0f);
248         ndc_r[1]=  ((float)(win_co[1]*2)/(h-1) - 1.0f);
249
250         return (fabs(ndc_r[0])<=1.0 && fabs(ndc_r[1])<=1.0);
251 }
252
253 static void renderwin_set_infotext(RenderWin *rw, char *info_text)
254 {
255         if (rw->info_text) MEM_freeN(rw->info_text);
256         rw->info_text= info_text?BLI_strdup(info_text):NULL;
257 }
258
259 static void renderwin_reset_view(RenderWin *rw)
260 {
261         int w, h;
262
263         if (rw->info_text) renderwin_set_infotext(rw, NULL);
264
265         /* now calculate a zoom for when image is larger than window */
266         window_get_size(rw->win, &w, &h);
267         h-= RW_HEADERY;
268
269         if(rw->rectx>w || rw->recty>h) {
270                 if(rw->rectx-w > rw->recty-h) rw->zoom= ((float)w)/((float)rw->rectx);
271                 else rw->zoom= ((float)h)/((float)rw->recty);
272         }
273         else rw->zoom= 1.0;
274
275         rw->zoomofs[0]= rw->zoomofs[1]= 0;
276         renderwin_queue_redraw(rw);
277 }
278
279 static void renderwin_draw_render_info(RenderWin *rw)
280 {
281         /* render text is added to top */
282         if(RW_HEADERY) {
283                 float colf[3];
284                 rcti rect;
285                 char *str;
286                 
287                 window_get_size(rw->win, &rect.xmax, &rect.ymax);
288                 rect.xmin= 0;
289                 rect.ymin= rect.ymax-RW_HEADERY;
290                 glEnable(GL_SCISSOR_TEST);
291                 glaDefine2DArea(&rect);
292                 
293                 /* clear header rect */
294                 BIF_SetTheme(NULL);     // sets view3d theme by default
295                 BIF_GetThemeColor3fv(TH_HEADER, colf);
296                 glClearColor(colf[0], colf[1], colf[2], 1.0); 
297                 glClear(GL_COLOR_BUFFER_BIT);
298                 
299                 str= BIF_render_text();
300                 
301                 if(str) {
302                         BIF_ThemeColor(TH_TEXT);
303                         glRasterPos2i(12, 5);
304                         BMF_DrawString(G.fonts, str);
305                 }
306                 
307                 BIF_SetTheme(curarea);  // restore theme
308         }       
309         
310 }
311
312 static void renderwin_draw(RenderWin *rw, int just_clear)
313 {
314         float fullrect[2][2];
315         int set_back_mainwindow;
316         rcti rect;
317
318         /* since renderwin uses callbacks (controlled by ghost) it can
319                 mess up active window output with redraw events after a render. 
320                 this is patchy, still WIP */
321         set_back_mainwindow = (winlay_get_active_window() != rw->win);
322         window_make_active(rw->win);
323         
324         rect.xmin= rect.ymin= 0;
325         window_get_size(rw->win, &rect.xmax, &rect.ymax);
326         rect.ymax-= RW_HEADERY;
327         
328         renderwin_get_fullrect(rw, fullrect);
329         
330         /* do this first, so window ends with correct scissor */
331         renderwin_draw_render_info(rw);
332         
333         glEnable(GL_SCISSOR_TEST);
334         glaDefine2DArea(&rect);
335         
336         glClearColor(.1875, .1875, .1875, 1.0); 
337         glClear(GL_COLOR_BUFFER_BIT);
338
339         if (just_clear) {
340                 glColor3ub(0, 0, 0);
341                 glRectfv(fullrect[0], fullrect[1]);
342         } else {
343                 RenderResult rres;
344                 RenderSpare *rspare= render_spare;
345                 
346                 if(rspare && rspare->showspare) {
347                         if(rspare->ibuf) {
348                                 rres.rectx= rspare->ibuf->x;
349                                 rres.recty= rspare->ibuf->y;
350                                 rres.rect32= (int *)rspare->ibuf->rect;
351                                 rres.rectf= rspare->ibuf->rect_float;
352                                 rres.rectz= rspare->ibuf->zbuf_float;
353                         }
354                         else
355                                 memset(&rres, 0, sizeof(rres));
356                 }
357                 else
358                         RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
359                 
360                 if(rres.rectf || rres.rect32) {
361                         
362                         glPixelZoom(rw->zoom, rw->zoom);
363                         if(rw->flags & RW_FLAGS_ALPHA) {
364                                 if(rres.rect32) {
365                                         /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
366                                         if(G.order==B_ENDIAN)
367                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
368                                         glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_LUMINANCE, GL_UNSIGNED_INT, rres.rect32);
369                                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
370                                 }
371                                 else {
372                                         float *trectf= MEM_mallocN(rres.rectx*rres.recty*4, "temp");
373                                         int a, b;
374                                         
375                                         for(a= rres.rectx*rres.recty -1, b= 4*a+3; a>=0; a--, b-=4)
376                                                 trectf[a]= rres.rectf[b];
377                                         
378                                         glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_LUMINANCE, GL_FLOAT, trectf);
379                                         MEM_freeN(trectf);
380                                 }
381                         }
382                         else {
383                                 if(rres.rect32)
384                                         glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rres.rect32);
385                                 else if(rres.rectf)
386                                         glaDrawPixelsSafe_to32(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, rres.rectf);
387                         }
388                         glPixelZoom(1.0, 1.0);
389                 }
390         }
391         
392         /* info text is overlayed on bottom */
393         if (rw->info_text) {
394                 float w;
395                 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
396                 glEnable(GL_BLEND);
397                 w=186.0*strlen(rw->info_text)/30;
398                 glColor4f(.5,.5,.5,.25);
399                 glRectf(0.0,0.0,w,30.0);
400                 glDisable(GL_BLEND);
401                 glColor3ub(255, 255, 255);
402                 glRasterPos2i(10, 10);
403                 BMF_DrawString(G.font, rw->info_text);
404         }
405         
406         window_swap_buffers(rw->win);
407         
408         if (set_back_mainwindow) mainwindow_make_active();      
409 }
410
411
412 /* ------ interactivity calls for RenderWin ------------- */
413 static void renderwin_zoom(RenderWin *rw, int ZoomIn) {
414         if (ZoomIn) {
415                 if (rw->zoom>0.26) {
416                         if(rw->zoom>1.0 && rw->zoom<2.0) rw->zoom= 1.0;
417                         else rw->zoom*= 0.5;
418                 }
419         } else {
420                 if (rw->zoom<15.9) {
421                         if(rw->zoom>0.5 && rw->zoom<1.0) rw->zoom= 1.0;
422                         else rw->zoom*= 2.0;
423                 }
424         }
425         if (rw->zoom>1.0) rw->flags |= RW_FLAGS_OLDZOOM;
426         if (rw->zoom==1.0) rw->flags &= ~RW_FLAGS_OLDZOOM;
427         renderwin_queue_redraw(rw);
428 }
429
430 #define FTOCHAR(val) val<=0.0f? 0 : (val>=(1.0f-0.5f/255.0f)? 255 :(char)((255.0f*val)+0.5f))
431
432 static void renderwin_mouse_moved(RenderWin *rw)
433 {
434         RenderResult rres;
435         RenderSpare *rspare= render_spare;
436                 
437         if(rspare && rspare->showspare) {
438                 if(rspare->ibuf) {
439                         rres.rectx= rspare->ibuf->x;
440                         rres.recty= rspare->ibuf->y;
441                         rres.rect32= (int *)rspare->ibuf->rect;
442                         rres.rectf= rspare->ibuf->rect_float;
443                         rres.rectz= rspare->ibuf->zbuf_float;
444                 }
445                 else
446                         memset(&rres, 0, sizeof(rres));
447         }
448         else
449                 RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
450
451         if (rw->flags & RW_FLAGS_PIXEL_EXAMINING) {
452                 int imgco[2], ofs=0;
453                 char buf[128];
454                 char *pxl;
455
456                 if (renderwin_win_to_image_co(rw, rw->lmouse, imgco)) {
457                         ofs= sprintf(buf, "X: %d Y: %d ", imgco[0], imgco[1]);
458                         if (rres.rect32) {
459                                 pxl= (char*) &rres.rect32[rres.rectx*imgco[1] + imgco[0]];
460                                 ofs+= sprintf(buf+ofs, " | R: %d G: %d B: %d A: %d", pxl[0], pxl[1], pxl[2], pxl[3]);   
461                         }
462                         if (rres.rectf) {
463                                 float *pxlf= rres.rectf + 4*(rres.rectx*imgco[1] + imgco[0]);
464                                 if(!rres.rect32){
465                                         ofs+= sprintf(buf+ofs, " | R: %d G: %d B: %d A: %d", FTOCHAR(pxlf[0]), FTOCHAR(pxlf[1]), FTOCHAR(pxlf[2]), FTOCHAR(pxlf[3]));
466                                 }
467                                 ofs+= sprintf(buf+ofs, " | R: %.3f G: %.3f B: %.3f A: %.3f ", pxlf[0], pxlf[1], pxlf[2], pxlf[3]);
468                         }
469                         if (rres.rectz) {
470                                 float *pxlz= &rres.rectz[rres.rectx*imgco[1] + imgco[0]];                       
471                                 sprintf(buf+ofs, "| Z: %.3f", *pxlz );
472                         }
473
474                         renderwin_set_infotext(rw, buf);
475                         renderwin_queue_redraw(rw);
476                 } else {
477                         renderwin_set_infotext(rw, NULL);
478                         renderwin_queue_redraw(rw);
479                 }
480         } 
481         else if (rw->flags & RW_FLAGS_PANNING) {
482                 int delta_x= rw->lmouse[0] - rw->pan_mouse_start[0];
483                 int delta_y= rw->lmouse[1] - rw->pan_mouse_start[1];
484         
485                 rw->zoomofs[0]= rw->pan_ofs_start[0] - delta_x/rw->zoom;
486                 rw->zoomofs[1]= rw->pan_ofs_start[1] - delta_y/rw->zoom;
487                 rw->zoomofs[0]= CLAMPIS(rw->zoomofs[0], -rres.rectx/2, rres.rectx/2);
488                 rw->zoomofs[1]= CLAMPIS(rw->zoomofs[1], -rres.recty/2, rres.recty/2);
489
490                 renderwin_queue_redraw(rw);
491         } 
492         else if (rw->flags & RW_FLAGS_OLDZOOM) {
493                 float ndc[2];
494                 int w, h;
495
496                 window_get_size(rw->win, &w, &h);
497                 h-= RW_HEADERY;
498                 renderwin_win_to_ndc(rw, rw->lmouse, ndc);
499
500                 rw->zoomofs[0]= -0.5*ndc[0]*(w-rres.rectx*rw->zoom)/rw->zoom;
501                 rw->zoomofs[1]= -0.5*ndc[1]*(h-rres.recty*rw->zoom)/rw->zoom;
502
503                 renderwin_queue_redraw(rw);
504         }
505 }
506
507 static void renderwin_mousebut_changed(RenderWin *rw)
508 {
509         if (rw->mbut[0]) {
510                 rw->flags|= RW_FLAGS_PIXEL_EXAMINING;
511         } 
512         else if (rw->mbut[1]) {
513                 rw->flags|= RW_FLAGS_PANNING;
514                 rw->pan_mouse_start[0]= rw->lmouse[0];
515                 rw->pan_mouse_start[1]= rw->lmouse[1];
516                 rw->pan_ofs_start[0]= rw->zoomofs[0];
517                 rw->pan_ofs_start[1]= rw->zoomofs[1];
518         } else if (rw->mbut[3]) {
519                 renderwin_zoom(rw, 0);
520                 rw->mbut[3]=0;
521         } else if (rw->mbut[4]) {
522                 renderwin_zoom(rw, 1);
523                 rw->mbut[4]=0;
524         } else {
525                 if (rw->flags & RW_FLAGS_PANNING) {
526                         rw->flags &= ~RW_FLAGS_PANNING;
527                         renderwin_queue_redraw(rw);
528                 }
529                 if (rw->flags & RW_FLAGS_PIXEL_EXAMINING) {
530                         rw->flags&= ~RW_FLAGS_PIXEL_EXAMINING;
531                         renderwin_set_infotext(rw, NULL);
532                         renderwin_queue_redraw(rw);
533                 }
534         }
535 }
536
537
538 /* handler for renderwin, passed on to Ghost */
539 static void renderwin_handler(Window *win, void *user_data, short evt, short val, char ascii)
540 {
541         RenderWin *rw= user_data;
542
543         // added this for safety, while render it's just creating bezerk results
544         if(G.rendering) {
545                 if(evt==ESCKEY && val) 
546                         rw->flags|= RW_FLAGS_ESCAPE;
547                 return;
548         }
549         
550         if (evt==RESHAPE) {
551                 renderwin_reshape(rw);
552         } 
553         else if (evt==REDRAW) {
554                 renderwin_draw(rw, 0);
555         } 
556         else if (evt==WINCLOSE) {
557                 BIF_close_render_display();
558         } 
559         else if (evt==INPUTCHANGE) {
560                 rw->active= val;
561
562                 if (!val && (rw->flags&RW_FLAGS_OLDZOOM)) {
563                         rw->flags&= ~RW_FLAGS_OLDZOOM;
564                         renderwin_reset_view(rw);
565                 }
566         } 
567         else if (ELEM(evt, MOUSEX, MOUSEY)) {
568                 rw->lmouse[evt==MOUSEY]= val;
569                 renderwin_mouse_moved(rw);
570         } 
571         else if (ELEM(evt, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
572                 int which=(evt==WHEELUPMOUSE?3:4); 
573                 rw->mbut[which]=val;
574                 renderwin_mousebut_changed(rw);
575         }
576         else if (ELEM3(evt, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
577                 int which= (evt==LEFTMOUSE)?0:(evt==MIDDLEMOUSE)?1:2;
578                 rw->mbut[which]= val;
579                 renderwin_mousebut_changed(rw);
580         } 
581         else if (val) {
582                 if (evt==ESCKEY) {
583                         if (rw->flags&RW_FLAGS_OLDZOOM) {
584                                 rw->flags&= ~RW_FLAGS_OLDZOOM;
585                                 renderwin_reset_view(rw);
586                         } 
587                         else {
588                                 rw->flags|= RW_FLAGS_ESCAPE;
589                                 mainwindow_raise();
590                                 mainwindow_make_active();
591                                 rw->active= 0;
592                         }
593                 } 
594                 else if( evt==AKEY) {
595                         rw->flags ^= RW_FLAGS_ALPHA;
596                         renderwin_queue_redraw(render_win);
597                 }
598                 else if (evt==JKEY) {
599                         if(G.rendering==0) BIF_swap_render_rects();
600                 } 
601                 else if (evt==ZKEY) {
602                         if (rw->flags&RW_FLAGS_OLDZOOM) {
603                                 rw->flags&= ~RW_FLAGS_OLDZOOM;
604                                 renderwin_reset_view(rw);
605                         } else {
606                                 rw->zoom= 2.0;
607                                 rw->flags|= RW_FLAGS_OLDZOOM;
608                                 renderwin_mouse_moved(rw);
609                         }
610                 } 
611                 else if (ELEM(evt,PADPLUSKEY,PAGEUPKEY))  {
612                         renderwin_zoom(rw, 0);
613                 } 
614                 else if (ELEM(evt,PADMINUS,PAGEDOWNKEY)) {
615                         renderwin_zoom(rw, 1);
616                 } 
617                 else if (evt==PADENTER || evt==HOMEKEY) {
618                         if (rw->flags&RW_FLAGS_OLDZOOM) {
619                                 rw->flags&= ~RW_FLAGS_OLDZOOM;
620                         }
621                         renderwin_reset_view(rw);
622                 } 
623                 else if (evt==F3KEY) {
624                         if(G.rendering==0) {
625                                 mainwindow_raise();
626                                 mainwindow_make_active();
627                                 rw->active= 0;
628                                 areawinset(find_biggest_area()->win);
629                                 BIF_save_rendered_image_fs();
630                         }
631                 } 
632                 else if (evt==F11KEY) {
633                         BIF_toggle_render_display();
634                 } 
635                 else if (evt==F12KEY) {
636                         if(G.rendering==0) 
637                                 BIF_do_render(0);
638                 }
639         }
640 }
641
642 static char *renderwin_get_title()
643 {
644         char *title="";
645         
646         if(BIF_show_render_spare()) {
647                 if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render (previous)";
648                 else title = "Blender:Render (previous)";
649         }
650         else {
651                 if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render";
652                 else title = "Blender:Render";
653         }
654
655         return title;
656 }
657
658 /* opens window and allocs struct */
659 static void open_renderwin(int winpos[2], int winsize[2], int imagesize[2])
660 {
661         extern void mywindow_build_and_set_renderwin( int orx, int ory, int sizex, int sizey); // mywindow.c
662         Window *win;
663         char *title;
664         
665         title= renderwin_get_title();
666         win= window_open(title, winpos[0], winpos[1], winsize[0], winsize[1]+RW_HEADERY, 0);
667
668         render_win= renderwin_alloc(win);
669         render_win->rectx= imagesize[0];
670         render_win->recty= imagesize[1];
671         
672         /* Ghost calls handler */
673         window_set_handler(win, renderwin_handler, render_win);
674
675         winlay_process_events(0);
676         window_make_active(render_win->win);
677         winlay_process_events(0);
678         
679         /* mywindow has to know about it too */
680         mywindow_build_and_set_renderwin(winpos[0], winpos[1], winsize[0], winsize[1]+RW_HEADERY);
681         /* and we should be able to draw 3d in it */
682         init_gl_stuff();
683         
684         renderwin_draw(render_win, 1);
685         renderwin_draw(render_win, 1);
686 }
687
688 /* -------------- callbacks for render loop: Window (RenderWin) ----------------------- */
689
690 /* calculations for window size and position */
691 void calc_renderwin_rectangle(int rectx, int recty, int posmask, int renderpos_r[2], int rendersize_r[2]) 
692 {
693         int scr_w, scr_h, x, y, div= 0;
694         float ndc_x= 0.0, ndc_y= 0.0;
695
696         winlay_get_screensize(&scr_w, &scr_h);
697
698         rendersize_r[0]= rectx;
699         rendersize_r[1]= recty;
700
701         rendersize_r[0]= CLAMPIS(rendersize_r[0], 0, scr_w);     
702         rendersize_r[1]= CLAMPIS(rendersize_r[1], 0, scr_h-RW_HEADERY);  
703         
704         for (y=-1; y<=1; y++) {
705                 for (x=-1; x<=1; x++) {
706                         if (posmask & (1<<((y+1)*3 + (x+1)))) {
707                                 ndc_x+= x;
708                                 ndc_y+= y;
709                                 div++;
710                         }
711                 }
712         }
713
714         if (div) {
715                 ndc_x/= div;
716                 ndc_y/= div;
717         }
718         
719         renderpos_r[0]= (scr_w-rendersize_r[0])*(ndc_x*0.5 + 0.5);
720 #ifdef __APPLE__
721         /* 44 pixels is topbar and window header... awaiting better fixes in ghost :) */
722         rendersize_r[1]= CLAMPIS(rendersize_r[1], 0, scr_h-44-RW_HEADERY);       
723         renderpos_r[1]= -44-RW_HEADERY+(scr_h-rendersize_r[1])*(ndc_y*0.5 + 0.5);
724 #else
725         renderpos_r[1]= -RW_HEADERY+(scr_h-rendersize_r[1])*(ndc_y*0.5 + 0.5);
726 #endif
727 }
728         
729 /* init renderwin, alloc/open/resize */
730 static void renderwin_init_display_cb(RenderResult *rr) 
731 {
732         if (G.afbreek != 1) {
733                 int rendersize[2], renderpos[2], imagesize[2];
734
735                 calc_renderwin_rectangle(rr->rectx, rr->recty, G.winpos, renderpos, rendersize);
736                 
737                 imagesize[0]= rr->rectx;
738                 imagesize[1]= rr->recty;
739
740                 if (!render_win) {
741                         open_renderwin(renderpos, rendersize, imagesize);
742                         renderwin_reset_view(render_win); // incl. autozoom for large images
743                 } else {
744                         int win_x, win_y;
745                         int win_w, win_h;
746
747                         window_get_position(render_win->win, &win_x, &win_y);
748                         window_get_size(render_win->win, &win_w, &win_h);
749                         win_h-= RW_HEADERY;
750
751                                 /* XXX, this is nasty and I guess bound to cause problems,
752                                  * but to ensure the window is at the user specified position
753                                  * and size we reopen the window all the time... we need
754                                  * a ghost _set_position to fix this -zr
755                                  */
756                                  
757                                  /* XXX, well... it is nasty yes, and reopens windows each time on
758                                     subsequent renders. Better rule is to make it reopen only only
759                                     size change, and use the preferred position only on open_renderwin
760                                         cases (ton)
761                                  */
762                         if(rendersize[0]!= win_w || rendersize[1]!= win_h) {
763                                 BIF_close_render_display();
764                                 open_renderwin(renderpos, rendersize, imagesize);
765                         }
766                         else {
767                                 window_raise(render_win->win);
768                                 window_make_active(render_win->win);
769                                 
770                                 mywinset(2);    // to assign scissor/viewport again in mywindow.c. is hackish yes, but otherwise it draws in header of button for ogl header
771                                 {
772                                         rcti win_rct;
773                                         win_rct.xmin= win_rct.ymin= 0;
774                                         window_get_size(render_win->win, &win_rct.xmax, &win_rct.ymax);
775                                         win_rct.ymax-= RW_HEADERY;
776                                         glaDefine2DArea(&win_rct);
777                                 }
778                         }
779
780                         renderwin_reset_view(render_win);
781                         render_win->active= 1;
782                 }
783                 /* make sure we are in normal draw again */
784                 render_win->flags &= ~RW_FLAGS_ALPHA;
785                 
786                 glFinish();
787         }
788 }
789
790 /* callback for redraw render win */
791 static void renderwin_clear_display_cb(RenderResult *rr) 
792 {
793         if (render_win) {
794                 window_make_active(render_win->win);
795                 renderwin_draw(render_win, 1);
796         }
797 }
798
799 /* XXX, this is not good, we do this without any regard to state
800 * ... better is to make this an optimization of a more clear
801 * implementation. the bug shows up when you do something like
802 * open the window, then draw part of the progress, then get
803 * a redraw event. whatever can go wrong will. -zr
804 *
805 * Note: blocked queue handling while rendering to prevent that (ton)
806 */
807
808 /* can get as well the full picture, as the parts while rendering */
809 static void renderwin_progress(RenderWin *rw, RenderResult *rr, volatile rcti *renrect)
810 {
811         rcti win_rct;
812         float *rectf= NULL, fullrect[2][2];
813         unsigned int *rect32= NULL;
814         int ymin, ymax, xmin, xmax;
815         
816         /* if renrect argument, we only display scanlines */
817         if(renrect) {
818                  /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
819                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
820                         return;
821                 
822                 /* xmin here is first subrect x coord, xmax defines subrect width */
823                 xmin = renrect->xmin;
824                 xmax = renrect->xmax - xmin;
825                 if (xmax<2) return;
826                 
827                 ymin= renrect->ymin;
828                 ymax= renrect->ymax - ymin;
829                 if(ymax<2)
830                         return;
831                 renrect->ymin= renrect->ymax;
832         }
833         else {
834                 xmin = ymin = 0;
835                 xmax = rr->rectx - 2*rr->crop;
836                 ymax = rr->recty - 2*rr->crop;
837         }
838         
839         /* renderwindow cruft */
840         win_rct.xmin= win_rct.ymin= 0;
841         window_get_size(rw->win, &win_rct.xmax, &win_rct.ymax);
842         win_rct.ymax-= RW_HEADERY;
843         renderwin_get_fullrect(rw, fullrect);
844         
845         /* find current float rect for display, first case is after composit... still weak */
846         if(rr->rectf)
847                 rectf= rr->rectf;
848         else {
849                 if(rr->rect32)
850                         rect32= (unsigned int *)rr->rect32;
851                 else {
852                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
853                         rectf= rr->renlay->rectf;
854                 }
855         }
856         if(rectf) {
857                 /* if scanline updates... */
858                 rectf+= 4*(rr->rectx*ymin + xmin);
859         
860                 /* when rendering more pixels than needed, we crop away cruft */
861                 if(rr->crop)
862                         rectf+= 4*(rr->crop*rr->rectx + rr->crop);
863         }
864         
865         /* tilerect defines drawing offset from (0,0) */
866         /* however, tilerect (xmin, ymin) is first pixel */
867         fullrect[0][0] += (rr->tilerect.xmin + rr->crop + xmin)*rw->zoom;
868         fullrect[0][1] += (rr->tilerect.ymin + rr->crop + ymin)*rw->zoom;
869
870         glEnable(GL_SCISSOR_TEST);
871         glaDefine2DArea(&win_rct);
872
873 #ifdef __APPLE__
874 #else
875         glDrawBuffer(GL_FRONT);
876 #endif
877         glPixelZoom(rw->zoom, rw->zoom);
878
879         if(rect32)
880                 glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], xmax, ymax, rr->rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect32);
881         else
882                 glaDrawPixelsSafe_to32(fullrect[0][0], fullrect[0][1], xmax, ymax, rr->rectx, rectf);
883         
884         glPixelZoom(1.0, 1.0);
885         
886 #ifdef __APPLE__
887         window_swap_buffers(render_win->win);
888 #else
889         glFlush();
890         glDrawBuffer(GL_BACK);
891 #endif  
892 }
893
894
895 /* in render window; display a couple of scanlines of rendered image */
896 static void renderwin_progress_display_cb(RenderResult *rr, volatile rcti *rect)
897 {
898         if (render_win) {
899                 renderwin_progress(render_win, rr, rect);
900         }
901 }
902
903 /* -------------- callbacks for render loop: interactivity ----------------------- */
904
905 /* string is RW_MAXTEXT chars min */
906 void make_renderinfo_string(RenderStats *rs, char *str)
907 {
908         extern char info_time_str[32];  // header_info.c
909         extern unsigned long mem_in_use, mmap_in_use;
910         float megs_used_memory, mmap_used_memory;
911         char *spos= str;
912         
913         megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
914         mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
915         
916         if(G.scene->lay & 0xFF000000)
917                 spos+= sprintf(spos, "Localview | ");
918         else if(G.scene->r.scemode & R_SINGLE_LAYER)
919                 spos+= sprintf(spos, "Single Layer | ");
920         
921         spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d ", (G.scene->r.cfra), rs->totvert, rs->totface);
922         if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
923         if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
924         spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
925
926         if(rs->curfield)
927                 spos+= sprintf(spos, "Field %d ", rs->curfield);
928         if(rs->curblur)
929                 spos+= sprintf(spos, "Blur %d ", rs->curblur);
930         
931         BLI_timestr(rs->lastframetime, info_time_str);
932         spos+= sprintf(spos, "Time:%s ", info_time_str);
933         
934         if(rs->infostr)
935                 spos+= sprintf(spos, "| %s ", rs->infostr);
936         
937         /* very weak... but 512 characters is quite safe... we cannot malloc during thread render */
938         if(spos >= str+RW_MAXTEXT)
939                 printf("WARNING! renderwin text beyond limit \n");
940         
941 }
942
943 /* callback for print info in top header of renderwin */
944 static void renderwin_renderinfo_cb(RenderStats *rs)
945 {
946         
947         if(render_win) {
948                 
949                 BIF_make_render_text(rs);
950                 
951 #ifdef __APPLE__
952 #else
953                 glDrawBuffer(GL_FRONT);
954 #endif
955                 renderwin_draw_render_info(render_win);
956                 
957 #ifdef __APPLE__
958                 window_swap_buffers(render_win->win);
959 #else
960                 glFlush();
961                 glDrawBuffer(GL_BACK);
962 #endif
963         }
964
965 }
966
967 /* -------------- callback system to allow ESC from rendering ----------------------- */
968
969 /* POSIX & WIN32: this function is called all the time, and should not use cpu or resources */
970 static int test_break(void)
971 {
972
973         if(G.afbreek==2) { /* code for testing queue */
974
975                 G.afbreek= 0;
976
977                 blender_test_break(); /* tests blender interface */
978
979                 if (G.afbreek==0 && render_win) { /* tests window */
980                         winlay_process_events(0);
981                         // render_win can be closed in winlay_process_events()
982                         if (render_win == 0 || (render_win->flags & RW_FLAGS_ESCAPE)) {
983                                 G.afbreek= 1;
984                         }
985                 }
986         }
987
988         if(G.afbreek==1) return 1;
989         else return 0;
990 }
991
992
993
994 #ifdef _WIN32
995 /* we use the multimedia time here */
996 static UINT uRenderTimerId;
997
998 void CALLBACK interruptESC(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
999 {
1000         if(G.afbreek==0) G.afbreek= 2;  /* code for read queue */
1001 }
1002
1003 /* WIN32: init SetTimer callback */
1004 static void init_test_break_callback()
1005 {
1006         timeBeginPeriod(50);
1007         uRenderTimerId = timeSetEvent(250, 1, interruptESC, 0, TIME_PERIODIC);
1008 }
1009
1010 /* WIN32: stop SetTimer callback */
1011 static void end_test_break_callback()
1012 {
1013         timeEndPeriod(50);
1014         timeKillEvent(uRenderTimerId);
1015 }
1016
1017 #else
1018 /* all other OS's support signal(SIGVTALRM/SIGALRM) */
1019
1020 /* XXX The ESC problem: some unix users reported that ESC doesn't cancel
1021  * renders anymore. Most complaints came from linux, but it's not
1022  * general, not all linux users have the problem.
1023  *
1024  * From tests, the systems that do have it are not signalling SIGVTALRM
1025  * interrupts (an issue with signals and threads). Using SIGALRM instead
1026  * fixes the problem, at least while we investigate better.
1027  *
1028  * ITIMER_REAL (SIGALRM): timer that counts real system time
1029  * ITIMER_VIRTUAL (SIGVTALRM): only counts time spent in its owner process
1030  *
1031  * Addendum: now SIGVTALRM is used on Solaris again, because SIGALRM can
1032  * kill the process there! */
1033
1034 /* POSIX: this function goes in the signal() callback */
1035 static void interruptESC(int sig)
1036 {
1037
1038         if(G.afbreek==0) G.afbreek= 2;  /* code for read queue */
1039
1040         /* call again, timer was reset */
1041 #ifdef __sun
1042         signal(SIGVTALRM, interruptESC);
1043 #else
1044         signal(SIGALRM, interruptESC);
1045 #endif
1046 }
1047
1048 /* POSIX: initialize timer and signal */
1049 static void init_test_break_callback()
1050 {
1051
1052         struct itimerval tmevalue;
1053
1054         tmevalue.it_interval.tv_sec = 0;
1055         tmevalue.it_interval.tv_usec = 250000;
1056         /* when the first ? */
1057         tmevalue.it_value.tv_sec = 0;
1058         tmevalue.it_value.tv_usec = 10000;
1059
1060 #ifdef __sun
1061         signal(SIGVTALRM, interruptESC);
1062         setitimer(ITIMER_VIRTUAL, &tmevalue, 0);
1063 #else
1064         signal(SIGALRM, interruptESC);
1065         setitimer(ITIMER_REAL, &tmevalue, 0);
1066 #endif
1067 }
1068
1069 /* POSIX: stop timer and callback */
1070 static void end_test_break_callback()
1071 {
1072         struct itimerval tmevalue;
1073
1074         memset(&tmevalue, 0, sizeof(struct itimerval));
1075
1076 #ifdef __sun
1077         setitimer(ITIMER_VIRTUAL, &tmevalue, 0);
1078         signal(SIGVTALRM, SIG_IGN);
1079 #else
1080         setitimer(ITIMER_REAL, &tmevalue, 0);
1081         signal(SIGALRM, SIG_IGN);
1082 #endif
1083 }
1084
1085
1086 #endif
1087
1088
1089
1090 /* -------------- callbacks for render loop: init & run! ----------------------- */
1091
1092
1093 /* - initialize displays
1094    - set callbacks
1095    - cleanup
1096 */
1097
1098 static void do_render(int anim)
1099 {
1100         Image *ima;
1101         Render *re= RE_NewRender(G.scene->id.name);
1102         unsigned int lay= G.scene->lay;
1103         int scemode= G.scene->r.scemode;
1104         int sculptmode= G.f & G_SCULPTMODE;
1105         
1106         /* UGLY! we set this flag to prevent renderwindow queue to execute another render */
1107         /* is reset in RE_BlenderFrame */
1108         G.rendering= 1;
1109
1110         /* set render callbacks, also starts ESC timer */
1111         BIF_init_render_callbacks(re, 1);
1112         
1113         waitcursor(1);
1114         if(render_win) 
1115                 window_set_cursor(render_win->win, CURSOR_WAIT);
1116         
1117         if(G.obedit)
1118                 exit_editmode(0);       /* 0 = no free data */
1119
1120         if(sculptmode) set_sculptmode();
1121
1122         /* allow localview render for objects with lights in normal layers */
1123         if(curarea->spacetype==SPACE_VIEW3D) {
1124                 /* if view is defined (might not be if called from script), check and set layers. */
1125                 if(G.vd) {
1126                         if(G.vd->lay & 0xFF000000) {
1127                                 G.scene->lay |= G.vd->lay;
1128                                 G.scene->r.scemode |= R_SINGLE_LAYER;
1129                         }
1130                         else G.scene->lay= G.vd->lay;
1131                 }
1132         }
1133         
1134         if(anim)
1135                 RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
1136         else
1137                 RE_BlenderFrame(re, G.scene, G.scene->r.cfra);
1138
1139         /* restore local view exception */
1140         G.scene->lay= lay;
1141         G.scene->r.scemode= scemode;
1142         
1143         if(render_win) window_set_cursor(render_win->win, CURSOR_STD);
1144         
1145         free_filesel_spec(G.scene->r.pic);
1146
1147         G.afbreek= 0;
1148         BIF_end_render_callbacks();
1149         
1150         /* after an envmap creation...  */
1151 //              if(R.flag & R_REDRAW_PRV) {
1152 //                      BIF_preview_changed(ID_TE);
1153 //              }
1154                 
1155         scene_update_for_newframe(G.scene, G.scene->lay);       // no redraw needed, this restores to view as we left it
1156         
1157         /* get a render result image, and make sure it is clean */
1158         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
1159         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
1160         
1161         if(sculptmode) set_sculptmode();
1162         
1163         waitcursor(0);
1164 }
1165
1166 /* called before render, store old render in spare buffer */
1167 static int render_store_spare(void)
1168 {
1169         RenderResult rres;
1170         RenderSpare *rspare= render_spare;
1171         
1172         if(rspare==0 || rspare->storespare==0)
1173                 return 0;
1174         
1175         /* only store when it does not show spare */
1176         if(rspare->showspare==0)
1177                 return 0;
1178         
1179         rspare->showspare= 0;
1180
1181         if(rspare->ibuf) {
1182                 IMB_freeImBuf(rspare->ibuf);
1183                 rspare->ibuf= NULL;
1184         }
1185         
1186         RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
1187
1188         rspare->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, 0, 0);
1189         
1190         if(rres.rect32) {
1191                 rspare->ibuf->rect= MEM_dupallocN(rres.rect32);
1192                 rspare->ibuf->flags |= IB_rect;
1193                 rspare->ibuf->mall |= IB_rect;
1194         }
1195         if(rres.rectf) {
1196                 rspare->ibuf->rect_float= MEM_dupallocN(rres.rectf);
1197                 rspare->ibuf->flags |= IB_rectfloat;
1198                 rspare->ibuf->mall |= IB_rectfloat;
1199         }
1200         if(rres.rectz) {
1201                 rspare->ibuf->zbuf_float= MEM_dupallocN(rres.rectz);
1202                 rspare->ibuf->flags |= IB_zbuffloat;
1203                 rspare->ibuf->mall |= IB_zbuffloat;
1204         }
1205
1206         return 1;
1207 }
1208
1209 /* -------------- API: externally called --------------- */
1210
1211 static void error_cb(char *str){error(str);}
1212 static int esc_timer_set= 0;
1213
1214 /* set callbacks, exported to sequence render too. 
1215    Only call in foreground (UI) renders. */
1216
1217 void BIF_init_render_callbacks(Render *re, int do_display)
1218 {
1219         if(do_display) {
1220                 if(G.displaymode!=R_DISPLAYWIN) {
1221                         if(render_win)
1222                                 BIF_close_render_display();
1223                         imagewindow_render_callbacks(re);
1224                 }
1225                 else {
1226                         RE_display_init_cb(re, renderwin_init_display_cb);
1227                         RE_display_draw_cb(re, renderwin_progress_display_cb);
1228                         RE_display_clear_cb(re, renderwin_clear_display_cb);
1229                         RE_stats_draw_cb(re, renderwin_renderinfo_cb);
1230                 }
1231         }
1232         
1233         RE_error_cb(re, error_cb);
1234         
1235         G.afbreek= 0;
1236         if(render_win)
1237                 render_win->flags &= ~RW_FLAGS_ESCAPE;
1238
1239         /* start esc timer. ensure it happens once only */
1240         if(esc_timer_set==0)
1241                 init_test_break_callback();
1242         esc_timer_set++;
1243         
1244         RE_test_break_cb(re, test_break);
1245         RE_timecursor_cb(re, set_timecursor);
1246         
1247 }
1248
1249 /* the init/end callbacks can be called multiple times (sequence render) */
1250 void BIF_end_render_callbacks(void)
1251 {
1252         esc_timer_set--;
1253         if(esc_timer_set==0) {
1254                 end_test_break_callback();
1255                 
1256                 if(render_win)
1257                         mainwindow_make_active();
1258         }
1259 }
1260
1261 void BIF_store_spare(void)
1262 {
1263         if(render_store_spare()) {
1264                 if(render_text)
1265                         BLI_strncpy(render_spare->render_text_spare, render_text, RW_MAXTEXT);
1266
1267                 if(render_win)
1268                         window_set_title(render_win->win, renderwin_get_title());
1269                 allqueue(REDRAWIMAGE, 0);
1270         }
1271 }
1272
1273 /* set up display, render an image or scene */
1274 void BIF_do_render(int anim)
1275 {
1276         int slink_flag = 0;
1277
1278         if (G.f & G_DOSCRIPTLINKS) {
1279                 BPY_do_all_scripts(SCRIPT_RENDER);
1280                 if (!anim) { /* avoid FRAMECHANGED slink in render callback */
1281                         G.f &= ~G_DOSCRIPTLINKS;
1282                         slink_flag = 1;
1283                 }
1284         }
1285         
1286         BIF_store_spare();
1287
1288         do_render(anim);
1289
1290         if(G.scene->use_nodes) {
1291                 allqueue(REDRAWNODE, 1);
1292                 allqueue(REDRAWIMAGE, 1);
1293         }
1294         if (slink_flag) G.f |= G_DOSCRIPTLINKS;
1295         if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_POSTRENDER);
1296 }
1297
1298 void do_ogl_view3d_render(Render *re, View3D *v3d, int winx, int winy)
1299 {
1300         float winmat[4][4];
1301
1302         update_for_newframe_muted();    /* here, since camera can be animated */
1303
1304         if(v3d->persp==V3D_CAMOB && v3d->camera) {
1305                 /* in camera view, use actual render winmat */
1306                 RE_GetCameraWindow(re, v3d->camera, CFRA, winmat);
1307                 drawview3d_render(v3d, winx, winy, winmat);
1308         }
1309         else
1310                 drawview3d_render(v3d, winx, winy, NULL);
1311 }
1312
1313 /* set up display, render the current area view in an image */
1314 /* the RE_Render is only used to make sure we got the picture in the result */
1315 void BIF_do_ogl_render(View3D *v3d, int anim)
1316 {
1317         Render *re= RE_NewRender(G.scene->id.name);
1318         RenderResult *rr;
1319         int winx, winy;
1320         
1321         G.afbreek= 0;
1322         init_test_break_callback();
1323         
1324         winx= (G.scene->r.size*G.scene->r.xsch)/100;
1325         winy= (G.scene->r.size*G.scene->r.ysch)/100;
1326         
1327         RE_InitState(re, NULL, &G.scene->r, winx, winy, NULL);
1328
1329         /* for now, result is defaulting to floats still... */
1330         rr= RE_GetResult(re);
1331         if(rr->rect32==NULL)
1332                 rr->rect32= MEM_mallocN(sizeof(int)*winx*winy, "32 bits rects");
1333         
1334         /* open window */
1335         renderwin_init_display_cb(rr);
1336         if(render_win)
1337                 render_win->flags &= ~RW_FLAGS_ESCAPE;
1338
1339         init_gl_stuff();
1340         
1341         waitcursor(1);
1342
1343         if(anim) {
1344                 bMovieHandle *mh= BKE_get_movie_handle(G.scene->r.imtype);
1345                 int cfrao= CFRA;
1346                 
1347                 if(BKE_imtype_is_movie(G.scene->r.imtype))
1348                         mh->start_movie(&G.scene->r, winx, winy);
1349                 
1350                 for(CFRA= SFRA; CFRA<=EFRA; CFRA++) {
1351                         /* user event can close window */
1352                         if(render_win==NULL)
1353                                 break;
1354
1355                         do_ogl_view3d_render(re, v3d, winx, winy);
1356                         glReadPixels(0, 0, winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, rr->rect32);
1357                         if((G.scene->r.scemode & R_STAMP_INFO) && (G.scene->r.stamp & R_STAMP_DRAW)) {
1358                                 BKE_stamp_buf((unsigned char *)rr->rect32, rr->rectf, rr->rectx, rr->recty, 3);
1359                         }
1360                         window_swap_buffers(render_win->win);
1361                         
1362                         if(BKE_imtype_is_movie(G.scene->r.imtype)) {
1363                                 mh->append_movie(CFRA, rr->rect32, winx, winy);
1364                                 printf("Append frame %d", G.scene->r.cfra);
1365                         }
1366                         else {
1367                                 ImBuf *ibuf= IMB_allocImBuf(winx, winy, G.scene->r.planes, 0, 0);
1368                                 char name[FILE_MAXDIR+FILE_MAXFILE];
1369                                 int ok;
1370                                 
1371                                 BKE_makepicstring(name, G.scene->r.pic, G.scene->r.cfra, G.scene->r.imtype);
1372
1373                                 ibuf->rect= (unsigned int *)rr->rect32;
1374                                 ok= BKE_write_ibuf(ibuf, name, G.scene->r.imtype, G.scene->r.subimtype, G.scene->r.quality);
1375                                 
1376                                 if(ok==0) {
1377                                         printf("Write error: cannot save %s\n", name);
1378                                         break;
1379                                 }
1380                                 else printf("Saved: %s", name);
1381                                 
1382                 /* imbuf knows which rects are not part of ibuf */
1383                                 IMB_freeImBuf(ibuf);    
1384                         }
1385                         /* movie stats prints have no line break */
1386                         printf("\n");
1387                         
1388                         if(test_break()) break;
1389                 }
1390                 
1391                 if(BKE_imtype_is_movie(G.scene->r.imtype))
1392                         mh->end_movie();
1393                 
1394                 CFRA= cfrao;
1395         }
1396         else {
1397                 do_ogl_view3d_render(re, v3d, winx, winy);
1398                 glReadPixels(0, 0, winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, rr->rect32);
1399                 if((G.scene->r.scemode & R_STAMP_INFO) && (G.scene->r.stamp & R_STAMP_DRAW)) {
1400                         BKE_stamp_buf((unsigned char *)rr->rect32, rr->rectf, rr->rectx, rr->recty, 3);
1401                 }
1402                 window_swap_buffers(render_win->win);
1403         }
1404         
1405         if(render_win)
1406                 renderwin_draw(render_win, 0);
1407
1408         mainwindow_make_active();
1409         
1410         if(anim)
1411                 scene_update_for_newframe(G.scene, G.scene->lay);       // no redraw needed, this restores to view as we left it
1412         
1413         end_test_break_callback();
1414         waitcursor(0);
1415 }
1416
1417 void BIF_redraw_render_rect(void)
1418 {
1419         /* redraw */
1420         if(render_win)
1421                 renderwin_queue_redraw(render_win);
1422         allqueue(REDRAWIMAGE, 0);
1423 }       
1424
1425 void BIF_swap_render_rects(void)
1426 {
1427         RenderResult rres;
1428         RenderSpare *rspare;
1429         ImBuf *ibuf;
1430         
1431         if(!render_spare)
1432                 render_spare= renderspare_alloc();
1433
1434         rspare= render_spare;
1435         rspare->storespare= 1;
1436         rspare->showspare ^= 1;
1437                 
1438         RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
1439         
1440         ibuf= rspare->ibuf;
1441         if(ibuf && (ibuf->x!=rres.rectx || ibuf->y!=rres.recty)) {
1442                 IMB_freeImBuf(ibuf);
1443                 rspare->ibuf= NULL;
1444         }
1445         
1446         if(render_win)
1447                 window_set_title(render_win->win, renderwin_get_title());
1448         
1449         /* redraw */
1450         BIF_redraw_render_rect();
1451 }                               
1452
1453 ImBuf *BIF_render_spare_imbuf()
1454 {
1455         return (render_spare)? render_spare->ibuf: NULL;
1456 }
1457
1458 int BIF_show_render_spare()
1459 {
1460         return (render_spare && render_spare->showspare);
1461 }
1462
1463 char *BIF_render_text()
1464 {
1465         if(render_spare && render_spare->showspare)
1466                 return render_spare->render_text_spare;
1467         else
1468                 return render_text;
1469 }
1470
1471 void BIF_make_render_text(RenderStats *rs)
1472 {
1473         if(!render_text)
1474                 render_text= MEM_callocN(RW_MAXTEXT, "rendertext");
1475         make_renderinfo_string(rs, render_text);
1476 }
1477
1478 /* called from usiblender.c too, to free and close renderwin */
1479
1480 void BIF_free_render_spare()
1481 {
1482         RenderSpare *rspare= render_spare;
1483
1484         if(render_text) {
1485                 MEM_freeN(render_text);
1486                 render_text= NULL;
1487         }
1488
1489         if(rspare) {
1490                 if (rspare->render_text_spare) MEM_freeN(rspare->render_text_spare);
1491                 if (rspare->ibuf) IMB_freeImBuf(rspare->ibuf);
1492                 
1493                 MEM_freeN(rspare);
1494                 render_spare= NULL;
1495         }
1496 }
1497         
1498 void BIF_close_render_display(void)
1499 {
1500         if (render_win) {
1501                 if (render_win->info_text) MEM_freeN(render_win->info_text);
1502                 window_destroy(render_win->win); /* ghost close window */
1503                 MEM_freeN(render_win);
1504
1505                 render_win= NULL;
1506         }
1507 }
1508
1509
1510 /* typical with F11 key, show image or hide/close */
1511 void BIF_toggle_render_display(void) 
1512 {
1513         
1514         if (G.displaymode!=R_DISPLAYWIN) {
1515                 imagewindow_toggle_render();
1516         }
1517         else {
1518                 if (render_win) {
1519                         if(render_win->active) {
1520                                 mainwindow_raise();
1521                                 mainwindow_make_active();
1522                                 render_win->active= 0;
1523                         }
1524                         else {
1525                                 window_raise(render_win->win);
1526                                 window_make_active(render_win->win);
1527                                 render_win->active= 1;
1528                         }
1529                 } 
1530                 else {
1531                         RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name));
1532                         if(rr) renderwin_init_display_cb(rr);
1533                 }
1534         }
1535 }
1536
1537 void BIF_renderwin_set_custom_cursor(unsigned char mask[16][2], unsigned char bitmap[16][2])
1538 {
1539         if (render_win) {
1540                 window_set_custom_cursor(render_win->win, mask, bitmap, 7, 7);
1541         }
1542 }