Disabled external gits
This commit is contained in:
718
cs440-acg/ext/openexr/OpenEXR_Viewers/exrdisplay/ImageView.cpp
Normal file
718
cs440-acg/ext/openexr/OpenEXR_Viewers/exrdisplay/ImageView.cpp
Normal file
@@ -0,0 +1,718 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
|
||||
// Digital Ltd. LLC
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Industrial Light & Magic nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class ImageView
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "ImageView.h"
|
||||
|
||||
#include <ImathMath.h>
|
||||
#include <ImathFun.h>
|
||||
#include <ImathLimits.h>
|
||||
#include <halfFunction.h>
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined PLATFORM_WINDOWS || defined _WIN32
|
||||
#include <windows.h>
|
||||
#include <FL/Fl.H>
|
||||
#include <GL/gl.h>
|
||||
#elif defined __APPLE__
|
||||
#include <FL/Fl.H>
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <FL/Fl.H>
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
using std::min;
|
||||
using std::max;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::cerr;
|
||||
using namespace IMATH;
|
||||
|
||||
ImageView::ImageView (int x, int y,
|
||||
int w, int h,
|
||||
const char label[],
|
||||
const IMF::Rgba pixels[],
|
||||
float* dataZ[],
|
||||
unsigned int sampleCount[],
|
||||
int zsize,
|
||||
int dw, int dh,
|
||||
int dx, int dy,
|
||||
Fl_Box *rgbaBox,
|
||||
float farPlane,
|
||||
float gamma,
|
||||
float exposure,
|
||||
float defog,
|
||||
float kneeLow,
|
||||
float kneeHigh)
|
||||
:
|
||||
Fl_Gl_Window (x, y, w, h, label),
|
||||
_gamma (gamma),
|
||||
_exposure (exposure),
|
||||
_defog (defog),
|
||||
_kneeLow (kneeLow),
|
||||
_kneeHigh (kneeHigh),
|
||||
_rawPixels (pixels),
|
||||
_dataZ (dataZ),
|
||||
_sampleCount (sampleCount),
|
||||
_fogR (0),
|
||||
_fogG (0),
|
||||
_fogB (0),
|
||||
_farPlane (farPlane),
|
||||
_dw (dw),
|
||||
_dh (dh),
|
||||
_dx (dx),
|
||||
_dy (dy),
|
||||
_zsize (zsize),
|
||||
_rgbaBox (rgbaBox),
|
||||
_screenPixels (dw * dh * 3)
|
||||
{
|
||||
computeFogColor();
|
||||
updateScreenPixels();
|
||||
|
||||
//
|
||||
// initialize z value chart
|
||||
//
|
||||
_chartwin = new Fl_Window (600, 300);
|
||||
_chartwin->label("Deep Pixel Display");
|
||||
|
||||
_chart = new Fl_Chart (20, 20,
|
||||
_chartwin->w()-40,
|
||||
_chartwin->h()-40,
|
||||
"Sample #");
|
||||
_chartMax = new Fl_Chart (20, 20,
|
||||
_chartwin->w()-40,
|
||||
_chartwin->h()-40,
|
||||
"");
|
||||
_chartMin = new Fl_Chart (20, 20,
|
||||
_chartwin->w()-40,
|
||||
_chartwin->h()-40,
|
||||
"");
|
||||
|
||||
findZbound();
|
||||
|
||||
//
|
||||
// initialize Deep 3d window
|
||||
//
|
||||
_gl3d = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ImageView::setExposure (float exposure)
|
||||
{
|
||||
_exposure = exposure;
|
||||
updateScreenPixels();
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageView::setDefog (float defog)
|
||||
{
|
||||
_defog = defog;
|
||||
updateScreenPixels();
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageView::setKneeLow (float kneeLow)
|
||||
{
|
||||
_kneeLow = kneeLow;
|
||||
updateScreenPixels();
|
||||
redraw();
|
||||
}
|
||||
|
||||
void
|
||||
ImageView::findZbound()
|
||||
{
|
||||
//
|
||||
// find zmax and zmin values of deep data to set bound
|
||||
//
|
||||
float zmax = limits<float>::min();
|
||||
float zmin = limits<float>::max();
|
||||
_maxCount = 0;
|
||||
|
||||
for (int k = 0; k < _zsize; k++)
|
||||
{
|
||||
float* z = _dataZ[k];
|
||||
unsigned int count = _sampleCount[k];
|
||||
|
||||
if (_maxCount < count)
|
||||
_maxCount = count;
|
||||
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
double val = double(z[i]);
|
||||
if (val > zmax && val < _farPlane)
|
||||
zmax = val;
|
||||
if (val < zmin)
|
||||
zmin = val;
|
||||
}
|
||||
}
|
||||
|
||||
if ( zmax > zmin)
|
||||
{
|
||||
cout << "z max: "<< zmax << ", z min: " << zmin << endl;
|
||||
_chart->bounds (zmin, zmax);
|
||||
}
|
||||
|
||||
_zmax = zmax;
|
||||
_zmin = zmin;
|
||||
}
|
||||
|
||||
void
|
||||
ImageView::setPixels(const IMF::Rgba pixels[/* w*h */],
|
||||
float* dataZ[/* w*h */],
|
||||
unsigned int sampleCount[/* w*h */],
|
||||
int zsize,
|
||||
int dw, int dh, int dx, int dy)
|
||||
{
|
||||
//
|
||||
// update data of imageview
|
||||
//
|
||||
_rawPixels = pixels;
|
||||
_dw = dw;
|
||||
_dh = dh;
|
||||
_dx = dx;
|
||||
_dy = dy;
|
||||
_dataZ = dataZ;
|
||||
_sampleCount = sampleCount;
|
||||
_zsize = zsize;
|
||||
|
||||
_screenPixels.resizeErase(dw*dh*3);
|
||||
|
||||
findZbound();
|
||||
|
||||
//
|
||||
// update Deep 3d window
|
||||
//
|
||||
GlWindow* temp;
|
||||
temp = _gl3d;
|
||||
_gl3d = NULL;
|
||||
|
||||
if (_gl3d != NULL){
|
||||
delete temp;
|
||||
}
|
||||
|
||||
updateScreenPixels();
|
||||
redraw();
|
||||
}
|
||||
|
||||
void
|
||||
ImageView::clearDataDisplay()
|
||||
{
|
||||
_chart->clear();
|
||||
|
||||
if (_gl3d != NULL)
|
||||
_gl3d->hide();
|
||||
}
|
||||
|
||||
void
|
||||
ImageView::setKneeHigh (float kneeHigh)
|
||||
{
|
||||
_kneeHigh = kneeHigh;
|
||||
updateScreenPixels();
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageView::draw()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
glLoadIdentity();
|
||||
glViewport (0, 0, w(), h());
|
||||
glOrtho(0, w(), h(), 0, -1, 1);
|
||||
}
|
||||
|
||||
glClearColor (0.3, 0.3, 0.3, 1.0);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (_dx + _dw <= 0 || _dx >= w())
|
||||
return;
|
||||
|
||||
for (int y = 0; y < _dh; ++y)
|
||||
{
|
||||
if (y + _dy < 0 || y + _dy >= h())
|
||||
continue;
|
||||
|
||||
glRasterPos2i (max (0, _dx), y + _dy + 1);
|
||||
|
||||
glDrawPixels (_dw + min (0, _dx), // width
|
||||
1, // height
|
||||
GL_RGB, // format
|
||||
GL_UNSIGNED_BYTE, // type
|
||||
_screenPixels + // pixels
|
||||
static_cast <ptrdiff_t> ((y * _dw - min (0, _dx)) * 3));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageView::computeFogColor ()
|
||||
{
|
||||
_fogR = 0;
|
||||
_fogG = 0;
|
||||
_fogB = 0;
|
||||
|
||||
for (int j = 0; j < _dw * _dh; ++j)
|
||||
{
|
||||
const IMF::Rgba &rp = _rawPixels[j];
|
||||
|
||||
if (rp.r.isFinite())
|
||||
_fogR += rp.r;
|
||||
|
||||
if (rp.g.isFinite())
|
||||
_fogG += rp.g;
|
||||
|
||||
if (rp.b.isFinite())
|
||||
_fogB += rp.b;
|
||||
}
|
||||
|
||||
_fogR /= _dw * _dh;
|
||||
_fogG /= _dw * _dh;
|
||||
_fogB /= _dw * _dh;
|
||||
}
|
||||
|
||||
void
|
||||
ImageView::drawChart (int x, int y, bool initChart)
|
||||
{
|
||||
if (x >= 0 && x < w() && y >= 0 && y < h())
|
||||
{
|
||||
int px = x - _dx;
|
||||
int py = y - _dy;
|
||||
|
||||
if (px >= 0 && px < _dw && py >= 0 && py < _dh)
|
||||
{
|
||||
float* z = _dataZ[py * _dw + px];
|
||||
unsigned int count = _sampleCount[py * _dw + px];
|
||||
|
||||
cout << "\nsample Count: " << count << endl;
|
||||
cout << "x: " << px << ", y: " << py << endl;
|
||||
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
printf ("pixel Z value %d: %.3f\n", i, float(z[i]));
|
||||
}
|
||||
|
||||
const IMF::Rgba &p = _rawPixels[py * _dw + px];
|
||||
|
||||
cout << "R = " << p.r << ", G = " << p.g << ","
|
||||
" B = " << p.b <<endl;
|
||||
|
||||
//
|
||||
// draw the chart
|
||||
//
|
||||
drawChartRef();
|
||||
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
double val = double(z[i]);
|
||||
if (val < _farPlane)
|
||||
{
|
||||
static char val_str[20];
|
||||
sprintf (val_str, "%.3lf", val);
|
||||
_chart->add (val, val_str, FL_BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
redraw();
|
||||
|
||||
if (initChart)
|
||||
{
|
||||
_chartwin->resizable (_chartwin);
|
||||
_chartwin->set_non_modal(); // make chart on top
|
||||
|
||||
if (!_chartwin->shown())
|
||||
_chartwin->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageView::drawChartRef ()
|
||||
{
|
||||
_chart->clear();
|
||||
_chart->bounds(_zmin, _zmax);
|
||||
|
||||
_chart->type (FL_LINE_CHART);
|
||||
_chart->label("Sample #");
|
||||
|
||||
_chartMax->clear();
|
||||
_chartMax->type (FL_SPIKE_CHART);
|
||||
static char val_str[20];
|
||||
sprintf (val_str, "Zmax : %.3lf", _zmax);
|
||||
_chartMax->label(val_str);
|
||||
_chartMax->align(FL_ALIGN_TOP_LEFT);
|
||||
_chartMax->box(FL_NO_BOX);
|
||||
|
||||
_chartMin->clear();
|
||||
_chartMin->type (FL_SPIKE_CHART);
|
||||
static char val_str1[20];
|
||||
sprintf (val_str1, "Zmin : %.3lf", _zmin);
|
||||
_chartMin->label(val_str1);
|
||||
_chartMin->align(FL_ALIGN_BOTTOM_LEFT);
|
||||
_chartMin->box(FL_NO_BOX);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ImageView::handle (int event)
|
||||
{
|
||||
|
||||
if (event == FL_PUSH)
|
||||
{
|
||||
// We want to get the other associated events for this widget so
|
||||
// return a non-zero value here.
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (event == FL_MOVE)
|
||||
{
|
||||
//
|
||||
// Print the red, green and blue values of
|
||||
// the pixel at the current cursor location.
|
||||
//
|
||||
|
||||
int x = Fl::event_x();
|
||||
int y = Fl::event_y();
|
||||
|
||||
if (x >= 0 && x < w() && y >= 0 && y < h())
|
||||
{
|
||||
int px = x - _dx;
|
||||
int py = y - _dy;
|
||||
|
||||
if (px >= 0 && px < _dw && py >= 0 && py < _dh)
|
||||
{
|
||||
const IMF::Rgba &p = _rawPixels[py * _dw + px];
|
||||
|
||||
sprintf (_rgbaBoxLabel,
|
||||
"r = %.3g g = %.3g b = %.3g",
|
||||
float (p.r), float (p.g), float (p.b));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (_rgbaBoxLabel, " ");
|
||||
}
|
||||
|
||||
_rgbaBox->label (_rgbaBoxLabel);
|
||||
|
||||
|
||||
if (_chartwin->shown() && _zsize > 0)
|
||||
{
|
||||
int x = Fl::event_x();
|
||||
int y = Fl::event_y();
|
||||
drawChart (x, y, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event == FL_RELEASE && Fl::event_button() == FL_LEFT_MOUSE)
|
||||
{
|
||||
//
|
||||
// Open a sample chart and print the z values of
|
||||
// the pixel at the current cursor location
|
||||
//
|
||||
|
||||
if(_zsize > 0)
|
||||
{
|
||||
int x = Fl::event_x();
|
||||
int y = Fl::event_y();
|
||||
|
||||
drawChart (x, y, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (event == FL_RELEASE && Fl::event_button() == FL_RIGHT_MOUSE)
|
||||
{
|
||||
if(_zsize > 0)
|
||||
{
|
||||
if (_gl3d == NULL)
|
||||
{
|
||||
//
|
||||
// initialize Deep 3d display
|
||||
//
|
||||
|
||||
_gl3d = new GlWindow(10, 10, 500, 500,
|
||||
"3D View", _rawPixels,
|
||||
_dataZ, _sampleCount,
|
||||
_dw, _dh, _zmax, _zmin,
|
||||
_farPlane);
|
||||
|
||||
_gl3d->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
_gl3d->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Fl_Gl_Window::handle (event);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
//
|
||||
// Conversion from raw pixel data to data for the OpenGL frame buffer:
|
||||
//
|
||||
// 1) Compensate for fogging by subtracting defog
|
||||
// from the raw pixel values.
|
||||
//
|
||||
// 2) Multiply the defogged pixel values by
|
||||
// 2^(exposure + 2.47393).
|
||||
//
|
||||
// 3) Values that are now 1.0 are called "middle gray".
|
||||
// If defog and exposure are both set to 0.0, then
|
||||
// middle gray corresponds to a raw pixel value of 0.18.
|
||||
// In step 6, middle gray values will be mapped to an
|
||||
// intensity 3.5 f-stops below the display's maximum
|
||||
// intensity.
|
||||
//
|
||||
// 4) Apply a knee function. The knee function has two
|
||||
// parameters, kneeLow and kneeHigh. Pixel values
|
||||
// below 2^kneeLow are not changed by the knee
|
||||
// function. Pixel values above kneeLow are lowered
|
||||
// according to a logarithmic curve, such that the
|
||||
// value 2^kneeHigh is mapped to 2^3.5. (In step 6,
|
||||
// this value will be mapped to the the display's
|
||||
// maximum intensity.)
|
||||
//
|
||||
// 5) Gamma-correct the pixel values, according to the
|
||||
// screen's gamma. (We assume that the gamma curve
|
||||
// is a simple power function.)
|
||||
//
|
||||
// 6) Scale the values such that middle gray pixels are
|
||||
// mapped to a frame buffer value that is 3.5 f-stops
|
||||
// below the display's maximum intensity. (84.65 if
|
||||
// the screen's gamma is 2.2)
|
||||
//
|
||||
// 7) Clamp the values to [0, 255].
|
||||
//
|
||||
|
||||
|
||||
float
|
||||
knee (double x, double f)
|
||||
{
|
||||
return float (IMATH::Math<double>::log (x * f + 1) / f);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
findKneeF (float x, float y)
|
||||
{
|
||||
float f0 = 0;
|
||||
float f1 = 1;
|
||||
|
||||
while (knee (x, f1) > y)
|
||||
{
|
||||
f0 = f1;
|
||||
f1 = f1 * 2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 30; ++i)
|
||||
{
|
||||
float f2 = (f0 + f1) / 2;
|
||||
float y2 = knee (x, f2);
|
||||
|
||||
if (y2 < y)
|
||||
f1 = f2;
|
||||
else
|
||||
f0 = f2;
|
||||
}
|
||||
|
||||
return (f0 + f1) / 2;
|
||||
}
|
||||
|
||||
|
||||
struct Gamma
|
||||
{
|
||||
float g, m, d, kl, f, s;
|
||||
|
||||
Gamma (float gamma,
|
||||
float exposure,
|
||||
float defog,
|
||||
float kneeLow,
|
||||
float kneeHigh);
|
||||
|
||||
float operator () (half h);
|
||||
};
|
||||
|
||||
|
||||
Gamma::Gamma
|
||||
(float gamma,
|
||||
float exposure,
|
||||
float defog,
|
||||
float kneeLow,
|
||||
float kneeHigh)
|
||||
:
|
||||
g (gamma),
|
||||
m (IMATH::Math<float>::pow (2, exposure + 2.47393)),
|
||||
d (defog),
|
||||
kl (IMATH::Math<float>::pow (2, kneeLow)),
|
||||
f (findKneeF (IMATH::Math<float>::pow (2, kneeHigh) - kl,
|
||||
IMATH::Math<float>::pow (2, 3.5) - kl)),
|
||||
s (255.0 * IMATH::Math<float>::pow (2, -3.5 * g))
|
||||
{}
|
||||
|
||||
|
||||
float
|
||||
Gamma::operator () (half h)
|
||||
{
|
||||
//
|
||||
// Defog
|
||||
//
|
||||
|
||||
float x = max (0.f, (h - d));
|
||||
|
||||
//
|
||||
// Exposure
|
||||
//
|
||||
|
||||
x *= m;
|
||||
|
||||
//
|
||||
// Knee
|
||||
//
|
||||
|
||||
if (x > kl)
|
||||
x = kl + knee (x - kl, f);
|
||||
|
||||
//
|
||||
// Gamma
|
||||
//
|
||||
|
||||
x = IMATH::Math<float>::pow (x, g);
|
||||
|
||||
//
|
||||
// Scale and clamp
|
||||
//
|
||||
|
||||
return clamp (x * s, 0.f, 255.f);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Dithering: Reducing the raw 16-bit pixel data to 8 bits for the
|
||||
// OpenGL frame buffer can sometimes lead to contouring in smooth
|
||||
// color ramps. Dithering with a simple Bayer pattern eliminates
|
||||
// visible contouring.
|
||||
//
|
||||
|
||||
unsigned char
|
||||
dither (float v, int x, int y)
|
||||
{
|
||||
static const float d[4][4] =
|
||||
{
|
||||
{0.f / 16, 8.f / 16, 2.f / 16, 10.f / 16},
|
||||
{12.f / 16, 4.f / 16, 14.f / 16, 6.f / 16},
|
||||
{3.f / 16, 11.f / 16, 1.f / 16, 9.f / 16},
|
||||
{15.f / 16, 7.f / 16, 13.f / 16, 5.f / 16}
|
||||
};
|
||||
|
||||
return (unsigned char) (v + d[y & 3][x & 3]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
float
|
||||
ImageView::findKnee (float x, float y)
|
||||
{
|
||||
return findKneeF (x, y);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageView::updateScreenPixels ()
|
||||
{
|
||||
halfFunction<float>
|
||||
rGamma (Gamma (_gamma,
|
||||
_exposure,
|
||||
_defog * _fogR,
|
||||
_kneeLow,
|
||||
_kneeHigh),
|
||||
-HALF_MAX, HALF_MAX,
|
||||
0.f, 255.f, 0.f, 0.f);
|
||||
|
||||
halfFunction<float>
|
||||
gGamma (Gamma (_gamma,
|
||||
_exposure,
|
||||
_defog * _fogG,
|
||||
_kneeLow,
|
||||
_kneeHigh),
|
||||
-HALF_MAX, HALF_MAX,
|
||||
0.f, 255.f, 0.f, 0.f);
|
||||
|
||||
halfFunction<float>
|
||||
bGamma (Gamma (_gamma,
|
||||
_exposure,
|
||||
_defog * _fogB,
|
||||
_kneeLow,
|
||||
_kneeHigh),
|
||||
-HALF_MAX, HALF_MAX,
|
||||
0.f, 255.f, 0.f, 0.f);
|
||||
|
||||
|
||||
for (int y = 0; y < _dh; ++y)
|
||||
{
|
||||
int i = y * _dw;
|
||||
|
||||
for (int x = 0; x < _dw; ++x)
|
||||
{
|
||||
int j = i + x;
|
||||
const IMF::Rgba &rp = _rawPixels[j];
|
||||
unsigned char *sp = _screenPixels + j * 3;
|
||||
sp[0] = dither (rGamma (rp.r), x, y);
|
||||
sp[1] = dither (gGamma (rp.g), x, y);
|
||||
sp[2] = dither (bGamma (rp.b), x, y);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user