This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/render/intern/source/initrender.c

1392 lines
30 KiB
C
Raw Normal View History

2002-10-12 11:37:38 +00:00
/**
* $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 <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
2002-10-12 11:37:38 +00:00
#ifdef WIN32
#include "BLI_winstuff.h"
#endif
#include "blendef.h"
2002-10-12 11:37:38 +00:00
#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
2002-10-12 11:37:38 +00:00
/* 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"
2002-10-12 11:37:38 +00:00
#include "renderHelp.h"
#include "jitter.h"
/* Own includes */
#include "initrender.h"
/* yafray: include for yafray export/render */
#include "YafRay_Api.h"
2002-10-12 11:37:38 +00:00
/* Some crud :/ */
#define ELEM3(a, b, c, d) ( ELEM(a, b, c) || (a)==(d) )
2002-10-12 11:37:38 +00:00
/* from render.c */
extern float fmask[256], centLut[16], *fmask1[9], *fmask2[9];
extern unsigned short *mask1[9], *mask2[9], *igamtab2;
2002-10-12 11:37:38 +00:00
extern char cmask[256], *centmask;
Material defmaterial;
short pa; /* pa is global part, for print */
2002-10-12 11:37:38 +00:00
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");
2002-10-12 11:37:38 +00:00
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 **************** */
2002-10-12 11:37:38 +00:00
float calc_weight(float *weight, int i, int j)
{
float x, y, dist, totw= 0.0, fac;
2002-10-12 11:37:38 +00:00
int a;
fac= R.r.gauss*R.r.gauss;
fac*= fac;
2002-10-12 11:37:38 +00:00
for(a=0; a<R.osa; a++) {
x= jit[a][0] + i;
y= jit[a][1] + j;
2002-10-12 11:37:38 +00:00
dist= sqrt(x*x+y*y);
weight[a]= 0.0;
/* gaussian weighting */
if(R.r.mode & R_GAUSS) {
if(dist<R.r.gauss) {
x = dist*R.r.gauss;
weight[a]= (1.0/exp(x*x) - 1.0/exp(fac));
}
}
else {
2002-10-12 11:37:38 +00:00
if(i==0 && j==0) weight[a]= 1.0;
}
2002-10-12 11:37:38 +00:00
totw+= weight[a];
}
return totw;
}
void RE_init_filt_mask(void)
{
static int firsttime=1;
static int lastosa=0;
static int lastgauss=0;
2002-10-12 11:37:38 +00:00
static float lastgamma= 0.0;
float gamma, igamma, flweight[32];
float weight[32], totw, val, *fpx1, *fpx2, *fpy1, *fpy2, *m3, *m4;
2002-10-12 11:37:38 +00:00
int i, j, a;
unsigned short *m1, *m2, shweight[32];
if(firsttime) {
firsttime= 0;
2002-10-12 11:37:38 +00:00
for(a=0; a<9;a++) {
mask1[a]= MEM_mallocN(256*sizeof(short), "initfilt");
mask2[a]= MEM_mallocN(256*sizeof(short), "initfilt");
fmask1[a]= MEM_mallocN(256*sizeof(float), "initfilt");
fmask2[a]= MEM_mallocN(256*sizeof(float), "initfilt");
2002-10-12 11:37:38 +00:00
}
for(a=0; a<256; a++) {
cmask[a]= 0;
if(a & 1) cmask[a]++;
if(a & 2) cmask[a]++;
if(a & 4) cmask[a]++;
if(a & 8) cmask[a]++;
if(a & 16) cmask[a]++;
if(a & 32) cmask[a]++;
if(a & 64) cmask[a]++;
if(a & 128) cmask[a]++;
}
centmask= MEM_mallocN(65536, "Initfilt3");
for(a=0; a<16; a++) {
centLut[a]= -0.45+((float)a)/16.0;
}
gamtab= MEM_mallocN(65536*sizeof(short), "initGaus2");
igamtab1= MEM_mallocN(256*sizeof(short), "initGaus2");
igamtab2= MEM_mallocN(65536*sizeof(short), "initGaus2");
return; // this case is called on startup
2002-10-12 11:37:38 +00:00
}
if(R.r.alphamode==R_ALPHAKEY) gamma= 1.0; /* gamma correction of alpha is nasty */
2002-10-12 11:37:38 +00:00
if(R.r.mode & R_GAMMA) gamma= 2.0;
else gamma= 1.0;
igamma= 1.0/gamma;
if(gamma!= lastgamma) {
lastgamma= gamma;
/* gamtab: in short, out short */
2002-10-12 11:37:38 +00:00
for(a=0; a<65536; a++) {
val= a;
val/= 65535.0;
if(gamma==2.0) val= sqrt(val);
else if(gamma!=1.0) val= pow(val, igamma);
gamtab[a]= (65535.99*val);
}
/* inverse gamtab1 : in byte, out short */
2002-10-12 11:37:38 +00:00
for(a=1; a<=256; a++) {
if(gamma==2.0) igamtab1[a-1]= a*a-1;
else if(gamma==1.0) igamtab1[a-1]= 256*a-1;
else {
val= a/256.0;
igamtab1[a-1]= (65535.0*pow(val, gamma)) -1 ;
}
}
/* inverse gamtab2 : in short, out short */
2002-10-12 11:37:38 +00:00
for(a=0; a<65536; a++) {
val= a;
val/= 65535.0;
if(gamma==2.0) val= val*val;
else val= pow(val, gamma);
igamtab2[a]= 65535.0*val;
}
}
if(R.osa && (lastosa!=R.osa || lastgauss != (R.r.mode & R_GAUSS)) ) {
lastosa= R.osa;
lastgauss= R.r.mode & R_GAUSS;
val= 1.0/((float)R.osa);
for(a=0; a<256; a++) {
fmask[a]= ((float)cmask[a])*val;
}
2002-10-12 11:37:38 +00:00
for(a=0; a<9;a++) {
memset(mask1[a], 0, 256*2);
memset(mask2[a], 0, 256*2);
memset(fmask1[a], 0, 256*4);
memset(fmask2[a], 0, 256*4);
}
2002-10-12 11:37:38 +00:00
/* calculate totw */
totw= 0.0;
for(j= -1; j<2; j++) {
for(i= -1; i<2; i++) {
totw+= calc_weight(weight, i, j);
}
2002-10-12 11:37:38 +00:00
}
for(j= -1; j<2; j++) {
for(i= -1; i<2; i++) {
/* calculate using jit, with offset the weights */
2002-10-12 11:37:38 +00:00
memset(weight, 0, sizeof(weight));
calc_weight(weight, i, j);
2002-10-12 11:37:38 +00:00
for(a=0; a<16; a++) shweight[a]= weight[a]*(65535.0/totw);
for(a=0; a<16; a++) flweight[a]= weight[a]*(1.0/totw);
2002-10-12 11:37:38 +00:00
m1= mask1[ 3*(j+1)+i+1 ];
m2= mask2[ 3*(j+1)+i+1 ];
m3= fmask1[ 3*(j+1)+i+1 ];
m4= fmask2[ 3*(j+1)+i+1 ];
2002-10-12 11:37:38 +00:00
for(a=0; a<256; a++) {
if(a & 1) {
m1[a]+= shweight[0];
m2[a]+= shweight[8];
m3[a]+= flweight[0];
m4[a]+= flweight[8];
}
if(a & 2) {
m1[a]+= shweight[1];
m2[a]+= shweight[9];
m3[a]+= flweight[1];
m4[a]+= flweight[9];
}
if(a & 4) {
m1[a]+= shweight[2];
m2[a]+= shweight[10];
m3[a]+= flweight[2];
m4[a]+= flweight[10];
}
if(a & 8) {
m1[a]+= shweight[3];
m2[a]+= shweight[11];
m3[a]+= flweight[3];
m4[a]+= flweight[11];
}
if(a & 16) {
m1[a]+= shweight[4];
m2[a]+= shweight[12];
m3[a]+= flweight[4];
m4[a]+= flweight[12];
}
if(a & 32) {
m1[a]+= shweight[5];
m2[a]+= shweight[13];
m3[a]+= flweight[5];
m4[a]+= flweight[13];
}
if(a & 64) {
m1[a]+= shweight[6];
m2[a]+= shweight[14];
m3[a]+= flweight[6];
m4[a]+= flweight[14];
}
if(a & 128) {
m1[a]+= shweight[7];
m2[a]+= shweight[15];
m3[a]+= flweight[7];
m4[a]+= flweight[15];
}
2002-10-12 11:37:38 +00:00
}
}
}
/* centmask: the correct subpixel offset per mask */
fpx1= MEM_mallocN(256*sizeof(float), "initgauss4");
fpx2= MEM_mallocN(256*sizeof(float), "initgauss4");
fpy1= MEM_mallocN(256*sizeof(float), "initgauss4");
fpy2= MEM_mallocN(256*sizeof(float), "initgauss4");
for(a=0; a<256; a++) {
fpx1[a]= fpx2[a]= 0.0;
fpy1[a]= fpy2[a]= 0.0;
if(a & 1) {
fpx1[a]+= jit[0][0];
fpy1[a]+= jit[0][1];
fpx2[a]+= jit[8][0];
fpy2[a]+= jit[8][1];
}
if(a & 2) {
fpx1[a]+= jit[1][0];
fpy1[a]+= jit[1][1];
fpx2[a]+= jit[9][0];
fpy2[a]+= jit[9][1];
}
if(a & 4) {
fpx1[a]+= jit[2][0];
fpy1[a]+= jit[2][1];
fpx2[a]+= jit[10][0];
fpy2[a]+= jit[10][1];
}
if(a & 8) {
fpx1[a]+= jit[3][0];
fpy1[a]+= jit[3][1];
fpx2[a]+= jit[11][0];
fpy2[a]+= jit[11][1];
}
if(a & 16) {
fpx1[a]+= jit[4][0];
fpy1[a]+= jit[4][1];
fpx2[a]+= jit[12][0];
fpy2[a]+= jit[12][1];
}
if(a & 32) {
fpx1[a]+= jit[5][0];
fpy1[a]+= jit[5][1];
fpx2[a]+= jit[13][0];
fpy2[a]+= jit[13][1];
}
if(a & 64) {
fpx1[a]+= jit[6][0];
fpy1[a]+= jit[6][1];
fpx2[a]+= jit[14][0];
fpy2[a]+= jit[14][1];
}
if(a & 128) {
fpx1[a]+= jit[7][0];
fpy1[a]+= jit[7][1];
fpx2[a]+= jit[15][0];
fpy2[a]+= jit[15][1];
}
2002-10-12 11:37:38 +00:00
}
for(a= (1<<R.osa)-1; a>0; 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;
2002-10-12 11:37:38 +00:00
}
MEM_freeN(fpx1);
MEM_freeN(fpx2);
MEM_freeN(fpy1);
MEM_freeN(fpy2);
2002-10-12 11:37:38 +00:00
}
}
void RE_free_filt_mask()
{
int a;
for(a=0; a<9; a++) {
MEM_freeN(mask1[a]);
MEM_freeN(mask2[a]);
MEM_freeN(fmask1[a]);
MEM_freeN(fmask2[a]);
2002-10-12 11:37:38 +00:00
}
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 */
2002-10-12 11:37:38 +00:00
if (BLI_exists(di) == 0) {
BLI_recurdir_fileops(di);
}
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
void RE_setwindowclip(int mode, int jmode)
{
extern float bluroffsx, bluroffsy; // rendercore.c... hackish (ton)
2002-10-12 11:37:38 +00:00
Camera *cam=0;
Phew, a lot of work, and no new features... Main target was to make the inner rendering loop using no globals anymore. This is essential for proper usage while raytracing, it caused a lot of hacks in the raycode as well, which even didn't work correctly for all situations (textures especially). Done this by creating a new local struct RenderInput, which replaces usage of the global struct Render R. The latter now only is used to denote image size, viewmatrix, and the like. Making the inner render loops using no globals caused 1000s of vars to be changed... but the result definitely is much nicer code, which enables making 'real' shaders in a next stage. It also enabled me to remove the hacks from ray.c Then i went to the task of removing redundant code. Especially the calculus of texture coords took place (identical) in three locations. Most obvious is the change in the unified render part, which is much less code now; it uses the same rendering routines as normal render now. (Note; not for halos yet!) I also removed 6 files called 'shadowbuffer' something. This was experimen- tal stuff from NaN days. And again saved a lot of double used code. Finally I went over the blenkernel and blender/src calls to render stuff. Here the same local data is used now, resulting in less dependency. I also moved render-texture to the render module, this was still in Kernel. (new file: texture.c) So! After this commit I will check on the autofiles, to try to fix that. MSVC people have to do it themselves. This commit will need quite some testing help, but I'm around!
2003-12-21 21:52:51 +00:00
float lens, minx, miny, maxx, maxy;
2002-10-12 11:37:38 +00:00
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;
2002-10-12 11:37:38 +00:00
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);
2002-10-12 11:37:38 +00:00
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];
2002-10-12 11:37:38 +00:00
}
else bluroffsx=bluroffsy= 0.0;
2002-10-12 11:37:38 +00:00
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);
}
/* ~~~~~~~~~~~~~~~~ PARTS ~~~~~~~~~~~~~~~~~~~~~~ */
#define PART_EMPTY -2
2002-10-12 11:37:38 +00:00
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 */
2002-10-12 11:37:38 +00:00
yparts= R.r.yparts;
for(nr=0;nr<xparts*yparts;nr++)
allparts[nr][0]= PART_EMPTY; /* clear array */
2002-10-12 11:37:38 +00:00
xpart= R.rectx/xparts;
ypart= R.recty/yparts;
/* if border: test if amount of parts can be fewer */
2002-10-12 11:37:38 +00:00
if(R.r.mode & R_BORDER) {
a= (xmaxb-xminb-1)/xpart+1; /* amount of parts in border */
2002-10-12 11:37:38 +00:00
if(a<xparts) xparts= a;
a= (ymaxb-yminb-1)/ypart+1; /* amount of parts in border */
2002-10-12 11:37:38 +00:00
if(a<yparts) yparts= a;
xpart= (xmaxb-xminb)/xparts;
ypart= (ymaxb-yminb)/yparts;
}
for(nr=0; nr<xparts*yparts; nr++) {
if(R.r.mode & R_PANORAMA) {
allparts[nr][0]= 0;
allparts[nr][1]= 0;
allparts[nr][2]= R.rectx;
allparts[nr][3]= R.recty;
}
else {
xd= (nr % xparts);
yd= (nr-xd)/xparts;
allparts[nr][0]= xminb+ xd*xpart;
allparts[nr][1]= yminb+ yd*ypart;
if(xd<R.r.xparts-1) allparts[nr][2]= allparts[nr][0]+xpart;
else allparts[nr][2]= xmaxb;
if(yd<R.r.yparts-1) allparts[nr][3]= allparts[nr][1]+ypart;
else allparts[nr][3]= ymaxb;
if(allparts[nr][2]-allparts[nr][0]<=0) allparts[nr][0]= PART_EMPTY;
if(allparts[nr][3]-allparts[nr][1]<=0) allparts[nr][0]= PART_EMPTY;
/* gauss needs 1 pixel extra to work */
if(xparts*yparts>1 && (R.r.mode & R_GAUSS)) {
allparts[nr][0]-= 1;
allparts[nr][1]-= 1;
allparts[nr][2]+= 1;
allparts[nr][3]+= 1;
}
2002-10-12 11:37:38 +00:00
}
}
2002-10-12 11:37:38 +00:00
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
short setpart(short nr) /* return 0 if incorrect part */
2002-10-12 11:37:38 +00:00
{
if(allparts[nr][0]== PART_EMPTY) return 0;
2002-10-12 11:37:38 +00:00
R.xstart= allparts[nr][0]-R.afmx;
R.ystart= allparts[nr][1]-R.afmy;
R.xend= allparts[nr][2]-R.afmx;
R.yend= allparts[nr][3]-R.afmy;
R.rectx= R.xend-R.xstart;
R.recty= R.yend-R.ystart;
return 1;
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
void addparttorect(short nr, Part *part)
{
unsigned int *rt, *rp;
int y, heigth, len, copylen;
2002-10-12 11:37:38 +00:00
/* the right offset in rectot */
2002-10-12 11:37:38 +00:00
rp= part->rect;
copylen=len= (allparts[nr][2]-allparts[nr][0]);
2002-10-12 11:37:38 +00:00
heigth= (allparts[nr][3]-allparts[nr][1]);
if(R.r.mode & R_GAUSS) {
rp+= 1+len;
copylen= len-2;
heigth -= 2;
rt= R.rectot+ (allparts[nr][1] + 1)*R.rectx+ (allparts[nr][0]+1);
}
else rt= R.rectot+ allparts[nr][1]*R.rectx+ allparts[nr][0];
2002-10-12 11:37:38 +00:00
for(y=0; y<heigth; y++) {
memcpy(rt, rp, 4*copylen);
rt+= R.rectx;
2002-10-12 11:37:38 +00:00
rp+= len;
}
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
void add_to_blurbuf(int blur)
{
static unsigned int *blurrect= 0;
int tot, gamval;
short facr, facb;
char *rtr, *rtb;
if(blur<0) {
if(blurrect) {
if(R.rectot) MEM_freeN(R.rectot);
R.rectot= blurrect;
blurrect= 0;
}
}
else if(blur==R.osa-1) {
/* first time */
2002-10-12 11:37:38 +00:00
blurrect= MEM_mallocN(R.rectx*R.recty*sizeof(int), "rectblur");
if(R.rectot) memcpy(blurrect, R.rectot, R.rectx*R.recty*4);
}
else if(blurrect) {
/* accumulate */
2002-10-12 11:37:38 +00:00
facr= 256/(R.osa-blur);
facb= 256-facr;
if(R.rectot) {
rtr= (char *)R.rectot;
rtb= (char *)blurrect;
tot= R.rectx*R.recty;
while(tot--) {
if( *((unsigned int *)rtb) != *((unsigned int *)rtr) ) {
if(R.r.mode & R_GAMMA) {
gamval= (facr* igamtab2[ rtr[0]<<8 ] + facb* igamtab2[ rtb[0]<<8 ])>>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 */
2002-10-12 11:37:38 +00:00
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();
}
2002-10-12 11:37:38 +00:00
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
void render() {
/* yafray: render, see above */
if (R.r.renderer==R_YAFRAY)
yafrayRender();
else
oldRenderLoop();
2002-10-12 11:37:38 +00:00
}
void oldRenderLoop(void) /* here the PART and FIELD loops */
2002-10-12 11:37:38 +00:00
{
Part *part;
unsigned int *rt, *rt1, *rt2;
int len, y;
short blur, a,fields,fi,parts; /* pa is a global because of print */
2002-10-12 11:37:38 +00:00
if (R.rectz) MEM_freeN(R.rectz);
R.rectz = 0;
/* FIELD LOOP */
2002-10-12 11:37:38 +00:00
fields= 1;
parts= R.r.xparts*R.r.yparts;
if(R.r.mode & R_FIELDS) {
fields= 2;
R.rectf1= R.rectf2= 0; /* field rects */
2002-10-12 11:37:38 +00:00
R.r.ysch/= 2;
R.afmy/= 2;
R.r.yasp*= 2;
R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp);
}
for(fi=0; fi<fields; fi++) {
/* INIT */
BLI_srand( 2*(G.scene->r.cfra)+fi);
Phew, a lot of work, and no new features... Main target was to make the inner rendering loop using no globals anymore. This is essential for proper usage while raytracing, it caused a lot of hacks in the raycode as well, which even didn't work correctly for all situations (textures especially). Done this by creating a new local struct RenderInput, which replaces usage of the global struct Render R. The latter now only is used to denote image size, viewmatrix, and the like. Making the inner render loops using no globals caused 1000s of vars to be changed... but the result definitely is much nicer code, which enables making 'real' shaders in a next stage. It also enabled me to remove the hacks from ray.c Then i went to the task of removing redundant code. Especially the calculus of texture coords took place (identical) in three locations. Most obvious is the change in the unified render part, which is much less code now; it uses the same rendering routines as normal render now. (Note; not for halos yet!) I also removed 6 files called 'shadowbuffer' something. This was experimen- tal stuff from NaN days. And again saved a lot of double used code. Finally I went over the blenkernel and blender/src calls to render stuff. Here the same local data is used now, resulting in less dependency. I also moved render-texture to the render module, this was still in Kernel. (new file: texture.c) So! After this commit I will check on the autofiles, to try to fix that. MSVC people have to do it themselves. This commit will need quite some testing help, but I'm around!
2003-12-21 21:52:51 +00:00
2002-10-12 11:37:38 +00:00
R.flag|= R_RENDERING;
if(fi==1) R.flag |= R_SEC_FIELD;
/* MOTIONBLUR loop */
2002-10-12 11:37:38 +00:00
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;
2002-10-12 11:37:38 +00:00
if(R.r.mode & R_MBLUR) set_mblur_offs(R.osa-blur);
initparts(); /* always do, because of border */
2002-10-12 11:37:38 +00:00
setpart(0);
2002-10-12 11:37:38 +00:00
RE_local_init_render_display();
RE_local_clear_render_display(R.win);
RE_local_timecursor((G.scene->r.cfra));
prepareScene();
2002-10-12 11:37:38 +00:00
/* PARTS */
R.parts.first= R.parts.last= 0;
for(pa=0; pa<parts; pa++) {
2002-10-12 11:37:38 +00:00
if(RE_local_test_break()) break;
if(pa) { /* because case pa==0 has been done */
2002-10-12 11:37:38 +00:00
if(setpart(pa)==0) break;
}
if(R.r.mode & R_MBLUR) RE_setwindowclip(0, blur);
else RE_setwindowclip(0,-1);
if(R.r.mode & R_PANORAMA) setPanoRot(pa);
/* HOMOGENIC COORDINATES AND ZBUF AND CLIP OPTIMISATION (per part) */
2002-10-12 11:37:38 +00:00
/* There may be some interference with z-coordinate */
/* calculation here? */
doClipping(RE_projectverto);
if(RE_local_test_break()) break;
/* rectot is for result and integer face indices */
2002-10-12 11:37:38 +00:00
R.rectot= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot");
if(R.r.mode & R_MBLUR) {
RE_local_printrenderinfo(0.0, R.osa - blur);
if(G.background && blur<R.osa) printf("\n"); // newline for percentage print
}
2002-10-12 11:37:38 +00:00
else RE_local_printrenderinfo(0.0, -1);
if(R.r.mode & R_UNIFIED) {
zBufShadeAdvanced();
}
else {
R.rectz = (unsigned int *)MEM_mallocN(sizeof(int)*R.rectx*R.recty, "rectz");
if(R.r.mode & R_OSA) zbufshadeDA();
else zbufshade();
}
/* exception */
2002-10-12 11:37:38 +00:00
if( (R.r.mode & R_BORDER) && (R.r.mode & R_MOVIECROP));
else {
/* HANDLE PART OR BORDER */
2002-10-12 11:37:38 +00:00
if(parts>1 || (R.r.mode & R_BORDER)) {
2002-10-12 11:37:38 +00:00
part= MEM_callocN(sizeof(Part), "part");
BLI_addtail(&R.parts, part);
part->rect= R.rectot;
R.rectot= NULL;
2002-10-12 11:37:38 +00:00
if (R.rectz) {
MEM_freeN(R.rectz);
R.rectz= NULL;
2002-10-12 11:37:38 +00:00
}
}
}
if(RE_local_test_break()) break;
2002-10-12 11:37:38 +00:00
}
/* JOIN PARTS OR INSERT BORDER */
2002-10-12 11:37:38 +00:00
/* exception: crop */
2002-10-12 11:37:38 +00:00
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");
2002-10-12 11:37:38 +00:00
part= R.parts.first;
for(pa=0; pa<parts; pa++) {
if(allparts[pa][0]== PART_EMPTY) break;
2002-10-12 11:37:38 +00:00
if(part==0) break;
if(R.r.mode & R_PANORAMA) {
if(pa) {
allparts[pa][0] += pa*R.r.xsch;
allparts[pa][2] += pa*R.r.xsch;
}
}
addparttorect(pa, part);
part= part->next;
}
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();
2002-10-12 11:37:38 +00:00
}
if(R.r.mode & R_MBLUR) {
add_to_blurbuf(blur);
}
/* END (blur loop) */
2002-10-12 11:37:38 +00:00
finalizeScene();
if(RE_local_test_break()) break;
}
/* definite free */
2002-10-12 11:37:38 +00:00
add_to_blurbuf(-1);
/* HANDLE FIELD */
2002-10-12 11:37:38 +00:00
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 */
2002-10-12 11:37:38 +00:00
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");
2002-10-12 11:37:38 +00:00
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; a<R.recty; a+=2) {
memcpy(rt, rt1, len);
rt+= R.rectx;
rt1+= R.rectx;
memcpy(rt, rt2, len);
rt+= R.rectx;
rt2+= R.rectx;
}
}
}
/* R.rectx= R.r.xsch; */
/* if(R.r.mode & R_PANORAMA) R.rectx*= R.r.xparts; */
/* R.recty= R.r.ysch; */
/* if border: still do skybuf */
2002-10-12 11:37:38 +00:00
if(R.r.mode & R_BORDER) {
if( (R.r.mode & R_MOVIECROP)==0) {
if(R.r.bufflag & 1) {
R.xstart= -R.afmx;
R.ystart= -R.afmy;
rt= R.rectot;
for(y=0; y<R.recty; y++, rt+= R.rectx) scanlinesky((char *)rt, y);
}
}
}
set_mblur_offs(0);
/* FREE */
2002-10-12 11:37:38 +00:00
/* zbuf test */
/* don't free R.rectz, only when its size is not the same as R.rectot */
if (R.rectz && parts == 1 && (R.r.mode & R_FIELDS) == 0);
else {
if(R.rectz) MEM_freeN(R.rectz);
R.rectz= 0;
}
if(R.rectf1) MEM_freeN(R.rectf1);
R.rectf1= 0;
if(R.rectf2) MEM_freeN(R.rectf2);
R.rectf2= 0;
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
extern unsigned short usegamtab;
void RE_initrender(struct View3D *ogl_render_view3d)
{
double start_time;
Image *bima;
char name[256];
/* scene data to R */
2002-10-12 11:37:38 +00:00
R.r= G.scene->r;
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) */
2002-10-12 11:37:38 +00:00
R.rectx= R.r.xsch;
R.recty= R.r.ysch;
/* IS RENDERING ALLOWED? */
/* forbidden combination */
2002-10-12 11:37:38 +00:00
if((R.r.mode & R_BORDER) && (R.r.mode & R_PANORAMA)) {
error("No border supported for Panorama");
2002-10-12 11:37:38 +00:00
G.afbreek= 1;
return;
}
if(R.r.xparts*R.r.yparts>=2 && (R.r.mode & R_MOVIECROP) && (R.r.mode & R_BORDER)) {
error("Combination of border, crop and parts not allowed");
G.afbreek= 1;
return;
}
2002-10-12 11:37:38 +00:00
if(R.r.xparts*R.r.yparts>64) {
error("No more than 64 parts supported");
2002-10-12 11:37:38 +00:00
G.afbreek= 1;
return;
}
2002-10-12 11:37:38 +00:00
if(R.r.yparts>1 && (R.r.mode & R_PANORAMA)) {
error("No Y-Parts supported for Panorama");
2002-10-12 11:37:38 +00:00
G.afbreek= 1;
return;
}
/* TEST BACKBUF */
2002-10-12 11:37:38 +00:00
/* 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);
2002-10-12 11:37:38 +00:00
if(R.backbuf) {
R.backbuf->id.us--;
bima= R.backbuf;
}
else bima= 0;
2002-10-12 11:37:38 +00:00
R.backbuf= add_image(name);
2002-10-12 11:37:38 +00:00
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);
2002-10-12 11:37:38 +00:00
}
}
}
usegamtab= 0; /* see also further */
2002-10-12 11:37:38 +00:00
if(R.r.mode & (R_OSA|R_MBLUR)) {
R.osa= R.r.osa;
if(R.osa>16) R.osa= 16;
2002-10-12 11:37:38 +00:00
init_render_jit(R.osa);
/* this value sometimes is reset temporally, for example in transp zbuf */
2002-10-12 11:37:38 +00:00
if(R.r.mode & R_GAMMA) {
if((R.r.mode & R_OSA)) usegamtab= 1;
}
}
else R.osa= 0;
/* always call, it does gamma tables used by alphaunder, but call after R.osa and jit was set */
RE_init_filt_mask();
2002-10-12 11:37:38 +00:00
/* when rendered without camera object */
/* it has to done here because of envmaps */
R.near= 0.1;
R.far= 1000.0;
2002-10-12 11:37:38 +00:00
if(R.afmx<1 || R.afmy<1) {
error("Image too small");
return;
}
R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp);
2002-10-12 11:37:38 +00:00
start_time= PIL_check_seconds_timer();
2002-10-12 11:37:38 +00:00
if(R.r.scemode & R_DOSEQ) {
R.rectx= R.r.xsch;
R.recty= R.r.ysch;
if(R.r.mode & R_PANORAMA) {
R.rectx*= R.r.xparts;
}
2002-10-12 11:37:38 +00:00
if(R.rectot) MEM_freeN(R.rectot);
R.rectot= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot");
2002-10-12 11:37:38 +00:00
RE_local_timecursor((G.scene->r.cfra));
2002-10-12 11:37:38 +00:00
if(RE_local_test_break()==0) do_render_seq();
/* display */
2002-10-12 11:37:38 +00:00
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;
2002-10-12 11:37:38 +00:00
if(R.rectot) MEM_freeN(R.rectot);
R.rectot= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot");
2002-10-12 11:37:38 +00:00
RE_local_init_render_display();
drawview3d_render(ogl_render_view3d);
}
else {
if(G.scene->camera==0) {
G.scene->camera= scene_find_camera(G.scene);
}
2002-10-12 11:37:38 +00:00
if(G.scene->camera==0) {
error("No camera");
/* needed because R.rectx and R.recty can be unmatching R.rectot */
if(R.rectot) MEM_freeN(R.rectot);
R.rectot= NULL;
2002-10-12 11:37:38 +00:00
G.afbreek=1;
return;
}
else {
2002-10-12 11:37:38 +00:00
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 */
2002-10-12 11:37:38 +00:00
}
}
/* display again: fields/seq/parts/pano etc */
if(R.rectot) {
2002-10-12 11:37:38 +00:00
RE_local_init_render_display();
RE_local_render_display(0, R.recty-1,
R.rectx, R.recty,
R.rectot);
2002-10-12 11:37:38 +00:00
}
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);
2002-10-12 11:37:38 +00:00
/* restore variables */
//R.osatex= 0;
//R.vlr= 0;
///* at cubemap */
/* these flags remain on, until reset in caller to render (renderwin.c) */
R.flag &= (R_RENDERING|R_ANIMRENDER);
2002-10-12 11:37:38 +00:00
}
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) */
2002-10-12 11:37:38 +00:00
R.r= G.scene->r;
/* START ANIMLOOP, everywhere NOT the cfra from R.r is gebruikt: because of rest blender */
2002-10-12 11:37:38 +00:00
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(R.r.mode & R_MOVIECROP) {
initparts();
setpart(0); // this will adjust r.rectx
}
2002-10-12 11:37:38 +00:00
if (0) {
#ifdef __sgi
} else if (R.r.imtype==R_MOVIE) {
start_movie();
#endif
#if defined(_WIN32) && !defined(FREE_WINDOWS)
2002-10-12 11:37:38 +00:00
} else if (R.r.imtype == R_AVICODEC) {
start_avi_codec();
#endif
#if WITH_QUICKTIME
} else if (R.r.imtype == R_QUICKTIME) {
start_qt();
2002-10-12 11:37:38 +00:00
#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; // unused now (ton)
2002-10-12 11:37:38 +00:00
RE_initrender(ogl_render_view3d);
/* WRITE IMAGE */
2002-10-12 11:37:38 +00:00
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)
2002-10-12 11:37:38 +00:00
} 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));
2002-10-12 11:37:38 +00:00
#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 !! */
2002-10-12 11:37:38 +00:00
}
if(G.afbreek==1) break;
}
(G.scene->r.cfra)= cfrao;
/* restore time */
2002-10-12 11:37:38 +00:00
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)
2002-10-12 11:37:38 +00:00
} else if (R.r.imtype == R_AVICODEC) {
end_avi_codec();
#endif
#ifdef WITH_QUICKTIME
} else if (R.r.imtype == R_QUICKTIME) {
end_qt();
2002-10-12 11:37:38 +00:00
#endif
} else if ELEM4(R.r.imtype, R_AVIRAW, R_AVIJPEG, R_MOVIE, R_AVICODEC) {
end_avi();
}
}
/* *************************************************** */
/* ******************* Screendumps ******************** */
/* moved to the windowControl thing */