1/*
2 * Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
3 *   Digital Ltd. LLC
4 * Distributed under the terms of the MIT License.
5 */
6
7#include "EXRGamma.h"
8#include "ImathFun.h"
9#include "ImathMath.h"
10
11#include <algorithm>
12
13using namespace std;
14
15
16float
17knee(double x, double f)
18{
19	return float (Imath::Math<double>::log (x * f + 1) / f);
20}
21
22
23float
24findKneeF(float x, float y)
25{
26	float f0 = 0;
27	float f1 = 1;
28
29	while (knee (x, f1) > y)
30	{
31	f0 = f1;
32	f1 = f1 * 2;
33	}
34
35	for (int i = 0; i < 30; ++i)
36	{
37	float f2 = (f0 + f1) / 2;
38	float y2 = knee (x, f2);
39
40	if (y2 < y)
41		f1 = f2;
42	else
43		f0 = f2;
44	}
45
46	return (f0 + f1) / 2;
47}
48
49
50Gamma::Gamma(float gamma,
51	float exposure,
52	float defog,
53	float kneeLow,
54	float kneeHigh)
55:
56	g (gamma),
57	m (Imath::Math<float>::pow(2, exposure + 2.47393)),
58	d (defog),
59	kl (Imath::Math<float>::pow(2, kneeLow)),
60	f (findKneeF (Imath::Math<float>::pow(2, kneeHigh) - kl,
61		Imath::Math<float>::pow(2, 3.5) - kl)),
62	s (255.0 * Imath::Math<float>::pow(2, -3.5 * g))
63{
64}
65
66
67float
68Gamma::operator() (half h)
69{
70	//
71	// Defog
72	//
73
74	float x = max (0.f, (h - d));
75
76	//
77	// Exposure
78	//
79
80	x *= m;
81
82	//
83	// Knee
84	//
85
86	if (x > kl)
87	x = kl + knee (x - kl, f);
88
89	//
90	// Gamma
91	//
92
93	x = Imath::Math<float>::pow (x, g);
94
95	//
96	// Scale and clamp
97	//
98
99	return Imath::clamp (x * s, 0.f, 255.f);
100}
101