Blender  V2.93
COM_TonemapOperation.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_TonemapOperation.h"
20 #include "BLI_math.h"
21 #include "BLI_utildefines.h"
22 
23 #include "IMB_colormanagement.h"
24 
25 namespace blender::compositor {
26 
28 {
31  this->m_imageReader = nullptr;
32  this->m_data = nullptr;
33  this->m_cachedInstance = nullptr;
34  this->flags.complex = true;
35 }
37 {
38  this->m_imageReader = this->getInputSocketReader(0);
40 }
41 
42 void TonemapOperation::executePixel(float output[4], int x, int y, void *data)
43 {
44  AvgLogLum *avg = (AvgLogLum *)data;
45 
46  this->m_imageReader->read(output, x, y, nullptr);
47  mul_v3_fl(output, avg->al);
48  float dr = output[0] + this->m_data->offset;
49  float dg = output[1] + this->m_data->offset;
50  float db = output[2] + this->m_data->offset;
51  output[0] /= ((dr == 0.0f) ? 1.0f : dr);
52  output[1] /= ((dg == 0.0f) ? 1.0f : dg);
53  output[2] /= ((db == 0.0f) ? 1.0f : db);
54  const float igm = avg->igm;
55  if (igm != 0.0f) {
56  output[0] = powf(MAX2(output[0], 0.0f), igm);
57  output[1] = powf(MAX2(output[1], 0.0f), igm);
58  output[2] = powf(MAX2(output[2], 0.0f), igm);
59  }
60 }
62 {
63  AvgLogLum *avg = (AvgLogLum *)data;
64  NodeTonemap *ntm = this->m_data;
65 
66  const float f = expf(-this->m_data->f);
67  const float m = (ntm->m > 0.0f) ? ntm->m : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
68  const float ic = 1.0f - ntm->c, ia = 1.0f - ntm->a;
69 
70  this->m_imageReader->read(output, x, y, nullptr);
71 
73  float I_l = output[0] + ic * (L - output[0]);
74  float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
75  float I_a = I_l + ia * (I_g - I_l);
76  output[0] /= (output[0] + powf(f * I_a, m));
77  I_l = output[1] + ic * (L - output[1]);
78  I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
79  I_a = I_l + ia * (I_g - I_l);
80  output[1] /= (output[1] + powf(f * I_a, m));
81  I_l = output[2] + ic * (L - output[2]);
82  I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
83  I_a = I_l + ia * (I_g - I_l);
84  output[2] /= (output[2] + powf(f * I_a, m));
85 }
86 
88 {
89  this->m_imageReader = nullptr;
90  delete this->m_cachedInstance;
92 }
93 
95  ReadBufferOperation *readOperation,
96  rcti *output)
97 {
98  rcti imageInput;
99 
100  NodeOperation *operation = getInputOperation(0);
101  imageInput.xmax = operation->getWidth();
102  imageInput.xmin = 0;
103  imageInput.ymax = operation->getHeight();
104  imageInput.ymin = 0;
105  if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) {
106  return true;
107  }
108  return false;
109 }
110 
112 {
113  lockMutex();
114  if (this->m_cachedInstance == nullptr) {
116  AvgLogLum *data = new AvgLogLum();
117 
118  float *buffer = tile->getBuffer();
119 
120  float lsum = 0.0f;
121  int p = tile->getWidth() * tile->getHeight();
122  float *bc = buffer;
123  float avl, maxl = -1e10f, minl = 1e10f;
124  const float sc = 1.0f / p;
125  float Lav = 0.0f;
126  float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
127  while (p--) {
129  Lav += L;
130  add_v3_v3(cav, bc);
131  lsum += logf(MAX2(L, 0.0f) + 1e-5f);
132  maxl = (L > maxl) ? L : maxl;
133  minl = (L < minl) ? L : minl;
134  bc += 4;
135  }
136  data->lav = Lav * sc;
137  mul_v3_v3fl(data->cav, cav, sc);
138  maxl = log((double)maxl + 1e-5);
139  minl = log((double)minl + 1e-5);
140  avl = lsum * sc;
141  data->auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
142  float al = exp((double)avl);
143  data->al = (al == 0.0f) ? 0.0f : (this->m_data->key / al);
144  data->igm = (this->m_data->gamma == 0.0f) ? 1 : (1.0f / this->m_data->gamma);
145  this->m_cachedInstance = data;
146  }
147  unlockMutex();
148  return this->m_cachedInstance;
149 }
150 
151 void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
152 {
153  /* pass */
154 }
155 
156 } // namespace blender::compositor
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
#define MAX2(a, b)
_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
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define output
a MemoryBuffer contains access to the data of a chunk
const int getHeight() const
get the height of this MemoryBuffer
const int getWidth() const
get the width of this MemoryBuffer
float * getBuffer()
get the data of this MemoryBuffer
NodeOperation contains calculation logic.
virtual void * initializeTileData(rcti *)
void addInputSocket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
NodeOperation * getInputOperation(unsigned int inputSocketindex)
void read(float result[4], int x, int y, void *chunkData)
void addOutputSocket(DataType datatype)
SocketReader * getInputSocketReader(unsigned int inputSocketindex)
virtual bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
void executePixel(float output[4], int x, int y, void *data) override
void deinitializeTileData(rcti *rect, void *data) override
SocketReader * m_imageReader
Cached reference to the reader.
void executePixel(float output[4], int x, int y, void *data) override
NodeTonemap * m_data
settings of the Tonemap
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override
void * initializeTileData(rcti *rect) override
AvgLogLum * m_cachedInstance
temporarily cache of the execution storage
@ None
The bottom left of the input image is the bottom left of the working area of the node,...
#define logf(x)
#define expf(x)
#define powf(x, y)
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
#define L
INLINE Rall1d< T, V, S > log(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:303
INLINE Rall1d< T, V, S > exp(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:295
struct blender::compositor::AvgLogLum AvgLogLum
temporarily storage during execution of Tone-map
temporarily storage during execution of Tone-map
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