root/cafu/trunk/CaSHL/Ward97.cpp

Revision 455, 7.5 KB (checked in by Carsten, 4 months ago)

Updated copyright banners (in C++ files).

Line 
1/*
2=================================================================================
3This file is part of Cafu, the open-source game engine and graphics engine
4for multiplayer, cross-platform, real-time 3D action.
5Copyright (C) 2002-2012 Carsten Fuchs Software.
6
7Cafu is free software: you can redistribute it and/or modify it under the terms
8of the GNU General Public License as published by the Free Software Foundation,
9either version 3 of the License, or (at your option) any later version.
10
11Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with Cafu. If not, see <http://www.gnu.org/licenses/>.
17
18For support and more information about Cafu, visit us at <http://www.cafu.de>.
19=================================================================================
20*/
21
22// Ward 97 Tone Reproduction Operator
23// **********************************
24
25const double DisplayLuminanceMax=80.0;
26
27
28bool HistogramCeiling(ArrayT<unsigned long>& Bins, double DeltaBin)
29{
30    unsigned long Total=0;
31    unsigned long BinNr;
32
33    for (BinNr=0; BinNr<Bins.Size(); BinNr++) Total+=Bins[BinNr];
34
35    unsigned long Tolerance=(unsigned long)(0.025*Total);
36    unsigned long Trimmings;
37
38    do
39    {
40        Trimmings=0;
41        Total    =0;
42        for (BinNr=0; BinNr<Bins.Size(); BinNr++) Total+=Bins[BinNr];
43
44        if (Total<Tolerance) return false;
45
46        for (BinNr=0; BinNr<Bins.Size(); BinNr++)
47        {
48            unsigned long Ceiling=(unsigned long)(Total*DeltaBin/log(DisplayLuminanceMax));
49
50            if (Bins[BinNr]>Ceiling)
51            {
52                Trimmings+=Bins[BinNr]-Ceiling;
53                Bins[BinNr]=Ceiling;
54            }
55        }
56    } while (Trimmings>Tolerance);
57
58    return true;
59}
60
61
62double MaxAbsCoeff(const ArrayT<double>& Coeffs)
63{
64    if (Coeffs.Size()==0) return 0.0;
65
66    double m=fabs(Coeffs[0]);
67
68    for (unsigned long CoeffNr=1; CoeffNr<Coeffs.Size(); CoeffNr++)
69        if (fabs(Coeffs[CoeffNr])>m) m=fabs(Coeffs[CoeffNr]);
70
71    return m;
72}
73
74
75// Diese Funktion findet einen Tone-Reproduction Operator (Funktion) nach Ward97,
76// anhand dessen die Energiewerte der Patches in RGB-Tripel umgewandelt werden.
77void ToneReproduction(const cf::SceneGraph::BspTreeNodeT& Map)
78{
79    printf("\n%-50s %s\n", "*** Tone Reproduction (Ward97) ***", GetTimeSinceProgramStart());
80
81    const unsigned long   NR_OF_SH_COEFFS=cf::SceneGraph::SHLMapManT::NrOfBands * cf::SceneGraph::SHLMapManT::NrOfBands;
82    const unsigned long   NrOfBins=300;
83    ArrayT<unsigned long> Bins;
84    unsigned long         BinNr;
85
86    for (BinNr=0; BinNr<NrOfBins; BinNr++) Bins.PushBack(0);
87
88    double MinBrightness=log(0.0001);
89    double MaxBrightness=MinBrightness;
90
91    // Suche die MaxBrightness
92    for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
93        for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
94        {
95            if (!Patches[FaceNr][PatchNr].InsideFace) continue;
96
97            double Luminance=MaxAbsCoeff(Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer);
98
99            if (Luminance<0.0001) continue;
100            double Brightness=log(Luminance);
101
102            if (Brightness>MaxBrightness) MaxBrightness=Brightness;
103        }
104
105    printf("MinBrightness: %9.5f\n", MinBrightness);
106    printf("MaxBrightness: %9.5f\n", MaxBrightness);
107
108    // Bilde das Histogram
109    for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
110        for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
111        {
112            if (!Patches[FaceNr][PatchNr].InsideFace) continue;
113
114            double Luminance=MaxAbsCoeff(Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer);
115
116            if (Luminance<0.0001) Luminance=0.0001;
117            double Brightness=log(Luminance);
118
119            BinNr=(unsigned long)((Brightness-MinBrightness)/(MaxBrightness-MinBrightness)*NrOfBins);
120            if (BinNr>NrOfBins-1) BinNr=NrOfBins-1;
121            Bins[BinNr]++;
122        }
123
124    /***********************************************************************************************
125    printf("Writing histogram file...\n");
126    FILE* FilePtr=fopen("histogr.dat", "wb");
127
128    if (FilePtr!=NULL)
129    {
130        fwrite(&NrOfBins, sizeof(NrOfBins), 1, FilePtr);
131
132        for (BinNr=0; BinNr<Bins.Size(); BinNr++)
133            fwrite(&Bins[BinNr], sizeof(unsigned long), 1, FilePtr);
134
135        fclose(FilePtr);
136    }
137    else printf("      WARNING: Unable to write histogram data file!\n");
138    ***********************************************************************************************/
139
140    // Arbeite die Ceiling in das Histogram ein
141    if (HistogramCeiling(Bins, (MaxBrightness-MinBrightness)/double(NrOfBins)))
142    {
143        // Bilde das Integral über Bins[0..NrOfBins-1] als einfache Summe und normalisiere
144        ArrayT<double> BinsNormSum;
145        unsigned long  Sum=0;
146
147        for (BinNr=0; BinNr<Bins.Size(); BinNr++)
148        {
149            BinsNormSum.PushBack(Sum);
150            Sum+=Bins[BinNr];
151        }
152        for (BinNr=0; BinNr<Bins.Size(); BinNr++) BinsNormSum[BinNr]/=double(Sum);
153
154        // Ordne nun anhand der DisplayLuminanceMax^BinsNormSum[i] Funktion RGB-Werte zu
155        for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
156            for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
157            {
158                if (!Patches[FaceNr][PatchNr].InsideFace) continue;
159
160                ArrayT<double>& TotalTransfer=Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer;
161                double          Luminance    =MaxAbsCoeff(TotalTransfer);
162
163                if (Luminance<0.0001) Luminance=0.0001;
164                double Brightness=log(Luminance);
165
166                BinNr=(unsigned long)((Brightness-MinBrightness)/(MaxBrightness-MinBrightness)*NrOfBins);
167                if (BinNr>NrOfBins-1) BinNr=NrOfBins-1;
168
169                double DisplayLuminance=pow(DisplayLuminanceMax, BinsNormSum[BinNr]);
170
171                for (unsigned long CoeffNr=0; CoeffNr<NR_OF_SH_COEFFS; CoeffNr++)
172                    TotalTransfer[CoeffNr]*=DisplayLuminance/Luminance;
173            }
174    }
175
176    // Skaliere die nun vorhandenen RGB-Werte der Patches linear in den gewünschten [0, 255] Bereich.
177    double Max=0;
178    for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
179        for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
180        {
181            if (!Patches[FaceNr][PatchNr].InsideFace) continue;
182
183            for (unsigned long CoeffNr=0; CoeffNr<NR_OF_SH_COEFFS; CoeffNr++)
184                if (fabs(Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer[CoeffNr])>Max) Max=fabs(Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer[CoeffNr]);
185        }
186
187    if (Max==0.0) Max=1.0;
188
189    // 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()).
190    Max=1.0/Max;
191
192    for (unsigned long FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
193        for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
194            for (unsigned long CoeffNr=0; CoeffNr<NR_OF_SH_COEFFS; CoeffNr++)
195                Patches[FaceNr][PatchNr].SHCoeffs_TotalTransfer[CoeffNr]*=Max;
196}
Note: See TracBrowser for help on using the browser.