Blender  V2.93
COM_ScaleOperation.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2011, Blender Foundation.
17  */
18 
19 #include "COM_ScaleOperation.h"
20 
21 namespace blender::compositor {
22 
23 #define USE_FORCE_BILINEAR
24 /* XXX - ignore input and use default from old compositor,
25  * could become an option like the transform node - campbell
26  *
27  * note: use bilinear because bicubic makes fuzzy even when not scaling at all (1:1)
28  */
29 
31 {
32 #ifdef USE_FORCE_BILINEAR
34 #else
35  m_sampler = -1;
36 #endif
37  m_variable_size = false;
38 }
39 
41 {
47  this->m_inputOperation = nullptr;
48  this->m_inputXOperation = nullptr;
49  this->m_inputYOperation = nullptr;
50 }
52 {
53  this->m_inputOperation = this->getInputSocketReader(0);
54  this->m_inputXOperation = this->getInputSocketReader(1);
55  this->m_inputYOperation = this->getInputSocketReader(2);
56  this->m_centerX = this->getWidth() / 2.0;
57  this->m_centerY = this->getHeight() / 2.0;
58 }
59 
61 {
62  this->m_inputOperation = nullptr;
63  this->m_inputXOperation = nullptr;
64  this->m_inputYOperation = nullptr;
65 }
66 
67 void ScaleOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
68 {
69  PixelSampler effective_sampler = getEffectiveSampler(sampler);
70 
71  float scaleX[4];
72  float scaleY[4];
73 
74  this->m_inputXOperation->readSampled(scaleX, x, y, effective_sampler);
75  this->m_inputYOperation->readSampled(scaleY, x, y, effective_sampler);
76 
77  const float scx = scaleX[0];
78  const float scy = scaleY[0];
79 
80  float nx = this->m_centerX + (x - this->m_centerX) / scx;
81  float ny = this->m_centerY + (y - this->m_centerY) / scy;
82  this->m_inputOperation->readSampled(output, nx, ny, effective_sampler);
83 }
84 
86  ReadBufferOperation *readOperation,
87  rcti *output)
88 {
89  rcti newInput;
90  if (!m_variable_size) {
91  float scaleX[4];
92  float scaleY[4];
93 
94  this->m_inputXOperation->readSampled(scaleX, 0, 0, PixelSampler::Nearest);
95  this->m_inputYOperation->readSampled(scaleY, 0, 0, PixelSampler::Nearest);
96 
97  const float scx = scaleX[0];
98  const float scy = scaleY[0];
99 
100  newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx + 1;
101  newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx - 1;
102  newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy + 1;
103  newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy - 1;
104  }
105  else {
106  newInput.xmax = this->getWidth();
107  newInput.xmin = 0;
108  newInput.ymax = this->getHeight();
109  newInput.ymin = 0;
110  }
111  return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
112 }
113 
114 // SCALE ABSOLUTE
116 {
122  this->m_inputOperation = nullptr;
123  this->m_inputXOperation = nullptr;
124  this->m_inputYOperation = nullptr;
125 }
127 {
128  this->m_inputOperation = this->getInputSocketReader(0);
129  this->m_inputXOperation = this->getInputSocketReader(1);
130  this->m_inputYOperation = this->getInputSocketReader(2);
131  this->m_centerX = this->getWidth() / 2.0;
132  this->m_centerY = this->getHeight() / 2.0;
133 }
134 
136 {
137  this->m_inputOperation = nullptr;
138  this->m_inputXOperation = nullptr;
139  this->m_inputYOperation = nullptr;
140 }
141 
143  float x,
144  float y,
145  PixelSampler sampler)
146 {
147  PixelSampler effective_sampler = getEffectiveSampler(sampler);
148 
149  float scaleX[4];
150  float scaleY[4];
151 
152  this->m_inputXOperation->readSampled(scaleX, x, y, effective_sampler);
153  this->m_inputYOperation->readSampled(scaleY, x, y, effective_sampler);
154 
155  const float scx = scaleX[0]; // target absolute scale
156  const float scy = scaleY[0]; // target absolute scale
157 
158  const float width = this->getWidth();
159  const float height = this->getHeight();
160  // div
161  float relativeXScale = scx / width;
162  float relativeYScale = scy / height;
163 
164  float nx = this->m_centerX + (x - this->m_centerX) / relativeXScale;
165  float ny = this->m_centerY + (y - this->m_centerY) / relativeYScale;
166 
167  this->m_inputOperation->readSampled(output, nx, ny, effective_sampler);
168 }
169 
171  ReadBufferOperation *readOperation,
172  rcti *output)
173 {
174  rcti newInput;
175  if (!m_variable_size) {
176  float scaleX[4];
177  float scaleY[4];
178 
179  this->m_inputXOperation->readSampled(scaleX, 0, 0, PixelSampler::Nearest);
180  this->m_inputYOperation->readSampled(scaleY, 0, 0, PixelSampler::Nearest);
181 
182  const float scx = scaleX[0];
183  const float scy = scaleY[0];
184  const float width = this->getWidth();
185  const float height = this->getHeight();
186  // div
187  float relateveXScale = scx / width;
188  float relateveYScale = scy / height;
189 
190  newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale;
191  newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale;
192  newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale;
193  newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale;
194  }
195  else {
196  newInput.xmax = this->getWidth();
197  newInput.xmin = 0;
198  newInput.ymax = this->getHeight();
199  newInput.ymin = 0;
200  }
201 
202  return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
203 }
204 
205 // Absolute fixed size
207 {
211  this->m_inputOperation = nullptr;
212  this->m_is_offset = false;
213 }
215 {
216  this->m_inputOperation = this->getInputSocketReader(0);
217  this->m_relX = this->m_inputOperation->getWidth() / (float)this->m_newWidth;
218  this->m_relY = this->m_inputOperation->getHeight() / (float)this->m_newHeight;
219 
220  /* *** all the options below are for a fairly special case - camera framing *** */
221  if (this->m_offsetX != 0.0f || this->m_offsetY != 0.0f) {
222  this->m_is_offset = true;
223 
224  if (this->m_newWidth > this->m_newHeight) {
225  this->m_offsetX *= this->m_newWidth;
226  this->m_offsetY *= this->m_newWidth;
227  }
228  else {
229  this->m_offsetX *= this->m_newHeight;
230  this->m_offsetY *= this->m_newHeight;
231  }
232  }
233 
234  if (this->m_is_aspect) {
235  /* apply aspect from clip */
236  const float w_src = this->m_inputOperation->getWidth();
237  const float h_src = this->m_inputOperation->getHeight();
238 
239  /* destination aspect is already applied from the camera frame */
240  const float w_dst = this->m_newWidth;
241  const float h_dst = this->m_newHeight;
242 
243  const float asp_src = w_src / h_src;
244  const float asp_dst = w_dst / h_dst;
245 
246  if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
247  if ((asp_src > asp_dst) == (this->m_is_crop == true)) {
248  /* fit X */
249  const float div = asp_src / asp_dst;
250  this->m_relX /= div;
251  this->m_offsetX += ((w_src - (w_src * div)) / (w_src / w_dst)) / 2.0f;
252  }
253  else {
254  /* fit Y */
255  const float div = asp_dst / asp_src;
256  this->m_relY /= div;
257  this->m_offsetY += ((h_src - (h_src * div)) / (h_src / h_dst)) / 2.0f;
258  }
259 
260  this->m_is_offset = true;
261  }
262  }
263  /* *** end framing options *** */
264 }
265 
267 {
268  this->m_inputOperation = nullptr;
269 }
270 
272  float x,
273  float y,
274  PixelSampler sampler)
275 {
276  PixelSampler effective_sampler = getEffectiveSampler(sampler);
277 
278  if (this->m_is_offset) {
279  float nx = ((x - this->m_offsetX) * this->m_relX);
280  float ny = ((y - this->m_offsetY) * this->m_relY);
281  this->m_inputOperation->readSampled(output, nx, ny, effective_sampler);
282  }
283  else {
284  this->m_inputOperation->readSampled(
285  output, x * this->m_relX, y * this->m_relY, effective_sampler);
286  }
287 }
288 
290  ReadBufferOperation *readOperation,
291  rcti *output)
292 {
293  rcti newInput;
294 
295  newInput.xmax = (input->xmax - m_offsetX) * this->m_relX + 1;
296  newInput.xmin = (input->xmin - m_offsetX) * this->m_relX;
297  newInput.ymax = (input->ymax - m_offsetY) * this->m_relY + 1;
298  newInput.ymin = (input->ymin - m_offsetY) * this->m_relY;
299 
300  return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
301 }
302 
303 void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2],
304  unsigned int /*preferredResolution*/[2])
305 {
306  unsigned int nr[2];
307  nr[0] = this->m_newWidth;
308  nr[1] = this->m_newHeight;
310  resolution[0] = this->m_newWidth;
311  resolution[1] = this->m_newHeight;
312 }
313 
314 } // namespace blender::compositor
typedef float(TangentPoint)[2]
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble ny
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
#define output
PixelSampler getEffectiveSampler(PixelSampler sampler)
void readSampled(float result[4], float x, float y, PixelSampler sampler)
void addInputSocket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
void addOutputSocket(DataType datatype)
void setResolutionInputSocketIndex(unsigned int index)
set the index of the input socket that will determine the resolution of this operation
virtual void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
determine the resolution of this node
SocketReader * getInputSocketReader(unsigned int inputSocketindex)
virtual bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override
calculate a single pixel
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override
calculate a single pixel
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) override
determine the resolution of this node
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override
calculate a single pixel
@ None
The bottom left of the input image is the bottom left of the working area of the node,...
#define fabsf(x)
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79