aa667884de64d9c9b71cedfac4941c86fc431e73
[blender.git] / source / blender / compositor / operations / COM_PreviewOperation.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_PreviewOperation.h"
24 #include "BLI_listbase.h"
25 #include "BKE_image.h"
26 #include "WM_api.h"
27 #include "WM_types.h"
28 #include "PIL_time.h"
29 #include "BLI_utildefines.h"
30 #include "BLI_math_color.h"
31 #include "COM_defines.h"
32 #include "BLI_math.h"
33 extern "C" {
34 #  include "MEM_guardedalloc.h"
35 #  include "IMB_imbuf.h"
36 #  include "IMB_imbuf_types.h"
37 #  include "IMB_colormanagement.h"
38 #  include "BKE_node.h"
39 }
40
41
42 PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings) : NodeOperation()
43 {
44         this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
45         this->m_preview = NULL;
46         this->m_outputBuffer = NULL;
47         this->m_input = NULL;
48         this->m_divider = 1.0f;
49         this->m_viewSettings = viewSettings;
50         this->m_displaySettings = displaySettings;
51 }
52
53 void PreviewOperation::verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key)
54 {
55         /* Size (0, 0) ensures the preview rect is not allocated in advance,
56          * this is set later in initExecution once the resolution is determined.
57          */
58         this->m_preview = BKE_node_preview_verify(previews, key, 0, 0, true);
59 }
60
61 void PreviewOperation::initExecution()
62 {
63         this->m_input = getInputSocketReader(0);
64         
65         if (this->getWidth() == (unsigned int)this->m_preview->xsize &&
66             this->getHeight() == (unsigned int)this->m_preview->ysize)
67         {
68                 this->m_outputBuffer = this->m_preview->rect;
69         }
70
71         if (this->m_outputBuffer == NULL) {
72                 this->m_outputBuffer = (unsigned char *)MEM_callocN(sizeof(unsigned char) * 4 * getWidth() * getHeight(), "PreviewOperation");
73                 if (this->m_preview->rect) {
74                         MEM_freeN(this->m_preview->rect);
75                 }
76                 this->m_preview->xsize = getWidth();
77                 this->m_preview->ysize = getHeight();
78                 this->m_preview->rect = this->m_outputBuffer;
79         }
80 }
81
82 void PreviewOperation::deinitExecution()
83 {
84         this->m_outputBuffer = NULL;
85         this->m_input = NULL;
86 }
87
88 void PreviewOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
89 {
90         int offset;
91         float color[4];
92         struct ColormanageProcessor *cm_processor;
93
94         cm_processor = IMB_colormanagement_display_processor_new(this->m_viewSettings, this->m_displaySettings);
95
96         for (int y = rect->ymin; y < rect->ymax; y++) {
97                 offset = (y * getWidth() + rect->xmin) * 4;
98                 for (int x = rect->xmin; x < rect->xmax; x++) {
99                         float rx = floor(x / this->m_divider);
100                         float ry = floor(y / this->m_divider);
101         
102                         color[0] = 0.0f;
103                         color[1] = 0.0f;
104                         color[2] = 0.0f;
105                         color[3] = 1.0f;
106                         this->m_input->readSampled(color, rx, ry, COM_PS_NEAREST);
107                         IMB_colormanagement_processor_apply_v4(cm_processor, color);
108                         F4TOCHAR4(color, this->m_outputBuffer + offset);
109                         offset += 4;
110                 }
111         }
112
113         IMB_colormanagement_processor_free(cm_processor);
114 }
115 bool PreviewOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
116 {
117         rcti newInput;
118
119         newInput.xmin = input->xmin / this->m_divider;
120         newInput.xmax = input->xmax / this->m_divider;
121         newInput.ymin = input->ymin / this->m_divider;
122         newInput.ymax = input->ymax / this->m_divider;
123
124         return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
125 }
126 void PreviewOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
127 {
128         NodeOperation::determineResolution(resolution, preferredResolution);
129         int width = resolution[0];
130         int height = resolution[1];
131         this->m_divider = 0.0f;
132         if (width > height) {
133                 this->m_divider = COM_PREVIEW_SIZE / (width - 1);
134         }
135         else {
136                 this->m_divider = COM_PREVIEW_SIZE / (height - 1);
137         }
138         width = width * this->m_divider;
139         height = height * this->m_divider;
140         
141         resolution[0] = width;
142         resolution[1] = height;
143 }
144
145 const CompositorPriority PreviewOperation::getRenderPriority() const
146 {
147         return COM_PRIORITY_LOW;
148 }