using System; using System.Runtime.InteropServices; public class Win32 { [DllImport("kernel32.dll") ] public static extern Boolean AllocConsole(); [DllImport("kernel32.dll") ] public static extern Boolean FreeConsole(); } //adapted from Realistic Image Synthesis Using Photon //Mapping, by Henrik Wann Jensen //Photons are stored in a heap (after all photons // have been accumulated //Note: a heap is a balanced binary tree stored in an array such that // if a node is at index i, then its left child is at index 2*i // and its right child is at 2*i+1 //This implies that indices start at 1, and NOT 0. public class PhotonMap { public PhotonMap(int n) { Win32.AllocConsole(); nphotons=0; max=n; orig=new Photon[max+1]; //so that heap can be addressed from index 1 heap=new Photon[max+1]; maxdist=1.0; maxsamples=100; nearest=null; } public void store(Vector p, Vector dir, Light source, Colour Id, Colour Is) { if (nphotons>=max) return; Photon ph=new Photon(p, dir, source, Id, Is); nphotons++; orig[nphotons]=ph; } public int photons() { return nphotons; } private void swap(int i, int j) { Photon tmp; tmp=orig[i]; orig[i]=orig[j]; orig[j]=tmp; } private void median_split(int start, int end, int median, int axis) { int left=start; int right=end; double v=0.0; while (right>left) { if (axis==0) v=orig[right].p.x; if (axis==1) v=orig[right].p.y; if (axis==2) v=orig[right].p.z; int i=left-1; int j=right; while (true) { if (axis==0) while (orig[i+1].p.xv)&&(j-1>left)) j--; if (axis==1) while ((orig[j-1].p.y>v)&&(j-1>left)) j--; if (axis==2) while ((orig[j-1].p.z>v)&&(j-1>left)) j--; j--; if (i>=j) break; swap(i, j); } swap(i, right); if (i>=median) right=i-1; if (i<=median) left=i+1; } } private void balance_segment(int index, int start, int end) { Vector extent; //compute median int median=1; while (4*median<=(end-start+1)) { median+=median; } if (3*median<=(end-start+1)) { median+=median; median+=start-1; } else { median=end-median+1; } //find splitting axis extent=bbox_max-bbox_min; int axis=0; if ((extent.x>extent.y)&&(extent.x>extent.z)) axis=0; else if (extent.y>extent.z) axis=1; else axis=2; //partition photons around median median_split(start, end, median, axis); heap[index]=orig[median]; heap[index].splitaxis=axis; //recursively balance left and right block if (median>start) { //balance left segment if (startbbox_max.x) bbox_max.x=orig[i].p.x; if (orig[i].p.y>bbox_max.y) bbox_max.x=orig[i].p.y; if (orig[i].p.z>bbox_max.z) bbox_max.x=orig[i].p.z; } balance_segment(1, 1, nphotons); lastbranch=nphotons/2-1; System.Console.Write("Heap built.\n"); } //visualize the photon map public Colour ViewMap(Vector p, double tolerance) { nearest=new PhotonList(1); nearest.maxdist=maxdist; nearest.searchdist=maxdist*maxdist; nearest.p=p; locate_photons(1, p); if (nearest.searchdist0.0) { //search the right half locate_photons(2*index+1, pos); if (dist1*dist1maxdist) { maxdist=dists[i]; } } return maxdist; } public void addPhoton(Photon p, double dist) { int pos, i; //always keep the largest photon in position 0. if (nummaxdist) { photons[num]=photons[0]; dists[num]=dists[0]; photons[0]=p; dists[0]=dist; maxdist=dist; } else { photons[num]=p; dists[num]=dist; } } num++; } else { if (distmaxdist) { maxdist=dists[i]; pos=i; } } if (pos!=0) { p=photons[0]; photons[0]=photons[pos]; photons[pos]=p; dists[pos]=dists[0]; dists[0]=maxdist; } searchdist=maxdist; } } } }