/** * $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ /* Global includes */ #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif #ifdef WIN32 #include "BLI_winstuff.h" #endif #include "blendef.h" #include "MEM_guardedalloc.h" #include "PIL_time.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BLI_rand.h" #include "MTC_matrixops.h" #include "DNA_image_types.h" #include "DNA_camera_types.h" #include "DNA_lamp_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_material.h" #include "BKE_object.h" #include "BKE_image.h" #include "BKE_ipo.h" #include "BKE_key.h" #include "BKE_ika.h" #include "BKE_action.h" #include "BKE_writeavi.h" #include "BKE_scene.h" #include "BIF_toolbox.h" #include "BIF_writeavicodec.h" #include "BIF_writemovie.h" /* start_movie(), append_movie(), end_movie() */ #include "BSE_drawview.h" #include "BSE_sequence.h" #ifdef WITH_QUICKTIME #include "quicktime_export.h" #endif /* this module */ #include "render.h" #include "render_intern.h" #include "RE_callbacks.h" #include "zbuf.h" #include "rendercore.h" /* part handler for the old renderer, shading functions */ #include "renderPreAndPost.h" #include "vanillaRenderPipe.h" #include "renderHelp.h" #include "jitter.h" /* Own includes */ #include "initrender.h" /* yafray: include for yafray export/render */ #include "YafRay_Api.h" /* Some crud :/ */ #define ELEM3(a, b, c, d) ( ELEM(a, b, c) || (a)==(d) ) /* from render.c */ extern float fmask[256], centLut[16]; extern unsigned short *mask1[9], *mask2[9], /* *igamtab1, */ *igamtab2/*, *gamtab */; extern char cmask[256], *centmask; Material defmaterial; short pa; /* pa is global part, for print */ short allparts[65][4]; int qscount; /* ********************* *********************** */ void init_def_material(void) { Material *ma; ma= &defmaterial; init_material(&defmaterial); init_render_material(ma); } void RE_init_render_data(void) { memset(&R, 0, sizeof(RE_Render)); memset(&O, 0, sizeof(Osa)); O.dxwin[0]= 1.0; O.dywin[1]= 1.0; R.blove= (VertRen **)MEM_callocN(sizeof(void *)*(TABLEINITSIZE),"Blove"); R.blovl= (VlakRen **)MEM_callocN(sizeof(void *)*(TABLEINITSIZE),"Blovl"); R.bloha= (HaloRen **)MEM_callocN(sizeof(void *)*(TABLEINITSIZE),"Bloha"); R.la= (LampRen **)MEM_mallocN(LAMPINITSIZE*sizeof(void *),"renderlamparray"); init_def_material(); } void RE_free_render_data() { MEM_freeN(R.blove); R.blove= 0; MEM_freeN(R.blovl); R.blovl= 0; MEM_freeN(R.bloha); R.bloha= 0; MEM_freeN(R.la); R.la= 0; if(R.rectot) MEM_freeN(R.rectot); if(R.rectz) MEM_freeN(R.rectz); if(R.rectspare) MEM_freeN(R.rectspare); R.rectot= 0; R.rectz= 0; R.rectspare= 0; end_render_material(&defmaterial); } /* ****************** GAMMA, MASKS and LUTS **************** */ float calc_weight(float *weight, int i, int j) { float x, y, dist, totw= 0.0, fac; int a; fac= R.r.gauss*R.r.gauss; fac*= fac; for(a=0; a0; a--) { val= count_mask(a); i= 8+(15.9*(fpy1[a & 255]+fpy2[a>>8])/val); CLAMP(i, 0, 15); j= 8+(15.9*(fpx1[a & 255]+fpx2[a>>8])/val); CLAMP(j, 0, 15); i= j + (i<<4); centmask[a]= i; } MEM_freeN(fpx1); MEM_freeN(fpx2); MEM_freeN(fpy1); MEM_freeN(fpy2); } void RE_free_filt_mask() { int a; for(a=0; a<9; a++) { MEM_freeN(mask1[a]); MEM_freeN(mask2[a]); } MEM_freeN(gamtab); MEM_freeN(igamtab1); MEM_freeN(igamtab2); MEM_freeN(centmask); } /* add stuff */ void defaultlamp() { LampRen *lar; lar= (LampRen *)MEM_callocN(sizeof(LampRen),"lampren"); R.la[R.totlamp++]=lar; lar->type= LA_SUN; lar->vec[0]= -R.viewmat[2][0]; lar->vec[1]= -R.viewmat[2][1]; lar->vec[2]= -R.viewmat[2][2]; Normalise(lar->vec); lar->r= 1.0; lar->g= 1.0; lar->b= 1.0; lar->lay= 65535; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void RE_make_existing_file(char *name) { char di[FILE_MAXDIR], fi[FILE_MAXFILE]; strcpy(di, name); BLI_splitdirstring(di, fi); /* test exist */ if (BLI_exists(di) == 0) { BLI_recurdir_fileops(di); } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void RE_setwindowclip(int mode, int jmode) { extern float bluroffsx, bluroffsy; // rendercore.c... hackish (ton) Camera *cam=0; float lens, minx, miny, maxx, maxy; float xd, yd, afmx, afmy; if(G.scene->camera==0) return; afmx= R.afmx; afmy= R.afmy; if(mode) { if(G.scene->camera->type==OB_LAMP) { /* fac= cos( PI*((float)(256- la->spsi))/512.0 ); */ /* phi= acos(fac); */ /* lens= 16.0*fac/sin(phi); */ lens= 35.0; R.near= 0.1; R.far= 1000.0; } else if(G.scene->camera->type==OB_CAMERA) { cam= G.scene->camera->data; lens= cam->lens; R.near= cam->clipsta; R.far= cam->clipend; } else { lens= 16.0; } if( (R.r.xasp*afmx) >= (R.r.yasp*afmy) ) { R.viewfac= (afmx*lens)/16.0; } else { R.viewfac= R.ycor*(afmy*lens)/16.0; } if(R.r.mode & R_ORTHO) { R.near*= 100.0; R.viewfac*= 100.0; } R.pixsize= R.near/R.viewfac; } /* revision / simplification of subpixel offsets: - the matrix will go without offset from start (e.g. -100) to end (e.g. +99). - filling in with zbuffer will set offset of 0.5. to make sure clipped faces fill in too - in shadepixel() again that 0.5 offset is corrected */ minx= R.xstart; miny= R.ycor*(R.ystart); maxx= R.xend; maxy= R.ycor*(R.yend); if(R.flag & R_SEC_FIELD) { if(R.r.mode & R_ODDFIELD) { miny-= .5*R.ycor; maxy-= .5*R.ycor; } else { miny+= .5*R.ycor; maxy+= .5*R.ycor; } } xd= yd= 0.0; if(jmode!= -1) { bluroffsx= xd= jit[jmode % R.osa][0]; bluroffsy= yd= R.ycor*jit[jmode % R.osa][1]; } else bluroffsx=bluroffsy= 0.0; minx= R.pixsize*(minx+xd); maxx= R.pixsize*(maxx+xd); miny= R.pixsize*(miny+yd); maxy= R.pixsize*(maxy+yd); if(R.r.mode & R_ORTHO) { i_window(minx, maxx, miny, maxy, R.near, 100.0*R.far, R.winmat); } else i_window(minx, maxx, miny, maxy, R.near, R.far, R.winmat); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void initparts() { short nr, xd, yd, xpart, ypart, xparts, yparts; short a, xminb, xmaxb, yminb, ymaxb; if(R.r.mode & R_BORDER) { xminb= R.r.border.xmin*R.rectx; xmaxb= R.r.border.xmax*R.rectx; yminb= R.r.border.ymin*R.recty; ymaxb= R.r.border.ymax*R.recty; if(xminb<0) xminb= 0; if(xmaxb>R.rectx) xmaxb= R.rectx; if(yminb<0) yminb= 0; if(ymaxb>R.recty) ymaxb= R.recty; } else { xminb=yminb= 0; xmaxb= R.rectx; ymaxb= R.recty; } xparts= R.r.xparts; /* for border */ yparts= R.r.yparts; for(nr=0;nrrect; len= (allparts[nr][2]-allparts[nr][0]); heigth= (allparts[nr][3]-allparts[nr][1]); for(y=0;y>8; rtb[0]= gamtab[ gamval ]>>8; gamval= (facr* igamtab2[ rtr[1]<<8 ] + facb* igamtab2[ rtb[1]<<8 ])>>8; rtb[1]= gamtab[ gamval ]>>8; gamval= (facr* igamtab2[ rtr[2]<<8 ] + facb* igamtab2[ rtb[2]<<8 ])>>8; rtb[2]= gamtab[ gamval ]>>8; gamval= (facr* igamtab2[ rtr[3]<<8 ] + facb* igamtab2[ rtb[3]<<8 ])>>8; rtb[3]= gamtab[ gamval ]>>8; } else { rtb[0]= (facr*rtr[0] + facb*rtb[0])>>8; rtb[1]= (facr*rtr[1] + facb*rtb[1])>>8; rtb[2]= (facr*rtr[2] + facb*rtb[2])>>8; rtb[3]= (facr*rtr[3] + facb*rtb[3])>>8; } } rtr+= 4; rtb+= 4; } } if(blur==0) { /* last time */ if(R.rectot) MEM_freeN(R.rectot); R.rectot= blurrect; blurrect= 0; } } } /* yafray: main yafray render/export call */ void yafrayRender() { R.flag |= R_RENDERING; /* !!! */ if (R.rectz) MEM_freeN(R.rectz); R.rectz = 0; // switch must be done before prepareScene() if (!R.r.YFexportxml) YAF_switchFile(); else YAF_switchPlugin(); printf("Starting scene conversion.\n"); prepareScene(); printf("Scene conversion done.\n"); YAF_exportScene(); finalizeScene(); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void render() { /* yafray: render, see above */ if (R.r.renderer==R_YAFRAY) yafrayRender(); else oldRenderLoop(); } void oldRenderLoop(void) /* here the PART and FIELD loops */ { Part *part; unsigned int *rt, *rt1, *rt2; int len, y; short blur, a,fields,fi,parts; /* pa is a global because of print */ if (R.rectz) MEM_freeN(R.rectz); R.rectz = 0; /* FIELD LOOP */ fields= 1; parts= R.r.xparts*R.r.yparts; if(R.r.mode & R_FIELDS) { fields= 2; R.rectf1= R.rectf2= 0; /* field rects */ R.r.ysch/= 2; R.afmy/= 2; R.r.yasp*= 2; R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp); } for(fi=0; fir.cfra)+fi); R.flag|= R_RENDERING; if(fi==1) R.flag |= R_SEC_FIELD; /* MOTIONBLUR loop */ if(R.r.mode & R_MBLUR) blur= R.osa; else blur= 1; while(blur--) { /* WINDOW */ R.rectx= R.r.xsch; R.recty= R.r.ysch; R.xstart= -R.afmx; R.ystart= -R.afmy; R.xend= R.xstart+R.rectx-1; R.yend= R.ystart+R.recty-1; if(R.r.mode & R_MBLUR) set_mblur_offs(R.osa-blur); initparts(); /* always do, because of border */ setpart(0); RE_local_init_render_display(); RE_local_clear_render_display(R.win); RE_local_timecursor((G.scene->r.cfra)); prepareScene(); /* PARTS */ R.parts.first= R.parts.last= 0; for(pa=0; pa1 || (R.r.mode & R_BORDER)) { part= MEM_callocN(sizeof(Part), "part"); BLI_addtail(&R.parts, part); part->rect= R.rectot; R.rectot= NULL; if (R.rectz) { MEM_freeN(R.rectz); R.rectz= NULL; } } } if(RE_local_test_break()) break; } /* JOIN PARTS OR INSERT BORDER */ /* exception: crop */ if( (R.r.mode & R_BORDER) && (R.r.mode & R_MOVIECROP)) ; else { R.rectx= R.r.xsch; R.recty= R.r.ysch; if(R.r.mode & R_PANORAMA) R.rectx*= R.r.xparts; if(parts>1 || (R.r.mode & R_BORDER)) { if(R.rectot) MEM_freeN(R.rectot); R.rectot=(unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); part= R.parts.first; for(pa=0; panext; } part= R.parts.first; while(part) { MEM_freeN(part->rect); part= part->next; } BLI_freelistN(&R.parts); } } if( (R.flag & R_HALO)) { if(RE_local_test_break()==0) add_halo_flare(); } if(R.r.mode & R_MBLUR) { add_to_blurbuf(blur); } /* END (blur loop) */ finalizeScene(); if(RE_local_test_break()) break; } /* definite free */ add_to_blurbuf(-1); /* HANDLE FIELD */ if(R.r.mode & R_FIELDS) { if(R.flag & R_SEC_FIELD) R.rectf2= R.rectot; else R.rectf1= R.rectot; R.rectot= 0; } if(RE_local_test_break()) break; } /* JOIN FIELDS */ if(R.r.mode & R_FIELDS) { R.r.ysch*= 2; R.afmy*= 2; R.recty*= 2; R.r.yasp/=2; if(R.rectot) MEM_freeN(R.rectot); /* happens when a render has been stopped */ R.rectot=(unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); if(RE_local_test_break()==0) { rt= R.rectot; if(R.r.mode & R_ODDFIELD) { rt2= R.rectf1; rt1= R.rectf2; } else { rt1= R.rectf1; rt2= R.rectf2; } len= 4*R.rectx; for(a=0; ar; R.r.postigamma= 1.0/R.r.postgamma; /* WINDOW size (sch='scherm' dutch for screen...) */ R.r.xsch= (R.r.size*R.r.xsch)/100; R.r.ysch= (R.r.size*R.r.ysch)/100; R.afmx= R.r.xsch/2; R.afmy= R.r.ysch/2; /* to be sure: when a premature return (rectx can differ from xsch) */ R.rectx= R.r.xsch; R.recty= R.r.ysch; /* IS RENDERING ALLOWED? */ /* forbidden combination */ if((R.r.mode & R_BORDER) && (R.r.mode & R_PANORAMA)) { error("No border allowed for Panorama"); G.afbreek= 1; return; } if(R.r.xparts*R.r.yparts>64) { error("No more than 64 parts"); G.afbreek= 1; return; } if(R.r.yparts>1 && (R.r.mode & R_PANORAMA)) { error("No Y-Parts allowed for Panorama"); G.afbreek= 1; return; } /* TEST BACKBUF */ /* If an image is specified for use as backdrop, that image is loaded */ /* here. */ if((R.r.bufflag & 1) && (G.scene->r.scemode & R_OGL)==0) { if(R.r.alphamode == R_ADDSKY) { strcpy(name, R.r.backbuf); BLI_convertstringcode(name, G.sce, G.scene->r.cfra); if(R.backbuf) { R.backbuf->id.us--; bima= R.backbuf; } else bima= 0; R.backbuf= add_image(name); if(bima && bima->id.us<1) { free_image_buffers(bima); } if(R.backbuf==0) { // error() doesnt work with render window open //error("No backbuf there!"); printf("Error: No backbuf %s\n", name); G.afbreek= 1; return; } } } usegamtab= 0; /* see also further */ if(R.r.mode & (R_OSA|R_MBLUR)) { R.osa= R.r.osa; if(R.osa>16) R.osa= 16; init_render_jit(R.osa); RE_init_filt_mask(); /* this value sometimes is reset temporally, for example in transp zbuf */ if(R.r.mode & R_GAMMA) { if((R.r.mode & R_OSA)) usegamtab= 1; } } else R.osa= 0; /* when rendered without camera object */ /* it has to done here because of envmaps */ R.near= 0.1; R.far= 1000.0; if(R.afmx<1 || R.afmy<1) { error("Image too small"); return; } R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp); start_time= PIL_check_seconds_timer(); if(R.r.scemode & R_DOSEQ) { R.rectx= R.r.xsch; R.recty= R.r.ysch; if(R.rectot) MEM_freeN(R.rectot); R.rectot= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); RE_local_timecursor((G.scene->r.cfra)); if(RE_local_test_break()==0) do_render_seq(); /* display */ if(R.rectot) RE_local_render_display(0, R.recty-1, R.rectx, R.recty, R.rectot); } else if(R.r.scemode & R_OGL) { R.rectx= R.r.xsch; R.recty= R.r.ysch; if(R.rectot) MEM_freeN(R.rectot); R.rectot= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); RE_local_init_render_display(); drawview3d_render(ogl_render_view3d); } else { if(G.scene->camera==0) { G.scene->camera= scene_find_camera(G.scene); } if(G.scene->camera==0) { error("No camera"); /* needed because R.rectx and R.recty can be unmatching R.rectot */ if(R.rectot) freeN(R.rectot); R.rectot= NULL; G.afbreek=1; return; } else { if(G.scene->camera->type==OB_CAMERA) { Camera *cam= G.scene->camera->data; if(cam->type==CAM_ORTHO) R.r.mode |= R_ORTHO; } render(); /* returns with complete rect xsch-ysch */ } } /* display again: fields/seq/parts/pano etc */ if(R.rectot) { RE_local_init_render_display(); RE_local_render_display(0, R.recty-1, R.rectx, R.recty, R.rectot); } else RE_local_clear_render_display(R.win); if ((G.scene->r.scemode & R_OGL)==0) /* header gets scrabled if renderwindow holds OGL context */ RE_local_printrenderinfo((PIL_check_seconds_timer() - start_time), -1); /* restore variables */ //R.osatex= 0; //R.vlr= 0; ///* at cubemap */ R.flag= 0; } void RE_animrender(struct View3D *ogl_render_view3d) { int cfrao; char name[256]; if(G.scene==0) return; /* scenedata to R: (for backbuf, R.rectx etc) */ R.r= G.scene->r; /* START ANIMLOOP, everywhere NOT the cfra from R.r is gebruikt: because of rest blender */ cfrao= (G.scene->r.cfra); if(G.scene->r.scemode & R_OGL) R.r.mode &= ~R_PANORAMA; // these calculations apply for // all movie formats R.rectx= (R.r.size*R.r.xsch)/100; R.recty= (R.r.size*R.r.ysch)/100; if(R.r.mode & R_PANORAMA) { R.rectx*= R.r.xparts; R.recty*= R.r.yparts; } if (0) { #ifdef __sgi } else if (R.r.imtype==R_MOVIE) { start_movie(); #endif #if defined(_WIN32) && !defined(FREE_WINDOWS) } else if (R.r.imtype == R_AVICODEC) { start_avi_codec(); #endif #if WITH_QUICKTIME } else if (R.r.imtype == R_QUICKTIME) { start_qt(); #endif } else if ELEM4(R.r.imtype, R_AVIRAW, R_AVIJPEG, R_MOVIE, R_AVICODEC) { if ELEM(R.r.imtype, R_MOVIE, R_AVICODEC) { printf("Selected movie format not supported on this platform,\nusing RAW AVI instead\n"); } start_avi(); } for((G.scene->r.cfra)=(G.scene->r.sfra); (G.scene->r.cfra)<=(G.scene->r.efra); (G.scene->r.cfra)++) { double starttime= PIL_check_seconds_timer(); R.flag= R_ANIMRENDER; RE_initrender(ogl_render_view3d); /* WRITE IMAGE */ if(RE_local_test_break()==0) { if (0) { #ifdef __sgi } else if (R.r.imtype == R_MOVIE) { append_movie((G.scene->r.cfra)); #endif #if defined(_WIN32) && !defined(FREE_WINDOWS) } else if (R.r.imtype == R_AVICODEC) { append_avi_codec((G.scene->r.cfra)); #endif #ifdef WITH_QUICKTIME } else if (R.r.imtype == R_QUICKTIME) { append_qt((G.scene->r.cfra)); #endif } else if ELEM4(R.r.imtype, R_AVIRAW, R_AVIJPEG, R_MOVIE, R_AVICODEC) { append_avi((G.scene->r.cfra)); } else { makepicstring(name, (G.scene->r.cfra)); schrijfplaatje(name); if(RE_local_test_break()==0) printf("Saved: %s", name); } timestr(PIL_check_seconds_timer()-starttime, name); printf(" Time: %s\n", name); fflush(stdout); /* needed for renderd !! */ } if(G.afbreek==1) break; } (G.scene->r.cfra)= cfrao; /* restore time */ if(R.r.mode & (R_FIELDS|R_MBLUR)) { do_all_ipos(); do_all_keys(); do_all_actions(); do_all_ikas(); } if (0) { #ifdef __sgi } else if (R.r.imtype==R_MOVIE) { end_movie(); #endif #if defined(_WIN32) && !defined(FREE_WINDOWS) } else if (R.r.imtype == R_AVICODEC) { end_avi_codec(); #endif #ifdef WITH_QUICKTIME } else if (R.r.imtype == R_QUICKTIME) { end_qt(); #endif } else if ELEM4(R.r.imtype, R_AVIRAW, R_AVIJPEG, R_MOVIE, R_AVICODEC) { end_avi(); } } /* *************************************************** */ /* ******************* Screendumps ******************** */ /* moved to the windowControl thing */