3 * ***** BEGIN GPL LICENSE BLOCK *****
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * The Original Code is Copyright (C) 2006 Blender Foundation.
20 * All rights reserved.
22 * The Original Code is: all of this file.
24 * Contributor(s): Alfredo de Greef (eeshlo)
26 * ***** END GPL LICENSE BLOCK *****
29 #include "../CMP_util.h"
31 static bNodeSocketType cmp_node_tonemap_in
[]= {
32 { SOCK_RGBA
, 1, "Image", 0.8f
, 0.8f
, 0.8f
, 1.0f
, 0.0f
, 1.0f
},
35 static bNodeSocketType cmp_node_tonemap_out
[]= {
36 { SOCK_RGBA
, 0, "Image", 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 1.0f
},
41 static float avgLogLum(CompBuf
*src
, float* auto_key
, float* Lav
, float* Cav
)
44 int p
= src
->x
*src
->y
;
45 fRGB
* bc
= (fRGB
*)src
->rect
;
46 float avl
, maxl
= -1e10f
, minl
= 1e10f
;
47 const float sc
= 1.f
/(src
->x
*src
->y
);
50 float L
= 0.212671f
*bc
[0][0] + 0.71516f
*bc
[0][1] + 0.072169f
*bc
[0][2];
53 lsum
+= logf(MAX2(L
, 0.f
) + 1e-5f
);
54 maxl
= (L
> maxl
) ? L
: maxl
;
55 minl
= (L
< minl
) ? L
: minl
;
60 maxl
= logf(maxl
+ 1e-5f
); minl
= logf(minl
+ 1e-5f
); avl
= lsum
*sc
;
61 *auto_key
= (maxl
> minl
) ? ((maxl
- avl
) / (maxl
- minl
)) : 1.f
;
66 static void tonemap(NodeTonemap
* ntm
, CompBuf
* dst
, CompBuf
* src
)
69 float dr
, dg
, db
, al
, igm
= (ntm
->gamma
==0.f
) ? 1 : (1.f
/ ntm
->gamma
);
70 float auto_key
, Lav
, Cav
[3] = {0, 0, 0};
72 al
= avgLogLum(src
, &auto_key
, &Lav
, Cav
);
73 al
= (al
== 0.f
) ? 0.f
: (ntm
->key
/ al
);
76 // Reinhard/Devlin photoreceptor
77 const float f
= expf(-ntm
->f
);
78 const float m
= (ntm
->m
> 0.f
) ? ntm
->m
: (0.3f
+ 0.7f
*powf(auto_key
, 1.4f
));
79 const float ic
= 1.f
- ntm
->c
, ia
= 1.f
- ntm
->a
;
80 if (ntm
->m
== 0.f
) printf("tonemap node, M: %g\n", m
);
81 for (y
=0; y
<src
->y
; ++y
) {
82 fRGB
* sp
= (fRGB
*)&src
->rect
[y
*src
->x
*src
->type
];
83 fRGB
* dp
= (fRGB
*)&dst
->rect
[y
*src
->x
*src
->type
];
84 for (x
=0; x
<src
->x
; ++x
) {
85 const float L
= 0.212671f
*sp
[x
][0] + 0.71516f
*sp
[x
][1] + 0.072169f
*sp
[x
][2];
86 float I_l
= sp
[x
][0] + ic
*(L
- sp
[x
][0]);
87 float I_g
= Cav
[0] + ic
*(Lav
- Cav
[0]);
88 float I_a
= I_l
+ ia
*(I_g
- I_l
);
89 dp
[x
][0] /= (dp
[x
][0] + powf(f
*I_a
, m
));
90 I_l
= sp
[x
][1] + ic
*(L
- sp
[x
][1]);
91 I_g
= Cav
[1] + ic
*(Lav
- Cav
[1]);
92 I_a
= I_l
+ ia
*(I_g
- I_l
);
93 dp
[x
][1] /= (dp
[x
][1] + powf(f
*I_a
, m
));
94 I_l
= sp
[x
][2] + ic
*(L
- sp
[x
][2]);
95 I_g
= Cav
[2] + ic
*(Lav
- Cav
[2]);
96 I_a
= I_l
+ ia
*(I_g
- I_l
);
97 dp
[x
][2] /= (dp
[x
][2] + powf(f
*I_a
, m
));
103 // Reinhard simple photographic tm (simplest, not using whitepoint var)
104 for (y
=0; y
<src
->y
; y
++) {
105 fRGB
* sp
= (fRGB
*)&src
->rect
[y
*src
->x
*src
->type
];
106 fRGB
* dp
= (fRGB
*)&dst
->rect
[y
*src
->x
*src
->type
];
107 for (x
=0; x
<src
->x
; x
++) {
108 fRGB_copy(dp
[x
], sp
[x
]);
109 fRGB_mult(dp
[x
], al
);
110 dr
= dp
[x
][0] + ntm
->offset
;
111 dg
= dp
[x
][1] + ntm
->offset
;
112 db
= dp
[x
][2] + ntm
->offset
;
113 dp
[x
][0] /= ((dr
== 0.f
) ? 1.f
: dr
);
114 dp
[x
][1] /= ((dg
== 0.f
) ? 1.f
: dg
);
115 dp
[x
][2] /= ((db
== 0.f
) ? 1.f
: db
);
117 dp
[x
][0] = powf(MAX2(dp
[x
][0], 0.f
), igm
);
118 dp
[x
][1] = powf(MAX2(dp
[x
][1], 0.f
), igm
);
119 dp
[x
][2] = powf(MAX2(dp
[x
][2], 0.f
), igm
);
126 static void node_composit_exec_tonemap(void *data
, bNode
*node
, bNodeStack
**in
, bNodeStack
**out
)
128 CompBuf
*new, *img
= in
[0]->data
;
130 if ((img
==NULL
) || (out
[0]->hasoutput
==0)) return;
132 if (img
->type
!= CB_RGBA
)
133 new = typecheck_compbuf(img
, CB_RGBA
);
135 new = dupalloc_compbuf(img
);
137 tonemap(node
->storage
, new, img
);
142 static void node_composit_init_tonemap(bNode
* node
)
144 NodeTonemap
*ntm
= MEM_callocN(sizeof(NodeTonemap
), "node tonemap data");
150 ntm
->m
= 0; // actual value is set according to input
151 // default a of 1 works well with natural HDR images, but not always so for cgi.
152 // Maybe should use 0 or at least lower initial value instead
158 bNodeType cmp_node_tonemap
= {
159 /* *next,*prev */ NULL
, NULL
,
160 /* type code */ CMP_NODE_TONEMAP
,
161 /* name */ "Tonemap",
162 /* width+range */ 150, 120, 200,
163 /* class+opts */ NODE_CLASS_OP_COLOR
, NODE_OPTIONS
,
164 /* input sock */ cmp_node_tonemap_in
,
165 /* output sock */ cmp_node_tonemap_out
,
166 /* storage */ "NodeTonemap",
167 /* execfunc */ node_composit_exec_tonemap
,
169 /* initfunc */ node_composit_init_tonemap
,
170 /* freestoragefunc */ node_free_standard_storage
,
171 /* copystoragefunc */ node_copy_standard_storage
,