Merging r46725 through r46963 from trunk into soc-2011-tomato
[blender-staging.git] / source / blender / compositor / operations / COM_GaussianBokehBlurOperation.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  * Contributor: 
19  *              Jeroen Bakker 
20  *              Monique Dewanchand
21  */
22
23 #include "COM_GaussianBokehBlurOperation.h"
24 #include "BLI_math.h"
25
26 extern "C" {
27         #include "RE_pipeline.h"
28 }
29
30 GaussianBokehBlurOperation::GaussianBokehBlurOperation(): BlurBaseOperation()
31 {
32         this->gausstab = NULL;
33 }
34
35 void *GaussianBokehBlurOperation::initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers)
36 {
37         updateGauss(memoryBuffers);
38         void *buffer = getInputOperation(0)->initializeTileData(NULL, memoryBuffers);
39         return buffer;
40 }
41
42 void GaussianBokehBlurOperation::updateGauss(MemoryBuffer **memoryBuffers)
43 {
44         if (this->gausstab == NULL) {
45                 float radxf;
46                 float radyf;
47                 int n;
48                 float *dgauss;
49                 float *ddgauss;
50                 float val;
51                 int j, i;
52                 const float width = this->getWidth();
53                 const float height = this->getHeight();
54                 updateSize(memoryBuffers);
55                 
56                 radxf = size*(float)this->data->sizex;
57                 if (radxf>width/2.0f)
58                         radxf = width/2.0f;
59                 else if (radxf<1.0f)
60                         radxf = 1.0f;
61         
62                 /* vertical */
63                 radyf = size*(float)this->data->sizey;
64                 if (radyf>height/2.0f)
65                         radyf = height/2.0f;
66                 else if (radyf<1.0f)
67                         radyf = 1.0f;
68         
69                 radx = ceil(radxf);
70                 rady = ceil(radyf);
71         
72                 n = (2*radx+1)*(2*rady+1);
73         
74                 /* create a full filter image */
75                 ddgauss = new float[n];
76                 dgauss = ddgauss;
77                 val = 0.0f;
78                 for (j=-rady; j<=rady; j++) {
79                         for (i=-radx; i<=radx; i++, dgauss++) {
80                                 float fj = (float)j / radyf;
81                                 float fi = (float)i / radxf;
82                                 float dist = sqrt(fj * fj + fi * fi);
83                                 *dgauss = RE_filter_value(this->data->filtertype, dist);
84                                 
85                                 val+= *dgauss;
86                         }
87                 }
88                 if (val!=0.0f) {
89                         val = 1.0f/val;
90                         for (j = n - 1; j>=0; j--)
91                                 ddgauss[j]*= val;
92                 }
93                 else ddgauss[4] = 1.0f;
94                 
95                 gausstab = ddgauss;
96         }
97 }
98
99 void GaussianBokehBlurOperation::executePixel(float *color, int x, int y, MemoryBuffer *inputBuffers[], void *data)
100 {
101         float tempColor[4];
102         tempColor[0] = 0;
103         tempColor[1] = 0;
104         tempColor[2] = 0;
105         tempColor[3] = 0;
106         float overallmultiplyer = 0;
107         MemoryBuffer *inputBuffer = (MemoryBuffer*)data;
108         float *buffer = inputBuffer->getBuffer();
109         int bufferwidth = inputBuffer->getWidth();
110         int bufferstartx = inputBuffer->getRect()->xmin;
111         int bufferstarty = inputBuffer->getRect()->ymin;
112
113         int miny = y - this->rady;
114         int maxy = y + this->rady;
115         int minx = x - this->radx;
116         int maxx = x + this->radx;
117         miny = max(miny, inputBuffer->getRect()->ymin);
118         minx = max(minx, inputBuffer->getRect()->xmin);
119         maxy = min(maxy, inputBuffer->getRect()->ymax);
120         maxx = min(maxx, inputBuffer->getRect()->xmax);
121
122         int index = 0;
123         int step = QualityStepHelper::getStep();
124         int offsetadd = QualityStepHelper::getOffsetAdd();
125         for (int ny = miny ; ny < maxy ; ny +=step) {
126                 int bufferindex = ((minx - bufferstartx)*4)+((ny-bufferstarty)*4*bufferwidth);
127                 for (int nx = minx ; nx < maxx ; nx +=step) {
128                         float multiplyer = gausstab[index];
129                         tempColor[0] += multiplyer * buffer[bufferindex];
130                         tempColor[1] += multiplyer * buffer[bufferindex+1];
131                         tempColor[2] += multiplyer * buffer[bufferindex+2];
132                         tempColor[3] += multiplyer * buffer[bufferindex+3];
133                         overallmultiplyer += multiplyer;
134                         index += step;
135                         bufferindex +=offsetadd;
136                 }
137         }
138         float divider = 1.0/overallmultiplyer;
139         color[0] = tempColor[0]*divider;
140         color[1] = tempColor[1]*divider;
141         color[2] = tempColor[2]*divider;
142         color[3] = tempColor[3]*divider;
143 }
144
145 void GaussianBokehBlurOperation::deinitExecution()
146 {
147         BlurBaseOperation::deinitExecution();
148         delete this->gausstab;
149         this->gausstab = NULL;
150 }
151
152 bool GaussianBokehBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
153 {
154         rcti newInput;
155         rcti sizeInput;
156         sizeInput.xmin = 0;
157         sizeInput.ymin = 0;
158         sizeInput.xmax = 5;
159         sizeInput.ymax = 5;
160         NodeOperation * operation = this->getInputOperation(1);
161         
162         if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
163                 return true;
164         }
165         else {
166                 if (this->gausstab) {
167                         int addx = radx;
168                         int addy = rady;
169                         newInput.xmax = input->xmax + addx;
170                         newInput.xmin = input->xmin - addx;
171                         newInput.ymax = input->ymax + addy;
172                         newInput.ymin = input->ymin - addy;
173                 }
174                 else {
175                         newInput.xmin = 0;
176                         newInput.ymin = 0;
177                         newInput.xmax = this->getWidth();
178                         newInput.ymax = this->getHeight();
179                 }
180                 return BlurBaseOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
181         }
182 }