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