Fix issue in Rocket.lua script.
[Cafu-Engine.git] / CaSHL / Ward97.cpp
blob89d16d075df5df239a401525b32e31e2ff6116d7
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 // Ward 97 Tone Reproduction Operator
8 // **********************************
10 const double DisplayLuminanceMax=80.0;
13 bool HistogramCeiling(ArrayT<unsigned long>& Bins, double DeltaBin)
15 unsigned long Total=0;
16 unsigned long BinNr;
18 for (BinNr=0; BinNr<Bins.Size(); BinNr++) Total+=Bins[BinNr];
20 unsigned long Tolerance=(unsigned long)(0.025*Total);
21 unsigned long Trimmings;
25 Trimmings=0;
26 Total =0;
27 for (BinNr=0; BinNr<Bins.Size(); BinNr++) Total+=Bins[BinNr];
29 if (Total<Tolerance) return false;
31 for (BinNr=0; BinNr<Bins.Size(); BinNr++)
33 unsigned long Ceiling=(unsigned long)(Total*DeltaBin/log(DisplayLuminanceMax));
35 if (Bins[BinNr]>Ceiling)
37 Trimmings+=Bins[BinNr]-Ceiling;
38 Bins[BinNr]=Ceiling;
41 } while (Trimmings>Tolerance);
43 return true;
47 double MaxAbsCoeff(const ArrayT<double>& Coeffs)
49 if (Coeffs.Size()==0) return 0.0;
51 double m=fabs(Coeffs[0]);
53 for (unsigned long CoeffNr=1; CoeffNr<Coeffs.Size(); CoeffNr++)
54 if (fabs(Coeffs[CoeffNr])>m) m=fabs(Coeffs[CoeffNr]);
56 return m;
60 // Diese Funktion findet einen Tone-Reproduction Operator (Funktion) nach Ward97,
61 // anhand dessen die Energiewerte der Patches in RGB-Tripel umgewandelt werden.
62 void ToneReproduction(const cf::SceneGraph::BspTreeNodeT& Map)
64 printf("\n%-50s %s\n", "*** Tone Reproduction (Ward97) ***", GetTimeSinceProgramStart());
66 const unsigned long NR_OF_SH_COEFFS=cf::SceneGraph::SHLMapManT::NrOfBands * cf::SceneGraph::SHLMapManT::NrOfBands;
67 const unsigned long NrOfBins=300;
68 ArrayT<unsigned long> Bins;
69 unsigned long BinNr;
71 for (BinNr=0; BinNr<NrOfBins; BinNr++) Bins.PushBack(0);
73 double MinBrightness=log(0.0001);
74 double MaxBrightness=MinBrightness;
76 // Suche die MaxBrightness
77 for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
78 for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
80 if (!Patches[FaceNr][PatchNr].InsideFace) continue;
82 double Luminance=MaxAbsCoeff(Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer);
84 if (Luminance<0.0001) continue;
85 double Brightness=log(Luminance);
87 if (Brightness>MaxBrightness) MaxBrightness=Brightness;
90 printf("MinBrightness: %9.5f\n", MinBrightness);
91 printf("MaxBrightness: %9.5f\n", MaxBrightness);
93 // Bilde das Histogram
94 for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
95 for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
97 if (!Patches[FaceNr][PatchNr].InsideFace) continue;
99 double Luminance=MaxAbsCoeff(Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer);
101 if (Luminance<0.0001) Luminance=0.0001;
102 double Brightness=log(Luminance);
104 BinNr=(unsigned long)((Brightness-MinBrightness)/(MaxBrightness-MinBrightness)*NrOfBins);
105 if (BinNr>NrOfBins-1) BinNr=NrOfBins-1;
106 Bins[BinNr]++;
109 /***********************************************************************************************
110 printf("Writing histogram file...\n");
111 FILE* FilePtr=fopen("histogr.dat", "wb");
113 if (FilePtr!=NULL)
115 fwrite(&NrOfBins, sizeof(NrOfBins), 1, FilePtr);
117 for (BinNr=0; BinNr<Bins.Size(); BinNr++)
118 fwrite(&Bins[BinNr], sizeof(unsigned long), 1, FilePtr);
120 fclose(FilePtr);
122 else printf(" WARNING: Unable to write histogram data file!\n");
123 ***********************************************************************************************/
125 // Arbeite die Ceiling in das Histogram ein
126 if (HistogramCeiling(Bins, (MaxBrightness-MinBrightness)/double(NrOfBins)))
128 // Bilde das Integral über Bins[0..NrOfBins-1] als einfache Summe und normalisiere
129 ArrayT<double> BinsNormSum;
130 unsigned long Sum=0;
132 for (BinNr=0; BinNr<Bins.Size(); BinNr++)
134 BinsNormSum.PushBack(Sum);
135 Sum+=Bins[BinNr];
137 for (BinNr=0; BinNr<Bins.Size(); BinNr++) BinsNormSum[BinNr]/=double(Sum);
139 // Ordne nun anhand der DisplayLuminanceMax^BinsNormSum[i] Funktion RGB-Werte zu
140 for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
141 for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
143 if (!Patches[FaceNr][PatchNr].InsideFace) continue;
145 ArrayT<double>& TotalTransfer=Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer;
146 double Luminance =MaxAbsCoeff(TotalTransfer);
148 if (Luminance<0.0001) Luminance=0.0001;
149 double Brightness=log(Luminance);
151 BinNr=(unsigned long)((Brightness-MinBrightness)/(MaxBrightness-MinBrightness)*NrOfBins);
152 if (BinNr>NrOfBins-1) BinNr=NrOfBins-1;
154 double DisplayLuminance=pow(DisplayLuminanceMax, BinsNormSum[BinNr]);
156 for (unsigned long CoeffNr=0; CoeffNr<NR_OF_SH_COEFFS; CoeffNr++)
157 TotalTransfer[CoeffNr]*=DisplayLuminance/Luminance;
161 // Skaliere die nun vorhandenen RGB-Werte der Patches linear in den gewünschten [0, 255] Bereich.
162 double Max=0;
163 for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
164 for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
166 if (!Patches[FaceNr][PatchNr].InsideFace) continue;
168 for (unsigned long CoeffNr=0; CoeffNr<NR_OF_SH_COEFFS; CoeffNr++)
169 if (fabs(Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer[CoeffNr])>Max) Max=fabs(Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer[CoeffNr]);
172 if (Max==0.0) Max=1.0;
174 // The 1.0 was 255.0 for CaLight, and should probably be 0.7... here (the fabs() value of the min/max values reported by DirectLighting()).
175 Max=1.0/Max;
177 for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
178 for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
179 for (unsigned long CoeffNr=0; CoeffNr<NR_OF_SH_COEFFS; CoeffNr++)
180 Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer[CoeffNr]*=Max;