ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapooc.c
Revision: 1.2
Committed: Mon Aug 14 21:12:10 2017 UTC (6 years, 8 months ago) by rschregle
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R1
Changes since 1.1: +5 -8 lines
Log Message:
Updated photon map code for Windows; no multproc or ooC for now

File Contents

# Content
1 /*
2 ======================================================================
3 Photon map interface to out-of-core octree
4
5 Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
6 (c) Lucerne University of Applied Sciences and Arts,
7 supported by the Swiss National Science Foundation (SNSF, #147053)
8 ======================================================================
9
10 $Id: pmapooc.c,v 1.1 2016/05/18 08:22:45 rschregle Exp $
11 */
12
13
14
15 #include "pmapdata.h" /* Includes pmapooc.h */
16 #include "source.h"
17 #include "oocsort.h"
18 #include "oocbuild.h"
19
20
21
22 /* Returns photon position as sorting key for OOC_Octree & friends (notably
23 * for Morton code generation).
24 * !!! Uses type conversion from float via TEMPORARY storage;
25 * !!! THIS IS NOT THREAD SAFE!
26 * !!! RETURNED KEY PERSISTS ONLY IF COPIED BEFORE NEXT CALL! */
27 RREAL *OOC_PhotonKey (const void *p)
28 {
29 static FVECT photonPos; /* Temp storage for type conversion */
30
31 VCOPY(photonPos, ((Photon*)p) -> pos);
32 return photonPos;
33 }
34
35
36
37 #ifdef DEBUG_OOC
38 static int OOC_CheckKeys (FILE *file, const OOC_Octree *oct)
39 {
40 Photon p, lastp;
41 RREAL *key;
42 OOC_MortonIdx zIdx, lastzIdx = 0;
43
44 rewind(file);
45 memset(&lastp, 0, sizeof(lastp));
46
47 while (fread(&p, sizeof(p), 1, file) > 0) {
48 key = OOC_PhotonKey(&p);
49 zIdx = OOC_KEY2MORTON(key, oct);
50
51 if (zIdx < lastzIdx) {
52 error(INTERNAL, "photons not sorted");
53 return -1;
54 }
55
56 if (zIdx == lastzIdx) {
57 sprintf(errmsg, "identical key %021ld "
58 "for [%.9f, %.9f, %.9f]\tand [%.9f, %.9f, %.9f]",
59 zIdx, lastp.pos [0], lastp.pos [1], lastp.pos [2],
60 p.pos [0], p.pos [1], p.pos [2]);
61 error(WARNING, errmsg);
62 }
63
64 lastzIdx = zIdx;
65 memcpy(&lastp, &p, sizeof(p));
66 }
67
68 return 0;
69 }
70 #endif
71
72
73
74 void OOC_BuildPhotonMap (struct PhotonMap *pmap, unsigned numProc)
75 {
76 FILE *leafFile;
77 char leafFname [1024];
78 FVECT d, octOrg;
79 int i;
80 RREAL octSize = 0;
81
82 /* Determine octree size and origin from pmap extent and init octree */
83 VCOPY(octOrg, pmap -> minPos);
84 VSUB(d, pmap -> maxPos, pmap -> minPos);
85 for (i = 0; i < 3; i++)
86 if (octSize < d [i])
87 octSize = d [i];
88
89 if (octSize < FTINY)
90 error(INTERNAL, "zero octree size in OOC_BuildPhotonMap");
91
92 /* Derive leaf filename from photon map and open file */
93 strncpy(leafFname, pmap -> fileName, sizeof(leafFname));
94 strncat(leafFname, PMAP_OOC_LEAFSUFFIX,
95 sizeof(leafFname) - strlen(leafFname) - 1);
96 if (!(leafFile = fopen(leafFname, "w+b")))
97 error(SYSTEM, "failed to open leaf file in OOC_BuildPhotonMap");
98
99 #ifdef DEBUG_OOC
100 eputs("Sorting photons by Morton code...\n");
101 #endif
102
103 /* Sort photons in heapfile by Morton code and write to leaf file */
104 if (OOC_Sort(pmap -> heap, leafFile, PMAP_OOC_NUMBLK, PMAP_OOC_BLKSIZE,
105 numProc, sizeof(Photon), octOrg, octSize, OOC_PhotonKey))
106 error(INTERNAL, "failed out-of-core photon sort in OOC_BuildPhotonMap");
107
108 /* Init and build octree */
109 OOC_Init(&pmap -> store, sizeof(Photon), octOrg, octSize, OOC_PhotonKey,
110 leafFile);
111
112 #ifdef DEBUG_OOC
113 eputs("Checking leaf file consistency...\n");
114 OOC_CheckKeys(leafFile, &pmap -> store);
115
116 eputs("Building out-of-core octree...\n");
117 #endif
118
119 if (!OOC_Build(&pmap -> store, PMAP_OOC_LEAFMAX, PMAP_OOC_MAXDEPTH))
120 error(INTERNAL, "failed out-of-core octree build in OOC_BuildPhotonMap");
121
122 #ifdef DEBUG_OOC
123 eputs("Checking out-of-core octree consistency...\n");
124 if (OOC_Check(&pmap -> store, OOC_ROOT(&pmap -> store),
125 octOrg, octSize, 0))
126 error(INTERNAL, "inconsistent out-of-core octree; Time4Harakiri");
127 #endif
128 }
129
130
131
132 int OOC_SavePhotons (const struct PhotonMap *pmap, FILE *out)
133 {
134 return OOC_SaveOctree(&pmap -> store, out);
135 }
136
137
138
139 int OOC_LoadPhotons (struct PhotonMap *pmap, FILE *nodeFile)
140 {
141 FILE *leafFile;
142 char leafFname [1024];
143
144 /* Derive leaf filename from photon map and open file */
145 strncpy(leafFname, pmap -> fileName, sizeof(leafFname));
146 strncat(leafFname, PMAP_OOC_LEAFSUFFIX,
147 sizeof(leafFname) - strlen(leafFname) - 1);
148
149 if (!(leafFile = fopen(leafFname, "r")))
150 error(SYSTEM, "failed to open leaf file in OOC_LoadPhotons");
151
152 if (OOC_LoadOctree(&pmap -> store, nodeFile, OOC_PhotonKey, leafFile))
153 return -1;
154
155 return 0;
156 }
157
158
159
160 void OOC_InitFindPhotons (struct PhotonMap *pmap)
161 {
162 if (OOC_InitNearest(&pmap -> squeue, pmap -> maxGather + 1,
163 sizeof(Photon)))
164 error(SYSTEM, "can't allocate photon search queue");
165 }
166
167
168
169 static void OOC_InitPhotonCache (struct PhotonMap *pmap)
170 /* Initialise OOC photon cache */
171 {
172 static char warn = 1;
173
174 if (!pmap -> store.cache && !pmap -> numDensity) {
175 if (pmapCacheSize > 0) {
176 const unsigned pageSize = pmapCachePageSize * pmap -> maxGather,
177 numPages = pmapCacheSize / pageSize;
178 /* Allocate & init I/O cache in octree */
179 pmap -> store.cache = malloc(sizeof(OOC_Cache));
180
181 if (!pmap -> store.cache ||
182 OOC_CacheInit(pmap -> store.cache, numPages, pageSize,
183 sizeof(Photon))) {
184 error(SYSTEM, "failed OOC photon map cache init");
185 }
186 }
187 else if (warn) {
188 error(WARNING, "OOC photon map cache DISABLED");
189 warn = 0;
190 }
191 }
192 }
193
194
195
196 typedef struct {
197 const PhotonMap *pmap;
198 const float *norm;
199 } OOC_FilterData;
200
201
202
203 int OOC_FilterPhoton (void *p, void *fd)
204 /* Filter callback for photon kNN search, used by OOC_FindNearest() */
205 {
206 const Photon *photon = p;
207 const OOC_FilterData *filtData = fd;
208 const PhotonMap *pmap = filtData -> pmap;
209
210 /* Reject photon if normal faces away (ignored for volume photons) with
211 * tolerance to account for perturbation; note photon normal is coded
212 * in range [-127,127], hence we factor this in */
213 if (filtData -> norm &&
214 DOT(filtData->norm, photon->norm) <= PMAP_NORM_TOL * 127 * frandom())
215 return 0;
216
217 if (isContribPmap(pmap) && pmap -> srcContrib) {
218 /* Lookup in contribution photon map */
219 OBJREC *srcMod;
220 const int srcIdx = photonSrcIdx(pmap, photon);
221
222 if (srcIdx < 0 || srcIdx >= nsources)
223 error(INTERNAL, "invalid light source index in photon map");
224
225 srcMod = findmaterial(source [srcIdx].so);
226
227 /* Reject photon if contributions from light source which emitted it
228 * are not sought */
229 if (!lu_find(pmap -> srcContrib, srcMod -> oname) -> data)
230 return 0;
231
232 /* Reject non-caustic photon if lookup for caustic contribs */
233 if (pmap -> lookupCaustic && !photon -> caustic)
234 return 0;
235 }
236
237 /* Accept photon */
238 return 1;
239 }
240
241
242
243 void OOC_FindPhotons (struct PhotonMap *pmap, const FVECT pos, const FVECT norm)
244 {
245 OOC_SearchFilter filt;
246 OOC_FilterData filtData;
247 float n [3];
248
249 /* Lazily init OOC cache */
250 if (!pmap -> store.cache)
251 OOC_InitPhotonCache(pmap);
252
253 /* Set up filter callback */
254 filtData.pmap = pmap;
255 VCOPY(n, norm);
256 filtData.norm = n;
257 filt.data = &filtData;
258 filt.func = OOC_FilterPhoton;
259
260 pmap -> maxDist2 = OOC_FindNearest(&pmap -> store,
261 OOC_ROOT(&pmap -> store), 0,
262 pmap -> store.org, pmap -> store.size,
263 pos, &filt, &pmap -> squeue,
264 pmap -> maxDist2);
265
266 if (pmap -> maxDist2 < 0)
267 error(INTERNAL, "failed k-NN photon lookup in OOC_FindPhotons");
268 }
269
270
271
272 void OOC_Find1Photon (struct PhotonMap* pmap, const FVECT pos,
273 const FVECT norm, Photon *photon)
274 {
275 OOC_SearchFilter filt;
276 OOC_FilterData filtData;
277 float n [3];
278
279 /* Lazily init OOC cache */
280 if (!pmap -> store.cache)
281 OOC_InitPhotonCache(pmap);
282
283 /* Set up filter callback */
284 filtData.pmap = pmap;
285 VCOPY(n, norm);
286 filtData.norm = n;
287 filt.data = &filtData;
288 filt.func = OOC_FilterPhoton;
289
290 pmap -> maxDist2 = OOC_Find1Nearest(&pmap -> store,
291 OOC_ROOT(&pmap -> store), 0,
292 pmap -> store.org, pmap -> store.size,
293 pos, &filt, photon, pmap -> maxDist2);
294
295 if (pmap -> maxDist2 < 0)
296 error(INTERNAL, "failed 1-NN photon lookup in OOC_Find1Photon");
297 }
298
299
300
301 int OOC_GetPhoton (struct PhotonMap *pmap, PhotonIdx idx,
302 Photon *photon)
303 {
304 return OOC_GetData(&pmap -> store, idx, photon);
305 }
306
307
308
309 Photon *OOC_GetNearestPhoton (const PhotonSearchQueue *squeue, PhotonIdx idx)
310 {
311 return OOC_GetNearest(squeue, idx);
312 }
313
314
315
316 PhotonIdx OOC_FirstPhoton (const struct PhotonMap* pmap)
317 {
318 return 0;
319 }