code cleanup:
[blender.git] / source / blender / compositor / operations / COM_CompositorOperation.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_CompositorOperation.h"
24 #include "COM_SocketConnection.h"
25 #include "BLI_listbase.h"
26 #include "BKE_image.h"
27
28 extern "C" {
29         #include "BLI_threads.h"
30         #include "RE_pipeline.h"
31         #include "RE_shader_ext.h"
32         #include "RE_render_ext.h"
33         #include "MEM_guardedalloc.h"
34         #include "render_types.h"
35 }
36 #include "PIL_time.h"
37
38
39 CompositorOperation::CompositorOperation() : NodeOperation()
40 {
41         this->addInputSocket(COM_DT_COLOR);
42         this->addInputSocket(COM_DT_VALUE);
43         this->addInputSocket(COM_DT_VALUE);
44
45         this->setRenderData(NULL);
46         this->m_outputBuffer = NULL;
47         this->m_depthBuffer = NULL;
48         this->m_imageInput = NULL;
49         this->m_alphaInput = NULL;
50         this->m_depthInput = NULL;
51
52         this->m_ignoreAlpha = false;
53         this->m_active = false;
54
55         this->m_sceneName[0] = '\0';
56 }
57
58 void CompositorOperation::initExecution()
59 {
60         if (!this->m_active)
61                 return;
62
63         // When initializing the tree during initial load the width and height can be zero.
64         this->m_imageInput = getInputSocketReader(0);
65         this->m_alphaInput = getInputSocketReader(1);
66         this->m_depthInput = getInputSocketReader(2);
67         if (this->getWidth() * this->getHeight() != 0) {
68                 this->m_outputBuffer = (float *) MEM_callocN(this->getWidth() * this->getHeight() * 4 * sizeof(float), "CompositorOperation");
69         }
70         if (this->m_depthInput != NULL) {
71                 this->m_depthBuffer = (float *) MEM_callocN(this->getWidth() * this->getHeight() * sizeof(float), "CompositorOperation");
72         }
73 }
74
75 void CompositorOperation::deinitExecution()
76 {
77         if (!this->m_active)
78                 return;
79
80         if (!isBreaked()) {
81                 Render *re = RE_GetRender(this->m_sceneName);
82                 RenderResult *rr = RE_AcquireResultWrite(re);
83
84                 if (rr) {
85                         if (rr->rectf != NULL) {
86                                 MEM_freeN(rr->rectf);
87                         }
88                         rr->rectf = this->m_outputBuffer;
89                         if (rr->rectz != NULL) {
90                                 MEM_freeN(rr->rectz);
91                         }
92                         rr->rectz = this->m_depthBuffer;
93                 }
94                 else {
95                         if (this->m_outputBuffer) {
96                                 MEM_freeN(this->m_outputBuffer);
97                         }
98                         if (this->m_depthBuffer) {
99                                 MEM_freeN(this->m_depthBuffer);
100                         }
101                 }
102
103                 if (re) {
104                         RE_ReleaseResult(re);
105                         re = NULL;
106                 }
107
108                 BLI_lock_thread(LOCK_DRAW_IMAGE);
109                 BKE_image_signal(BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), NULL, IMA_SIGNAL_FREE);
110                 BLI_unlock_thread(LOCK_DRAW_IMAGE);
111         }
112         else {
113                 if (this->m_outputBuffer) {
114                         MEM_freeN(this->m_outputBuffer);
115                 }
116                 if (this->m_depthBuffer) {
117                         MEM_freeN(this->m_depthBuffer);
118                 }
119         }
120
121         this->m_outputBuffer = NULL;
122         this->m_depthBuffer = NULL;
123         this->m_imageInput = NULL;
124         this->m_alphaInput = NULL;
125         this->m_depthInput = NULL;
126 }
127
128
129 void CompositorOperation::executeRegion(rcti *rect, unsigned int tileNumber)
130 {
131         float color[8]; // 7 is enough
132         float *buffer = this->m_outputBuffer;
133         float *zbuffer = this->m_depthBuffer;
134
135         if (!buffer) return;
136         int x1 = rect->xmin;
137         int y1 = rect->ymin;
138         int x2 = rect->xmax;
139         int y2 = rect->ymax;
140         int offset = (y1 * this->getWidth() + x1);
141         int add = (this->getWidth() - (x2 - x1));
142         int offset4 = offset * COM_NUMBER_OF_CHANNELS;
143         int x;
144         int y;
145         bool breaked = false;
146         int dx = 0, dy = 0;
147
148         const RenderData *rd = this->m_rd;
149
150         if (rd->mode & R_BORDER && rd->mode & R_CROP) {
151         /*!
152            When using cropped render result, need to re-position area of interest,
153            so it'll natch bounds of render border within frame. By default, canvas
154            will be centered between full frame and cropped frame, so we use such
155            scheme to map cropped coordinates to full-frame coordinates
156
157                    ^ Y
158                    |                      Width
159                    +------------------------------------------------+
160                    |                                                |
161                    |                                                |
162                    |  Centered canvas, we map coordinate from it    |
163                    |              +------------------+              |
164                    |              |                  |              |  H
165                    |              |                  |              |  e
166                    |  +------------------+ . Center  |              |  i
167                    |  |           |      |           |              |  g
168                    |  |           |      |           |              |  h
169                    |  |....dx.... +------|-----------+              |  t
170                    |  |           . dy   |                          |
171                    |  +------------------+                          |
172                    |  Render border, we map coordinates to it       |
173                    |                                                |    X
174                    +------------------------------------------------+---->
175                                         Full frame
176                  */
177
178                 int full_width  = rd->xsch * rd->size / 100;
179                 int full_height = rd->ysch * rd->size / 100;
180
181                 dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f;
182                 dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f;
183         }
184
185         for (y = y1; y < y2 && (!breaked); y++) {
186                 for (x = x1; x < x2 && (!breaked); x++) {
187                         int input_x = x + dx, input_y = y + dy;
188
189                         this->m_imageInput->read(color, input_x, input_y, COM_PS_NEAREST);
190                         if (this->m_ignoreAlpha) {
191                                 color[3] = 1.0f;
192                         }
193                         else {
194                                 if (this->m_alphaInput != NULL) {
195                                         this->m_alphaInput->read(&(color[3]), input_x, input_y, COM_PS_NEAREST);
196                                 }
197                         }
198
199                         copy_v4_v4(buffer + offset4, color);
200
201                         if (this->m_depthInput != NULL) {
202                                 this->m_depthInput->read(color, input_x, input_y, COM_PS_NEAREST);
203                                 zbuffer[offset] = color[0];
204                         }
205                         offset4 += COM_NUMBER_OF_CHANNELS;
206                         offset++;
207                         if (isBreaked()) {
208                                 breaked = true;
209                         }
210                 }
211                 offset += add;
212                 offset4 += add * COM_NUMBER_OF_CHANNELS;
213         }
214 }
215
216 void CompositorOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
217 {
218         int width = this->m_rd->xsch * this->m_rd->size / 100;
219         int height = this->m_rd->ysch * this->m_rd->size / 100;
220
221         // check actual render resolution with cropping it may differ with cropped border.rendering
222         // FIX for: [31777] Border Crop gives black (easy)
223         Render *re = RE_GetRender(this->m_sceneName);
224         if (re) {
225                 RenderResult *rr = RE_AcquireResultRead(re);
226                 if (rr) {
227                         width = rr->rectx;
228                         height = rr->recty;
229                 }
230                 RE_ReleaseResult(re);
231         }
232
233         preferredResolution[0] = width;
234         preferredResolution[1] = height;
235
236         NodeOperation::determineResolution(resolution, preferredResolution);
237
238         resolution[0] = width;
239         resolution[1] = height;
240 }