Files
test2/source/blender/render/intern/source/initrender.c
Brecht Van Lommel 41fb3626f3 2.5: Render
* UI layout for scene buttons has quite some changes, I tried to
  better organize things according to the pipeline, and also showing
  important properties by default, and collapsing less important ones.

Some changes compared to 2.4x:
* Panorama is now a Camera property.
* Sequence and Compositing are now enabled by default, but will only
  do something when there is a node tree using nodes, or a strip in the
  sequence editor.
* Enabling Full Sample now automatically enables Save Buffers too.
* Stamp option to include info in file is removed, it now simply always
  does this if one of the stamp infos is enabled.
* Xvid, H.264 and Ogg Theora are now directly in the file format menu,
  but still using FFMPEG. Unfortunately Ogg is broken at the moment
  (also in 2.4x), so that's disabled. And Xvid crashes on 64bit linux,
  maybe solvable by upgrading extern/xvidcore/, using ubuntu libs makes
  it work.
* Organized file format menu by image/movie types.

Added:
* Render layers RNA wrapped, operatorized, layouted.
* FFMPEG format/codec options are now working.

Defaults changed:
* Compositing & Sequencer enabled.
* Tiles set to 8x8.
* Time/Date/Frame/Scene/Camera/Filename enabled for stamp.
2009-07-13 19:09:13 +00:00

685 lines
15 KiB
C

