Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F86309646
pmapdump.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
Sat, Oct 5, 18:02
Size
18 KB
Mime Type
text/x-c
Expires
Mon, Oct 7, 18:02 (2 d)
Engine
blob
Format
Raw Data
Handle
21397380
Attached To
R10977 RADIANCE Photon Map
pmapdump.c
View Options
#ifndef lint
static
const
char
RCSid
[]
=
"$Id: pmapdump.c,v 2.18 2021/02/18 17:08:50 rschregle Exp $"
;
#endif
/*
======================================================================
Dump photon maps as RADIANCE scene description or ASCII point list
to stdout
Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
(c) Fraunhofer Institute for Solar Energy Systems,
supported by the German Research Foundation
(DFG LU-204/10-2, "Fassadenintegrierte Regelsysteme FARESYS")
(c) Lucerne University of Applied Sciences and Arts,
supported by the Swiss National Science Foundation
(SNSF #147053, "Daylight Redirecting Components",
SNSF #179067, "Light Fields for Spatio-Temporal Glare Assessment")
(c) Tokyo University of Science,
supported by the JSPS Grants-in-Aid for Scientific Research
(KAKENHI JP19KK0115, "Three-Dimensional Light Flow")
======================================================================
$Id: pmapdump.c,v 2.18 2021/02/18 17:08:50 rschregle Exp $
*/
#include "pmap.h"
#include "pmapio.h"
#include "rtio.h"
#include "resolu.h"
#include "random.h"
#include "math.h"
/* Defaults */
/* Sphere radius as fraction of avg. intersphere dist */
/* Relative scale for sphere radius (fudge factor) */
/* Number of spheres */
#define RADCOEFF 0.05
#define RADSCALE 1.0
#define NSPHERES 10000
/* Formats for ASCII output as XYZ RGB points plus optional normals
(incident directions for volume photons) and path IDs */
#define POINTFMT "%g\t%g\t%g\t%g\t%g\t%g"
#define NORMFMT "\t%f\t%f\t%f"
#define PATHFMT "\t%u:%lu"
#define SRCFMT "\t%u"
#define TIMEFMT "\t%g"
/* Seed for random number generator; this determines the sequence of
* photons extracted. TODO: Make accessible as option??? */
#define RANDSEED 0
#define BOOLOPTSTR(v) ((v) ? "+" : "-")
/* RADIANCE material and object defs for each photon type */
typedef
struct
{
char
*
mat
,
*
obj
;
}
RadianceDef
;
extern
char
VersionID
[];
const
RadianceDef
radDefs
[]
=
{
{
"void glow mat.global
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.global sphere obj.global
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.pglobal
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.pglobal sphere obj.pglobal
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.caustic
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.caustic sphere obj.caustic
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.volume
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.volume sphere obj.volume
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.direct
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.direct sphere obj.direct
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.contrib
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.contrib sphere obj.contrib
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.transient
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.transient sphere obj.transient
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.lightflow
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.lightflow sphere obj.lightflow
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.tlightflow
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.tlightflow sphere obj.tlightflow
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
},
{
"void glow mat.contrib
\n
0
\n
0
\n
4 %g %g %g 0
\n
"
,
"mat.contrib sphere obj.contrib
\n
0
\n
0
\n
4 %g %g %g %g
\n
"
}
};
/* Default colour codes are as follows: global = blue
precomp global = cyan
caustic = red
transient = white
volume/lightflow = green
direct = magenta
contrib = yellow */
const
COLOR
colDefs
[]
=
{
{
0.25
,
0.25
,
2
},
{
0.1
,
1
,
1
},
{
1
,
0.1
,
0.1
},
{
0.1
,
1
,
0.1
},
{
1
,
0.1
,
1
},
{
1
,
1
,
0.1
},
{
1
,
1
,
1
},
{
0.1
,
1
,
0.1
},
{
1
,
1
,
1
},
{
1
,
1
,
0.1
}
};
/* Option defaults */
unsigned
fluxCol
=
0
,
points
=
0
,
normals
=
0
,
aux
=
0
,
normalise
=
0
;
long
numSpheres
=
NSPHERES
;
RREAL
fluxNorm
=
0
,
radScale
=
RADSCALE
;
void
printdefaults
()
{
unsigned
ptype
;
printf
(
"-a%s
\t\t\t\t
# dump %s
\n
"
,
BOOLOPTSTR
(
points
),
points
?
"ASCII point list"
:
"RADIANCE scene description"
);
printf
(
"-A%s
\t\t\t\t
# %sdump auxiliary data (with -a+)
\n
"
,
BOOLOPTSTR
(
aux
),
aux
?
""
:
"don't "
);
for
(
ptype
=
0
;
ptype
<
NUM_PMAP_TYPES
;
ptype
++
)
printf
(
"-c %.3f %.3f %.3f
\t\t
# %s photon colour
\n
"
,
colDefs
[
ptype
][
0
],
colDefs
[
ptype
][
1
],
colDefs
[
ptype
][
2
],
pmapName
[
ptype
]
);
printf
(
"-f%s
\t\t\t\t
# %sdump photon flux
\n
"
,
BOOLOPTSTR
(
fluxCol
),
fluxCol
?
""
:
"don't "
);
printf
(
"-n %lu
\t\t\t
# number of points/spheres
\n
"
,
numSpheres
);
printf
(
"-N%s
\t\t\t\t
# %sdump normals (with -a+)
\n
"
,
BOOLOPTSTR
(
normals
),
normals
?
""
:
"don't "
);
printf
(
"-O %.3f
\t\t\t
# %snormalise photon flux (with -f+)
\n
"
,
fluxNorm
,
fluxNorm
>
FTINY
?
" "
:
"don't "
);
printf
(
"-P%s
\t\t\t\t
# %sdump photon path IDs (same as -A%s)
\n
"
,
BOOLOPTSTR
(
aux
),
aux
?
""
:
"don't "
,
BOOLOPTSTR
(
aux
)
);
printf
(
"-r %.3f
\t\t\t
# sphere radius scale (with -a-)
\n
"
,
radScale
);
}
static
int
setBool
(
char
*
str
,
unsigned
pos
,
unsigned
*
var
)
{
switch
((
str
)
[
pos
])
{
case
'\0'
:
*
var
=
!*
var
;
break
;
case
'y'
:
case
'Y'
:
case
't'
:
case
'T'
:
case
'+'
:
case
'1'
:
*
var
=
1
;
break
;
case
'n'
:
case
'N'
:
case
'f'
:
case
'F'
:
case
'-'
:
case
'0'
:
*
var
=
0
;
break
;
default:
return
0
;
}
return
1
;
}
int
main
(
int
argc
,
char
**
argv
)
{
char
format
[
MAXFMTLEN
];
RREAL
rad
,
extent
,
dumpRatio
,
fluxMax
=
0
;
unsigned
arg
,
j
,
ptype
,
dim
;
long
photonOffset
;
unsigned
long
photonCnt
;
COLOR
col
=
{
0
,
0
,
0
};
FILE
*
pmapFile
;
PhotonMap
pm
;
Photon
p
;
#ifdef PMAP_OOC
char
leafFname
[
1024
];
#endif
#ifdef PMAP_CONTRIB
PreComputedContrib
pcContrib
;
#endif
if
(
argc
<
2
)
{
puts
(
"Dump photon maps as RADIANCE scene description "
"or ASCII point list
\n
"
);
printf
(
"Usage:
\n
"
"%s [-a [-N][-A]] [-r radscale1] [-n num1] "
"[-f [-O norm1] | -c r1 g1 b1] pmap1
\n
"
"
\t
[-a [-N][-A]] [-r radscale2] [-n num2] "
"[-f [-O norm2] | -c r2 g2 b2] pmap2 ...
\n
"
,
argv
[
0
]
);
return
1
;
}
/* Parse options */
for
(
arg
=
1
;
arg
<
argc
;
arg
++
)
{
if
(
!
strcmp
(
argv
[
arg
],
"-version"
))
{
puts
(
VersionID
);
quit
(
0
);
}
if
(
!
strcmp
(
argv
[
arg
],
"-defaults"
)
||
!
strcmp
(
argv
[
arg
],
"-help"
)
)
{
printdefaults
();
quit
(
0
);
}
if
(
argv
[
arg
][
0
]
==
'-'
)
{
switch
(
argv
[
arg
][
1
])
{
case
'a'
:
if
(
!
setBool
(
argv
[
arg
],
2
,
&
points
))
error
(
USER
,
"invalid option syntax at -a"
);
break
;
case
'A'
:
/* Dump type-specific auxiliary data */
case
'P'
:
/* Dump paths; kept for backward compatibility */
if
(
!
setBool
(
argv
[
arg
],
2
,
&
aux
))
error
(
USER
,
"invalid option syntax at -A / -P"
);
break
;
case
'c'
:
if
(
fluxCol
)
error
(
USER
,
"-f and -c are mutually exclusive"
);
if
(
badarg
(
argc
-
arg
-
1
,
&
argv
[
arg
+
1
],
"fff"
))
error
(
USER
,
"invalid RGB colour"
);
for
(
j
=
0
;
j
<
3
;
j
++
)
col
[
j
]
=
atof
(
argv
[
++
arg
]);
break
;
case
'f'
:
if
(
intens
(
col
)
>
0
)
error
(
USER
,
"-f and -c are mutually exclusive"
);
if
(
!
setBool
(
argv
[
arg
],
2
,
&
fluxCol
))
error
(
USER
,
"invalid option syntax at -f"
);
break
;
case
'n'
:
if
((
numSpheres
=
parseMultiplier
(
argv
[
++
arg
]))
<=
0
)
error
(
USER
,
"invalid number of points/spheres"
);
break
;
case
'N'
:
if
(
!
setBool
(
argv
[
arg
],
2
,
&
normals
))
error
(
USER
,
"invalid option syntax at -N"
);
break
;
case
'O'
:
if
((
fluxNorm
=
atof
(
argv
[
++
arg
]))
<=
FTINY
)
error
(
USER
,
"invalid normalisation factor"
);
break
;
case
'r'
:
if
((
radScale
=
atof
(
argv
[
++
arg
]))
<=
FTINY
)
error
(
USER
,
"invalid radius scale"
);
break
;
default:
sprintf
(
errmsg
,
"unknown option %s"
,
argv
[
arg
]);
error
(
USER
,
errmsg
);
return
-
1
;
}
continue
;
}
/* Check for compatible options */
if
((
normals
||
aux
)
&&
!
points
)
error
(
USER
,
"options -A, -N, -P require -a+"
);
if
(
fluxNorm
>
FTINY
&&
!
fluxCol
)
error
(
USER
,
"photon flux normalisation requires -f+"
);
/* Open next photon map file */
if
(
!
(
pmapFile
=
fopen
(
argv
[
arg
],
"rb"
)))
{
sprintf
(
errmsg
,
"can't open %s"
,
argv
[
arg
]);
error
(
SYSTEM
,
errmsg
);
}
/* Get format string */
strcpy
(
format
,
PMAP_FORMAT_GLOB
);
if
(
checkheader
(
pmapFile
,
format
,
NULL
)
!=
1
)
{
sprintf
(
errmsg
,
"photon map file %s has an unknown format"
,
argv
[
arg
]
);
error
(
USER
,
errmsg
);
}
/* Identify photon map type from format string */
for
(
ptype
=
0
;
ptype
<
NUM_PMAP_TYPES
&&
strcmp
(
pmapFormat
[
ptype
],
format
);
ptype
++
);
if
(
!
validPmapType
(
ptype
))
{
sprintf
(
errmsg
,
"file %s contains an unknown photon map type"
,
argv
[
arg
]
);
error
(
USER
,
errmsg
);
}
/* Get file format version and check for compatibility */
if
(
strcmp
(
getstr
(
format
,
pmapFile
),
PMAP_FILEVER
))
error
(
USER
,
"incompatible photon map file format"
);
if
(
!
points
)
{
/* Dump command line as comment */
fputs
(
"# "
,
stdout
);
printargs
(
argc
,
argv
,
stdout
);
fputc
(
'\n'
,
stdout
);
}
/* Set point/sphere colour if independent of photon flux,
output RADIANCE material def if required */
if
(
!
fluxCol
)
{
if
(
intens
(
col
)
<=
0
)
copycolor
(
col
,
colDefs
[
ptype
]);
if
(
!
points
)
{
printf
(
radDefs
[
ptype
].
mat
,
col
[
0
],
col
[
1
],
col
[
2
]);
fputc
(
'\n'
,
stdout
);
}
}
/* Get number of photons as fixed size, which possibly results in
* padding of MSB with 0 on some platforms. Unlike sizeof() however,
* this ensures portability since this value may span 32 or 64 bits
* depending on platform. */
pm
.
numPhotons
=
getint
(
PMAP_LONGSIZE
,
pmapFile
);
/* Skip avg photon flux */
for
(
j
=
0
;
j
<
3
;
j
++
)
getflt
(
pmapFile
);
/* Get distribution extent (min & max photon positions) */
for
(
j
=
0
;
j
<
3
;
j
++
)
{
pm
.
minPos
[
j
]
=
getflt
(
pmapFile
);
pm
.
maxPos
[
j
]
=
getflt
(
pmapFile
);
}
/* Skip centre of gravity, and avg photon dist to it */
for
(
j
=
0
;
j
<
4
;
j
++
)
getflt
(
pmapFile
);
/* Get photon velocity, skip min/max/avg path length */
pm
.
velocity
=
getflt
(
pmapFile
);
for
(
j
=
0
;
j
<
3
;
j
++
)
getflt
(
pmapFile
);
#ifdef PMAP_CONTRIB
if
(
ptype
==
PMAP_TYPE_CONTRIB_CHILD
)
{
/* Precomputed contribution photon map; skip mode and num bins */
getint
(
sizeof
(
pmap
->
contribMode
),
pmapFile
);
getint
(
sizeof
(
pcContrib
.
l
),
pmapFile
);
getint
(
sizeof
(
pcContrib
.
nCompressedBins
),
pmapFile
);
}
#endif
/* Sphere radius based on avg intersphere dist depending on
whether the distribution occupies a 1D line (!), a 2D plane,
or 3D volume (= sphere distrib density ^-1/d, where d is the
dimensionality of the distribution) */
for
(
j
=
0
,
extent
=
1.0
,
dim
=
0
;
j
<
3
;
j
++
)
{
rad
=
pm
.
maxPos
[
j
]
-
pm
.
minPos
[
j
];
if
(
rad
>
FTINY
)
{
dim
++
;
extent
*=
rad
;
}
}
rad
=
radScale
*
RADCOEFF
*
pow
(
extent
/
numSpheres
,
1.
/
dim
);
/* Photon dump probability to satisfy target sphere count */
dumpRatio
=
min
(
1
,
(
float
)
numSpheres
/
pm
.
numPhotons
);
#ifdef PMAP_OOC
/* Open leaf file with filename derived from pmap, replace pmapFile
* (which is currently the node file) */
strncpy
(
leafFname
,
argv
[
arg
],
sizeof
(
leafFname
)
-
1
);
strncat
(
leafFname
,
PMAP_OOC_LEAFSUFFIX
,
sizeof
(
leafFname
)
-
1
);
fclose
(
pmapFile
);
if
(
!
(
pmapFile
=
fopen
(
leafFname
,
"rb"
)))
{
sprintf
(
errmsg
,
"cannot open leaf file %s"
,
leafFname
);
error
(
SYSTEM
,
errmsg
);
}
#endif
/* Remember start of photons in file (if we need to reiterate with
* normalisation) */
photonOffset
=
ftell
(
pmapFile
);
/* Set flux normalisation flag for reiteration in loop below */
normalise
=
fluxNorm
>
FTINY
;
do
{
/* Set random number seed to obtain identical sequence of
* photons if reiterating with normalisation */
srandom
(
RANDSEED
);
/* Reset file pointer to start of photons (if reiterating with
* normalisation) */
if
(
fseek
(
pmapFile
,
photonOffset
,
SEEK_SET
)
<
0
)
error
(
SYSTEM
,
"failed seek in photon map file"
);
/* Read photons */
for
(
photonCnt
=
pm
.
numPhotons
;
photonCnt
;
photonCnt
--
)
{
#ifdef PMAP_OOC
/* Get entire photon record from ooC octree leaf file
!!! OOC PMAP FILES CURRENTLY DON'T USE PORTABLE I/O !!! */
if
(
!
fread
(
&
p
,
sizeof
(
p
),
1
,
pmapFile
))
{
sprintf
(
errmsg
,
"error reading OOC leaf file %s"
,
leafFname
);
error
(
SYSTEM
,
errmsg
);
}
#else
/* kd-tree */
/* Get photon position */
for
(
j
=
0
;
j
<
3
;
j
++
)
p
.
pos
[
j
]
=
getflt
(
pmapFile
);
/* Get photon normal (dumped with -N) */
for
(
j
=
0
;
j
<
3
;
j
++
)
p
.
norm
[
j
]
=
getint
(
1
,
pmapFile
);
/* Get photon flux */
#ifdef PMAP_FLOAT_FLUX
for
(
j
=
0
;
j
<
3
;
j
++
)
p
.
flux
[
j
]
=
getflt
(
pmapFile
);
#else
for
(
j
=
0
;
j
<
4
;
j
++
)
p
.
flux
[
j
]
=
getint
(
1
,
pmapFile
);
#endif
/* Get photon's auxiliary field (dumped with -A/-P) */
getbinary
(
&
p
.
aux
,
1
,
sizeof
(
p
.
aux
),
pmapFile
);
/* Get photon's flags (includes subprocess prefix for path ID */
p
.
flags
=
getint
(
sizeof
(
p
.
flags
),
pmapFile
);
#endif
/* Dump photon probabilistically acc. to target sphere count */
if
(
frandom
()
<=
dumpRatio
)
{
if
(
fluxCol
)
{
/* Get photon flux */
getPhotonFlux
(
&
p
,
col
);
/* Scale by dumpRatio for energy conservation */
scalecolor
(
col
,
1.0
/
dumpRatio
);
}
if
(
!
normalise
)
{
if
(
fluxNorm
>
FTINY
)
{
/* Normalise photon flux (with maximum flux found in
* previous iteration) and output */
scalecolor
(
col
,
fluxMax
>
FTINY
?
fluxNorm
/
fluxMax
:
0
);
}
if
(
!
points
)
{
if
(
fluxCol
)
{
/* Dump material def if variable (depends on flux) */
printf
(
radDefs
[
ptype
].
mat
,
col
[
0
],
col
[
1
],
col
[
2
]);
fputc
(
'\n'
,
stdout
);
}
printf
(
radDefs
[
ptype
].
obj
,
p
.
pos
[
0
],
p
.
pos
[
1
],
p
.
pos
[
2
],
rad
);
fputc
(
'\n'
,
stdout
);
}
else
{
/* Dump as XYZ RGB point */
printf
(
POINTFMT
,
p
.
pos
[
0
],
p
.
pos
[
1
],
p
.
pos
[
2
],
col
[
0
],
col
[
1
]
,
col
[
2
]
);
if
(
normals
)
printf
(
NORMFMT
,
p
.
norm
[
0
]
/
127.
,
p
.
norm
[
1
]
/
127.
,
p
.
norm
[
2
]
/
127.
);
if
(
aux
)
/* Interpret auxiliary data depending on photon type */
switch
(
ptype
)
{
case
PMAP_TYPE_TRANSIENT
:
#ifdef PMAP_PHOTONFLOW
case
PMAP_TYPE_TRANSLIGHTFLOW
:
#endif
/* Aux field contains path length; calculate
photon's time of flight */
printf
(
TIMEFMT
,
p
.
aux
.
pathLen
/
pm
.
velocity
);
break
;
case
PMAP_TYPE_CONTRIB
:
/* Aux field contains photon's emitting light
source index */
printf
(
SRCFMT
,
p
.
aux
.
contribSrc
);
break
;
default:
/* Aux field contains photon's path ID; prefix with
photon's process index for uniqueness */
printf
(
PATHFMT
,
p
.
proc
,
(
unsigned
long
)
p
.
aux
.
pathID
);
}
fputc
(
'\n'
,
stdout
);
}
}
else
{
/* normalise == 1; find max flux for normalisation in next
iteration */
if
(
intens
(
col
)
>
fluxMax
)
fluxMax
=
intens
(
col
);
}
}
if
(
ferror
(
pmapFile
)
||
feof
(
pmapFile
))
{
sprintf
(
errmsg
,
"error reading %s"
,
argv
[
arg
]);
error
(
USER
,
errmsg
);
}
}
}
while
(
!
(
normalise
^=
1
));
fclose
(
pmapFile
);
/* Reset defaults for next dump */
radScale
=
RADSCALE
;
numSpheres
=
NSPHERES
;
col
[
0
]
=
col
[
1
]
=
col
[
2
]
=
fluxNorm
=
fluxMax
=
0.
;
fluxCol
=
points
=
aux
=
0
;
}
return
0
;
}
Event Timeline
Log In to Comment