1/*****************************************************************************/
2// Copyright 2007 Adobe Systems Incorporated
3// All Rights Reserved.
4//
5// NOTICE:  Adobe permits you to use, modify, and distribute this file in
6// accordance with the terms of the Adobe license agreement accompanying it.
7/*****************************************************************************/
8
9/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_hue_sat_map.cpp#1 $ */
10/* $DateTime: 2012/05/30 13:28:51 $ */
11/* $Change: 832332 $ */
12/* $Author: tknoll $ */
13
14/*****************************************************************************/
15
16#include "dng_hue_sat_map.h"
17
18#include "dng_assertions.h"
19#include "dng_auto_ptr.h"
20#include "dng_bottlenecks.h"
21#include "dng_exceptions.h"
22#include "dng_host.h"
23
24/*****************************************************************************/
25
26dng_hue_sat_map::dng_hue_sat_map ()
27
28	:	fHueDivisions (0)
29	,	fSatDivisions (0)
30	,	fValDivisions (0)
31	,	fHueStep      (0)
32	,	fValStep	  (0)
33	,	fDeltas       ()
34
35	{
36
37	}
38
39/*****************************************************************************/
40
41dng_hue_sat_map::dng_hue_sat_map (const dng_hue_sat_map &src)
42
43	:	fHueDivisions (0)
44	,	fSatDivisions (0)
45	,	fValDivisions (0)
46	,	fHueStep      (0)
47	,	fValStep	  (0)
48	,	fDeltas       ()
49
50	{
51
52	*this = src;
53
54	}
55
56/*****************************************************************************/
57
58dng_hue_sat_map &dng_hue_sat_map::operator= (const dng_hue_sat_map &rhs)
59	{
60
61	if (this != &rhs)
62		{
63
64		if (!rhs.IsValid ())
65			{
66
67			SetInvalid ();
68
69			}
70
71		else
72			{
73
74			fHueDivisions = rhs.fHueDivisions;
75			fSatDivisions = rhs.fSatDivisions;
76			fValDivisions = rhs.fValDivisions;
77
78			fHueStep = rhs.fHueStep;
79			fValStep = rhs.fValStep;
80
81			fDeltas = rhs.fDeltas;
82
83			}
84
85		}
86
87	return *this;
88
89	}
90
91/*****************************************************************************/
92
93dng_hue_sat_map::~dng_hue_sat_map ()
94	{
95
96	}
97
98/*****************************************************************************/
99
100void dng_hue_sat_map::SetDivisions (uint32 hueDivisions,
101									uint32 satDivisions,
102									uint32 valDivisions)
103	{
104
105	DNG_ASSERT (hueDivisions >= 1, "Must have at least 1 hue division.");
106	DNG_ASSERT (satDivisions >= 2, "Must have at least 2 sat divisions.");
107
108	if (valDivisions == 0)
109		valDivisions = 1;
110
111	if (hueDivisions == fHueDivisions &&
112		satDivisions == fSatDivisions &&
113		valDivisions == fValDivisions)
114		{
115		return;
116		}
117
118	fHueDivisions = hueDivisions;
119	fSatDivisions = satDivisions;
120	fValDivisions = valDivisions;
121
122	fHueStep = satDivisions;
123	fValStep = SafeUint32Mult(hueDivisions, fHueStep);
124
125	uint32 size = SafeUint32Mult(DeltasCount (), (uint32) sizeof (HSBModify));
126
127	fDeltas.Allocate (size);
128
129	DoZeroBytes (fDeltas.Buffer (), size);
130
131	}
132
133/*****************************************************************************/
134
135void dng_hue_sat_map::GetDelta (uint32 hueDiv,
136								uint32 satDiv,
137								uint32 valDiv,
138								HSBModify &modify) const
139	{
140
141	if (hueDiv >= fHueDivisions ||
142		satDiv >= fSatDivisions ||
143		valDiv >= fValDivisions ||
144		fDeltas.Buffer () == NULL)
145		{
146
147		DNG_REPORT ("Bad parameters to dng_hue_sat_map::GetDelta");
148
149		ThrowProgramError ();
150
151		}
152
153	int32 offset = valDiv * fValStep +
154				   hueDiv * fHueStep +
155				   satDiv;
156
157	const HSBModify *deltas = GetConstDeltas ();
158
159	modify.fHueShift = deltas [offset].fHueShift;
160	modify.fSatScale = deltas [offset].fSatScale;
161	modify.fValScale = deltas [offset].fValScale;
162
163	}
164
165/*****************************************************************************/
166
167void dng_hue_sat_map::SetDeltaKnownWriteable (uint32 hueDiv,
168											  uint32 satDiv,
169											  uint32 valDiv,
170											  const HSBModify &modify)
171	{
172
173	if (hueDiv >= fHueDivisions ||
174		satDiv >= fSatDivisions ||
175		valDiv >= fValDivisions ||
176		fDeltas.Buffer () == NULL)
177		{
178
179		DNG_REPORT ("Bad parameters to dng_hue_sat_map::SetDelta");
180
181		ThrowProgramError ();
182
183		}
184
185	// Set this entry.
186
187	int32 offset = valDiv * fValStep +
188				   hueDiv * fHueStep +
189				   satDiv;
190
191	SafeGetDeltas () [offset] = modify;
192
193	// The zero saturation entry is required to have a value scale
194	// of 1.0f.
195
196	if (satDiv == 0)
197		{
198
199		if (modify.fValScale != 1.0f)
200			{
201
202			#if qDNGValidate
203
204			ReportWarning ("Value scale for zero saturation entries must be 1.0");
205
206			#endif
207
208			SafeGetDeltas () [offset] . fValScale = 1.0f;
209
210			}
211
212		}
213
214	// If we are settings the first saturation entry and we have not
215	// set the zero saturation entry yet, fill in the zero saturation entry
216	// by extrapolating first saturation entry.
217
218	if (satDiv == 1)
219		{
220
221		HSBModify zeroSatModify;
222
223		GetDelta (hueDiv, 0, valDiv, zeroSatModify);
224
225		if (zeroSatModify.fValScale != 1.0f)
226			{
227
228			zeroSatModify.fHueShift = modify.fHueShift;
229			zeroSatModify.fSatScale = modify.fSatScale;
230			zeroSatModify.fValScale = 1.0f;
231
232			SetDelta (hueDiv, 0, valDiv, zeroSatModify);
233
234			}
235
236		}
237
238	}
239
240/*****************************************************************************/
241
242bool dng_hue_sat_map::operator== (const dng_hue_sat_map &rhs) const
243	{
244
245	if (fHueDivisions != rhs.fHueDivisions ||
246		fSatDivisions != rhs.fSatDivisions ||
247		fValDivisions != rhs.fValDivisions)
248		return false;
249
250	if (!IsValid ())
251		return true;
252
253	return memcmp (GetConstDeltas (),
254				   rhs.GetConstDeltas (),
255				   DeltasCount () * sizeof (HSBModify)) == 0;
256
257	}
258
259/*****************************************************************************/
260
261dng_hue_sat_map * dng_hue_sat_map::Interpolate (const dng_hue_sat_map &map1,
262											    const dng_hue_sat_map &map2,
263											    real64 weight1)
264	{
265
266	if (weight1 >= 1.0)
267		{
268
269		if (!map1.IsValid ())
270			{
271
272			DNG_REPORT ("map1 is not valid");
273
274			ThrowProgramError ();
275
276			}
277
278		return new dng_hue_sat_map (map1);
279
280		}
281
282	if (weight1 <= 0.0)
283		{
284
285		if (!map2.IsValid ())
286			{
287			DNG_REPORT ("map2 is not valid");
288
289			ThrowProgramError ();
290
291			}
292
293		return new dng_hue_sat_map (map2);
294
295		}
296
297	// Both maps must be valid if we are using both.
298
299	if (!map1.IsValid () || !map2.IsValid ())
300		{
301
302		DNG_REPORT ("map1 or map2 is not valid");
303
304		ThrowProgramError ();
305
306		}
307
308	// Must have the same dimensions.
309
310	if (map1.fHueDivisions != map2.fHueDivisions ||
311		map1.fSatDivisions != map2.fSatDivisions ||
312		map1.fValDivisions != map2.fValDivisions)
313		{
314
315		DNG_REPORT ("map1 and map2 have different sizes");
316
317		ThrowProgramError ();
318
319		}
320
321	// Make table to hold interpolated results.
322
323	AutoPtr<dng_hue_sat_map> result (new dng_hue_sat_map);
324
325	result->SetDivisions (map1.fHueDivisions,
326						  map1.fSatDivisions,
327						  map1.fValDivisions);
328
329	// Interpolate between the tables.
330
331	real32 w1 = (real32) weight1;
332	real32 w2 = 1.0f - w1;
333
334	const HSBModify *data1 = map1.GetConstDeltas ();
335	const HSBModify *data2 = map2.GetConstDeltas ();
336
337	HSBModify *data3 = result->SafeGetDeltas ();
338
339	uint32 count = map1.DeltasCount ();
340
341	for (uint32 index = 0; index < count; index++)
342		{
343
344		data3->fHueShift = w1 * data1->fHueShift +
345						   w2 * data2->fHueShift;
346
347		data3->fSatScale = w1 * data1->fSatScale +
348						   w2 * data2->fSatScale;
349
350		data3->fValScale = w1 * data1->fValScale +
351						   w2 * data2->fValScale;
352
353		data1++;
354		data2++;
355		data3++;
356
357		}
358
359	// Return interpolated tables.
360
361	return result.Release ();
362
363	}
364
365/*****************************************************************************/
366