c34931471c7c6f07eb237bbd06a7fe0f7f004c30
[blender-staging.git] / source / blender / compositor / operations / COM_TranslateOperation.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  *              Thomas Beck (plasmasolutions.de)
22  */
23
24 #include "COM_TranslateOperation.h"
25
26 TranslateOperation::TranslateOperation() : NodeOperation()
27 {
28         this->addInputSocket(COM_DT_COLOR);
29         this->addInputSocket(COM_DT_VALUE);
30         this->addInputSocket(COM_DT_VALUE);
31         this->addOutputSocket(COM_DT_COLOR);
32         this->setResolutionInputSocketIndex(0);
33         this->m_inputOperation = NULL;
34         this->m_inputXOperation = NULL;
35         this->m_inputYOperation = NULL;
36         this->m_isDeltaSet = false;
37 }
38 void TranslateOperation::initExecution()
39 {
40         this->m_inputOperation = this->getInputSocketReader(0);
41         this->m_inputXOperation = this->getInputSocketReader(1);
42         this->m_inputYOperation = this->getInputSocketReader(2);
43
44         ensureDelta();
45
46         //Calculate the relative offset once per execution, no need to do this per pixel
47         this->m_relativeOffsetX = fmodf(this->getDeltaX(), this->getWidth());
48         this->m_relativeOffsetY = fmodf(this->getDeltaY(), this->getHeight());
49
50 }
51
52 void TranslateOperation::deinitExecution()
53 {
54         this->m_inputOperation = NULL;
55         this->m_inputXOperation = NULL;
56         this->m_inputYOperation = NULL;
57 }
58
59
60 void TranslateOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
61 {
62         ensureDelta();
63
64         float originalXPos = x - this->getDeltaX();
65         float originalYPos = y - this->getDeltaY();
66
67         switch(m_wrappingType) {
68                 case 0:
69                         //Intentionally empty, originalXPos and originalYPos have been set before
70                         break;
71                 case 1:
72                         // wrap only on the x-axis
73                         originalXPos = this->getWrappedOriginalXPos(x);
74                         break;
75                 case 2:
76                         // wrap only on the y-axis
77                         originalYPos = this->getWrappedOriginalYPos(y);
78                         break;
79                 case 3:
80                         // wrap on both
81                         originalXPos = this->getWrappedOriginalXPos(x);
82                         originalYPos = this->getWrappedOriginalYPos(y);
83                         break;
84         }
85
86         this->m_inputOperation->read(output, originalXPos , originalYPos, sampler);
87
88 }
89
90 bool TranslateOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
91 {
92         rcti newInput;
93
94         ensureDelta();
95
96         newInput.xmin = input->xmin - this->getDeltaX();
97         newInput.xmax = input->xmax - this->getDeltaX();
98         newInput.ymin = input->ymin - this->getDeltaY();
99         newInput.ymax = input->ymax - this->getDeltaY();
100
101         if (m_wrappingType == 1 || m_wrappingType == 3){
102                 // wrap only on the x-axis if tile is wrapping
103                 newInput.xmin = getWrappedOriginalXPos(input->xmin);
104                 newInput.xmax = getWrappedOriginalXPos(input->xmax);
105                 if(newInput.xmin > newInput.xmax){
106                         newInput.xmin = 0;
107                         newInput.xmax = this->getWidth();
108                 }
109         }
110         if(m_wrappingType == 2 || m_wrappingType == 3) {
111                 // wrap only on the y-axis if tile is wrapping
112                 newInput.ymin = getWrappedOriginalYPos(input->ymin);
113                 newInput.ymax = getWrappedOriginalYPos(input->ymax);
114                 if (newInput.ymin > newInput.ymax){
115                         newInput.ymin = 0;
116                         newInput.ymax = this->getHeight();
117                 }
118         }
119
120
121         return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
122 }
123
124 void TranslateOperation::setWrapping(char wrapping_type)
125 {
126         m_wrappingType = wrapping_type;
127 }
128
129 float TranslateOperation::getWrappedOriginalXPos(float x)
130 {
131         float originalXPos = 0;
132
133         // Positive offset: Append image data from the left
134         if ( this->m_relativeOffsetX > 0 ) {
135                 if ( x < this->m_relativeOffsetX )
136                         originalXPos = this->getWidth() - this->m_relativeOffsetX + x;
137                 else
138                         originalXPos =  x - this->m_relativeOffsetX;
139         } else {
140                 // Negative offset: Append image data from the right
141                 if (x < (this->getWidth() + this->m_relativeOffsetX))
142                         originalXPos = x - this->m_relativeOffsetX;
143                 else
144                         originalXPos = x - (this->getWidth() + this->m_relativeOffsetX);
145         }
146
147         while (originalXPos < 0) originalXPos += this->m_width;
148         return fmodf(originalXPos, this->getWidth());
149 }
150
151
152 float TranslateOperation::getWrappedOriginalYPos(float y)
153 {
154         float originalYPos = 0;
155
156         // Positive offset: Append image data from the bottom
157         if (  this->m_relativeOffsetY > 0 ) {
158                 if ( y < this->m_relativeOffsetY )
159                         originalYPos = this->getHeight()- this->m_relativeOffsetY + y;
160                 else
161                         originalYPos =  y - this->m_relativeOffsetY;
162         } else {
163                 // Negative offset: Append image data from the top
164                 if (y < (this->getHeight() + this->m_relativeOffsetY))
165                         originalYPos = y - this->m_relativeOffsetY;
166                 else
167                         originalYPos = y - (this->getHeight() + this->m_relativeOffsetY);
168         }
169
170         while (originalYPos < 0) originalYPos += this->m_height;
171         return fmodf(originalYPos, this->getHeight());
172 }