Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTon Roosendaal <ton@blender.org>2005-08-25 17:11:04 +0400
committerTon Roosendaal <ton@blender.org>2005-08-25 17:11:04 +0400
commit8d940dfafe577ea92c279cc41e791b0012c78d2b (patch)
tree88d286b2bc9ad136e7f96661fcd802d2811a52f2
parentc9f01eefcd3c21da95c7245a6b1f54ceae4024b1 (diff)
Random() issues with rendering...
- AO and soft shadow AreaLight tables were generated without fixed seed, causing animations to give unwanted amounts of noise. - Made sure these tables now are calculated before render, with fixed seed - Then found out the BLI_rand() has very bad seeding... it showed up as patterns. After some experimenting, found a nice method using noise.c hash tables. For compatibility with old code, named it BLI_srandom() to use this next to the BLI_srand(). This follows libc rand() and random() naming convention. - Then of course threading should work... so made a BLI_thread_rand version of the calls. Now supports up to 16 threads, comments added in .h and .c Result is stable animation render with AO and soft shadow. But, please test and feedback!
-rw-r--r--source/blender/blenlib/BLI_rand.h18
-rw-r--r--source/blender/blenlib/intern/rand.c40
-rw-r--r--source/blender/makesdna/DNA_world_types.h4
-rw-r--r--source/blender/render/extern/include/render.h7
-rw-r--r--source/blender/render/intern/source/initrender.c8
-rw-r--r--source/blender/render/intern/source/ray.c134
-rw-r--r--source/blender/render/intern/source/rendercore.c20
-rw-r--r--source/blender/renderconverter/intern/convertBlenderScene.c28
-rw-r--r--source/blender/src/previewrender.c2
9 files changed, 157 insertions, 104 deletions
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index e6b0146cfab..da2ecb79651 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -55,6 +55,9 @@ void rng_shuffleArray(struct RNG *rng, void *data, int elemSize, int numElems);
/** Seed the random number generator */
void BLI_srand (unsigned int seed);
+ /** Better seed for the random number generator, using noise.c hash[] */
+void BLI_srandom (unsigned int seed);
+
/** Return a pseudo-random number N where 0<=N<(2^31) */
int BLI_rand (void);
@@ -77,5 +80,20 @@ void BLI_fillrand (void *addr, int len);
*/
void BLI_array_randomize (void *data, int elemSize, int numElems, unsigned int seed);
+
+ /** Better seed for the random number generator, using noise.c hash[] */
+ /** Allows up to 16 threads to address */
+void BLI_thread_srandom (int thread, unsigned int seed);
+
+ /** Return a pseudo-random number N where 0<=N<(2^31) */
+ /** Allows up to 16 threads to address */
+int BLI_thread_rand (int thread);
+
+ /** Return a pseudo-random number N where 0.0f<=N<1.0f */
+ /** Allows up to 16 threads to address */
+float BLI_thread_frand (int thread);
+
+
+
#endif
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index 191d63f9748..a8b59fc58f3 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -48,7 +48,7 @@ typedef unsigned __int64 r_uint64;
typedef unsigned long long r_uint64;
#endif
-#define MULTIPLIER 0x5DEECE66D
+#define MULTIPLIER 0x5DEECE66DLL
#define ADDEND 0xB
#define LOWSEED 0x330E
@@ -78,7 +78,7 @@ void rng_seed(RNG *rng, unsigned int seed) {
}
int rng_getInt(RNG *rng) {
- rng->X= (MULTIPLIER*rng->X + ADDEND)&0x0000FFFFFFFFFFFF;
+ rng->X= (MULTIPLIER*rng->X + ADDEND)&0x0000FFFFFFFFFFFFLL;
return (int) (rng->X>>17);
}
@@ -112,10 +112,22 @@ void rng_shuffleArray(RNG *rng, void *data, int elemSize, int numElems)
static RNG theBLI_rng = {0};
+/* note, this one creates periodical patterns */
void BLI_srand(unsigned int seed) {
rng_seed(&theBLI_rng, seed);
}
+/* using hash table to create better seed */
+void BLI_srandom(unsigned int seed) {
+ extern unsigned char hash[]; // noise.c
+
+ rng_seed(&theBLI_rng, seed + hash[seed & 255]);
+ seed= rng_getInt(&theBLI_rng);
+ rng_seed(&theBLI_rng, seed + hash[seed & 255]);
+ seed= rng_getInt(&theBLI_rng);
+ rng_seed(&theBLI_rng, seed + hash[seed & 255]);
+}
+
int BLI_rand(void) {
return rng_getInt(&theBLI_rng);
}
@@ -144,3 +156,27 @@ void BLI_array_randomize(void *data, int elemSize, int numElems, unsigned int se
rng_shuffleArray(&rng, data, elemSize, numElems);
}
+/* ********* for threaded random ************** */
+#define MAX_RNG_THREADS 16
+
+static RNG rng_tab[MAX_RNG_THREADS];
+
+void BLI_thread_srandom(int thread, unsigned int seed)
+{
+ extern unsigned char hash[]; // noise.c
+
+ rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
+ seed= rng_getInt(&rng_tab[thread]);
+ rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
+ seed= rng_getInt(&rng_tab[thread]);
+ rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
+}
+
+int BLI_thread_rand(int thread) {
+ return rng_getInt(&rng_tab[thread]);
+}
+
+float BLI_thread_frand(int thread) {
+ return rng_getFloat(&rng_tab[thread]);
+}
+
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
index 06f52de8e6a..e284044a633 100644
--- a/source/blender/makesdna/DNA_world_types.h
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -88,6 +88,7 @@ typedef struct World {
* bit 3: (gameengine): Activity culling is enabled.
*/
short mode;
+ int physicsEngine; /* here it's aligned */
float misi, miststa, mistdist, misthi;
@@ -101,9 +102,8 @@ typedef struct World {
/* ambient occlusion */
float aodist, aodistfac, aoenergy, aobias;
short aomode, aosamp, aomix, aocolor;
+ float *aosphere;
- int physicsEngine;
-
struct Ipo *ipo;
struct MTex *mtex[10];
diff --git a/source/blender/render/extern/include/render.h b/source/blender/render/extern/include/render.h
index b0c7939b3ab..3aef5a678d0 100644
--- a/source/blender/render/extern/include/render.h
+++ b/source/blender/render/extern/include/render.h
@@ -188,6 +188,13 @@ void ramp_spec_result(float *specr, float *specg, float *specb, ShadeInput *shi)
/* --------------------------------------------------------------------- */
+/* ray.c (2) */
+/* --------------------------------------------------------------------- */
+void init_jitter_plane(LampRen *lar);
+void init_ao_sphere(float *sphere, int tot, int iter);
+
+
+/* --------------------------------------------------------------------- */
/* renderdatabase (3) */
/* --------------------------------------------------------------------- */
struct VlakRen *RE_findOrAddVlak(int nr);
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index ee03bd8a873..259c84750d2 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -876,7 +876,7 @@ static void yafrayRender(void)
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
// exported to other files, belongs in include... later
-SDL_mutex *render_abuf_lock=NULL, *load_ibuf_lock=NULL, *make_table_lock= NULL;
+SDL_mutex *render_abuf_lock=NULL, *load_ibuf_lock=NULL;
static void renderloop_setblending(void)
@@ -920,7 +920,6 @@ static void mainRenderLoop(void) /* here the PART and FIELD loops */
/* create mutexes for threaded render */
render_abuf_lock = SDL_CreateMutex();
load_ibuf_lock = SDL_CreateMutex();
- make_table_lock = SDL_CreateMutex();
if(R.rectz) MEM_freeN(R.rectz);
R.rectz = NULL;
@@ -944,7 +943,7 @@ static void mainRenderLoop(void) /* here the PART and FIELD loops */
for(fi=0; fi<fields; fi++) {
/* INIT */
- BLI_srand( 2*(G.scene->r.cfra)+fi);
+ BLI_srandom( 2*(G.scene->r.cfra)+fi);
R.flag|= R_RENDERING;
if(fi==1) R.flag |= R_SEC_FIELD;
@@ -962,7 +961,6 @@ static void mainRenderLoop(void) /* here the PART and FIELD loops */
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 */
@@ -1175,10 +1173,8 @@ static void mainRenderLoop(void) /* here the PART and FIELD loops */
/* mutexes free */
SDL_DestroyMutex(load_ibuf_lock);
SDL_DestroyMutex(render_abuf_lock);
- SDL_DestroyMutex(make_table_lock);
load_ibuf_lock= NULL;
render_abuf_lock= NULL;
- make_table_lock= NULL;
}
void render() {
diff --git a/source/blender/render/intern/source/ray.c b/source/blender/render/intern/source/ray.c
index 52266bc156e..50d7d60a19b 100644
--- a/source/blender/render/intern/source/ray.c
+++ b/source/blender/render/intern/source/ray.c
@@ -121,7 +121,6 @@ static int accepted, rejected, coherent_ray;
/* prototypes ------------------------ */
void freeoctree(void);
void makeoctree(void);
-float *test_jitter(int resol, int iter, float xsize, float ysize);
int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr);
/* **************** ocval method ******************* */
@@ -1594,29 +1593,6 @@ static void DP_energy(float *table, float *vec, int tot, float xsize, float ysiz
vec[1]= vec[1] - ysize*floor(vec[1]/ysize + 0.5);
}
-
-float *test_jitter(int resol, int iter, float xsize, float ysize)
-{
- static float jitter[2*256];
- float *fp;
- int x;
-
- /* fill table with random locations, area_size large */
- fp= jitter;
- for(x=0; x<resol*resol; x++, fp+=2) {
- fp[0]= (BLI_frand()-0.5)*xsize;
- fp[1]= (BLI_frand()-0.5)*ysize;
- }
-
- while(iter--) {
- fp= jitter;
- for(x=0; x<resol*resol; x++, fp+=2) {
- DP_energy(jitter, fp, resol*resol, xsize, ysize);
- }
- }
- return jitter;
-}
-
// random offset of 1 in 2
static void jitter_plane_offset(float *jitter1, float *jitter2, int tot, float sizex, float sizey, float ofsx, float ofsy)
{
@@ -1633,57 +1609,56 @@ static void jitter_plane_offset(float *jitter1, float *jitter2, int tot, float s
}
}
-/* table around origin, -0.5*size to 0.5*size */
-static float *jitter_plane(LampRen *lar, int xs, int ys)
+/* called from convertBlenderScene.c */
+/* we do this in advance to get consistant random, not alter the render seed, and be threadsafe */
+void init_jitter_plane(LampRen *lar)
{
float *fp;
- int tot, x, iter=12;
+ int x, iter=12, tot= lar->ray_totsamp;
- tot= lar->ray_totsamp;
+ fp=lar->jitter= MEM_mallocN(4*tot*2*sizeof(float), "lamp jitter tab");
- if(lar->jitter==NULL) {
- extern SDL_mutex *make_table_lock; // initrender.c
- if(make_table_lock) SDL_mutexP(make_table_lock);
-
- /* check again, since other thread could have entered */
- if(lar->jitter==NULL) {
-
-
- fp=lar->jitter= MEM_mallocN(4*tot*2*sizeof(float), "lamp jitter tab");
-
- /* fill table with random locations, area_size large */
- for(x=0; x<tot; x++, fp+=2) {
- fp[0]= (BLI_frand()-0.5)*lar->area_size;
- fp[1]= (BLI_frand()-0.5)*lar->area_sizey;
- }
-
- while(iter--) {
- fp= lar->jitter;
- for(x=tot; x>0; x--, fp+=2) {
- DP_energy(lar->jitter, fp, tot, lar->area_size, lar->area_sizey);
- }
- }
-
- jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5, 0.0);
- jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5, 0.5);
- jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0, 0.5);
+ /* set per-lamp fixed seed */
+ BLI_srandom(tot);
+
+ /* fill table with random locations, area_size large */
+ for(x=0; x<tot; x++, fp+=2) {
+ fp[0]= (BLI_frand()-0.5)*lar->area_size;
+ fp[1]= (BLI_frand()-0.5)*lar->area_sizey;
+ }
+
+ while(iter--) {
+ fp= lar->jitter;
+ for(x=tot; x>0; x--, fp+=2) {
+ DP_energy(lar->jitter, fp, tot, lar->area_size, lar->area_sizey);
}
-
- if(make_table_lock) SDL_mutexV(make_table_lock);
}
-
+
+ /* create the dithered tables */
+ jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5, 0.0);
+ jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5, 0.5);
+ jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0, 0.5);
+}
+
+/* table around origin, -0.5*size to 0.5*size */
+static float *give_jitter_plane(LampRen *lar, int xs, int ys)
+{
+ int tot;
+
+ tot= lar->ray_totsamp;
+
if(lar->ray_samp_type & LA_SAMP_JITTER) {
/* made it threadsafe */
if(ys & 1) {
if(lar->xold1!=xs || lar->yold1!=ys) {
- jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, BLI_frand(), BLI_frand());
+ jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, BLI_thread_frand(1), BLI_thread_frand(1));
lar->xold1= xs; lar->yold1= ys;
}
return lar->jitter+2*tot;
}
else {
if(lar->xold2!=xs || lar->yold2!=ys) {
- jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, BLI_frand(), BLI_frand());
+ jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, BLI_thread_frand(0), BLI_thread_frand(0));
lar->xold2= xs; lar->yold2= ys;
}
return lar->jitter+4*tot;
@@ -1907,11 +1882,15 @@ static void DS_energy(float *sphere, int tot, float *vec)
}
-static void DistributedSpherical(float *sphere, int tot, int iter)
+/* called from convertBlenderScene.c */
+/* creates an equally distributed spherical sample pattern */
+void init_ao_sphere(float *sphere, int tot, int iter)
{
float *fp;
int a;
+ BLI_srandom(tot);
+
/* init */
fp= sphere;
for(a=0; a<tot; a++, fp+= 3) {
@@ -1948,56 +1927,51 @@ static float *threadsafe_table_sphere(int test, int xs, int ys)
static float *sphere_sampler(int type, int resol, int xs, int ys)
{
- static float sphere[2*3*256];
- float *sphere1;
int tot;
float *vec;
- if(resol>16) return sphere;
+ if(resol>16) resol= 16;
tot= 2*resol*resol;
if (type & WO_AORNDSMP) {
+ static float sphere[2*3*256];
int a;
- /* total random sampling */
+ /* total random sampling. NOT THREADSAFE! (should be removed, is not useful) */
vec= sphere;
for (a=0; a<tot; a++, vec+=3) {
RandomSpherical(vec);
}
+
+ return sphere;
}
else {
- static int last_distr= 0;
+ float *sphere;
float cosf, sinf, cost, sint;
float ang, *vec1;
int a;
- if(last_distr!=resol) {
- last_distr= resol;
- DistributedSpherical(sphere, tot, 16);
- }
-
- sphere1= threadsafe_table_sphere(1, xs, ys);
- if(sphere1==NULL) {
- sphere1= threadsafe_table_sphere(0, xs, ys);
+ sphere= threadsafe_table_sphere(1, xs, ys); // returns table if xs and ys were equal to last call
+ if(sphere==NULL) {
+ sphere= threadsafe_table_sphere(0, xs, ys);
// random rotation
- ang= BLI_frand();
+ ang= BLI_thread_frand(ys & 1);
sinf= sin(ang); cosf= cos(ang);
- ang= BLI_frand();
+ ang= BLI_thread_frand(ys & 1);
sint= sin(ang); cost= cos(ang);
- vec= sphere;
- vec1= sphere1;
+ vec= R.wrld.aosphere;
+ vec1= sphere;
for (a=0; a<tot; a++, vec+=3, vec1+=3) {
vec1[0]= cost*cosf*vec[0] - sinf*vec[1] + sint*cosf*vec[2];
vec1[1]= cost*sinf*vec[0] + cosf*vec[1] + sint*sinf*vec[2];
vec1[2]= -sint*vec[0] + cost*vec[2];
}
}
- return sphere1;
+ return sphere;
}
- return sphere;
}
@@ -2157,7 +2131,7 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
else shadfac[3]= 1.0; // 1.0=full light
fac= 0.0;
- jitlamp= jitter_plane(lar, floor(shi->xs+0.5), floor(shi->ys+0.5));
+ jitlamp= give_jitter_plane(lar, floor(shi->xs+0.5), floor(shi->ys+0.5));
a= lar->ray_totsamp;
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index b6f712c0212..9f0cf4f23f3 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -2536,8 +2536,11 @@ static int do_renderlineDA(void *poin)
float fcol[4], *acol=NULL, *rb1, *rb2, *rb3;
long *rd= rl->rd;
int zbuf, samp, curmask, face, mask, fullmask;
- int b, x, full_osa;
-
+ int b, x, full_osa, seed;
+
+ /* we set per pixel a fixed seed, for random AO and shadow samples */
+ seed= (R.ystart + rl->y + R.afmy)*R.r.xsch + R.xstart + R.afmx;
+
fullmask= (1<<R.osa)-1;
rb1= rl->rb1;
rb2= rl->rb2;
@@ -2549,7 +2552,9 @@ static int do_renderlineDA(void *poin)
}
for(x=0; x<R.rectx; x++, rd++) {
-
+
+ BLI_thread_srandom(rl->y & 1, seed+x);
+
ps= (PixStr *)(*rd);
mask= 0;
@@ -2829,7 +2834,10 @@ static int do_renderline(void *poin)
struct renderline *rl= poin;
float *fcol= rl->rowbuf;
float *acol=NULL;
- int x, *rz, *rp;
+ int x, *rz, *rp, seed;
+
+ /* we set per pixel a fixed seed, for random AO and shadow samples */
+ seed= (R.ystart + rl->y + R.afmy)*R.r.xsch + R.xstart + R.afmx;
if(R.flag & R_ZTRA) { /* zbuf tra */
abufsetrow(rl->acol, rl->ys);
@@ -2837,6 +2845,8 @@ static int do_renderline(void *poin)
}
for(x=0, rz= rl->rz, rp= rl->rp; x<R.rectx; x++, rz++, rp++, fcol+=4) {
+ BLI_thread_srandom(rl->ys & 1, seed+x);
+
shadepixel_sky((float)x, rl->y, *rz, *rp, 0, fcol);
if(acol) {
if(acol[3]!=0.0) addAlphaOverFloat(fcol, acol);
@@ -2848,7 +2858,7 @@ static int do_renderline(void *poin)
scanlinehalo(rl->rz, rl->rowbuf, rl->ys);
}
- transferColourBufferToOutput(rl->rowbuf, rl->y);
+ transferColourBufferToOutput(rl->rowbuf, rl->ys);
if(R.rectftot) {
memcpy(R.rectftot + 4*rl->ys*R.rectx, rl->rowbuf, 4*sizeof(float)*R.rectx);
diff --git a/source/blender/renderconverter/intern/convertBlenderScene.c b/source/blender/renderconverter/intern/convertBlenderScene.c
index bc9aceb9ad5..b6fb272036e 100644
--- a/source/blender/renderconverter/intern/convertBlenderScene.c
+++ b/source/blender/renderconverter/intern/convertBlenderScene.c
@@ -1540,7 +1540,7 @@ static void area_lamp_vectors(LampRen *lar)
}
/* If lar takes more lamp data, the decoupling will be better. */
-void RE_add_render_lamp(Object *ob, int doshadbuf)
+void RE_add_render_lamp(Object *ob, int actual_render)
{
Lamp *la;
LampRen *lar, **temp;
@@ -1715,13 +1715,17 @@ void RE_add_render_lamp(Object *ob, int doshadbuf)
}
}
- /* yafray: shadowbuffers only needed for internal render */
- if (R.r.renderer==R_INTERN)
- {
- if( (R.r.mode & R_SHADOW) && (lar->mode & LA_SHAD) && (la->type==LA_SPOT) && doshadbuf ) {
- /* Per lamp, one shadow buffer is made. */
- Mat4CpyMat4(mat, ob->obmat);
- RE_initshadowbuf(lar, mat); // mat is altered
+ /* yafray: shadowbuffers and jitter only needed for internal render */
+ if (actual_render && R.r.renderer==R_INTERN) {
+ if(R.r.mode & R_SHADOW) {
+ if (la->type==LA_SPOT && (lar->mode & LA_SHAD) ) {
+ /* Per lamp, one shadow buffer is made. */
+ Mat4CpyMat4(mat, ob->obmat);
+ RE_initshadowbuf(lar, mat); // mat is altered
+ }
+ else if(la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) ) {
+ init_jitter_plane(lar);
+ }
}
}
@@ -2300,6 +2304,10 @@ void RE_freeRotateBlenderScene(void)
end_render_textures();
end_render_materials();
end_radio_render();
+ if(R.wrld.aosphere) {
+ MEM_freeN(R.wrld.aosphere);
+ R.wrld.aosphere= NULL;
+ }
R.totvlak=R.totvert=R.totlamp=R.tothalo= 0;
}
@@ -2484,6 +2492,10 @@ void RE_rotateBlenderScene(void)
}
init_render_world(); /* do first, because of ambient. also requires R.osa set correct */
+ if( (R.wrld.mode & WO_AMB_OCC) && (R.r.mode & R_RAYTRACE) ) {
+ R.wrld.aosphere= MEM_mallocN(2*3*R.wrld.aosamp*R.wrld.aosamp*sizeof(float), "AO sphere");
+ init_ao_sphere(R.wrld.aosphere, R.wrld.aosamp*R.wrld.aosamp, 16);
+ }
init_render_textures();
init_render_materials();
diff --git a/source/blender/src/previewrender.c b/source/blender/src/previewrender.c
index 622e1e4bbf4..5c0902ab5b9 100644
--- a/source/blender/src/previewrender.c
+++ b/source/blender/src/previewrender.c
@@ -1140,7 +1140,7 @@ void BIF_previewrender(SpaceButs *sbuts)
init_render_world();
init_render_textures(); /* do not do it twice!! (brightness) */
R.totlamp= 0;
- RE_add_render_lamp(ob, 0); /* 0=no shadbuf */
+ RE_add_render_lamp(ob, 0); /* 0=no shadbuf or tables */
lar= R.la[0];
/* exceptions: */