4 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
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. The Blender
10 * Foundation also sells licenses for use in proprietary software under
11 * the Blender License. See http://www.blender.org/BL/ for information
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
30 * ***** END GPL/BL DUAL LICENSE BLOCK *****
34 /* for the multimedia timer */
48 #include "BLI_winstuff.h"
50 /* for signal callback, not (fully) supported at windows */
58 #include "BLI_blenlib.h"
60 #include "MEM_guardedalloc.h"
64 #include "DNA_view3d_types.h"
65 #include "DNA_screen_types.h"
66 #include "DNA_scene_types.h"
67 #include "DNA_vec_types.h"
69 #include "BKE_global.h"
70 #include "BKE_scene.h"
71 #include "BKE_utildefines.h"
72 #include "BKE_writeavi.h" /* movie handle */
75 #include "BIF_glutil.h"
76 #include "BIF_graphics.h"
77 #include "BIF_screen.h"
78 #include "BIF_space.h"
79 #include "BIF_mywindow.h"
80 #include "BIF_renderwin.h"
81 #include "BIF_resources.h"
82 #include "BIF_toets.h"
83 #include "BIF_writeimage.h"
85 #include "BDR_editobject.h"
86 #include "BPY_extern.h" /* for BPY_do_all_scripts */
89 #include "BSE_drawview.h"
90 #include "BSE_filesel.h"
91 #include "BSE_headerbuttons.h"
93 #include "RE_pipeline.h"
99 /* ------------ renderwin struct, to prevent too much global vars --------- */
100 /* ------------ only used for display in a 2nd window --------- */
103 /* flags escape presses during event handling
104 * so we can test for user break later.
106 #define RW_FLAGS_ESCAPE (1<<0)
107 /* old zoom style (2x, locked to mouse, exits
108 * when mouse leaves window), to be removed
111 #define RW_FLAGS_OLDZOOM (1<<1)
112 /* on when image is being panned with middlemouse
114 #define RW_FLAGS_PANNING (1<<2)
115 /* on when the mouse is dragging over the image
116 * to examine pixel values.
118 #define RW_FLAGS_PIXEL_EXAMINING (1<<3)
120 /* forces draw of alpha */
121 #define RW_FLAGS_ALPHA (1<<4)
123 /* space for info text */
124 #define RW_HEADERY 18
129 int rectx, recty; /* size of image */
130 float zoom, zoomofs[2];
138 float pan_mouse_start[2], pan_ofs_start[2];
141 char *render_text, *render_text_spare;
145 static RenderWin *render_win= NULL;
147 /* --------------- help functions for RenderWin struct ---------------------------- */
150 /* only called in function open_renderwin */
151 static RenderWin *renderwin_alloc(Window *win)
153 RenderWin *rw= MEM_mallocN(sizeof(*rw), "RenderWin");
158 rw->zoomofs[0]= rw->zoomofs[1]= 0;
160 rw->render_text= rw->render_text_spare= NULL;
162 rw->lmouse[0]= rw->lmouse[1]= 0;
163 rw->mbut[0]= rw->mbut[1]= rw->mbut[2]= 0;
169 static void renderwin_queue_redraw(RenderWin *rw)
171 window_queue_redraw(rw->win); // to ghost
174 static void renderwin_reshape(RenderWin *rw)
179 static void renderwin_get_fullrect(RenderWin *rw, float fullrect_r[2][2])
181 float display_w, display_h;
182 float cent_x, cent_y;
185 window_get_size(rw->win, &w, &h);
188 display_w= rw->rectx*rw->zoom;
189 display_h= rw->recty*rw->zoom;
190 cent_x= (rw->zoomofs[0] + rw->rectx/2)*rw->zoom;
191 cent_y= (rw->zoomofs[1] + rw->recty/2)*rw->zoom;
193 fullrect_r[0][0]= w/2 - cent_x;
194 fullrect_r[0][1]= h/2 - cent_y;
195 fullrect_r[1][0]= fullrect_r[0][0] + display_w;
196 fullrect_r[1][1]= fullrect_r[0][1] + display_h;
200 * Project window coordinate to image pixel coordinate.
201 * Returns true if resulting coordinate is within image.
203 static int renderwin_win_to_image_co(RenderWin *rw, int winco[2], int imgco_r[2])
205 float fullrect[2][2];
207 renderwin_get_fullrect(rw, fullrect);
209 imgco_r[0]= (int) ((winco[0]-fullrect[0][0])/rw->zoom);
210 imgco_r[1]= (int) ((winco[1]-fullrect[0][1])/rw->zoom);
212 return (imgco_r[0]>=0 && imgco_r[1]>=0 && imgco_r[0]<rw->rectx && imgco_r[1]<rw->recty);
216 * Project window coordinates to normalized device coordinates
217 * Returns true if resulting coordinate is within window.
219 static int renderwin_win_to_ndc(RenderWin *rw, int win_co[2], float ndc_r[2])
223 window_get_size(rw->win, &w, &h);
226 ndc_r[0]= ((float)(win_co[0]*2)/(w-1) - 1.0f);
227 ndc_r[1]= ((float)(win_co[1]*2)/(h-1) - 1.0f);
229 return (fabs(ndc_r[0])<=1.0 && fabs(ndc_r[1])<=1.0);
232 static void renderwin_set_infotext(RenderWin *rw, char *info_text)
234 if (rw->info_text) MEM_freeN(rw->info_text);
235 rw->info_text= info_text?BLI_strdup(info_text):NULL;
238 static void renderwin_reset_view(RenderWin *rw)
242 if (rw->info_text) renderwin_set_infotext(rw, NULL);
244 /* now calculate a zoom for when image is larger than window */
245 window_get_size(rw->win, &w, &h);
248 if(rw->rectx>w || rw->recty>h) {
249 if(rw->rectx-w > rw->recty-h) rw->zoom= ((float)w)/((float)rw->rectx);
250 else rw->zoom= ((float)h)/((float)rw->recty);
254 rw->zoomofs[0]= rw->zoomofs[1]= 0;
255 renderwin_queue_redraw(rw);
258 static void renderwin_draw_render_info(RenderWin *rw)
260 /* render text is added to top */
265 window_get_size(rw->win, &rect.xmax, &rect.ymax);
267 rect.ymin= rect.ymax-RW_HEADERY;
268 glEnable(GL_SCISSOR_TEST);
269 glaDefine2DArea(&rect);
271 /* clear header rect */
272 BIF_SetTheme(NULL); // sets view3d theme by default
273 BIF_GetThemeColor3fv(TH_HEADER, colf);
274 glClearColor(colf[0], colf[1], colf[2], 1.0);
275 glClear(GL_COLOR_BUFFER_BIT);
277 if(rw->render_text) {
278 BIF_ThemeColor(TH_TEXT);
279 glRasterPos2i(12, 5);
280 BMF_DrawString(G.fonts, rw->render_text);
283 BIF_SetTheme(curarea); // restore theme
288 static void renderwin_draw(RenderWin *rw, int just_clear)
292 RE_GetResultImage(RE_GetRender("Render"), &rres);
295 float fullrect[2][2];
296 int set_back_mainwindow;
299 /* since renderwin uses callbacks (controlled by ghost) it can
300 mess up active window output with redraw events after a render.
301 this is patchy, still WIP */
302 set_back_mainwindow = (winlay_get_active_window() != rw->win);
303 window_make_active(rw->win);
305 rect.xmin= rect.ymin= 0;
306 window_get_size(rw->win, &rect.xmax, &rect.ymax);
307 rect.ymax-= RW_HEADERY;
309 renderwin_get_fullrect(rw, fullrect);
311 /* do this first, so window ends with correct scissor */
312 renderwin_draw_render_info(rw);
314 glEnable(GL_SCISSOR_TEST);
315 glaDefine2DArea(&rect);
317 glClearColor(.1875, .1875, .1875, 1.0);
318 glClear(GL_COLOR_BUFFER_BIT);
322 glRectfv(fullrect[0], fullrect[1]);
324 glPixelZoom(rw->zoom, rw->zoom);
325 if(rw->flags & RW_FLAGS_ALPHA) {
326 /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
327 // glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
328 // glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rr->rectx, rr->recty, GL_LUMINANCE, GL_UNSIGNED_INT, R.rectot);
329 // glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
333 glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rres.rect32);
335 glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_FLOAT, rres.rectf);
337 glPixelZoom(1.0, 1.0);
340 /* info text is overlayed on bottom */
343 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
345 w=186.0*strlen(rw->info_text)/30;
346 glColor4f(.5,.5,.5,.25);
347 glRectf(0.0,0.0,w,30.0);
349 glColor3ub(255, 255, 255);
350 glRasterPos2i(10, 10);
351 BMF_DrawString(G.font, rw->info_text);
354 window_swap_buffers(rw->win);
356 if (set_back_mainwindow) mainwindow_make_active();
360 /* ------ interactivity calls for RenderWin ------------- */
362 static void renderwin_mouse_moved(RenderWin *rw)
366 RE_GetResultImage(RE_GetRender("Render"), &rres);
368 if (rw->flags & RW_FLAGS_PIXEL_EXAMINING) {
373 if (renderwin_win_to_image_co(rw, rw->lmouse, imgco)) {
375 pxl= (char*) &rres.rect32[rres.rectx*imgco[1] + imgco[0]];
376 ofs= sprintf(buf, "R: %d G: %d B: %d A: %d", pxl[0], pxl[1], pxl[2], pxl[3]);
379 float *pxlf= rres.rectf + 4*(rres.rectx*imgco[1] + imgco[0]);
380 ofs+= sprintf(buf+ofs, " | R: %.3f G: %.3f B: %.3f A: %.3f ", pxlf[0], pxlf[1], pxlf[2], pxlf[3]);
383 float *pxlz= &rres.rectz[rres.rectx*imgco[1] + imgco[0]];
384 sprintf(buf+ofs, "| Z: %.3f", *pxlz );
387 renderwin_set_infotext(rw, buf);
388 renderwin_queue_redraw(rw);
390 renderwin_set_infotext(rw, NULL);
391 renderwin_queue_redraw(rw);
394 else if (rw->flags & RW_FLAGS_PANNING) {
395 int delta_x= rw->lmouse[0] - rw->pan_mouse_start[0];
396 int delta_y= rw->lmouse[1] - rw->pan_mouse_start[1];
398 rw->zoomofs[0]= rw->pan_ofs_start[0] - delta_x/rw->zoom;
399 rw->zoomofs[1]= rw->pan_ofs_start[1] - delta_y/rw->zoom;
400 rw->zoomofs[0]= CLAMPIS(rw->zoomofs[0], -rres.rectx/2, rres.rectx/2);
401 rw->zoomofs[1]= CLAMPIS(rw->zoomofs[1], -rres.recty/2, rres.recty/2);
403 renderwin_queue_redraw(rw);
405 else if (rw->flags & RW_FLAGS_OLDZOOM) {
409 window_get_size(rw->win, &w, &h);
411 renderwin_win_to_ndc(rw, rw->lmouse, ndc);
413 rw->zoomofs[0]= -0.5*ndc[0]*(w-rres.rectx*rw->zoom)/rw->zoom;
414 rw->zoomofs[1]= -0.5*ndc[1]*(h-rres.recty*rw->zoom)/rw->zoom;
416 renderwin_queue_redraw(rw);
420 static void renderwin_mousebut_changed(RenderWin *rw)
423 rw->flags|= RW_FLAGS_PIXEL_EXAMINING;
425 else if (rw->mbut[1]) {
426 rw->flags|= RW_FLAGS_PANNING;
427 rw->pan_mouse_start[0]= rw->lmouse[0];
428 rw->pan_mouse_start[1]= rw->lmouse[1];
429 rw->pan_ofs_start[0]= rw->zoomofs[0];
430 rw->pan_ofs_start[1]= rw->zoomofs[1];
433 if (rw->flags & RW_FLAGS_PANNING) {
434 rw->flags &= ~RW_FLAGS_PANNING;
435 renderwin_queue_redraw(rw);
437 if (rw->flags & RW_FLAGS_PIXEL_EXAMINING) {
438 rw->flags&= ~RW_FLAGS_PIXEL_EXAMINING;
439 renderwin_set_infotext(rw, NULL);
440 renderwin_queue_redraw(rw);
446 /* handler for renderwin, passed on to Ghost */
447 static void renderwin_handler(Window *win, void *user_data, short evt, short val, char ascii)
449 RenderWin *rw= user_data;
451 // added this for safety, while render it's just creating bezerk results
453 if(evt==ESCKEY && val)
454 rw->flags|= RW_FLAGS_ESCAPE;
459 renderwin_reshape(rw);
461 else if (evt==REDRAW) {
462 renderwin_draw(rw, 0);
464 else if (evt==WINCLOSE) {
465 BIF_close_render_display();
467 else if (evt==INPUTCHANGE) {
470 if (!val && (rw->flags&RW_FLAGS_OLDZOOM)) {
471 rw->flags&= ~RW_FLAGS_OLDZOOM;
472 renderwin_reset_view(rw);
475 else if (ELEM(evt, MOUSEX, MOUSEY)) {
476 rw->lmouse[evt==MOUSEY]= val;
477 renderwin_mouse_moved(rw);
479 else if (ELEM3(evt, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
480 int which= (evt==LEFTMOUSE)?0:(evt==MIDDLEMOUSE)?1:2;
481 rw->mbut[which]= val;
482 renderwin_mousebut_changed(rw);
486 if (rw->flags&RW_FLAGS_OLDZOOM) {
487 rw->flags&= ~RW_FLAGS_OLDZOOM;
488 renderwin_reset_view(rw);
491 rw->flags|= RW_FLAGS_ESCAPE;
493 mainwindow_make_active();
497 else if( evt==AKEY) {
498 rw->flags ^= RW_FLAGS_ALPHA;
499 renderwin_queue_redraw(render_win);
501 else if (evt==JKEY) {
502 // if(R.flag==0) BIF_swap_render_rects();
504 else if (evt==ZKEY) {
505 if (rw->flags&RW_FLAGS_OLDZOOM) {
506 rw->flags&= ~RW_FLAGS_OLDZOOM;
507 renderwin_reset_view(rw);
510 rw->flags|= RW_FLAGS_OLDZOOM;
511 renderwin_mouse_moved(rw);
514 else if (evt==PADPLUSKEY) {
516 if(rw->zoom>0.5 && rw->zoom<1.0) rw->zoom= 1.0;
518 renderwin_queue_redraw(rw);
521 else if (evt==PADMINUS) {
523 if(rw->zoom>1.0 && rw->zoom<2.0) rw->zoom= 1.0;
525 renderwin_queue_redraw(rw);
528 else if (evt==PADENTER || evt==HOMEKEY) {
529 if (rw->flags&RW_FLAGS_OLDZOOM) {
530 rw->flags&= ~RW_FLAGS_OLDZOOM;
532 renderwin_reset_view(rw);
534 else if (evt==F3KEY) {
536 // mainwindow_raise();
537 // mainwindow_make_active();
539 // areawinset(find_biggest_area()->win);
540 // BIF_save_rendered_image_fs();
543 else if (evt==F11KEY) {
544 BIF_toggle_render_display();
546 else if (evt==F12KEY) {
547 /* if it's rendering, this flag is set */
548 // if(R.flag==0) BIF_do_render(0);
553 static char *renderwin_get_title(int doswap)
561 if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render (spare)";
562 else title = "Blender:Render (spare)";
565 if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render";
566 else title = "Blender:Render";
572 /* opens window and allocs struct */
573 static void open_renderwin(int winpos[2], int winsize[2], int imagesize[2])
575 extern void mywindow_build_and_set_renderwin( int orx, int ory, int sizex, int sizey); // mywindow.c
579 title= renderwin_get_title(0); /* 0 = no swap */
580 win= window_open(title, winpos[0], winpos[1], winsize[0], winsize[1]+RW_HEADERY, 0);
582 render_win= renderwin_alloc(win);
583 render_win->rectx= imagesize[0];
584 render_win->recty= imagesize[1];
586 /* Ghost calls handler */
587 window_set_handler(win, renderwin_handler, render_win);
589 winlay_process_events(0);
590 window_make_active(render_win->win);
591 winlay_process_events(0);
593 /* mywindow has to know about it too */
594 mywindow_build_and_set_renderwin(winpos[0], winpos[1], winsize[0], winsize[1]+RW_HEADERY);
595 /* and we should be able to draw 3d in it */
598 renderwin_draw(render_win, 1);
599 renderwin_draw(render_win, 1);
602 /* -------------- callbacks for render loop: Window (RenderWin) ----------------------- */
604 /* calculations for window size and position */
605 void calc_renderwin_rectangle(int rectx, int recty, int posmask, int renderpos_r[2], int rendersize_r[2])
607 int scr_w, scr_h, x, y, div= 0;
608 float ndc_x= 0.0, ndc_y= 0.0;
610 winlay_get_screensize(&scr_w, &scr_h);
612 rendersize_r[0]= rectx;
613 rendersize_r[1]= recty;
615 rendersize_r[0]= CLAMPIS(rendersize_r[0], 0, scr_w);
616 rendersize_r[1]= CLAMPIS(rendersize_r[1], 0, scr_h-RW_HEADERY);
618 for (y=-1; y<=1; y++) {
619 for (x=-1; x<=1; x++) {
620 if (posmask & (1<<((y+1)*3 + (x+1)))) {
633 renderpos_r[0]= (scr_w-rendersize_r[0])*(ndc_x*0.5 + 0.5);
635 /* 44 pixels is topbar and window header... awaiting better fixes in ghost :) */
636 rendersize_r[1]= CLAMPIS(rendersize_r[1], 0, scr_h-44-RW_HEADERY);
637 renderpos_r[1]= -44-RW_HEADERY+(scr_h-rendersize_r[1])*(ndc_y*0.5 + 0.5);
639 renderpos_r[1]= -RW_HEADERY+(scr_h-rendersize_r[1])*(ndc_y*0.5 + 0.5);
643 /* init renderwin, alloc/open/resize */
644 static void renderwin_init_display_cb(RenderResult *rr)
646 if (G.afbreek == 0) {
647 int rendersize[2], renderpos[2], imagesize[2];
649 calc_renderwin_rectangle(rr->rectx, rr->recty, G.winpos, renderpos, rendersize);
651 imagesize[0]= rr->rectx;
652 imagesize[1]= rr->recty;
655 open_renderwin(renderpos, rendersize, imagesize);
656 renderwin_reset_view(render_win); // incl. autozoom for large images
661 window_get_position(render_win->win, &win_x, &win_y);
662 window_get_size(render_win->win, &win_w, &win_h);
665 /* XXX, this is nasty and I guess bound to cause problems,
666 * but to ensure the window is at the user specified position
667 * and size we reopen the window all the time... we need
668 * a ghost _set_position to fix this -zr
671 /* XXX, well... it is nasty yes, and reopens windows each time on
672 subsequent renders. Better rule is to make it reopen only only
673 size change, and use the preferred position only on open_renderwin
676 if(rendersize[0]!= win_w || rendersize[1]!= win_h) {
677 BIF_close_render_display();
678 open_renderwin(renderpos, rendersize, imagesize);
681 window_raise(render_win->win);
682 window_make_active(render_win->win);
684 mywinset(2); // to assign scissor/viewport again in mywindow.c. is hackish yes, but otherwise it draws in header of button for ogl header
687 win_rct.xmin= win_rct.ymin= 0;
688 window_get_size(render_win->win, &win_rct.xmax, &win_rct.ymax);
689 win_rct.ymax-= RW_HEADERY;
690 glaDefine2DArea(&win_rct);
694 renderwin_reset_view(render_win);
695 render_win->flags&= ~RW_FLAGS_ESCAPE;
696 render_win->active= 1;
698 /* make sure we are in normal draw again */
699 render_win->flags &= ~RW_FLAGS_ALPHA;
705 /* callback for redraw render win */
706 static void renderwin_clear_display_cb(RenderResult *rr)
709 window_make_active(render_win->win);
710 renderwin_draw(render_win, 1);
714 /* XXX, this is not good, we do this without any regard to state
715 * ... better is to make this an optimization of a more clear
716 * implementation. the bug shows up when you do something like
717 * open the window, then draw part of the progress, then get
718 * a redraw event. whatever can go wrong will. -zr
720 * Note: blocked queue handling while rendering to prevent that (ton)
723 /* can get as well the full picture, as the parts while rendering */
724 static void renderwin_progress(RenderWin *rw, RenderResult *rr, rcti *unused)
727 float *rectf, fullrect[2][2];
729 /* renderwindow cruft */
730 win_rct.xmin= win_rct.ymin= 0;
731 window_get_size(rw->win, &win_rct.xmax, &win_rct.ymax);
732 win_rct.ymax-= RW_HEADERY;
733 renderwin_get_fullrect(rw, fullrect);
735 /* find current float rect for display, first case is after composit... still weak */
739 RenderLayer *rl= rr->layers.first;
742 /* when rendering more pixels than needed, we crop away cruft */
744 rectf+= 4*(rr->crop*rr->rectx + rr->crop);
746 /* tilerect defines drawing offset from (0,0) */
747 /* however, tilerect (xmin, ymin) is first pixel */
748 fullrect[0][0] += (rr->tilerect.xmin+rr->crop)*rw->zoom;
749 fullrect[0][1] += (rr->tilerect.ymin+rr->crop)*rw->zoom;
751 glEnable(GL_SCISSOR_TEST);
752 glaDefine2DArea(&win_rct);
754 glDrawBuffer(GL_FRONT);
755 glPixelZoom(rw->zoom, rw->zoom);
756 glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rr->rectx-2*rr->crop, rr->recty-2*rr->crop, rr->rectx,
757 GL_RGBA, GL_FLOAT, rectf);
758 glPixelZoom(1.0, 1.0);
760 glDrawBuffer(GL_BACK);
764 /* in render window; display a couple of scanlines of rendered image */
765 static void renderwin_progress_display_cb(RenderResult *rr, rcti *rect)
768 renderwin_progress(render_win, rr, rect);
772 /* -------------- callbacks for render loop: interactivity ----------------------- */
775 /* callback for print info in top header of renderwin */
776 static void printrenderinfo_cb(RenderStats *rs)
778 extern char info_time_str[32]; // header_info.c
779 extern int mem_in_use;
780 static float megs_used_memory;
781 char str[300], *spos= str;
784 megs_used_memory= mem_in_use/(1024.0*1024.0);
787 spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d Ha:%d La:%d Mem:%.2fM", (G.scene->r.cfra), rs->totvert, rs->totface, rs->tothalo, rs->totlamp, megs_used_memory);
789 spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d La:%d Mem:%.2fM", (G.scene->r.cfra), rs->totvert, rs->totface, rs->totlamp, megs_used_memory);
791 BLI_timestr(rs->lastframetime, info_time_str);
792 spos+= sprintf(spos, " Time:%s ", info_time_str);
795 if(render_win->render_text) MEM_freeN(render_win->render_text);
796 render_win->render_text= BLI_strdup(str);
797 glDrawBuffer(GL_FRONT);
798 renderwin_draw_render_info(render_win);
800 glDrawBuffer(GL_BACK);
805 /* -------------- callback system to allow ESC from rendering ----------------------- */
807 /* POSIX & WIN32: this function is called all the time, and should not use cpu or resources */
808 static int test_break(void)
811 if(G.afbreek==2) { /* code for testing queue */
815 blender_test_break(); /* tests blender interface */
817 if (G.afbreek==0 && render_win) { /* tests window */
818 winlay_process_events(0);
819 // render_win can be closed in winlay_process_events()
820 if (render_win == 0 || (render_win->flags & RW_FLAGS_ESCAPE)) {
826 if(G.afbreek==1) return 1;
833 /* we use the multimedia time here */
834 static UINT uRenderTimerId;
836 void CALLBACK interruptESC(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
838 if(G.afbreek==0) G.afbreek= 2; /* code for read queue */
841 /* WIN32: init SetTimer callback */
842 static void init_test_break_callback()
845 uRenderTimerId = timeSetEvent(250, 1, interruptESC, 0, TIME_PERIODIC);
848 /* WIN32: stop SetTimer callback */
849 static void end_test_break_callback()
852 timeKillEvent(uRenderTimerId);
856 /* all other OS's support signal(SIGVTALRM) */
858 /* POSIX: this function goes in the signal() callback */
859 static void interruptESC(int sig)
862 if(G.afbreek==0) G.afbreek= 2; /* code for read queue */
864 /* call again, timer was reset */
865 signal(SIGVTALRM, interruptESC);
868 /* POSIX: initialize timer and signal */
869 static void init_test_break_callback()
872 struct itimerval tmevalue;
874 tmevalue.it_interval.tv_sec = 0;
875 tmevalue.it_interval.tv_usec = 250000;
876 /* wanneer de eerste ? */
877 tmevalue.it_value.tv_sec = 0;
878 tmevalue.it_value.tv_usec = 10000;
880 signal(SIGVTALRM, interruptESC);
881 setitimer(ITIMER_VIRTUAL, &tmevalue, 0);
885 /* POSIX: stop timer and callback */
886 static void end_test_break_callback()
888 struct itimerval tmevalue;
890 tmevalue.it_value.tv_sec = 0;
891 tmevalue.it_value.tv_usec = 0;
892 setitimer(ITIMER_VIRTUAL, &tmevalue, 0);
893 signal(SIGVTALRM, SIG_IGN);
902 /* -------------- callbacks for render loop: init & run! ----------------------- */
905 /* - initialize displays
910 static void do_render(int anim)
912 Render *re= RE_NewRender("Render");
914 /* we set this flag to prevent renderwindow queue to execute another render */
919 RE_display_init_cb(re, renderwin_init_display_cb);
920 RE_display_draw_cb(re, renderwin_progress_display_cb);
921 RE_display_clear_cb(re, renderwin_clear_display_cb);
922 init_test_break_callback();
923 RE_test_break_cb(re, test_break);
924 RE_timecursor_cb(re, set_timecursor);
925 RE_stats_draw_cb(re, printrenderinfo_cb);
927 if(render_win) window_set_cursor(render_win->win, CURSOR_WAIT);
931 exit_editmode(0); /* 0 = no free data */
934 RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
936 RE_BlenderFrame(re, G.scene, G.scene->r.cfra);
938 if(render_win) window_set_cursor(render_win->win, CURSOR_STD);
940 free_filesel_spec(G.scene->r.pic);
943 end_test_break_callback();
945 mainwindow_make_active();
947 /* after an envmap creation... */
948 // if(R.flag & R_REDRAW_PRV) {
949 // BIF_preview_changed(ID_TE);
951 allqueue(REDRAWBUTSSCENE, 0); // visualize fbuf for example
953 // before scene update!
956 scene_update_for_newframe(G.scene, G.scene->lay); // no redraw needed, this restores to view as we left it
958 waitcursor(0); // waitcursor checks rendering R.flag...
962 /* used for swapping with spare buffer, when images are different size */
963 static void scalefastrect(unsigned int *recto, unsigned int *rectn, int oldx, int oldy, int newx, int newy)
965 unsigned int *rect, *newrect;
967 int ofsx, ofsy, stepx, stepy;
969 stepx = (int)((65536.0 * (oldx - 1.0) / (newx - 1.0)) + 0.5);
970 stepy = (int)((65536.0 * (oldy - 1.0) / (newy - 1.0)) + 0.5);
974 for (y = newy; y > 0 ; y--){
976 rect += (ofsy >> 16) * oldx;
979 for (x = newx ; x>0 ; x--){
980 *newrect++ = rect[ofsx >> 16];
986 /* -------------- API: externally called --------------- */
988 /* not used anywhere ??? */
990 void BIF_renderwin_make_active(void)
993 window_make_active(render_win->win);
999 /* set up display, render an image or scene */
1000 void BIF_do_render(int anim)
1004 if (G.f & G_DOSCRIPTLINKS) {
1005 BPY_do_all_scripts(SCRIPT_RENDER);
1006 if (!anim) { /* avoid FRAMECHANGED slink in render callback */
1007 G.f &= ~G_DOSCRIPTLINKS;
1012 /* if start render in 3d win, use layer from window (e.g also local view) */
1013 if(curarea && curarea->spacetype==SPACE_VIEW3D) {
1014 int lay= G.scene->lay;
1015 if(G.vd->lay & 0xFF000000) // localview
1016 G.scene->lay |= G.vd->lay;
1017 else G.scene->lay= G.vd->lay;
1023 else do_render(anim);
1025 if(G.scene->use_nodes)
1026 allqueue(REDRAWNODE, 1);
1027 if (slink_flag) G.f |= G_DOSCRIPTLINKS;
1028 if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_POSTRENDER);
1031 /* set up display, render the current area view in an image */
1032 /* the RE_Render is only used to make sure we got the picture in the result */
1033 void BIF_do_ogl_render(View3D *v3d, int anim)
1035 Render *re= RE_NewRender("Render");
1040 init_test_break_callback();
1042 winx= (G.scene->r.size*G.scene->r.xsch)/100;
1043 winy= (G.scene->r.size*G.scene->r.ysch)/100;
1045 RE_InitState(re, &G.scene->r, winx, winy, NULL);
1047 /* for now, result is defaulting to floats still... */
1048 rr= RE_GetResult(re);
1049 if(rr->rect32==NULL)
1050 rr->rect32= MEM_mallocN(sizeof(int)*winx*winy, "32 bits rects");
1053 renderwin_init_display_cb(rr);
1059 bMovieHandle *mh= BKE_get_movie_handle(G.scene->r.imtype);
1062 mh->start_movie(&G.scene->r, winx, winy);
1064 for(CFRA= SFRA; CFRA<=EFRA; CFRA++) {
1065 drawview3d_render(v3d, winx, winy);
1066 glReadPixels(0, 0, winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, rr->rect32);
1067 window_swap_buffers(render_win->win);
1069 mh->append_movie(CFRA, rr->rect32, winx, winy);
1070 if(test_break()) break;
1076 drawview3d_render(v3d, winx, winy);
1077 glReadPixels(0, 0, winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, rr->rect32);
1078 window_swap_buffers(render_win->win);
1081 mainwindow_make_active();
1084 scene_update_for_newframe(G.scene, G.scene->lay); // no redraw needed, this restores to view as we left it
1086 end_test_break_callback();
1090 void BIF_redraw_render_rect(void)
1094 renderwin_queue_redraw(render_win);
1098 void BIF_swap_render_rects(void)
1103 if(R.rectspare==0) {
1104 R.rectspare= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot");
1108 else if(R.sparex!=R.rectx || R.sparey!=R.recty) {
1109 temp= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot");
1111 scalefastrect(R.rectspare, temp, R.sparex, R.sparey, R.rectx, R.recty);
1112 MEM_freeN(R.rectspare);
1120 R.rectot= R.rectspare;
1124 char *tmp= render_win->render_text_spare;
1125 render_win->render_text_spare= render_win->render_text;
1126 render_win->render_text= tmp;
1128 window_set_title(render_win->win, renderwin_get_title(1));
1133 BIF_redraw_render_rect();
1137 /* called from usiblender.c too, to free and close renderwin */
1138 void BIF_close_render_display(void)
1141 if (render_win->info_text) MEM_freeN(render_win->info_text);
1142 if (render_win->render_text) MEM_freeN(render_win->render_text);
1143 if (render_win->render_text_spare) MEM_freeN(render_win->render_text_spare);
1145 window_destroy(render_win->win); /* ghost close window */
1146 MEM_freeN(render_win);
1153 /* typical with F11 key, show image or hide/close */
1154 void BIF_toggle_render_display(void)
1158 if(render_win->active) {
1160 mainwindow_make_active();
1161 render_win->active= 0;
1164 window_raise(render_win->win);
1165 window_make_active(render_win->win);
1166 render_win->active= 1;
1170 RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
1171 if(rr) renderwin_init_display_cb(rr);
1175 void BIF_renderwin_set_custom_cursor(unsigned char mask[16][2], unsigned char bitmap[16][2])
1178 window_set_custom_cursor(render_win->win, mask, bitmap, 7, 7);