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