~ubuntu-branches/ubuntu/saucy/openexr/saucy

« back to all changes in this revision

Viewing changes to exrdisplay/ImageView.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adeodato Simó
  • Date: 2008-03-24 23:00:21 UTC
  • mfrom: (3.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20080324230021-gnofz9mnvcj1xlv3
Tags: 1.6.1-3
Disable (hopefully temporarily) the test suite on arm and ia64.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
///////////////////////////////////////////////////////////////////////////
2
 
//
3
 
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
4
 
// Digital Ltd. LLC
5
 
// 
6
 
// All rights reserved.
7
 
// 
8
 
// Redistribution and use in source and binary forms, with or without
9
 
// modification, are permitted provided that the following conditions are
10
 
// met:
11
 
// *       Redistributions of source code must retain the above copyright
12
 
// notice, this list of conditions and the following disclaimer.
13
 
// *       Redistributions in binary form must reproduce the above
14
 
// copyright notice, this list of conditions and the following disclaimer
15
 
// in the documentation and/or other materials provided with the
16
 
// distribution.
17
 
// *       Neither the name of Industrial Light & Magic nor the names of
18
 
// its contributors may be used to endorse or promote products derived
19
 
// from this software without specific prior written permission. 
20
 
// 
21
 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
 
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
 
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 
//
33
 
///////////////////////////////////////////////////////////////////////////
34
 
 
35
 
 
36
 
 
37
 
//----------------------------------------------------------------------------
38
 
//
39
 
//      class ImageView
40
 
//
41
 
//----------------------------------------------------------------------------
42
 
 
43
 
#include <ImageView.h>
44
 
#include <ImathMath.h>
45
 
#include <ImathFun.h>
46
 
#include <halfFunction.h>
47
 
#include <algorithm>
48
 
 
49
 
#if defined PLATFORM_WINDOWS
50
 
#ifdef WIN32
51
 
#ifndef WIN32_LEAN_AND_MEAN
52
 
#define WIN32_LEAN_AND_MEAN
53
 
#endif
54
 
#endif
55
 
#include <windows.h>
56
 
#include <GL/gl.h>
57
 
#elif defined PLATFORM_DARWIN_PPC
58
 
#include <OpenGL/gl.h>
59
 
#else
60
 
#include <GL/gl.h>
61
 
#endif
62
 
 
63
 
using std::min;
64
 
using std::max;
65
 
using Imath::clamp;
66
 
 
67
 
 
68
 
ImageView::ImageView (int x, int y,
69
 
                      int w, int h,
70
 
                      const char label[],
71
 
                      const Imf::Rgba pixels[],
72
 
                      int dw, int dh,
73
 
                      int dx, int dy,
74
 
                      float exposure,
75
 
                      float defog,
76
 
                      float kneeLow,
77
 
                      float kneeHigh)
78
 
:
79
 
    Fl_Gl_Window (x, y, w, h, label),
80
 
    _exposure (exposure),
81
 
    _defog (defog),
82
 
    _kneeLow (kneeLow),
83
 
    _kneeHigh (kneeHigh),
84
 
    _rawPixels (pixels),
85
 
    _fogR (0),
86
 
    _fogG (0),
87
 
    _fogB (0),
88
 
    _dw (dw),
89
 
    _dh (dh),
90
 
    _dx (dx),
91
 
    _dy (dy),
92
 
    _screenPixels (dw * dh * 3)
93
 
{
94
 
    computeFogColor();
95
 
    updateScreenPixels();
96
 
}
97
 
 
98
 
 
99
 
void
100
 
ImageView::setExposure (float exposure)
101
 
{
102
 
    _exposure = exposure;
103
 
    updateScreenPixels();
104
 
    redraw();
105
 
}
106
 
 
107
 
 
108
 
void
109
 
ImageView::setDefog (float defog)
110
 
{
111
 
    _defog = defog;
112
 
    updateScreenPixels();
113
 
    redraw();
114
 
}
115
 
 
116
 
 
117
 
void
118
 
ImageView::setKneeLow (float kneeLow)
119
 
{
120
 
    _kneeLow = kneeLow;
121
 
    updateScreenPixels();
122
 
    redraw();
123
 
}
124
 
 
125
 
 
126
 
void
127
 
ImageView::setKneeHigh (float kneeHigh)
128
 
{
129
 
    _kneeHigh = kneeHigh;
130
 
    updateScreenPixels();
131
 
    redraw();
132
 
}
133
 
 
134
 
 
135
 
void
136
 
ImageView::draw()
137
 
{
138
 
    if (!valid())
139
 
    {
140
 
        glLoadIdentity();
141
 
        glViewport (0, 0, w(), h());
142
 
        glOrtho(0, w(), h(), 0, -1, 1);
143
 
    }
144
 
 
145
 
    glClearColor (0.3, 0.3, 0.3, 1.0);
146
 
    glClear (GL_COLOR_BUFFER_BIT);
147
 
 
148
 
    if (_dx + _dw <= 0 || _dx >= w())
149
 
        return;
150
 
 
151
 
    for (int y = 0; y < _dh; ++y)
152
 
    {
153
 
        if (y + _dy < 0 || y + _dy >= h())
154
 
            continue;
155
 
 
156
 
        glRasterPos2i (max (0, _dx), y + _dy + 1);
157
 
 
158
 
        glDrawPixels (_dw + min (0, _dx),                            // width
159
 
                      1,                                             // height
160
 
                      GL_RGB,                                        // format
161
 
                      GL_UNSIGNED_BYTE,                              // type
162
 
                      _screenPixels +                                // pixels
163
 
                        static_cast <ptrdiff_t> ((y * _dw - min (0, _dx)) * 3));
164
 
    }
165
 
}
166
 
 
167
 
 
168
 
void
169
 
ImageView::computeFogColor ()
170
 
{
171
 
    _fogR = 0;
172
 
    _fogG = 0;
173
 
    _fogB = 0;
174
 
 
175
 
    for (int j = 0; j < _dw * _dh; ++j)
176
 
    {
177
 
        const Imf::Rgba &rp = _rawPixels[j];
178
 
 
179
 
        if (rp.r.isFinite())
180
 
            _fogR += rp.r;
181
 
 
182
 
        if (rp.g.isFinite())
183
 
            _fogG += rp.g;
184
 
 
185
 
        if (rp.b.isFinite())
186
 
            _fogB += rp.b;
187
 
    }
188
 
 
189
 
    _fogR /= _dw * _dh;
190
 
    _fogG /= _dw * _dh;
191
 
    _fogB /= _dw * _dh;
192
 
}
193
 
 
194
 
 
195
 
namespace {
196
 
 
197
 
//
198
 
// Conversion from raw pixel data to data for the OpenGL frame buffer:
199
 
//
200
 
//  1) Compensate for fogging by subtracting defog
201
 
//     from the raw pixel values.
202
 
//
203
 
//  2) Multiply the defogged pixel values by
204
 
//     2^(exposure + 2.47393).
205
 
//
206
 
//  3) Values, which are now 1.0, are called "middle gray".
207
 
//     If defog and exposure are both set to 0.0, then
208
 
//     middle gray corresponds to a raw pixel value of 0.18.
209
 
//     In step 6, middle gray values will be mapped to an
210
 
//     intensity 3.5 f-stops below the display's maximum
211
 
//     intensity.
212
 
//
213
 
//  4) Apply a knee function.  The knee function has two
214
 
//     parameters, kneeLow and kneeHigh.  Pixel values
215
 
//     below 2^kneeLow are not changed by the knee
216
 
//     function.  Pixel values above kneeLow are lowered
217
 
//     according to a logarithmic curve, such that the
218
 
//     value 2^kneeHigh is mapped to 2^3.5 (in step 6,
219
 
//     this value will be mapped to the the display's
220
 
//     maximum intensity).
221
 
//
222
 
//  5) Gamma-correct the pixel values, assuming that the
223
 
//     screen's gamma is 2.2 (or 1 / 0.4545).
224
 
//
225
 
//  6) Scale the values such that pixels middle gray
226
 
//     pixels are mapped to 84.66 (or 3.5 f-stops below
227
 
//     the display's maximum intensity).
228
 
//
229
 
//  7) Clamp the values to [0, 255].
230
 
//
231
 
 
232
 
 
233
 
float
234
 
knee (double x, double f)
235
 
{
236
 
    return float (Imath::Math<double>::log (x * f + 1) / f);
237
 
}
238
 
 
239
 
 
240
 
float
241
 
findKneeF (float x, float y)
242
 
{
243
 
    float f0 = 0;
244
 
    float f1 = 1;
245
 
 
246
 
    while (knee (x, f1) > y)
247
 
    {
248
 
        f0 = f1;
249
 
        f1 = f1 * 2;
250
 
    }
251
 
 
252
 
    for (int i = 0; i < 30; ++i)
253
 
    {
254
 
        float f2 = (f0 + f1) / 2;
255
 
        float y2 = knee (x, f2);
256
 
 
257
 
        if (y2 < y)
258
 
            f1 = f2;
259
 
        else
260
 
            f0 = f2;
261
 
    }
262
 
 
263
 
    return (f0 + f1) / 2;
264
 
}
265
 
 
266
 
 
267
 
struct Gamma
268
 
{
269
 
    float m, d, kl, f;
270
 
 
271
 
    Gamma (float exposure, float defog, float kneeLow, float kneeHigh);
272
 
    float operator () (half h);
273
 
};
274
 
 
275
 
 
276
 
Gamma::Gamma (float exposure, float defog, float kneeLow, float kneeHigh):
277
 
    m (Imath::Math<float>::pow (2, exposure + 2.47393)),
278
 
    d (defog),
279
 
    kl (Imath::Math<float>::pow (2, kneeLow)),
280
 
    f (findKneeF (Imath::Math<float>::pow (2, kneeHigh) - kl, 
281
 
                  Imath::Math<float>::pow (2, 3.5) - kl))
282
 
{}
283
 
 
284
 
 
285
 
float
286
 
Gamma::operator () (half h)
287
 
{
288
 
    //
289
 
    // Defog
290
 
    //
291
 
 
292
 
    float x = max (0.f, (h - d));
293
 
 
294
 
    //
295
 
    // Exposure
296
 
    //
297
 
 
298
 
    x *= m;
299
 
 
300
 
    //
301
 
    // Knee
302
 
    //
303
 
 
304
 
    if (x > kl)
305
 
        x = kl + knee (x - kl, f);
306
 
 
307
 
    //
308
 
    // Gamma
309
 
    //
310
 
 
311
 
    x = Imath::Math<float>::pow (x, 0.4545f);
312
 
 
313
 
    //
314
 
    // Scale and clamp
315
 
    //
316
 
 
317
 
    return clamp (x * 84.66f, 0.f, 255.f);
318
 
}
319
 
 
320
 
 
321
 
//
322
 
//  Dithering: Reducing the raw 16-bit pixel data to 8 bits for the
323
 
//  OpenGL frame buffer can sometimes lead to contouring in smooth
324
 
//  color ramps.  Dithering with a simple Bayer pattern eliminates
325
 
//  visible contouring.
326
 
//
327
 
 
328
 
unsigned char
329
 
dither (float v, int x, int y)
330
 
{
331
 
    static const float d[4][4] =
332
 
    {
333
 
         0.f / 16,  8.f / 16,  2.f / 16, 10.f / 16,
334
 
        12.f / 16,  4.f / 16, 14.f / 16,  6.f / 16,
335
 
         3.f / 16, 11.f / 16,  1.f / 16,  9.f / 16,
336
 
        15.f / 16,  7.f / 16, 13.f / 16,  5.f / 16,
337
 
    };
338
 
 
339
 
    return (unsigned char) (v + d[y & 3][x & 3]);
340
 
}
341
 
 
342
 
} // namespace
343
 
 
344
 
 
345
 
void
346
 
ImageView::updateScreenPixels ()
347
 
{
348
 
    halfFunction<float>
349
 
        rGamma (Gamma (_exposure,
350
 
                       _defog * _fogR,
351
 
                       _kneeLow,
352
 
                       _kneeHigh),
353
 
                -HALF_MAX, HALF_MAX);
354
 
 
355
 
    halfFunction<float>
356
 
        gGamma (Gamma (_exposure,
357
 
                       _defog * _fogG,
358
 
                       _kneeLow,
359
 
                       _kneeHigh),
360
 
                -HALF_MAX, HALF_MAX);
361
 
 
362
 
    halfFunction<float>
363
 
        bGamma (Gamma (_exposure,
364
 
                       _defog * _fogB,
365
 
                       _kneeLow,
366
 
                       _kneeHigh),
367
 
                -HALF_MAX, HALF_MAX);
368
 
 
369
 
    for (int y = 0; y < _dh; ++y)
370
 
    {
371
 
        int i = y * _dw;
372
 
 
373
 
        for (int x = 0; x < _dw; ++x)
374
 
        {
375
 
            int j = i + x;
376
 
            const Imf::Rgba &rp = _rawPixels[j];
377
 
            unsigned char *sp = _screenPixels + j * 3;
378
 
 
379
 
            sp[0] = dither (rGamma (rp.r), x, y);
380
 
            sp[1] = dither (gGamma (rp.g), x, y);
381
 
            sp[2] = dither (bGamma (rp.b), x, y);
382
 
        }
383
 
    }
384
 
}