/*****************************************************************************/
// Copyright 2007 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_hue_sat_map.cpp#1 $ */
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */
/*****************************************************************************/
#include "dng_hue_sat_map.h"
#include "dng_assertions.h"
#include "dng_auto_ptr.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_host.h"
/*****************************************************************************/
dng_hue_sat_map::dng_hue_sat_map ()
: fHueDivisions (0)
, fSatDivisions (0)
, fValDivisions (0)
, fHueStep (0)
, fValStep (0)
, fDeltas ()
{
}
/*****************************************************************************/
dng_hue_sat_map::dng_hue_sat_map (const dng_hue_sat_map &src)
: fHueDivisions (0)
, fSatDivisions (0)
, fValDivisions (0)
, fHueStep (0)
, fValStep (0)
, fDeltas ()
{
*this = src;
}
/*****************************************************************************/
dng_hue_sat_map &dng_hue_sat_map::operator= (const dng_hue_sat_map &rhs)
{
if (this != &rhs)
{
if (!rhs.IsValid ())
{
SetInvalid ();
}
else
{
fHueDivisions = rhs.fHueDivisions;
fSatDivisions = rhs.fSatDivisions;
fValDivisions = rhs.fValDivisions;
fHueStep = rhs.fHueStep;
fValStep = rhs.fValStep;
fDeltas = rhs.fDeltas;
}
}
return *this;
}
/*****************************************************************************/
dng_hue_sat_map::~dng_hue_sat_map ()
{
}
/*****************************************************************************/
void dng_hue_sat_map::SetDivisions (uint32 hueDivisions,
uint32 satDivisions,
uint32 valDivisions)
{
DNG_ASSERT (hueDivisions >= 1, "Must have at least 1 hue division.");
DNG_ASSERT (satDivisions >= 2, "Must have at least 2 sat divisions.");
if (valDivisions == 0)
valDivisions = 1;
if (hueDivisions == fHueDivisions &&
satDivisions == fSatDivisions &&
valDivisions == fValDivisions)
{
return;
}
fHueDivisions = hueDivisions;
fSatDivisions = satDivisions;
fValDivisions = valDivisions;
fHueStep = satDivisions;
fValStep = SafeUint32Mult(hueDivisions, fHueStep);
uint32 size = SafeUint32Mult(DeltasCount (), (uint32) sizeof (HSBModify));
fDeltas.Allocate (size);
DoZeroBytes (fDeltas.Buffer (), size);
}
/*****************************************************************************/
void dng_hue_sat_map::GetDelta (uint32 hueDiv,
uint32 satDiv,
uint32 valDiv,
HSBModify &modify) const
{
if (hueDiv >= fHueDivisions ||
satDiv >= fSatDivisions ||
valDiv >= fValDivisions ||
fDeltas.Buffer () == NULL)
{
DNG_REPORT ("Bad parameters to dng_hue_sat_map::GetDelta");
ThrowProgramError ();
}
int32 offset = valDiv * fValStep +
hueDiv * fHueStep +
satDiv;
const HSBModify *deltas = GetConstDeltas ();
modify.fHueShift = deltas [offset].fHueShift;
modify.fSatScale = deltas [offset].fSatScale;
modify.fValScale = deltas [offset].fValScale;
}
/*****************************************************************************/
void dng_hue_sat_map::SetDeltaKnownWriteable (uint32 hueDiv,
uint32 satDiv,
uint32 valDiv,
const HSBModify &modify)
{
if (hueDiv >= fHueDivisions ||
satDiv >= fSatDivisions ||
valDiv >= fValDivisions ||
fDeltas.Buffer () == NULL)
{
DNG_REPORT ("Bad parameters to dng_hue_sat_map::SetDelta");
ThrowProgramError ();
}
// Set this entry.
int32 offset = valDiv * fValStep +
hueDiv * fHueStep +
satDiv;
SafeGetDeltas () [offset] = modify;
// The zero saturation entry is required to have a value scale
// of 1.0f.
if (satDiv == 0)
{
if (modify.fValScale != 1.0f)
{
#if qDNGValidate
ReportWarning ("Value scale for zero saturation entries must be 1.0");
#endif
SafeGetDeltas () [offset] . fValScale = 1.0f;
}
}
// If we are settings the first saturation entry and we have not
// set the zero saturation entry yet, fill in the zero saturation entry
// by extrapolating first saturation entry.
if (satDiv == 1)
{
HSBModify zeroSatModify;
GetDelta (hueDiv, 0, valDiv, zeroSatModify);
if (zeroSatModify.fValScale != 1.0f)
{
zeroSatModify.fHueShift = modify.fHueShift;
zeroSatModify.fSatScale = modify.fSatScale;
zeroSatModify.fValScale = 1.0f;
SetDelta (hueDiv, 0, valDiv, zeroSatModify);
}
}
}
/*****************************************************************************/
bool dng_hue_sat_map::operator== (const dng_hue_sat_map &rhs) const
{
if (fHueDivisions != rhs.fHueDivisions ||
fSatDivisions != rhs.fSatDivisions ||
fValDivisions != rhs.fValDivisions)
return false;
if (!IsValid ())
return true;
return memcmp (GetConstDeltas (),
rhs.GetConstDeltas (),
DeltasCount () * sizeof (HSBModify)) == 0;
}
/*****************************************************************************/
dng_hue_sat_map * dng_hue_sat_map::Interpolate (const dng_hue_sat_map &map1,
const dng_hue_sat_map &map2,
real64 weight1)
{
if (weight1 >= 1.0)
{
if (!map1.IsValid ())
{
DNG_REPORT ("map1 is not valid");
ThrowProgramError ();
}
return new dng_hue_sat_map (map1);
}
if (weight1 <= 0.0)
{
if (!map2.IsValid ())
{
DNG_REPORT ("map2 is not valid");
ThrowProgramError ();
}
return new dng_hue_sat_map (map2);
}
// Both maps must be valid if we are using both.
if (!map1.IsValid () || !map2.IsValid ())
{
DNG_REPORT ("map1 or map2 is not valid");
ThrowProgramError ();
}
// Must have the same dimensions.
if (map1.fHueDivisions != map2.fHueDivisions ||
map1.fSatDivisions != map2.fSatDivisions ||
map1.fValDivisions != map2.fValDivisions)
{
DNG_REPORT ("map1 and map2 have different sizes");
ThrowProgramError ();
}
// Make table to hold interpolated results.
AutoPtr<dng_hue_sat_map> result (new dng_hue_sat_map);
result->SetDivisions (map1.fHueDivisions,
map1.fSatDivisions,
map1.fValDivisions);
// Interpolate between the tables.
real32 w1 = (real32) weight1;
real32 w2 = 1.0f - w1;
const HSBModify *data1 = map1.GetConstDeltas ();
const HSBModify *data2 = map2.GetConstDeltas ();
HSBModify *data3 = result->SafeGetDeltas ();
uint32 count = map1.DeltasCount ();
for (uint32 index = 0; index < count; index++)
{
data3->fHueShift = w1 * data1->fHueShift +
w2 * data2->fHueShift;
data3->fSatScale = w1 * data1->fSatScale +
w2 * data2->fSatScale;
data3->fValScale = w1 * data1->fValScale +
w2 * data2->fValScale;
data1++;
data2++;
data3++;
}
// Return interpolated tables.
return result.Release ();
}
/*****************************************************************************/