Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / intern / cycles / render / filter.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "camera.h"
20 #include "device.h"
21 #include "filter.h"
22 #include "scene.h"
23
24 #include "util_algorithm.h"
25 #include "util_debug.h"
26 #include "util_math.h"
27
28 CCL_NAMESPACE_BEGIN
29
30 Filter::Filter()
31 {
32         filter_type = FILTER_BOX;
33         filter_width = 1.0f;
34         need_update = true;
35 }
36
37 Filter::~Filter()
38 {
39 }
40
41 static float filter_func_box(float v, float width)
42 {
43         return (float)1;
44 }
45
46 static float filter_func_gaussian(float v, float width)
47 {
48         v *= (float)2/width;
49         return (float)expf((float)-2*v*v);
50 }
51
52 static vector<float> filter_table(FilterType type, float width)
53 {
54         const int filter_table_size = 256;
55         vector<float> filter_table_cdf(filter_table_size+1);
56         vector<float> filter_table(filter_table_size+1);
57         float (*filter_func)(float, float) = NULL;
58         int i, half_size = filter_table_size/2;
59
60         switch(type) {
61                 case FILTER_BOX:
62                         filter_func = filter_func_box;
63                         break;
64                 case FILTER_GAUSSIAN:
65                         filter_func = filter_func_gaussian;
66                         break;
67                 default:
68                         assert(0);
69         }
70
71         /* compute cumulative distribution function */
72         filter_table_cdf[0] = 0.0f;
73         
74         for(i=0; i<filter_table_size; i++) {
75                 float x = i*width*0.5f/(filter_table_size-1);
76                 float y = filter_func(x, width);
77                 filter_table_cdf[i+1] += filter_table_cdf[i] + fabsf(y);
78         }
79
80         for(i=0; i<=filter_table_size; i++)
81                 filter_table_cdf[i] /= filter_table_cdf[filter_table_size];
82         
83         /* create importance sampling table */
84         for(i=0; i<=half_size; i++) {
85                 float x = i/(float)half_size;
86                 int index = upper_bound(filter_table_cdf.begin(), filter_table_cdf.end(), x) - filter_table_cdf.begin();
87                 float t;
88
89                 if(index < filter_table_size+1) {
90                         t = (x - filter_table_cdf[index])/(filter_table_cdf[index+1] - filter_table_cdf[index]);
91                 }
92                 else {
93                         t = 0.0f;
94                         index = filter_table_size;
95                 }
96
97                 float y = ((index + t)/(filter_table_size))*width;
98
99                 filter_table[half_size+i] = 0.5f*(1.0f + y);
100                 filter_table[half_size-i] = 0.5f*(1.0f - y);
101         }
102
103         return filter_table;
104 }
105
106 void Filter::device_update(Device *device, DeviceScene *dscene)
107 {
108         if(!need_update)
109                 return;
110
111         device_free(device, dscene);
112
113         /* update __filter_table */
114         vector<float> table = filter_table(filter_type, filter_width);
115
116         dscene->filter_table.copy(&table[0], table.size());
117         device->tex_alloc("__filter_table", dscene->filter_table, true);
118
119         need_update = false;
120 }
121
122 void Filter::device_free(Device *device, DeviceScene *dscene)
123 {
124         device->tex_free(dscene->filter_table);
125         dscene->filter_table.clear();
126 }
127
128 bool Filter::modified(const Filter& filter)
129 {
130         return !(filter_type == filter.filter_type &&
131                 filter_width == filter.filter_width);
132 }
133
134 void Filter::tag_update(Scene *scene)
135 {
136         need_update = true;
137 }
138
139 CCL_NAMESPACE_END
140