Fix T70439: Local view always including new objects
[blender.git] / source / blender / compositor / intern / COM_MemoryBuffer.h
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2011, Blender Foundation.
17  */
18
19 class MemoryBuffer;
20
21 #ifndef __COM_MEMORYBUFFER_H__
22 #define __COM_MEMORYBUFFER_H__
23
24 #include "COM_ExecutionGroup.h"
25 #include "COM_MemoryProxy.h"
26 #include "COM_SocketReader.h"
27
28 extern "C" {
29 #include "BLI_math.h"
30 #include "BLI_rect.h"
31 }
32
33 /**
34  * \brief state of a memory buffer
35  * \ingroup Memory
36  */
37 typedef enum MemoryBufferState {
38   /** \brief memory has been allocated on creator device and CPU machine,
39    * but kernel has not been executed */
40   COM_MB_ALLOCATED = 1,
41   /** \brief memory is available for use, content has been created */
42   COM_MB_AVAILABLE = 2,
43   /** \brief chunk is consolidated from other chunks. special state.*/
44   COM_MB_TEMPORARILY = 6,
45 } MemoryBufferState;
46
47 typedef enum MemoryBufferExtend {
48   COM_MB_CLIP,
49   COM_MB_EXTEND,
50   COM_MB_REPEAT,
51 } MemoryBufferExtend;
52
53 class MemoryProxy;
54
55 /**
56  * \brief a MemoryBuffer contains access to the data of a chunk
57  */
58 class MemoryBuffer {
59  private:
60   /**
61    * \brief proxy of the memory (same for all chunks in the same buffer)
62    */
63   MemoryProxy *m_memoryProxy;
64
65   /**
66    * \brief the type of buffer COM_DT_VALUE, COM_DT_VECTOR, COM_DT_COLOR
67    */
68   DataType m_datatype;
69
70   /**
71    * \brief region of this buffer inside relative to the MemoryProxy
72    */
73   rcti m_rect;
74
75   /**
76    * brief refers to the chunk-number within the execution-group where related to the MemoryProxy
77    * \see memoryProxy
78    */
79   unsigned int m_chunkNumber;
80
81   /**
82    * \brief state of the buffer
83    */
84   MemoryBufferState m_state;
85
86   /**
87    * \brief the actual float buffer/data
88    */
89   float *m_buffer;
90
91   /**
92    * \brief the number of channels of a single value in the buffer.
93    * For value buffers this is 1, vector 3 and color 4
94    */
95   unsigned int m_num_channels;
96
97   int m_width;
98   int m_height;
99
100  public:
101   /**
102    * \brief construct new MemoryBuffer for a chunk
103    */
104   MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect);
105
106   /**
107    * \brief construct new temporarily MemoryBuffer for an area
108    */
109   MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect);
110
111   /**
112    * \brief construct new temporarily MemoryBuffer for an area
113    */
114   MemoryBuffer(DataType datatype, rcti *rect);
115
116   /**
117    * \brief destructor
118    */
119   ~MemoryBuffer();
120
121   /**
122    * \brief read the ChunkNumber of this MemoryBuffer
123    */
124   unsigned int getChunkNumber()
125   {
126     return this->m_chunkNumber;
127   }
128
129   unsigned int get_num_channels()
130   {
131     return this->m_num_channels;
132   }
133
134   /**
135    * \brief get the data of this MemoryBuffer
136    * \note buffer should already be available in memory
137    */
138   float *getBuffer()
139   {
140     return this->m_buffer;
141   }
142
143   /**
144    * \brief after execution the state will be set to available by calling this method
145    */
146   void setCreatedState()
147   {
148     this->m_state = COM_MB_AVAILABLE;
149   }
150
151   inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
152   {
153     int w = this->m_width;
154     int h = this->m_height;
155     x = x - m_rect.xmin;
156     y = y - m_rect.ymin;
157
158     switch (extend_x) {
159       case COM_MB_CLIP:
160         break;
161       case COM_MB_EXTEND:
162         if (x < 0) {
163           x = 0;
164         }
165         if (x >= w) {
166           x = w;
167         }
168         break;
169       case COM_MB_REPEAT:
170         x = (x >= 0.0f ? (x % w) : (x % w) + w);
171         break;
172     }
173
174     switch (extend_y) {
175       case COM_MB_CLIP:
176         break;
177       case COM_MB_EXTEND:
178         if (y < 0) {
179           y = 0;
180         }
181         if (y >= h) {
182           y = h;
183         }
184         break;
185       case COM_MB_REPEAT:
186         y = (y >= 0.0f ? (y % h) : (y % h) + h);
187         break;
188     }
189   }
190
191   inline void wrap_pixel(float &x,
192                          float &y,
193                          MemoryBufferExtend extend_x,
194                          MemoryBufferExtend extend_y)
195   {
196     float w = (float)this->m_width;
197     float h = (float)this->m_height;
198     x = x - m_rect.xmin;
199     y = y - m_rect.ymin;
200
201     switch (extend_x) {
202       case COM_MB_CLIP:
203         break;
204       case COM_MB_EXTEND:
205         if (x < 0) {
206           x = 0.0f;
207         }
208         if (x >= w) {
209           x = w;
210         }
211         break;
212       case COM_MB_REPEAT:
213         x = fmodf(x, w);
214         break;
215     }
216
217     switch (extend_y) {
218       case COM_MB_CLIP:
219         break;
220       case COM_MB_EXTEND:
221         if (y < 0) {
222           y = 0.0f;
223         }
224         if (y >= h) {
225           y = h;
226         }
227         break;
228       case COM_MB_REPEAT:
229         y = fmodf(y, h);
230         break;
231     }
232   }
233
234   inline void read(float *result,
235                    int x,
236                    int y,
237                    MemoryBufferExtend extend_x = COM_MB_CLIP,
238                    MemoryBufferExtend extend_y = COM_MB_CLIP)
239   {
240     bool clip_x = (extend_x == COM_MB_CLIP && (x < m_rect.xmin || x >= m_rect.xmax));
241     bool clip_y = (extend_y == COM_MB_CLIP && (y < m_rect.ymin || y >= m_rect.ymax));
242     if (clip_x || clip_y) {
243       /* clip result outside rect is zero */
244       memset(result, 0, this->m_num_channels * sizeof(float));
245     }
246     else {
247       int u = x;
248       int v = y;
249       this->wrap_pixel(u, v, extend_x, extend_y);
250       const int offset = (this->m_width * y + x) * this->m_num_channels;
251       float *buffer = &this->m_buffer[offset];
252       memcpy(result, buffer, sizeof(float) * this->m_num_channels);
253     }
254   }
255
256   inline void readNoCheck(float *result,
257                           int x,
258                           int y,
259                           MemoryBufferExtend extend_x = COM_MB_CLIP,
260                           MemoryBufferExtend extend_y = COM_MB_CLIP)
261   {
262     int u = x;
263     int v = y;
264
265     this->wrap_pixel(u, v, extend_x, extend_y);
266     const int offset = (this->m_width * v + u) * this->m_num_channels;
267
268     BLI_assert(offset >= 0);
269     BLI_assert(offset < this->determineBufferSize() * this->m_num_channels);
270     BLI_assert(!(extend_x == COM_MB_CLIP && (u < m_rect.xmin || u >= m_rect.xmax)) &&
271                !(extend_y == COM_MB_CLIP && (v < m_rect.ymin || v >= m_rect.ymax)));
272 #if 0
273     /* always true */
274     BLI_assert((int)(MEM_allocN_len(this->m_buffer) / sizeof(*this->m_buffer)) ==
275                (int)(this->determineBufferSize() * COM_NUMBER_OF_CHANNELS));
276 #endif
277     float *buffer = &this->m_buffer[offset];
278     memcpy(result, buffer, sizeof(float) * this->m_num_channels);
279   }
280
281   void writePixel(int x, int y, const float color[4]);
282   void addPixel(int x, int y, const float color[4]);
283   inline void readBilinear(float *result,
284                            float x,
285                            float y,
286                            MemoryBufferExtend extend_x = COM_MB_CLIP,
287                            MemoryBufferExtend extend_y = COM_MB_CLIP)
288   {
289     float u = x;
290     float v = y;
291     this->wrap_pixel(u, v, extend_x, extend_y);
292     if ((extend_x != COM_MB_REPEAT && (u < 0.0f || u >= this->m_width)) ||
293         (extend_y != COM_MB_REPEAT && (v < 0.0f || v >= this->m_height))) {
294       copy_vn_fl(result, this->m_num_channels, 0.0f);
295       return;
296     }
297     BLI_bilinear_interpolation_wrap_fl(this->m_buffer,
298                                        result,
299                                        this->m_width,
300                                        this->m_height,
301                                        this->m_num_channels,
302                                        u,
303                                        v,
304                                        extend_x == COM_MB_REPEAT,
305                                        extend_y == COM_MB_REPEAT);
306   }
307
308   void readEWA(float *result, const float uv[2], const float derivatives[2][2]);
309
310   /**
311    * \brief is this MemoryBuffer a temporarily buffer (based on an area, not on a chunk)
312    */
313   inline bool isTemporarily() const
314   {
315     return this->m_state == COM_MB_TEMPORARILY;
316   }
317
318   /**
319    * \brief add the content from otherBuffer to this MemoryBuffer
320    * \param otherBuffer: source buffer
321    *
322    * \note take care when running this on a new buffer since it wont fill in
323    *       uninitialized values in areas where the buffers don't overlap.
324    */
325   void copyContentFrom(MemoryBuffer *otherBuffer);
326
327   /**
328    * \brief get the rect of this MemoryBuffer
329    */
330   rcti *getRect()
331   {
332     return &this->m_rect;
333   }
334
335   /**
336    * \brief get the width of this MemoryBuffer
337    */
338   int getWidth() const;
339
340   /**
341    * \brief get the height of this MemoryBuffer
342    */
343   int getHeight() const;
344
345   /**
346    * \brief clear the buffer. Make all pixels black transparent.
347    */
348   void clear();
349
350   MemoryBuffer *duplicate();
351
352   float getMaximumValue();
353   float getMaximumValue(rcti *rect);
354
355  private:
356   unsigned int determineBufferSize();
357
358 #ifdef WITH_CXX_GUARDEDALLOC
359   MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer")
360 #endif
361 };
362
363 #endif