Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F63717231
ambient.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, May 22, 01:28
Size
19 KB
Mime Type
text/x-c
Expires
Fri, May 24, 01:28 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
17810080
Attached To
R10977 RADIANCE Photon Map
ambient.c
View Options
static
const
char
RCSid
[]
=
"$Id: ambient.c,v 2.114 2022/04/11 00:45:30 greg Exp $"
;
/*
* ambient.c - routines dealing with ambient (inter-reflected) component.
*
* Declarations of external symbols in ambient.h
*/
#include "copyright.h"
#include <string.h>
#include "platform.h"
#include "ray.h"
#include "otypes.h"
#include "otspecial.h"
#include "resolu.h"
#include "ambient.h"
#include "random.h"
#include "pmapamb.h"
#ifndef OCTSCALE
#define OCTSCALE 1.0
/* ceil((valid rad.)/(cube size)) */
#endif
#ifndef MAXASET
#define MAXASET 4095
/* maximum number of elements in ambient set */
#endif
OBJECT
ambset
[
MAXASET
+
1
]
=
{
0
};
/* ambient include/exclude set */
double
maxarad
;
/* maximum ambient radius */
double
minarad
;
/* minimum ambient radius */
static
AMBTREE
atrunk
;
/* our ambient trunk node */
static
FILE
*
ambfp
=
NULL
;
/* ambient file pointer */
static
int
nunflshed
=
0
;
/* number of unflushed ambient values */
static
double
avsum
=
0.
;
/* computed ambient value sum (log) */
static
unsigned
int
navsum
=
0
;
/* number of values in avsum */
static
unsigned
int
nambvals
=
0
;
/* total number of indirect values */
static
unsigned
int
nambshare
=
0
;
/* number of values from file */
static
FILE
*
ambinp
=
NULL
;
/* auxiliary file for input */
static
long
lastpos
=
-
1
;
/* last flush position */
#define AMBFLUSH (BUFSIZ/AMBVALSIZ)
#define newambval() (AMBVAL *)malloc(sizeof(AMBVAL))
#define tfunc(lwr, x, upr) (((x)-(lwr))/((upr)-(lwr)))
static
void
initambfile
(
int
creat
);
static
void
avsave
(
AMBVAL
*
av
);
static
AMBVAL
*
avstore
(
AMBVAL
*
aval
);
static
AMBTREE
*
newambtree
(
void
);
static
void
freeambtree
(
AMBTREE
*
atp
);
typedef
void
unloadtf_t
(
AMBVAL
*
);
static
unloadtf_t
avinsert
;
static
unloadtf_t
avfree
;
static
void
unloadatree
(
AMBTREE
*
at
,
unloadtf_t
*
f
);
static
void
sortambvals
(
void
);
static
int
plugaleak
(
RAY
*
r
,
AMBVAL
*
ap
,
FVECT
anorm
,
double
ang
);
static
double
sumambient
(
COLOR
acol
,
RAY
*
r
,
FVECT
rn
,
int
al
,
AMBTREE
*
at
,
FVECT
c0
,
double
s
);
static
int
makeambient
(
COLOR
acol
,
RAY
*
r
,
FVECT
rn
,
int
al
);
static
int
extambient
(
COLOR
cr
,
AMBVAL
*
ap
,
FVECT
pv
,
FVECT
nv
,
FVECT
uvw
[
3
]);
#ifdef F_SETLKW
static
void
aflock
(
int
typ
);
#endif
void
setambres
(
/* set ambient resolution */
int
ar
)
{
ambres
=
ar
<
0
?
0
:
ar
;
/* may be done already */
/* set min & max radii */
if
(
ar
<=
0
)
{
minarad
=
0
;
maxarad
=
thescene
.
cusize
*
0.2
;
}
else
{
minarad
=
thescene
.
cusize
/
ar
;
maxarad
=
64.0
*
minarad
;
/* heuristic */
if
(
maxarad
>
thescene
.
cusize
*
0.2
)
maxarad
=
thescene
.
cusize
*
0.2
;
}
if
(
minarad
<=
FTINY
)
minarad
=
10.0
*
FTINY
;
if
(
maxarad
<=
minarad
)
maxarad
=
64.0
*
minarad
;
}
void
setambacc
(
/* set ambient accuracy */
double
newa
)
{
static
double
olda
;
/* remember previous setting here */
newa
*=
(
newa
>
0
);
if
(
fabs
(
newa
-
olda
)
>=
.05
*
(
newa
+
olda
))
{
ambacc
=
newa
;
if
(
ambacc
>
FTINY
&&
nambvals
>
0
)
sortambvals
();
/* rebuild tree */
}
}
void
setambient
(
void
)
/* initialize calculation */
{
int
readonly
=
0
;
long
flen
;
AMBVAL
amb
;
/* make sure we're fresh */
ambdone
();
/* init ambient limits */
setambres
(
ambres
);
setambacc
(
ambacc
);
if
(
ambfile
==
NULL
||
!
ambfile
[
0
])
return
;
if
(
ambacc
<=
FTINY
)
{
sprintf
(
errmsg
,
"zero ambient accuracy so
\"
%s
\"
not opened"
,
ambfile
);
error
(
WARNING
,
errmsg
);
return
;
}
/* open ambient file */
if
((
ambfp
=
fopen
(
ambfile
,
"r+"
))
==
NULL
)
readonly
=
(
ambfp
=
fopen
(
ambfile
,
"r"
))
!=
NULL
;
if
(
ambfp
!=
NULL
)
{
initambfile
(
0
);
/* file exists */
lastpos
=
ftell
(
ambfp
);
while
(
readambval
(
&
amb
,
ambfp
))
avstore
(
&
amb
);
nambshare
=
nambvals
;
/* share loaded values */
if
(
readonly
)
{
sprintf
(
errmsg
,
"loaded %u values from read-only ambient file"
,
nambvals
);
error
(
WARNING
,
errmsg
);
fclose
(
ambfp
);
/* close file so no writes */
ambfp
=
NULL
;
return
;
/* avoid ambsync() */
}
/* align file pointer */
lastpos
+=
(
long
)
nambvals
*
AMBVALSIZ
;
flen
=
lseek
(
fileno
(
ambfp
),
(
off_t
)
0
,
SEEK_END
);
if
(
flen
!=
lastpos
)
{
sprintf
(
errmsg
,
"ignoring last %ld values in ambient file (corrupted)"
,
(
flen
-
lastpos
)
/
AMBVALSIZ
);
error
(
WARNING
,
errmsg
);
fseek
(
ambfp
,
lastpos
,
SEEK_SET
);
ftruncate
(
fileno
(
ambfp
),
(
off_t
)
lastpos
);
}
}
else
if
((
ambfp
=
fopen
(
ambfile
,
"w+"
))
!=
NULL
)
{
initambfile
(
1
);
/* else create new file */
fflush
(
ambfp
);
lastpos
=
ftell
(
ambfp
);
}
else
{
sprintf
(
errmsg
,
"cannot open ambient file
\"
%s
\"
"
,
ambfile
);
error
(
SYSTEM
,
errmsg
);
}
#ifdef F_SETLKW
aflock
(
F_UNLCK
);
/* release file */
#endif
}
void
ambdone
(
void
)
/* close ambient file and free memory */
{
if
(
ambfp
!=
NULL
)
{
/* close ambient file */
ambsync
();
fclose
(
ambfp
);
ambfp
=
NULL
;
if
(
ambinp
!=
NULL
)
{
fclose
(
ambinp
);
ambinp
=
NULL
;
}
lastpos
=
-
1
;
}
/* free ambient tree */
unloadatree
(
&
atrunk
,
avfree
);
/* reset state variables */
avsum
=
0.
;
navsum
=
0
;
nambvals
=
0
;
nambshare
=
0
;
}
void
ambnotify
(
/* record new modifier */
OBJECT
obj
)
{
static
int
hitlimit
=
0
;
OBJREC
*
o
;
char
**
amblp
;
if
(
obj
==
OVOID
)
{
/* starting over */
ambset
[
0
]
=
0
;
hitlimit
=
0
;
return
;
}
o
=
objptr
(
obj
);
if
(
hitlimit
||
!
ismodifier
(
o
->
otype
))
return
;
for
(
amblp
=
amblist
;
*
amblp
!=
NULL
;
amblp
++
)
if
(
!
strcmp
(
o
->
oname
,
*
amblp
))
{
if
(
ambset
[
0
]
>=
MAXASET
)
{
error
(
WARNING
,
"too many modifiers in ambient list"
);
hitlimit
++
;
return
;
/* should this be fatal? */
}
insertelem
(
ambset
,
obj
);
return
;
}
}
void
multambient
(
/* compute ambient component & multiply by coef. */
COLOR
aval
,
RAY
*
r
,
FVECT
nrm
)
{
static
double
logAvgAbsorp
=
1
;
static
int
rdepth
=
0
;
/* ambient recursion */
COLOR
acol
,
caustic
;
int
i
,
ok
;
double
d
,
l
;
/* PMAP: Factor in ambient from photon map, if enabled and ray is
* ambient. Return as all ambient components accounted for, else
* continue. */
if
(
ambPmap
(
aval
,
r
,
rdepth
))
return
;
if
(
logAvgAbsorp
>
0
)
/* exclude in -aw to avoid growth */
logAvgAbsorp
=
log
(
1.
-
AVGREFL
);
/* PMAP: Factor in specular-diffuse ambient (caustics) from photon
* map, if enabled and ray is primary, else caustic is zero. Continue
* with RADIANCE ambient calculation */
copycolor
(
caustic
,
aval
);
ambPmapCaustic
(
caustic
,
r
,
rdepth
);
if
(
ambdiv
<=
0
)
/* no ambient calculation */
goto
dumbamb
;
/* check number of bounces */
if
(
rdepth
>=
ambounce
)
goto
dumbamb
;
/* check ambient list */
if
(
ambincl
!=
-
1
&&
r
->
ro
!=
NULL
&&
ambincl
!=
inset
(
ambset
,
r
->
ro
->
omod
))
goto
dumbamb
;
if
(
ambacc
<=
FTINY
)
{
/* no ambient storage */
FVECT
uvd
[
2
];
float
dgrad
[
2
],
*
dgp
=
NULL
;
if
(
nrm
!=
r
->
ron
&&
DOT
(
nrm
,
r
->
ron
)
<
0.9999
)
dgp
=
dgrad
;
/* compute rotational grad. */
copycolor
(
acol
,
aval
);
rdepth
++
;
ok
=
doambient
(
acol
,
r
,
r
->
rweight
,
uvd
,
NULL
,
NULL
,
dgp
,
NULL
);
rdepth
--
;
if
(
!
ok
)
goto
dumbamb
;
if
((
ok
>
0
)
&
(
dgp
!=
NULL
))
{
/* apply texture */
FVECT
v1
;
VCROSS
(
v1
,
r
->
ron
,
nrm
);
d
=
1.0
;
for
(
i
=
3
;
i
--
;
)
d
+=
v1
[
i
]
*
(
dgp
[
0
]
*
uvd
[
0
][
i
]
+
dgp
[
1
]
*
uvd
[
1
][
i
]);
if
(
d
>=
0.05
)
scalecolor
(
acol
,
d
);
}
copycolor
(
aval
,
acol
);
/* PMAP: add in caustic */
addcolor
(
aval
,
caustic
);
return
;
}
/* interpolate ambient value */
setcolor
(
acol
,
0.0
,
0.0
,
0.0
);
d
=
sumambient
(
acol
,
r
,
nrm
,
rdepth
,
&
atrunk
,
thescene
.
cuorg
,
thescene
.
cusize
);
if
(
d
>
FTINY
)
{
d
=
1.0
/
d
;
scalecolor
(
acol
,
d
);
multcolor
(
aval
,
acol
);
/* PMAP: add in caustic */
addcolor
(
aval
,
caustic
);
return
;
}
rdepth
++
;
/* need to cache new value */
ok
=
makeambient
(
acol
,
r
,
nrm
,
rdepth
-
1
);
rdepth
--
;
if
(
ok
)
{
multcolor
(
aval
,
acol
);
/* computed new value */
/* PMAP: add in caustic */
addcolor
(
aval
,
caustic
);
return
;
}
dumbamb:
/* return global value */
if
((
ambvwt
<=
0
)
|
(
navsum
==
0
))
{
multcolor
(
aval
,
ambval
);
/* PMAP: add in caustic */
addcolor
(
aval
,
caustic
);
return
;
}
l
=
bright
(
ambval
);
/* average in computations */
if
(
l
>
FTINY
)
{
d
=
(
log
(
l
)
*
(
double
)
ambvwt
+
avsum
+
logAvgAbsorp
*
navsum
)
/
(
double
)(
ambvwt
+
navsum
);
d
=
exp
(
d
)
/
l
;
scalecolor
(
aval
,
d
);
multcolor
(
aval
,
ambval
);
/* apply color of ambval */
}
else
{
d
=
exp
(
avsum
/
(
double
)
navsum
+
logAvgAbsorp
);
scalecolor
(
aval
,
d
);
/* neutral color */
}
}
/* Plug a potential leak where ambient cache value is occluded */
static
int
plugaleak
(
RAY
*
r
,
AMBVAL
*
ap
,
FVECT
anorm
,
double
ang
)
{
const
double
cost70sq
=
0.1169778
;
/* cos(70deg)^2 */
RAY
rtst
;
FVECT
vdif
;
double
normdot
,
ndotd
,
nadotd
;
double
a
,
b
,
c
,
t
[
2
];
ang
+=
2.
*
PI
*
(
ang
<
0
);
/* check direction flags */
if
(
!
(
ap
->
corral
>>
(
int
)(
ang
*
(
16.
/
PI
))
&
1
)
)
return
(
0
);
/*
* Generate test ray, targeting 20 degrees above sample point plane
* along surface normal from cache position. This should be high
* enough to miss local geometry we don't really care about.
*/
VSUB
(
vdif
,
ap
->
pos
,
r
->
rop
);
normdot
=
DOT
(
anorm
,
r
->
ron
);
ndotd
=
DOT
(
vdif
,
r
->
ron
);
nadotd
=
DOT
(
vdif
,
anorm
);
a
=
normdot
*
normdot
-
cost70sq
;
b
=
2.0
*
(
normdot
*
ndotd
-
nadotd
*
cost70sq
);
c
=
ndotd
*
ndotd
-
DOT
(
vdif
,
vdif
)
*
cost70sq
;
if
(
quadratic
(
t
,
a
,
b
,
c
)
!=
2
)
return
(
1
);
/* should rarely happen */
if
(
t
[
1
]
<=
FTINY
)
return
(
0
);
/* should fail behind test */
rayorigin
(
&
rtst
,
SHADOW
,
r
,
NULL
);
VSUM
(
rtst
.
rdir
,
vdif
,
anorm
,
t
[
1
]);
/* further dist. > plane */
rtst
.
rmax
=
normalize
(
rtst
.
rdir
);
/* short ray test */
while
(
localhit
(
&
rtst
,
&
thescene
))
{
/* check for occluder */
OBJREC
*
m
=
findmaterial
(
rtst
.
ro
);
if
(
m
!=
NULL
&&
!
istransp
(
m
->
otype
)
&&
!
isBSDFproxy
(
m
)
&&
(
rtst
.
clipset
==
NULL
||
!
inset
(
rtst
.
clipset
,
rtst
.
ro
->
omod
)))
return
(
1
);
/* plug light leak */
VCOPY
(
rtst
.
rorg
,
rtst
.
rop
);
/* skip invisible surface */
rtst
.
rmax
-=
rtst
.
rot
;
rayclear
(
&
rtst
);
}
return
(
0
);
/* seems we're OK */
}
static
double
sumambient
(
/* get interpolated ambient value */
COLOR
acol
,
RAY
*
r
,
FVECT
rn
,
int
al
,
AMBTREE
*
at
,
FVECT
c0
,
double
s
)
{
/* initial limit is 10 degrees plus ambacc radians */
const
double
minangle
=
10.0
*
PI
/
180.
;
double
maxangle
=
minangle
+
ambacc
;
double
wsum
=
0.0
;
FVECT
ck0
;
int
i
,
j
;
AMBVAL
*
av
;
if
(
at
->
kid
!=
NULL
)
{
/* sum children first */
s
*=
0.5
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
for
(
j
=
0
;
j
<
3
;
j
++
)
{
ck0
[
j
]
=
c0
[
j
];
if
(
1
<<
j
&
i
)
ck0
[
j
]
+=
s
;
if
(
r
->
rop
[
j
]
<
ck0
[
j
]
-
OCTSCALE
*
s
)
break
;
if
(
r
->
rop
[
j
]
>
ck0
[
j
]
+
(
1.0
+
OCTSCALE
)
*
s
)
break
;
}
if
(
j
==
3
)
wsum
+=
sumambient
(
acol
,
r
,
rn
,
al
,
at
->
kid
+
i
,
ck0
,
s
);
}
/* good enough? */
if
(
wsum
>=
0.05
&&
s
>
minarad
*
10.0
)
return
(
wsum
);
}
/* adjust maximum angle */
if
(
at
->
alist
!=
NULL
&&
(
at
->
alist
->
lvl
<=
al
)
&
(
r
->
rweight
<
0.6
))
maxangle
=
(
maxangle
-
PI
/
2.
)
*
pow
(
r
->
rweight
,
0.13
)
+
PI
/
2.
;
/* sum this node */
for
(
av
=
at
->
alist
;
av
!=
NULL
;
av
=
av
->
next
)
{
double
u
,
v
,
d
,
delta_r2
,
delta_t2
;
COLOR
ct
;
FVECT
uvw
[
3
];
/*
* Ambient level test
*/
if
(
av
->
lvl
>
al
||
/* list sorted, so this works */
(
av
->
lvl
==
al
)
&
(
av
->
weight
<
0.9
*
r
->
rweight
))
break
;
/*
* Direction test using unperturbed normal
*/
decodedir
(
uvw
[
2
],
av
->
ndir
);
d
=
DOT
(
uvw
[
2
],
r
->
ron
);
if
(
d
<=
0.0
)
/* >= 90 degrees */
continue
;
delta_r2
=
2.0
-
2.0
*
d
;
/* approx. radians^2 */
if
(
delta_r2
>=
maxangle
*
maxangle
)
continue
;
/*
* Modified ray behind test
*/
VSUB
(
ck0
,
r
->
rop
,
av
->
pos
);
d
=
DOT
(
ck0
,
uvw
[
2
]);
if
(
d
<
-
minarad
*
ambacc
-
.001
)
continue
;
d
/=
av
->
rad
[
0
];
delta_t2
=
d
*
d
;
if
(
delta_t2
>=
ambacc
*
ambacc
)
continue
;
/*
* Elliptical radii test based on Hessian
*/
decodedir
(
uvw
[
0
],
av
->
udir
);
VCROSS
(
uvw
[
1
],
uvw
[
2
],
uvw
[
0
]);
d
=
(
u
=
DOT
(
ck0
,
uvw
[
0
]))
/
av
->
rad
[
0
];
delta_t2
+=
d
*
d
;
d
=
(
v
=
DOT
(
ck0
,
uvw
[
1
]))
/
av
->
rad
[
1
];
delta_t2
+=
d
*
d
;
if
(
delta_t2
>=
ambacc
*
ambacc
)
continue
;
/*
* Test for potential light leak
*/
if
(
av
->
corral
&&
plugaleak
(
r
,
av
,
uvw
[
2
],
atan2a
(
v
,
u
)))
continue
;
/*
* Extrapolate value and compute final weight (hat function)
*/
if
(
!
extambient
(
ct
,
av
,
r
->
rop
,
rn
,
uvw
))
continue
;
d
=
tfunc
(
maxangle
,
sqrt
(
delta_r2
),
0.0
)
*
tfunc
(
ambacc
,
sqrt
(
delta_t2
),
0.0
);
scalecolor
(
ct
,
d
);
addcolor
(
acol
,
ct
);
wsum
+=
d
;
}
return
(
wsum
);
}
static
int
makeambient
(
/* make a new ambient value for storage */
COLOR
acol
,
RAY
*
r
,
FVECT
rn
,
int
al
)
{
AMBVAL
amb
;
FVECT
uvw
[
3
];
int
i
;
amb
.
weight
=
1.0
;
/* compute weight */
for
(
i
=
al
;
i
--
>
0
;
)
amb
.
weight
*=
AVGREFL
;
if
(
r
->
rweight
<
0.1
*
amb
.
weight
)
/* heuristic override */
amb
.
weight
=
1.25
*
r
->
rweight
;
setcolor
(
acol
,
AVGREFL
,
AVGREFL
,
AVGREFL
);
/* compute ambient */
i
=
doambient
(
acol
,
r
,
amb
.
weight
,
uvw
,
amb
.
rad
,
amb
.
gpos
,
amb
.
gdir
,
&
amb
.
corral
);
scalecolor
(
acol
,
1.
/
AVGREFL
);
/* undo assumed reflectance */
if
(
i
<=
0
||
amb
.
rad
[
0
]
<=
FTINY
)
/* no Hessian or zero radius */
return
(
i
);
/* store value */
VCOPY
(
amb
.
pos
,
r
->
rop
);
amb
.
ndir
=
encodedir
(
r
->
ron
);
amb
.
udir
=
encodedir
(
uvw
[
0
]);
amb
.
lvl
=
al
;
copycolor
(
amb
.
val
,
acol
);
/* insert into tree */
avsave
(
&
amb
);
/* and save to file */
if
(
rn
!=
r
->
ron
)
{
/* texture */
VCOPY
(
uvw
[
2
],
r
->
ron
);
extambient
(
acol
,
&
amb
,
r
->
rop
,
rn
,
uvw
);
}
return
(
1
);
}
static
int
extambient
(
/* extrapolate value at pv, nv */
COLOR
cr
,
AMBVAL
*
ap
,
FVECT
pv
,
FVECT
nv
,
FVECT
uvw
[
3
]
)
{
const
double
min_d
=
0.05
;
const
double
max_d
=
20.
;
static
FVECT
my_uvw
[
3
];
FVECT
v1
;
int
i
;
double
d
=
1.0
;
/* zeroeth order */
if
(
uvw
==
NULL
)
{
/* need local coordinates? */
decodedir
(
my_uvw
[
2
],
ap
->
ndir
);
decodedir
(
my_uvw
[
0
],
ap
->
udir
);
VCROSS
(
my_uvw
[
1
],
my_uvw
[
2
],
my_uvw
[
0
]);
uvw
=
my_uvw
;
}
for
(
i
=
3
;
i
--
;
)
/* gradient due to translation */
d
+=
(
pv
[
i
]
-
ap
->
pos
[
i
])
*
(
ap
->
gpos
[
0
]
*
uvw
[
0
][
i
]
+
ap
->
gpos
[
1
]
*
uvw
[
1
][
i
]);
VCROSS
(
v1
,
uvw
[
2
],
nv
);
/* gradient due to rotation */
for
(
i
=
3
;
i
--
;
)
d
+=
v1
[
i
]
*
(
ap
->
gdir
[
0
]
*
uvw
[
0
][
i
]
+
ap
->
gdir
[
1
]
*
uvw
[
1
][
i
]);
if
(
d
<
min_d
)
/* clamp min/max scaling */
d
=
min_d
;
else
if
(
d
>
max_d
)
d
=
max_d
;
copycolor
(
cr
,
ap
->
val
);
scalecolor
(
cr
,
d
);
return
(
d
>
min_d
);
}
static
void
avinsert
(
/* insert ambient value in our tree */
AMBVAL
*
av
)
{
AMBTREE
*
at
;
AMBVAL
*
ap
;
AMBVAL
avh
;
FVECT
ck0
;
double
s
;
int
branch
;
int
i
;
if
(
av
->
rad
[
0
]
<=
FTINY
)
error
(
CONSISTENCY
,
"zero ambient radius in avinsert"
);
at
=
&
atrunk
;
VCOPY
(
ck0
,
thescene
.
cuorg
);
s
=
thescene
.
cusize
;
while
(
s
*
(
OCTSCALE
/
2
)
>
av
->
rad
[
1
]
*
ambacc
)
{
if
(
at
->
kid
==
NULL
)
if
((
at
->
kid
=
newambtree
())
==
NULL
)
error
(
SYSTEM
,
"out of memory in avinsert"
);
s
*=
0.5
;
branch
=
0
;
for
(
i
=
0
;
i
<
3
;
i
++
)
if
(
av
->
pos
[
i
]
>
ck0
[
i
]
+
s
)
{
ck0
[
i
]
+=
s
;
branch
|=
1
<<
i
;
}
at
=
at
->
kid
+
branch
;
}
avh
.
next
=
at
->
alist
;
/* order by increasing level */
for
(
ap
=
&
avh
;
ap
->
next
!=
NULL
;
ap
=
ap
->
next
)
if
(
ap
->
next
->
lvl
>
av
->
lvl
||
(
ap
->
next
->
lvl
==
av
->
lvl
)
&
(
ap
->
next
->
weight
<=
av
->
weight
)
)
break
;
av
->
next
=
ap
->
next
;
ap
->
next
=
(
AMBVAL
*
)
av
;
at
->
alist
=
avh
.
next
;
}
static
void
initambfile
(
/* initialize ambient file */
int
cre8
)
{
extern
char
*
progname
,
*
octname
;
static
char
*
mybuf
=
NULL
;
#ifdef F_SETLKW
aflock
(
cre8
?
F_WRLCK
:
F_RDLCK
);
#endif
SET_FILE_BINARY
(
ambfp
);
if
(
mybuf
==
NULL
)
mybuf
=
(
char
*
)
bmalloc
(
BUFSIZ
+
8
);
setbuf
(
ambfp
,
mybuf
);
if
(
cre8
)
{
/* new file */
newheader
(
"RADIANCE"
,
ambfp
);
fprintf
(
ambfp
,
"%s -av %g %g %g -aw %d -ab %d -aa %g "
,
progname
,
colval
(
ambval
,
RED
),
colval
(
ambval
,
GRN
),
colval
(
ambval
,
BLU
),
ambvwt
,
ambounce
,
ambacc
);
fprintf
(
ambfp
,
"-ad %d -as %d -ar %d "
,
ambdiv
,
ambssamp
,
ambres
);
fprintf
(
ambfp
,
"-dt %g -dc %g -ss %g -lr %d -lw %g "
,
shadthresh
,
shadcert
,
specjitter
,
maxdepth
,
minweight
);
if
(
octname
!=
NULL
)
fputs
(
octname
,
ambfp
);
fputc
(
'\n'
,
ambfp
);
fprintf
(
ambfp
,
"SOFTWARE= %s
\n
"
,
VersionID
);
fputnow
(
ambfp
);
fputformat
(
AMBFMT
,
ambfp
);
fputc
(
'\n'
,
ambfp
);
putambmagic
(
ambfp
);
}
else
if
(
checkheader
(
ambfp
,
AMBFMT
,
NULL
)
<
0
||
!
hasambmagic
(
ambfp
))
error
(
USER
,
"bad ambient file"
);
}
static
void
avsave
(
/* insert and save an ambient value */
AMBVAL
*
av
)
{
avstore
(
av
);
if
(
ambfp
==
NULL
)
return
;
if
(
writambval
(
av
,
ambfp
)
<
0
)
goto
writerr
;
if
(
++
nunflshed
>=
AMBFLUSH
)
if
(
ambsync
()
==
EOF
)
goto
writerr
;
return
;
writerr:
error
(
SYSTEM
,
"error writing to ambient file"
);
}
static
AMBVAL
*
avstore
(
/* allocate memory and save aval */
AMBVAL
*
aval
)
{
AMBVAL
*
av
;
double
d
;
if
((
av
=
newambval
())
==
NULL
)
error
(
SYSTEM
,
"out of memory in avstore"
);
*
av
=
*
aval
;
av
->
next
=
NULL
;
nambvals
++
;
d
=
bright
(
av
->
val
);
if
(
d
>
FTINY
)
{
/* add to log sum for averaging */
avsum
+=
log
(
d
);
navsum
++
;
}
avinsert
(
av
);
/* insert in our cache tree */
return
(
av
);
}
#define ATALLOCSZ 512
/* #/8 trees to allocate at once */
static
AMBTREE
*
atfreelist
=
NULL
;
/* free ambient tree structures */
static
AMBTREE
*
newambtree
(
void
)
/* allocate 8 ambient tree structs */
{
AMBTREE
*
atp
,
*
upperlim
;
if
(
atfreelist
==
NULL
)
{
/* get more nodes */
atfreelist
=
(
AMBTREE
*
)
malloc
(
ATALLOCSZ
*
8
*
sizeof
(
AMBTREE
));
if
(
atfreelist
==
NULL
)
return
(
NULL
);
/* link new free list */
upperlim
=
atfreelist
+
8
*
(
ATALLOCSZ
-
1
);
for
(
atp
=
atfreelist
;
atp
<
upperlim
;
atp
+=
8
)
atp
->
kid
=
atp
+
8
;
atp
->
kid
=
NULL
;
}
atp
=
atfreelist
;
atfreelist
=
atp
->
kid
;
memset
(
atp
,
0
,
8
*
sizeof
(
AMBTREE
));
return
(
atp
);
}
static
void
freeambtree
(
/* free 8 ambient tree structs */
AMBTREE
*
atp
)
{
atp
->
kid
=
atfreelist
;
atfreelist
=
atp
;
}
static
void
unloadatree
(
/* unload an ambient value tree */
AMBTREE
*
at
,
unloadtf_t
*
f
)
{
AMBVAL
*
av
;
int
i
;
/* transfer values at this node */
for
(
av
=
at
->
alist
;
av
!=
NULL
;
av
=
at
->
alist
)
{
at
->
alist
=
av
->
next
;
av
->
next
=
NULL
;
(
*
f
)(
av
);
}
if
(
at
->
kid
==
NULL
)
return
;
for
(
i
=
0
;
i
<
8
;
i
++
)
/* transfer and free children */
unloadatree
(
at
->
kid
+
i
,
f
);
freeambtree
(
at
->
kid
);
at
->
kid
=
NULL
;
}
static
void
avfree
(
AMBVAL
*
av
)
{
free
(
av
);
}
static
void
sortambvals
(
void
)
/* resort ambient values */
{
AMBTREE
oldatrunk
=
atrunk
;
atrunk
.
alist
=
NULL
;
atrunk
.
kid
=
NULL
;
unloadatree
(
&
oldatrunk
,
avinsert
);
}
#ifdef F_SETLKW
static
void
aflock
(
/* lock/unlock ambient file */
int
typ
)
{
static
struct
flock
fls
;
/* static so initialized to zeroes */
if
(
typ
==
fls
.
l_type
)
/* already called? */
return
;
fls
.
l_type
=
typ
;
do
if
(
fcntl
(
fileno
(
ambfp
),
F_SETLKW
,
&
fls
)
!=
-
1
)
return
;
while
(
errno
==
EINTR
);
error
(
SYSTEM
,
"cannot (un)lock ambient file"
);
}
int
ambsync
(
void
)
/* synchronize ambient file */
{
long
flen
;
AMBVAL
avs
;
int
n
;
if
(
ambfp
==
NULL
)
/* no ambient file? */
return
(
0
);
/* gain appropriate access */
aflock
(
nunflshed
?
F_WRLCK
:
F_RDLCK
);
/* see if file has grown */
if
((
flen
=
lseek
(
fileno
(
ambfp
),
(
off_t
)
0
,
SEEK_END
))
<
0
)
goto
seekerr
;
if
((
n
=
flen
-
lastpos
)
>
0
)
{
/* file has grown */
if
(
ambinp
==
NULL
)
{
/* get new file pointer */
ambinp
=
fopen
(
ambfile
,
"rb"
);
if
(
ambinp
==
NULL
)
error
(
SYSTEM
,
"fopen failed in ambsync"
);
}
if
(
fseek
(
ambinp
,
lastpos
,
SEEK_SET
)
<
0
)
goto
seekerr
;
while
(
n
>=
AMBVALSIZ
)
{
/* load contributed values */
if
(
!
readambval
(
&
avs
,
ambinp
))
{
sprintf
(
errmsg
,
"ambient file
\"
%s
\"
corrupted near character %ld"
,
ambfile
,
flen
-
n
);
error
(
WARNING
,
errmsg
);
break
;
}
avstore
(
&
avs
);
n
-=
AMBVALSIZ
;
}
lastpos
=
flen
-
n
;
/* check alignment */
if
(
n
&&
lseek
(
fileno
(
ambfp
),
(
off_t
)
lastpos
,
SEEK_SET
)
<
0
)
goto
seekerr
;
}
n
=
fflush
(
ambfp
);
/* calls write() at last */
lastpos
+=
(
long
)
nunflshed
*
AMBVALSIZ
;
aflock
(
F_UNLCK
);
/* release file */
nunflshed
=
0
;
return
(
n
);
seekerr:
error
(
SYSTEM
,
"seek failed in ambsync"
);
return
(
EOF
);
/* pro forma return */
}
#else
/* ! F_SETLKW */
int
ambsync
(
void
)
/* flush ambient file */
{
if
(
ambfp
==
NULL
)
return
(
0
);
nunflshed
=
0
;
return
(
fflush
(
ambfp
));
}
#endif
/* ! F_SETLKW */
Event Timeline
Log In to Comment