cleanup: style
[blender-staging.git] / source / blender / compositor / intern / COM_MemoryBuffer.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_MemoryBuffer.h"
24
25 #include "MEM_guardedalloc.h"
26
27 using std::min;
28 using std::max;
29
30 static unsigned int determine_num_channels(DataType datatype)
31 {
32         switch (datatype) {
33                 case COM_DT_VALUE:
34                         return COM_NUM_CHANNELS_VALUE;
35                 case COM_DT_VECTOR:
36                         return COM_NUM_CHANNELS_VECTOR;
37                 case COM_DT_COLOR:
38                 default:
39                         return COM_NUM_CHANNELS_COLOR;
40         }
41 }
42
43 unsigned int MemoryBuffer::determineBufferSize()
44 {
45         return getWidth() * getHeight();
46 }
47
48 int MemoryBuffer::getWidth() const
49 {
50         return this->m_width;
51 }
52 int MemoryBuffer::getHeight() const
53 {
54         return this->m_height;
55 }
56
57 MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect)
58 {
59         BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
60         this->m_width = BLI_rcti_size_x(&this->m_rect);
61         this->m_height = BLI_rcti_size_y(&this->m_rect);
62         this->m_memoryProxy = memoryProxy;
63         this->m_chunkNumber = chunkNumber;
64         this->m_num_channels = determine_num_channels(memoryProxy->getDataType());
65         this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
66         this->m_state = COM_MB_ALLOCATED;
67         this->m_datatype = memoryProxy->getDataType();;
68 }
69
70 MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect)
71 {
72         BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
73         this->m_width = BLI_rcti_size_x(&this->m_rect);
74         this->m_height = BLI_rcti_size_y(&this->m_rect);
75         this->m_memoryProxy = memoryProxy;
76         this->m_chunkNumber = -1;
77         this->m_num_channels = determine_num_channels(memoryProxy->getDataType());
78         this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
79         this->m_state = COM_MB_TEMPORARILY;
80         this->m_datatype = memoryProxy->getDataType();
81 }
82 MemoryBuffer::MemoryBuffer(DataType dataType, rcti *rect)
83 {
84         BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
85         this->m_width = BLI_rcti_size_x(&this->m_rect);
86         this->m_height = BLI_rcti_size_y(&this->m_rect);
87         this->m_height = this->m_rect.ymax - this->m_rect.ymin;
88         this->m_memoryProxy = NULL;
89         this->m_chunkNumber = -1;
90         this->m_num_channels = determine_num_channels(dataType);
91         this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
92         this->m_state = COM_MB_TEMPORARILY;
93         this->m_datatype = dataType;
94 }
95 MemoryBuffer *MemoryBuffer::duplicate()
96 {
97         MemoryBuffer *result = new MemoryBuffer(this->m_memoryProxy, &this->m_rect);
98         memcpy(result->m_buffer, this->m_buffer, this->determineBufferSize() * this->m_num_channels * sizeof(float));
99         return result;
100 }
101 void MemoryBuffer::clear()
102 {
103         memset(this->m_buffer, 0, this->determineBufferSize() * this->m_num_channels * sizeof(float));
104 }
105
106
107 float MemoryBuffer::getMaximumValue()
108 {
109         float result = this->m_buffer[0];
110         const unsigned int size = this->determineBufferSize();
111         unsigned int i;
112
113         const float *fp_src = this->m_buffer;
114
115         for (i = 0; i < size; i++, fp_src += this->m_num_channels) {
116                 float value = *fp_src;
117                 if (value > result) {
118                         result = value;
119                 }
120         }
121
122         return result;
123 }
124
125 float MemoryBuffer::getMaximumValue(rcti *rect)
126 {
127         rcti rect_clamp;
128
129         /* first clamp the rect by the bounds or we get un-initialized values */
130         BLI_rcti_isect(rect, &this->m_rect, &rect_clamp);
131
132         if (!BLI_rcti_is_empty(&rect_clamp)) {
133                 MemoryBuffer *temp = new MemoryBuffer(this->m_datatype, &rect_clamp);
134                 temp->copyContentFrom(this);
135                 float result = temp->getMaximumValue();
136                 delete temp;
137                 return result;
138         }
139         else {
140                 BLI_assert(0);
141                 return 0.0f;
142         }
143 }
144
145 MemoryBuffer::~MemoryBuffer()
146 {
147         if (this->m_buffer) {
148                 MEM_freeN(this->m_buffer);
149                 this->m_buffer = NULL;
150         }
151 }
152
153 void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer)
154 {
155         if (!otherBuffer) {
156                 BLI_assert(0);
157                 return;
158         }
159         unsigned int otherY;
160         unsigned int minX = max(this->m_rect.xmin, otherBuffer->m_rect.xmin);
161         unsigned int maxX = min(this->m_rect.xmax, otherBuffer->m_rect.xmax);
162         unsigned int minY = max(this->m_rect.ymin, otherBuffer->m_rect.ymin);
163         unsigned int maxY = min(this->m_rect.ymax, otherBuffer->m_rect.ymax);
164         int offset;
165         int otherOffset;
166
167
168         for (otherY = minY; otherY < maxY; otherY++) {
169                 otherOffset = ((otherY - otherBuffer->m_rect.ymin) * otherBuffer->m_width + minX - otherBuffer->m_rect.xmin) * this->m_num_channels;
170                 offset = ((otherY - this->m_rect.ymin) * this->m_width + minX - this->m_rect.xmin) * this->m_num_channels;
171                 memcpy(&this->m_buffer[offset], &otherBuffer->m_buffer[otherOffset], (maxX - minX) * this->m_num_channels * sizeof(float));
172         }
173 }
174
175 void MemoryBuffer::writePixel(int x, int y, const float color[4])
176 {
177         if (x >= this->m_rect.xmin && x < this->m_rect.xmax &&
178             y >= this->m_rect.ymin && y < this->m_rect.ymax)
179         {
180                 const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * this->m_num_channels;
181                 memcpy(&this->m_buffer[offset], color, sizeof(float)*this->m_num_channels);     }
182 }
183
184 void MemoryBuffer::addPixel(int x, int y, const float color[4])
185 {
186         if (x >= this->m_rect.xmin && x < this->m_rect.xmax &&
187             y >= this->m_rect.ymin && y < this->m_rect.ymax)
188         {
189                 const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * this->m_num_channels;
190                  float *dst = &this->m_buffer[offset];
191                  const float *src = color;
192                  for (int i = 0; i < this->m_num_channels ; i++, dst++, src++) {
193                          *dst += *src;
194                  }
195         }
196 }
197
198 typedef struct ReadEWAData {
199         MemoryBuffer *buffer;
200         PixelSampler sampler;
201         float ufac, vfac;
202 } ReadEWAData;
203
204 static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4])
205 {
206         ReadEWAData *data = (ReadEWAData *) userdata;
207         switch (data->sampler) {
208                 case COM_PS_NEAREST:
209                         data->buffer->read(result, x, y);
210                         break;
211                 case COM_PS_BILINEAR:
212                         data->buffer->readBilinear(result,
213                                                    (float)x + data->ufac,
214                                                    (float)y + data->vfac);
215                         break;
216                 case COM_PS_BICUBIC:
217                         /* TOOD(sergey): no readBicubic method yet */
218                         data->buffer->readBilinear(result,
219                                                    (float)x + data->ufac,
220                                                    (float)y + data->vfac);
221                         break;
222                 default:
223                         zero_v4(result);
224                         break;
225         }
226 }
227
228 void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2], PixelSampler sampler)
229 {
230         BLI_assert(this->m_datatype == COM_DT_COLOR);
231         ReadEWAData data;
232         data.buffer = this;
233         data.sampler = sampler;
234         data.ufac = uv[0] - floorf(uv[0]);
235         data.vfac = uv[1] - floorf(uv[1]);
236
237         int width = this->getWidth(), height = this->getHeight();
238         /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
239          * but compositor uses pixel space. For now let's just divide the values and
240          * switch compositor to normalized space for EWA later.
241          */
242         float uv_normal[2] = {uv[0] / width, uv[1] / height};
243         float du_normal[2] = {derivatives[0][0] / width, derivatives[0][1] / height};
244         float dv_normal[2] = {derivatives[1][0] / width, derivatives[1][1] / height};
245
246         BLI_ewa_filter(this->getWidth(), this->getHeight(),
247                        false,
248                        true,
249                        uv_normal, du_normal, dv_normal,
250                        read_ewa_pixel_sampled,
251                        &data,
252                        result);
253 }