Cleanup: comment line length (editors)
[blender.git] / source / blender / compositor / intern / COM_MemoryBuffer.h
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 class MemoryBuffer;
24
25 #ifndef __COM_MEMORYBUFFER_H__
26 #define __COM_MEMORYBUFFER_H__
27
28 #include "COM_ExecutionGroup.h"
29 #include "COM_MemoryProxy.h"
30 #include "COM_SocketReader.h"
31
32 extern "C" {
33 #  include "BLI_math.h"
34 #  include "BLI_rect.h"
35 }
36
37 /**
38  * \brief state of a memory buffer
39  * \ingroup Memory
40  */
41 typedef enum MemoryBufferState {
42         /** \brief memory has been allocated on creator device and CPU machine, but kernel has not been executed */
43         COM_MB_ALLOCATED = 1,
44         /** \brief memory is available for use, content has been created */
45         COM_MB_AVAILABLE = 2,
46         /** \brief chunk is consolidated from other chunks. special state.*/
47         COM_MB_TEMPORARILY = 6
48 } MemoryBufferState;
49
50 typedef enum MemoryBufferExtend {
51         COM_MB_CLIP,
52         COM_MB_EXTEND,
53         COM_MB_REPEAT
54 } MemoryBufferExtend;
55
56 class MemoryProxy;
57
58 /**
59  * \brief a MemoryBuffer contains access to the data of a chunk
60  */
61 class MemoryBuffer {
62 private:
63         /**
64          * \brief proxy of the memory (same for all chunks in the same buffer)
65          */
66         MemoryProxy *m_memoryProxy;
67
68         /**
69          * \brief the type of buffer COM_DT_VALUE, COM_DT_VECTOR, COM_DT_COLOR
70          */
71         DataType m_datatype;
72
73
74         /**
75          * \brief region of this buffer inside relative to the MemoryProxy
76          */
77         rcti m_rect;
78
79         /**
80          * brief refers to the chunknumber within the executiongroup where related to the MemoryProxy
81          * \see memoryProxy
82          */
83         unsigned int m_chunkNumber;
84
85         /**
86          * \brief state of the buffer
87          */
88         MemoryBufferState m_state;
89
90         /**
91          * \brief the actual float buffer/data
92          */
93         float *m_buffer;
94
95         /**
96          * \brief the number of channels of a single value in the buffer.
97          * For value buffers this is 1, vector 3 and color 4
98          */
99         unsigned int m_num_channels;
100
101         int m_width;
102         int m_height;
103
104 public:
105         /**
106          * \brief construct new MemoryBuffer for a chunk
107          */
108         MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect);
109
110         /**
111          * \brief construct new temporarily MemoryBuffer for an area
112          */
113         MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect);
114
115         /**
116          * \brief construct new temporarily MemoryBuffer for an area
117          */
118         MemoryBuffer(DataType datatype, rcti *rect);
119
120         /**
121          * \brief destructor
122          */
123         ~MemoryBuffer();
124
125         /**
126          * \brief read the ChunkNumber of this MemoryBuffer
127          */
128         unsigned int getChunkNumber() { return this->m_chunkNumber; }
129
130         unsigned int get_num_channels() { return this->m_num_channels; }
131
132         /**
133          * \brief get the data of this MemoryBuffer
134          * \note buffer should already be available in memory
135          */
136         float *getBuffer() { return this->m_buffer; }
137
138         /**
139          * \brief after execution the state will be set to available by calling this method
140          */
141         void setCreatedState()
142         {
143                 this->m_state = COM_MB_AVAILABLE;
144         }
145
146         inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
147         {
148                 int w = this->m_width;
149                 int h = this->m_height;
150                 x = x - m_rect.xmin;
151                 y = y - m_rect.ymin;
152
153                 switch (extend_x) {
154                         case COM_MB_CLIP:
155                                 break;
156                         case COM_MB_EXTEND:
157                                 if (x < 0) x = 0;
158                                 if (x >= w) x = w;
159                                 break;
160                         case COM_MB_REPEAT:
161                                 x = (x >= 0.0f ? (x % w) : (x % w) + w);
162                                 break;
163                 }
164
165                 switch (extend_y) {
166                         case COM_MB_CLIP:
167                                 break;
168                         case COM_MB_EXTEND:
169                                 if (y < 0) y = 0;
170                                 if (y >= h) y = h;
171                                 break;
172                         case COM_MB_REPEAT:
173                                 y = (y >= 0.0f ? (y % h) : (y % h) + h);
174                                 break;
175                 }
176         }
177
178         inline void wrap_pixel(float &x, float &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
179         {
180                 float w = (float)this->m_width;
181                 float h = (float)this->m_height;
182                 x = x - m_rect.xmin;
183                 y = y - m_rect.ymin;
184
185                 switch (extend_x) {
186                         case COM_MB_CLIP:
187                                 break;
188                         case COM_MB_EXTEND:
189                                 if (x < 0) x = 0.0f;
190                                 if (x >= w) x = w;
191                                 break;
192                         case COM_MB_REPEAT:
193                                 x = fmodf(x, w);
194                                 break;
195                 }
196
197                 switch (extend_y) {
198                         case COM_MB_CLIP:
199                                 break;
200                         case COM_MB_EXTEND:
201                                 if (y < 0) y = 0.0f;
202                                 if (y >= h) y = h;
203                                 break;
204                         case COM_MB_REPEAT:
205                                 y = fmodf(y, h);
206                                 break;
207                 }
208         }
209
210         inline void read(float *result, int x, int y,
211                          MemoryBufferExtend extend_x = COM_MB_CLIP,
212                          MemoryBufferExtend extend_y = COM_MB_CLIP)
213         {
214                 bool clip_x = (extend_x == COM_MB_CLIP && (x < m_rect.xmin || x >= m_rect.xmax));
215                 bool clip_y = (extend_y == COM_MB_CLIP && (y < m_rect.ymin || y >= m_rect.ymax));
216                 if (clip_x || clip_y) {
217                         /* clip result outside rect is zero */
218                         memset(result, 0, this->m_num_channels * sizeof(float));
219                 }
220                 else {
221                         int u = x;
222                         int v = y;
223                         this->wrap_pixel(u, v, extend_x, extend_y);
224                         const int offset = (this->m_width * y + x) * this->m_num_channels;
225                         float *buffer = &this->m_buffer[offset];
226                         memcpy(result, buffer, sizeof(float) * this->m_num_channels);
227                 }
228         }
229
230         inline void readNoCheck(float *result, int x, int y,
231                                 MemoryBufferExtend extend_x = COM_MB_CLIP,
232                                 MemoryBufferExtend extend_y = COM_MB_CLIP)
233         {
234                 int u = x;
235                 int v = y;
236
237                 this->wrap_pixel(u, v, extend_x, extend_y);
238                 const int offset = (this->m_width * v + u) * this->m_num_channels;
239
240                 BLI_assert(offset >= 0);
241                 BLI_assert(offset < this->determineBufferSize() * this->m_num_channels);
242                 BLI_assert(!(extend_x == COM_MB_CLIP && (u < m_rect.xmin || u >= m_rect.xmax)) &&
243                            !(extend_y == COM_MB_CLIP && (v < m_rect.ymin || v >= m_rect.ymax)));
244 #if 0
245                 /* always true */
246                 BLI_assert((int)(MEM_allocN_len(this->m_buffer) / sizeof(*this->m_buffer)) ==
247                            (int)(this->determineBufferSize() * COM_NUMBER_OF_CHANNELS));
248 #endif
249                 float *buffer = &this->m_buffer[offset];
250                 memcpy(result, buffer, sizeof(float) * this->m_num_channels);
251         }
252
253         void writePixel(int x, int y, const float color[4]);
254         void addPixel(int x, int y, const float color[4]);
255         inline void readBilinear(float *result, float x, float y,
256                                  MemoryBufferExtend extend_x = COM_MB_CLIP,
257                                  MemoryBufferExtend extend_y = COM_MB_CLIP)
258         {
259                 float u = x;
260                 float v = y;
261                 this->wrap_pixel(u, v, extend_x, extend_y);
262                 if ((extend_x != COM_MB_REPEAT && (u < 0.0f || u >= this->m_width)) ||
263                     (extend_y != COM_MB_REPEAT && (v < 0.0f || v >= this->m_height)))
264                 {
265                         copy_vn_fl(result, this->m_num_channels, 0.0f);
266                         return;
267                 }
268                 BLI_bilinear_interpolation_wrap_fl(
269                         this->m_buffer, result, this->m_width, this->m_height, this->m_num_channels, u, v,
270                         extend_x == COM_MB_REPEAT, extend_y == COM_MB_REPEAT);
271         }
272
273         void readEWA(float *result, const float uv[2], const float derivatives[2][2]);
274
275         /**
276          * \brief is this MemoryBuffer a temporarily buffer (based on an area, not on a chunk)
277          */
278         inline bool isTemporarily() const { return this->m_state == COM_MB_TEMPORARILY; }
279
280         /**
281          * \brief add the content from otherBuffer to this MemoryBuffer
282          * \param otherBuffer: source buffer
283          *
284          * \note take care when running this on a new buffer since it wont fill in
285          *       uninitialized values in areas where the buffers don't overlap.
286          */
287         void copyContentFrom(MemoryBuffer *otherBuffer);
288
289         /**
290          * \brief get the rect of this MemoryBuffer
291          */
292         rcti *getRect() { return &this->m_rect; }
293
294         /**
295          * \brief get the width of this MemoryBuffer
296          */
297         int getWidth() const;
298
299         /**
300          * \brief get the height of this MemoryBuffer
301          */
302         int getHeight() const;
303
304         /**
305          * \brief clear the buffer. Make all pixels black transparent.
306          */
307         void clear();
308
309         MemoryBuffer *duplicate();
310
311         float getMaximumValue();
312         float getMaximumValue(rcti *rect);
313 private:
314         unsigned int determineBufferSize();
315
316 #ifdef WITH_CXX_GUARDEDALLOC
317         MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer")
318 #endif
319 };
320
321 #endif