11cb4f7fc74c8287c79d7bdef9f2837f947b5ed5
[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 "DNA_scene_types.h"
27 #include "BKE_image.h"
28
29 extern "C" {
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
44         this->setScene(NULL);
45         this->outputBuffer = NULL;
46         this->imageInput = NULL;
47         this->alphaInput = NULL;
48 }
49
50 void CompositorOperation::initExecution()
51 {
52         // When initializing the tree during initial load the width and height can be zero.
53         this->imageInput = getInputSocketReader(0);
54         this->alphaInput = getInputSocketReader(1);
55         if (this->getWidth() * this->getHeight() != 0) {
56                 this->outputBuffer = (float *) MEM_callocN(this->getWidth() * this->getHeight() * 4 * sizeof(float), "CompositorOperation");
57         }
58 }
59
60 void CompositorOperation::deinitExecution()
61 {
62         if (isBreaked()) {
63                 const Scene *scene = this->scene;
64                 Render *re = RE_GetRender(scene->id.name);
65                 RenderResult *rr = RE_AcquireResultWrite(re);
66                 if (rr) {
67                         if (rr->rectf  != NULL) {
68                                 MEM_freeN(rr->rectf);
69                         }
70                         rr->rectf = outputBuffer;
71                 }
72                 else {
73                         if (this->outputBuffer) {
74                                 MEM_freeN(this->outputBuffer);
75                         }
76                 }
77                 if (re) {
78                         RE_ReleaseResult(re);
79                         re = NULL;
80                 }
81                 BKE_image_signal(BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), NULL, IMA_SIGNAL_FREE);
82         }
83         else {
84                 if (this->outputBuffer) {
85                         MEM_freeN(this->outputBuffer);
86                 }
87         }
88
89         this->outputBuffer = NULL;
90         this->imageInput = NULL;
91         this->alphaInput = NULL;
92 }
93
94
95 void CompositorOperation::executeRegion(rcti *rect, unsigned int tileNumber, MemoryBuffer **memoryBuffers)
96 {
97         float color[8]; // 7 is enough
98         float *buffer = this->outputBuffer;
99
100         if (!buffer) return;
101         int x1 = rect->xmin;
102         int y1 = rect->ymin;
103         int x2 = rect->xmax;
104         int y2 = rect->ymax;
105         int offset = (y1 * this->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
106         int x;
107         int y;
108         bool breaked = false;
109
110         for (y = y1; y < y2 && (!breaked); y++) {
111                 for (x = x1; x < x2 && (!breaked); x++) {
112                         imageInput->read(color, x, y, COM_PS_NEAREST, memoryBuffers);
113                         if (alphaInput != NULL) {
114                                 alphaInput->read(&(color[3]), x, y, COM_PS_NEAREST, memoryBuffers);
115                         }
116                         copy_v4_v4(buffer + offset, color);
117                         offset += COM_NUMBER_OF_CHANNELS;
118                         if (isBreaked()) {
119                                 breaked = true;
120                         }
121                 }
122                 offset += (this->getWidth() - (x2 - x1)) * COM_NUMBER_OF_CHANNELS;
123         }
124 }
125
126 void CompositorOperation::determineResolution(unsigned int resolution[], unsigned int preferredResolution[])
127 {
128         int width = this->scene->r.xsch * this->scene->r.size / 100;
129         int height = this->scene->r.ysch * this->scene->r.size / 100;
130
131         // check actual render resolution with cropping it may differ with cropped border.rendering
132         // FIX for: [31777] Border Crop gives black (easy)
133         Render *re = RE_GetRender(this->scene->id.name);
134         if (re) {
135                 RenderResult *rr = RE_AcquireResultRead(re);
136                 if (rr) {
137                         width = rr->rectx;
138                         height = rr->recty;
139                 }
140                 RE_ReleaseResult(re);
141         }
142
143         preferredResolution[0] = width;
144         preferredResolution[1] = height;
145
146         NodeOperation::determineResolution(resolution, preferredResolution);
147
148         resolution[0] = width;
149         resolution[1] = height;
150 }