7ee5e2f7c5762d21554409e7f81572e66173f4c6
[blender.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 static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4])
199 {
200         MemoryBuffer *buffer = (MemoryBuffer *) userdata;
201         buffer->read(result, x, y);
202 }
203
204 void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2])
205 {
206         BLI_assert(this->m_datatype == COM_DT_COLOR);
207         float inv_width = 1.0f / (float)this->getWidth(),
208               inv_height = 1.0f / (float)this->getHeight();
209         /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
210          * but compositor uses pixel space. For now let's just divide the values and
211          * switch compositor to normalized space for EWA later.
212          */
213         float uv_normal[2] = {uv[0] * inv_width, uv[1] * inv_height};
214         float du_normal[2] = {derivatives[0][0] * inv_width, derivatives[0][1] * inv_height};
215         float dv_normal[2] = {derivatives[1][0] * inv_width, derivatives[1][1] * inv_height};
216
217         BLI_ewa_filter(this->getWidth(), this->getHeight(),
218                        false,
219                        true,
220                        uv_normal, du_normal, dv_normal,
221                        read_ewa_pixel_sampled,
222                        this,
223                        result);
224 }