/**
* $Id$
*
* ***** BEGIN GPL 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.
*
* 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.
*
* Contributors: 2004/2005/2006 Blender Foundation, full recode
*
* ***** END GPL LICENSE BLOCK *****
*/
/* Global includes */
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "MEM_guardedalloc.h"
#include "PIL_time.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_jitter.h"
#include "MTC_matrixops.h"
#include "DNA_camera_types.h"
#include "DNA_group_types.h"
#include "DNA_image_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_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_action.h"
#include "BKE_writeavi.h"
#include "BKE_scene.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#ifdef WITH_QUICKTIME
#include "quicktime_export.h"
#endif
/* this module */
#include "renderpipeline.h"
#include "render_types.h"
#include "rendercore.h"
#include "pixelshading.h"
#include "zbuf.h"
/* Own includes */
#include "initrender.h"
/* ********************** */
static void init_render_jit(Render *re)
{
static float jit[32][2]; /* simple caching */
static int lastjit= 0;
if(lastjit!=re->r.osa) {
memset(jit, 0, sizeof(jit));
BLI_initjit(jit[0], re->r.osa);
}
lastjit= re->r.osa;
memcpy(re->jit, jit, sizeof(jit));
}
/* ****************** MASKS and LUTS **************** */
static float filt_quadratic(float x)
{
if (x < 0.0f) x = -x;
if (x < 0.5f) return 0.75f-(x*x);
if (x < 1.5f) return 0.50f*(x-1.5f)*(x-1.5f);
return 0.0f;
}
static float filt_cubic(float x)
{
float x2= x*x;
if (x < 0.0f) x = -x;
if (x < 1.0f) return 0.5*x*x2 - x2 + 2.0f/3.0f;
if (x < 2.0f) return (2.0-x)*(2.0-x)*(2.0-x)/6.0f;
return 0.0f;
}
static float filt_catrom(float x)
{
float x2= x*x;
if (x < 0.0f) x = -x;
if (x < 1.0f) return 1.5f*x2*x - 2.5f*x2 + 1.0f;
if (x < 2.0f) return -0.5f*x2*x + 2.5*x2 - 4.0f*x + 2.0f;
return 0.0f;
}
static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */
{
float b = 1.0f/3.0f, c = 1.0f/3.0f;
float p0 = ( 6.0 - 2.0*b ) / 6.0;
float p2 = (-18.0 + 12.0*b + 6.0*c) / 6.0;
float p3 = ( 12.0 - 9.0*b - 6.0*c) / 6.0;
float q0 = ( 8.0*b + 24.0*c) / 6.0;
float q1 = ( - 12.0*b - 48.0*c) / 6.0;
float q2 = ( 6.0*b + 30.0*c) / 6.0;
float q3 = ( - b - 6.0*c) / 6.0;
if (x<-2.0) return 0.0;
if (x<-1.0) return (q0-x*(q1-x*(q2-x*q3)));
if (x< 0.0) return (p0+x*x*(p2-x*p3));
if (x< 1.0) return (p0+x*x*(p2+x*p3));
if (x< 2.0) return (q0+x*(q1+x*(q2+x*q3)));
return 0.0;
}
/* x ranges from -1 to 1 */
float RE_filter_value(int type, float x)
{
float gaussfac= 1.6f;
x= ABS(x);
switch(type) {
case R_FILTER_BOX:
if(x>1.0) return 0.0f;
return 1.0;
case R_FILTER_TENT:
if(x>1.0) return 0.0f;
return 1.0f-x;
case R_FILTER_GAUSS:
x*= gaussfac;
return (1.0/exp(x*x) - 1.0/exp(gaussfac*gaussfac*2.25));
case R_FILTER_MITCH:
return filt_mitchell(x*gaussfac);
case R_FILTER_QUAD:
return filt_quadratic(x*gaussfac);
case R_FILTER_CUBIC:
return filt_cubic(x*gaussfac);
case R_FILTER_CATROM:
return filt_catrom(x*gaussfac);
}
return 0.0f;
}
static float calc_weight(Render *re, float *weight, int i, int j)
{
float x, y, dist, totw= 0.0;
int a;
for(a=0; a<re->osa; a++) {
x= re->jit[a][0] + i;
y= re->jit[a][1] + j;
dist= sqrt(x*x+y*y);
weight[a]= 0.0;
/* Weighting choices */
switch(re->r.filtertype) {
case R_FILTER_BOX:
if(i==0 && j==0) weight[a]= 1.0;
break;
case R_FILTER_TENT:
if(dist < re->r.gauss)
weight[a]= re->r.gauss - dist;
break;
case R_FILTER_GAUSS:
x = dist*re->r.gauss;
weight[a]= (1.0/exp(x*x) - 1.0/exp(re->r.gauss*re->r.gauss*2.25));
break;
case R_FILTER_MITCH:
weight[a]= filt_mitchell(dist*re->r.gauss);
break;
case R_FILTER_QUAD:
weight[a]= filt_quadratic(dist*re->r.gauss);
break;
case R_FILTER_CUBIC:
weight[a]= filt_cubic(dist*re->r.gauss);
break;
case R_FILTER_CATROM:
weight[a]= filt_catrom(dist*re->r.gauss);
break;
}
totw+= weight[a];
}
return totw;
}
void free_sample_tables(Render *re)
{
int a;
if(re->samples) {
for(a=0; a<9; a++) {
MEM_freeN(re->samples->fmask1[a]);
MEM_freeN(re->samples->fmask2[a]);
}
MEM_freeN(re->samples->centmask);
MEM_freeN(re->samples);
re->samples= NULL;
}
}
/* based on settings in render, it makes the lookup tables */
void make_sample_tables(Render *re)
{
static int firsttime= 1;
SampleTables *st;
float flweight[32];
float weight[32], totw, val, *fpx1, *fpx2, *fpy1, *fpy2, *m3, *m4;
int i, j, a;
/* optimization tables, only once */
if(firsttime) {
firsttime= 0;
}
free_sample_tables(re);
init_render_jit(re); /* needed for mblur too */
if(re->osa==0) {
/* just prevents cpu cycles for larger render and copying */
re->r.filtertype= 0;
return;
}
st= re->samples= MEM_callocN(sizeof(SampleTables), "sample tables");
for(a=0; a<9;a++) {
st->fmask1[a]= MEM_callocN(256*sizeof(float), "initfilt");
st->fmask2[a]= MEM_callocN(256*sizeof(float), "initfilt");
}
for(a=0; a<256; a++) {
st->cmask[a]= 0;
if(a & 1) st->cmask[a]++;
if(a & 2) st->cmask[a]++;
if(a & 4) st->cmask[a]++;
if(a & 8) st->cmask[a]++;
if(a & 16) st->cmask[a]++;
if(a & 32) st->cmask[a]++;
if(a & 64) st->cmask[a]++;
if(a & 128) st->cmask[a]++;
}
st->centmask= MEM_mallocN((1<<re->osa), "Initfilt3");
for(a=0; a<16; a++) {
st->centLut[a]= -0.45+((float)a)/16.0;
}
/* calculate totw */
totw= 0.0;
for(j= -1; j<2; j++) {
for(i= -1; i<2; i++) {
totw+= calc_weight(re, weight, i, j);
}
}
for(j= -1; j<2; j++) {
for(i= -1; i<2; i++) {
/* calculate using jit, with offset the weights */
memset(weight, 0, sizeof(weight));
calc_weight(re, weight, i, j);
for(a=0; a<16; a++) flweight[a]= weight[a]*(1.0/totw);
m3= st->fmask1[ 3*(j+1)+i+1 ];
m4= st->fmask2[ 3*(j+1)+i+1 ];
for(a=0; a<256; a++) {
if(a & 1) {
m3[a]+= flweight[0];
m4[a]+= flweight[8];
}
if(a & 2) {
m3[a]+= flweight[1];
m4[a]+= flweight[9];
}
if(a & 4) {
m3[a]+= flweight[2];
m4[a]+= flweight[10];
}
if(a & 8) {
m3[a]+= flweight[3];
m4[a]+= flweight[11];
}
if(a & 16) {
m3[a]+= flweight[4];
m4[a]+= flweight[12];
}
if(a & 32) {
m3[a]+= flweight[5];
m4[a]+= flweight[13];
}
if(a & 64) {
m3[a]+= flweight[6];
m4[a]+= flweight[14];
}
if(a & 128) {
m3[a]+= flweight[7];
m4[a]+= flweight[15];
}
}
}
}
/* 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]+= re->jit[0][0];
fpy1[a]+= re->jit[0][1];
fpx2[a]+= re->jit[8][0];
fpy2[a]+= re->jit[8][1];
}
if(a & 2) {
fpx1[a]+= re->jit[1][0];
fpy1[a]+= re->jit[1][1];
fpx2[a]+= re->jit[9][0];
fpy2[a]+= re->jit[9][1];
}
if(a & 4) {
fpx1[a]+= re->jit[2][0];
fpy1[a]+= re->jit[2][1];
fpx2[a]+= re->jit[10][0];
fpy2[a]+= re->jit[10][1];
}
if(a & 8) {
fpx1[a]+= re->jit[3][0];
fpy1[a]+= re->jit[3][1];
fpx2[a]+= re->jit[11][0];
fpy2[a]+= re->jit[11][1];
}
if(a & 16) {
fpx1[a]+= re->jit[4][0];
fpy1[a]+= re->jit[4][1];
fpx2[a]+= re->jit[12][0];
fpy2[a]+= re->jit[12][1];
}
if(a & 32) {
fpx1[a]+= re->jit[5][0];
fpy1[a]+= re->jit[5][1];
fpx2[a]+= re->jit[13][0];
fpy2[a]+= re->jit[13][1];
}
if(a & 64) {
fpx1[a]+= re->jit[6][0];
fpy1[a]+= re->jit[6][1];
fpx2[a]+= re->jit[14][0];
fpy2[a]+= re->jit[14][1];
}
if(a & 128) {
fpx1[a]+= re->jit[7][0];
fpy1[a]+= re->jit[7][1];
fpx2[a]+= re->jit[15][0];
fpy2[a]+= re->jit[15][1];
}
}
for(a= (1<<re->osa)-1; a>0; a--) {
val= st->cmask[a & 255] + st->cmask[a>>8];
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);
st->centmask[a]= i;
}
MEM_freeN(fpx1);
MEM_freeN(fpx2);
MEM_freeN(fpy1);
MEM_freeN(fpy2);
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* call this after InitState() */
/* per render, there's one persistant viewplane. Parts will set their own viewplanes */
void RE_SetCamera(Render *re, Object *camera)
{
Camera *cam=NULL;
rctf viewplane;
float pixsize, clipsta, clipend;
float lens, shiftx=0.0, shifty=0.0, winside;
/* question mark */
re->ycor= ( (float)re->r.yasp)/( (float)re->r.xasp);
if(re->r.mode & R_FIELDS)
re->ycor *= 2.0f;
if(camera->type==OB_CAMERA) {
cam= camera->data;
if(cam->type==CAM_ORTHO) re->r.mode |= R_ORTHO;
if(cam->flag & CAM_PANORAMA) re->r.mode |= R_PANORAMA;
/* solve this too... all time depending stuff is in convertblender.c?
* Need to update the camera early because it's used for projection matrices
* and other stuff BEFORE the animation update loop is done
* */
#if 0 // XXX old animation system
if(cam->ipo) {
calc_ipo(cam->ipo, frame_to_float(re->scene, re->r.cfra));
execute_ipo(&cam->id, cam->ipo);
}
#endif // XXX old animation system
lens= cam->lens;
shiftx=cam->shiftx;
shifty=cam->shifty;
clipsta= cam->clipsta;
clipend= cam->clipend;
}
else if(camera->type==OB_LAMP) {
Lamp *la= camera->data;
float fac= cos( M_PI*la->spotsize/360.0 );
float phi= acos(fac);
lens= 16.0*fac/sin(phi);
if(lens==0.0f)
lens= 35.0;
clipsta= la->clipsta;
clipend= la->clipend;
}
else { /* envmap exception... */
lens= re->lens;
if(lens==0.0f)
lens= 16.0;
clipsta= re->clipsta;
clipend= re->clipend;
if(clipsta==0.0f || clipend==0.0f) {
clipsta= 0.1f;
clipend= 1000.0f;
}
}
/* ortho only with camera available */
if(cam && (re->r.mode & R_ORTHO)) {
if( (re->r.xasp*re->winx) >= (re->r.yasp*re->winy) ) {
re->viewfac= re->winx;
}
else {
re->viewfac= re->ycor*re->winy;
}
/* ortho_scale == 1.0 means exact 1 to 1 mapping */
pixsize= cam->ortho_scale/re->viewfac;
}
else {
if( (re->r.xasp*re->winx) >= (re->r.yasp*re->winy) ) {
re->viewfac= (re->winx*lens)/32.0;
}
else {
re->viewfac= re->ycor*(re->winy*lens)/32.0;
}
pixsize= clipsta/re->viewfac;
}
/* viewplane fully centered, zbuffer fills in jittered between -.5 and +.5 */
winside= MAX2(re->winx, re->winy);
viewplane.xmin= -0.5f*(float)re->winx + shiftx*winside;
viewplane.ymin= -0.5f*re->ycor*(float)re->winy + shifty*winside;
viewplane.xmax= 0.5f*(float)re->winx + shiftx*winside;
viewplane.ymax= 0.5f*re->ycor*(float)re->winy + shifty*winside;
if(re->flag & R_SEC_FIELD) {
if(re->r.mode & R_ODDFIELD) {
viewplane.ymin-= .5*re->ycor;
viewplane.ymax-= .5*re->ycor;
}
else {
viewplane.ymin+= .5*re->ycor;
viewplane.ymax+= .5*re->ycor;
}
}
/* the window matrix is used for clipping, and not changed during OSA steps */
/* using an offset of +0.5 here would give clip errors on edges */
viewplane.xmin= pixsize*(viewplane.xmin);
viewplane.xmax= pixsize*(viewplane.xmax);
viewplane.ymin= pixsize*(viewplane.ymin);
viewplane.ymax= pixsize*(viewplane.ymax);
re->viewdx= pixsize;
re->viewdy= re->ycor*pixsize;
if(re->r.mode & R_ORTHO)
RE_SetOrtho(re, &viewplane, clipsta, clipend);
else
RE_SetWindow(re, &viewplane, clipsta, clipend);
}
void RE_SetPixelSize(Render *re, float pixsize)
{
re->viewdx= pixsize;
re->viewdy= re->ycor*pixsize;
}
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[][4])
{
re->r.cfra= frame;
RE_SetCamera(re, camera);
Mat4CpyMat4(mat, re->winmat);
}
/* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */
void freeparts(Render *re)
{
RenderPart *part= re->parts.first;
while(part) {
if(part->rectp) MEM_freeN(part->rectp);
if(part->rectz) MEM_freeN(part->rectz);
part= part->next;
}
BLI_freelistN(&re->parts);
}
void initparts(Render *re)
{
int nr, xd, yd, partx, party, xparts, yparts;
int xminb, xmaxb, yminb, ymaxb;
freeparts(re);
/* this is render info for caller, is not reset when parts are freed! */
re->i.totpart= 0;
re->i.curpart= 0;
re->i.partsdone= 0;
/* just for readable code.. */
xminb= re->disprect.xmin;
yminb= re->disprect.ymin;
xmaxb= re->disprect.xmax;
ymaxb= re->disprect.ymax;
xparts= re->r.xparts;
yparts= re->r.yparts;
/* mininum part size, but for exr tile saving it was checked already */
if(!(re->r.scemode & (R_EXR_TILE_FILE|R_FULL_SAMPLE))) {
if(re->r.mode & R_PANORAMA) {
if(ceil(re->rectx/(float)xparts) < 8)
xparts= 1 + re->rectx/8;
}
else
if(ceil(re->rectx/(float)xparts) < 64)
xparts= 1 + re->rectx/64;
if(ceil(re->recty/(float)yparts) < 64)
yparts= 1 + re->recty/64;
}
/* part size */
partx= ceil(re->rectx/(float)xparts);
party= ceil(re->recty/(float)yparts);
re->xparts= xparts;
re->yparts= yparts;
re->partx= partx;
re->party= party;
/* calculate rotation factor of 1 pixel */
if(re->r.mode & R_PANORAMA)
re->panophi= panorama_pixel_rot(re);
for(nr=0; nr<xparts*yparts; nr++) {
rcti disprect;
int rectx, recty;
xd= (nr % xparts);
yd= (nr-xd)/xparts;
disprect.xmin= xminb+ xd*partx;
disprect.ymin= yminb+ yd*party;
/* ensure we cover the entire picture, so last parts go to end */
if(xd<xparts-1) {
disprect.xmax= disprect.xmin + partx;
if(disprect.xmax > xmaxb)
disprect.xmax = xmaxb;
}
else disprect.xmax= xmaxb;
if(yd<yparts-1) {
disprect.ymax= disprect.ymin + party;
if(disprect.ymax > ymaxb)
disprect.ymax = ymaxb;
}
else disprect.ymax= ymaxb;
rectx= disprect.xmax - disprect.xmin;
recty= disprect.ymax - disprect.ymin;
/* so, now can we add this part? */
if(rectx>0 && recty>0) {
RenderPart *pa= MEM_callocN(sizeof(RenderPart), "new part");
/* Non-box filters need 2 pixels extra to work */
if((re->r.filtertype || (re->r.mode & R_EDGE))) {
pa->crop= 2;
disprect.xmin -= pa->crop;
disprect.ymin -= pa->crop;
disprect.xmax += pa->crop;
disprect.ymax += pa->crop;
rectx+= 2*pa->crop;
recty+= 2*pa->crop;
}
pa->disprect= disprect;
pa->rectx= rectx;
pa->recty= recty;
BLI_addtail(&re->parts, pa);
re->i.totpart++;
}
}
}