2012-01-29 17:39:56 +00:00
|
|
|
#include "color.h"
|
|
|
|
|
2013-11-15 22:26:44 +00:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cmath>
|
2013-11-03 12:00:31 +00:00
|
|
|
#include "PackStream.h"
|
2013-11-15 22:26:44 +00:00
|
|
|
#include "Curve.h"
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2013-01-14 19:07:56 +00:00
|
|
|
/******************************** ColorProfile ********************************/
|
2013-11-11 14:42:11 +00:00
|
|
|
class ColorProfile
|
2013-01-14 19:07:56 +00:00
|
|
|
{
|
2013-11-11 14:42:11 +00:00
|
|
|
public:
|
2013-01-14 19:07:56 +00:00
|
|
|
double minvalue;
|
|
|
|
double maxvalue;
|
2013-09-18 15:10:34 +00:00
|
|
|
Color(*mapper)(Color col, double exposure);
|
2013-02-05 21:25:30 +00:00
|
|
|
double exposure;
|
2013-01-14 19:07:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ColorProfile* colorProfileCreate()
|
|
|
|
{
|
|
|
|
ColorProfile* profile;
|
|
|
|
|
2013-11-02 15:43:43 +00:00
|
|
|
profile = new ColorProfile;
|
2013-01-14 19:07:56 +00:00
|
|
|
|
2013-02-05 21:25:30 +00:00
|
|
|
colorProfileSetToneMapping(profile, TONE_MAPPING_UNCHARTED, 2.0);
|
2013-01-14 19:07:56 +00:00
|
|
|
colorProfileClear(profile);
|
|
|
|
|
|
|
|
return profile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void colorProfileDelete(ColorProfile* profile)
|
|
|
|
{
|
2013-11-02 15:43:43 +00:00
|
|
|
delete profile;
|
2013-01-14 19:07:56 +00:00
|
|
|
}
|
|
|
|
|
2013-02-05 21:25:30 +00:00
|
|
|
static inline double _uncharted2Tonemap(double x)
|
|
|
|
{
|
|
|
|
double A = 0.15;
|
|
|
|
double B = 0.50;
|
|
|
|
double C = 0.10;
|
|
|
|
double D = 0.20;
|
|
|
|
double E = 0.02;
|
|
|
|
double F = 0.30;
|
|
|
|
|
2013-09-18 15:10:34 +00:00
|
|
|
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
|
2013-02-05 21:25:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static Color _toneMappingUncharted(Color pixel, double exposure)
|
|
|
|
{
|
|
|
|
double W = 11.2;
|
|
|
|
double white_scale = 1.0 / _uncharted2Tonemap(W);
|
|
|
|
|
|
|
|
pixel.r = pow(_uncharted2Tonemap(pixel.r * exposure) * white_scale, 1.0 / 2.2);
|
|
|
|
pixel.g = pow(_uncharted2Tonemap(pixel.g * exposure) * white_scale, 1.0 / 2.2);
|
|
|
|
pixel.b = pow(_uncharted2Tonemap(pixel.b * exposure) * white_scale, 1.0 / 2.2);
|
|
|
|
|
|
|
|
return pixel;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Color _toneMappingReinhard(Color pixel, double exposure)
|
|
|
|
{
|
|
|
|
pixel.r = (pixel.r * exposure) / (1.0 + pixel.r * exposure);
|
|
|
|
pixel.g = (pixel.g * exposure) / (1.0 + pixel.g * exposure);
|
|
|
|
pixel.b = (pixel.b * exposure) / (1.0 + pixel.b * exposure);
|
|
|
|
|
|
|
|
return pixel;
|
|
|
|
}
|
|
|
|
|
2013-11-15 22:26:44 +00:00
|
|
|
static Color _toneMappingClamp(Color pixel, double)
|
2013-06-14 11:39:45 +00:00
|
|
|
{
|
|
|
|
pixel.r = pixel.r > 1.0 ? 1.0 : pixel.r;
|
|
|
|
pixel.g = pixel.g > 1.0 ? 1.0 : pixel.g;
|
|
|
|
pixel.b = pixel.b > 1.0 ? 1.0 : pixel.b;
|
|
|
|
|
|
|
|
return pixel;
|
|
|
|
}
|
|
|
|
|
2013-02-05 21:25:30 +00:00
|
|
|
void colorProfileSetToneMapping(ColorProfile* profile, ToneMappingOperator tonemapper, double exposure)
|
|
|
|
{
|
2013-06-14 11:39:45 +00:00
|
|
|
switch (tonemapper)
|
2013-02-05 21:25:30 +00:00
|
|
|
{
|
2013-09-18 15:10:34 +00:00
|
|
|
case TONE_MAPPING_REIHNARD:
|
|
|
|
profile->mapper = _toneMappingReinhard;
|
|
|
|
break;
|
|
|
|
case TONE_MAPPING_UNCHARTED:
|
|
|
|
profile->mapper = _toneMappingUncharted;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
profile->mapper = _toneMappingClamp;
|
2013-02-05 21:25:30 +00:00
|
|
|
}
|
|
|
|
profile->exposure = exposure;
|
|
|
|
}
|
|
|
|
|
2013-11-11 14:42:11 +00:00
|
|
|
void colorProfileSave(PackStream*, ColorProfile*)
|
2013-01-14 19:07:56 +00:00
|
|
|
{
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
2013-11-11 14:42:11 +00:00
|
|
|
void colorProfileLoad(PackStream*, ColorProfile*)
|
2013-01-14 19:07:56 +00:00
|
|
|
{
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
void colorProfileClear(ColorProfile* profile)
|
|
|
|
{
|
|
|
|
profile->minvalue = 0.0;
|
|
|
|
profile->maxvalue = 3.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int colorProfileCollect(ColorProfile* profile, Color pixel)
|
|
|
|
{
|
|
|
|
int changed = 0;
|
|
|
|
double value = pixel.r + pixel.g + pixel.b;
|
|
|
|
|
|
|
|
if (value < profile->minvalue)
|
|
|
|
{
|
|
|
|
profile->minvalue = value;
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
if (value > profile->maxvalue)
|
|
|
|
{
|
|
|
|
profile->maxvalue = value;
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
Color colorProfileApply(ColorProfile* profile, Color pixel)
|
|
|
|
{
|
2013-02-05 21:25:30 +00:00
|
|
|
return profile->mapper(pixel, profile->exposure);
|
2013-01-14 19:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************** ColorGradation ********************************/
|
|
|
|
struct ColorGradation
|
|
|
|
{
|
|
|
|
Curve* red;
|
|
|
|
Curve* green;
|
|
|
|
Curve* blue;
|
|
|
|
};
|
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
ColorGradation* colorGradationCreate()
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-03-08 15:10:25 +00:00
|
|
|
ColorGradation* result;
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2013-11-02 15:43:43 +00:00
|
|
|
result = new ColorGradation;
|
2013-11-15 22:26:44 +00:00
|
|
|
result->red = new Curve;
|
|
|
|
result->green = new Curve;
|
|
|
|
result->blue = new Curve;
|
2013-01-14 19:07:56 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
void colorGradationDelete(ColorGradation* gradation)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
delete gradation->red;
|
|
|
|
delete gradation->green;
|
|
|
|
delete gradation->blue;
|
2013-11-02 15:43:43 +00:00
|
|
|
delete gradation;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
void colorGradationCopy(ColorGradation* source, ColorGradation* destination)
|
2012-01-29 17:39:56 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
source->red->copy(destination->red);
|
|
|
|
source->green->copy(destination->green);
|
|
|
|
source->blue->copy(destination->blue);
|
2012-03-08 15:10:25 +00:00
|
|
|
}
|
2012-01-29 17:39:56 +00:00
|
|
|
|
2012-06-22 22:13:55 +00:00
|
|
|
void colorGradationClear(ColorGradation* gradation)
|
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->red->clear();
|
|
|
|
gradation->green->clear();
|
|
|
|
gradation->blue->clear();
|
2012-06-22 22:13:55 +00:00
|
|
|
}
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
void colorGradationSave(PackStream* stream, ColorGradation* gradation)
|
2012-03-08 15:10:25 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->red->save(stream);
|
|
|
|
gradation->green->save(stream);
|
|
|
|
gradation->blue->save(stream);
|
2012-01-29 17:39:56 +00:00
|
|
|
}
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
void colorGradationLoad(PackStream* stream, ColorGradation* gradation)
|
2012-01-29 17:39:56 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->red->load(stream);
|
|
|
|
gradation->green->load(stream);
|
|
|
|
gradation->blue->load(stream);
|
2012-03-08 15:10:25 +00:00
|
|
|
}
|
2012-01-29 17:39:56 +00:00
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
void colorGradationGetRedCurve(ColorGradation* gradation, Curve* curve)
|
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->red->copy(curve);
|
2012-01-29 17:39:56 +00:00
|
|
|
}
|
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
void colorGradationGetGreenCurve(ColorGradation* gradation, Curve* curve)
|
2012-02-21 13:41:02 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->green->copy(curve);
|
2012-02-21 13:41:02 +00:00
|
|
|
}
|
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
void colorGradationGetBlueCurve(ColorGradation* gradation, Curve* curve)
|
2012-02-21 13:41:02 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->blue->copy(curve);
|
2012-02-21 13:41:02 +00:00
|
|
|
}
|
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
void colorGradationSetRedCurve(ColorGradation* gradation, Curve* curve)
|
2012-02-21 13:41:02 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
curve->copy(gradation->red);
|
|
|
|
gradation->red->validate();
|
2012-02-21 13:41:02 +00:00
|
|
|
}
|
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
void colorGradationSetGreenCurve(ColorGradation* gradation, Curve* curve)
|
2012-02-21 13:41:02 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
curve->copy(gradation->green);
|
|
|
|
gradation->green->validate();
|
2012-02-21 13:41:02 +00:00
|
|
|
}
|
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
void colorGradationSetBlueCurve(ColorGradation* gradation, Curve* curve)
|
2012-02-21 13:41:02 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
curve->copy(gradation->blue);
|
|
|
|
gradation->blue->validate();
|
2012-02-21 13:41:02 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void colorGradationQuickAdd(ColorGradation* gradation, double value, Color* col)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-03-08 15:10:25 +00:00
|
|
|
colorGradationQuickAddRgb(gradation, value, col->r, col->g, col->b);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void colorGradationQuickAddRgb(ColorGradation* gradation, double value, double r, double g, double b)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->red->addPoint(value, r);
|
|
|
|
gradation->red->validate();
|
2012-03-08 15:10:25 +00:00
|
|
|
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->green->addPoint(value, g);
|
|
|
|
gradation->green->validate();
|
2012-03-08 15:10:25 +00:00
|
|
|
|
2013-11-15 22:26:44 +00:00
|
|
|
gradation->blue->addPoint(value, b);
|
|
|
|
gradation->blue->validate();
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
Color colorGradationGet(ColorGradation* gradation, double value)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
Color result;
|
|
|
|
|
2013-11-15 22:26:44 +00:00
|
|
|
result.r = gradation->red->getValue(value);
|
|
|
|
result.g = gradation->green->getValue(value);
|
|
|
|
result.b = gradation->blue->getValue(value);
|
2012-03-08 15:10:25 +00:00
|
|
|
result.a = 1.0;
|
2013-01-14 19:07:56 +00:00
|
|
|
|
2012-03-08 15:10:25 +00:00
|
|
|
return result;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|