~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to app/base/cpercep.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (C) 1999-2002 Adam D. Moss (the "Author").  All Rights Reserved.
 
3
 
 
4
Permission is hereby granted, free of charge, to any person obtaining a copy
 
5
of this software and associated documentation files (the "Software"), to deal
 
6
in the Software without restriction, including without limitation the rights
 
7
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
8
copies of the Software, and to permit persons to whom the Software is fur-
 
9
nished to do so, subject to the following conditions:
 
10
 
 
11
The above copyright notice and this permission notice shall be included in
 
12
all copies or substantial portions of the Software.
 
13
 
 
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
15
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
 
16
NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
17
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 
18
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
 
19
NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
20
 
 
21
Except as contained in this notice, the name of the Author of the
 
22
Software shall not be used in advertising or otherwise to promote the sale,
 
23
use or other dealings in this Software without prior written authorization
 
24
from the Author.
 
25
*/
 
26
 
 
27
/*
 
28
  cpercep.c: The CPercep Functions v0.9: 2002-02-10
 
29
  Adam D. Moss: adam@gimp.org <http://www.foxbox.org/adam/code/cpercep/>
 
30
 
 
31
  This code module concerns itself with conversion from a hard-coded
 
32
  RGB colour space (sRGB by default) to CIE L*a*b* and back again with
 
33
  (primarily) precision and (secondarily) speed, oriented largely
 
34
  towards the purposes of quantifying the PERCEPTUAL difference between
 
35
  two arbitrary RGB colours with a minimum of fuss.
 
36
 
 
37
  Motivation One: The author is disheartened at the amount of graphics
 
38
  processing software around which uses weighted or non-weighted
 
39
  Euclidean distance between co-ordinates within a (poorly-defined) RGB
 
40
  space as the basis of what should really be an estimate of perceptual
 
41
  difference to the human eye.  Certainly it's fast to do it that way,
 
42
  but please think carefully about whether your particular application
 
43
  should be tolerating sloppy results for the sake of real-time response.
 
44
 
 
45
  Motivation Two: Lack of tested, re-usable and free code available
 
46
  for this purpose.  The difficulty in finding something similar to
 
47
  CPercep with a free license motivated this project; I hope that this
 
48
  code also serves to illustrate how to perform the
 
49
  R'G'B'->XYZ->L*a*b*->XYZ->R'G'B' transformation correctly since I
 
50
  was distressed to note how many of the equations and code snippets
 
51
  on the net were omitting the reverse transform and/or were using
 
52
  incorrectly-derived or just plain wrong constants.
 
53
 
 
54
  TODO: document functions, rename erroneously-named arguments
 
55
*/
 
56
 
 
57
#include "config.h"
 
58
 
 
59
#include <glib-object.h>
 
60
 
 
61
#include <libgimpmath/gimpmath.h>
 
62
 
 
63
#ifndef __GLIBC__
 
64
/* cbrt() is a GNU extension */
 
65
#define cbrt(x) (pow(x, 1.0/3.0))
 
66
#endif
 
67
 
 
68
#include "cpercep.h"
 
69
 
 
70
 
 
71
/* defines:
 
72
 
 
73
   SANITY: emits warnings when passed non-sane colours (and usually
 
74
   corrects them) -- useful when debugging.
 
75
 
 
76
   APPROX: speeds up the conversion from RGB to the colourspace by
 
77
   assuming that the RGB values passed in are integral and definitely
 
78
   in the range 0->255
 
79
 
 
80
   SRGB: assumes that the RGB values being passed in (and out) are
 
81
   destined for an sRGB-alike display device (a typical modern monitor)
 
82
   -- if you change this then you'll probably want to change ASSUMED_GAMMA,
 
83
   the phosphor colours and the white point definition.
 
84
*/
 
85
 
 
86
/* #define SANITY */
 
87
#define APPROX
 
88
#define SRGB
 
89
 
 
90
 
 
91
#ifdef SRGB
 
92
#define ASSUMED_GAMMA (2.2F)
 
93
#else
 
94
/*#define ASSUMED_GAMMA (2.591F)*/
 
95
#define ASSUMED_GAMMA (2.2F)
 
96
#endif
 
97
 
 
98
#define REV_GAMMA ((1.0F / ASSUMED_GAMMA))
 
99
 
 
100
 
 
101
/* define characteristics of the source RGB space (and the space
 
102
   within which we try to behave linearly). */
 
103
 
 
104
/* Phosphor colours: */
 
105
 
 
106
/* sRGB/HDTV phosphor colours */
 
107
static const double pxr = 0.64F;
 
108
static const double pyr = 0.33F;
 
109
static const double pxg = 0.30F;
 
110
static const double pyg = 0.60F;
 
111
static const double pxb = 0.15F;
 
112
static const double pyb = 0.06F;
 
113
 
 
114
/* White point: */
 
115
 
 
116
/* D65 (6500K) (recommended but not a common display default) */
 
117
static const double lxn = 0.312713F;
 
118
static const double lyn = 0.329016F;
 
119
 
 
120
/* D50 (5000K) */
 
121
/*static const double lxn = 0.3457F; */
 
122
/*static const double lyn = 0.3585F; */
 
123
 
 
124
/* D55 (5500K) */
 
125
/*static const double lxn = 0.3324F; */
 
126
/*static const double lyn = 0.3474F; */
 
127
 
 
128
/* D93 (9300K) (a common monitor default, but poor colour reproduction) */
 
129
/* static const double lxn = 0.2848F; */
 
130
/* static const double lyn = 0.2932F; */
 
131
 
 
132
/* illum E (normalized) */
 
133
/*static const double lxn = 1.0/3.0F; */
 
134
/*static const double lyn = 1.0/3.0F; */
 
135
 
 
136
/* illum C (average sunlight) */
 
137
/*static const double lxn = 0.3101F; */
 
138
/*static const double lyn = 0.3162F; */
 
139
 
 
140
/* illum B (direct sunlight) */
 
141
/*static const double lxn = 0.3484F; */
 
142
/*static const double lyn = 0.3516F; */
 
143
 
 
144
/* illum A (tungsten lamp) */
 
145
/*static const double lxn = 0.4476F; */
 
146
/*static const double lyn = 0.4074F; */
 
147
 
 
148
 
 
149
static const double LRAMP = 7.99959199F;
 
150
 
 
151
 
 
152
static double xnn, znn;
 
153
 
 
154
static double powtable[256];
 
155
 
 
156
 
 
157
#ifndef CLAMP
 
158
#define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x)))
 
159
#endif
 
160
 
 
161
 
 
162
static void
 
163
init_powtable(const double gamma)
 
164
{
 
165
  int i;
 
166
 
 
167
#ifndef SRGB
 
168
  /* pure gamma function */
 
169
  for (i=0; i<256; i++)
 
170
    {
 
171
      powtable[i] = pow((i)/255.0F, gamma);
 
172
    }
 
173
#else
 
174
  /* sRGB gamma curve */
 
175
  for (i=0; i<11 /* 0.03928 * 255 */; i++)
 
176
    {
 
177
      powtable[i] = (i) / (255.0F * 12.92F);
 
178
    }
 
179
  for (; i<256; i++)
 
180
    {
 
181
      powtable[i] = pow( (((i) / 255.0F) + 0.055F) / 1.055F, 2.4F);
 
182
    }
 
183
#endif
 
184
}
 
185
 
 
186
 
 
187
typedef double CMatrix[3][3];
 
188
typedef double CVector[3];
 
189
 
 
190
static CMatrix Mrgb_to_xyz, Mxyz_to_rgb;
 
191
 
 
192
static int
 
193
Minvert (CMatrix src, CMatrix dest)
 
194
{
 
195
  double det;
 
196
 
 
197
  dest[0][0] = src[1][1] * src[2][2] - src[1][2] * src[2][1];
 
198
  dest[0][1] = src[0][2] * src[2][1] - src[0][1] * src[2][2];
 
199
  dest[0][2] = src[0][1] * src[1][2] - src[0][2] * src[1][1];
 
200
  dest[1][0] = src[1][2] * src[2][0] - src[1][0] * src[2][2];
 
201
  dest[1][1] = src[0][0] * src[2][2] - src[0][2] * src[2][0];
 
202
  dest[1][2] = src[0][2] * src[1][0] - src[0][0] * src[1][2];
 
203
  dest[2][0] = src[1][0] * src[2][1] - src[1][1] * src[2][0];
 
204
  dest[2][1] = src[0][1] * src[2][0] - src[0][0] * src[2][1];
 
205
  dest[2][2] = src[0][0] * src[1][1] - src[0][1] * src[1][0];
 
206
 
 
207
  det =
 
208
    src[0][0] * dest[0][0] +
 
209
    src[0][1] * dest[1][0] +
 
210
    src[0][2] * dest[2][0];
 
211
 
 
212
  if (det <= 0.0F)
 
213
    {
 
214
#ifdef SANITY
 
215
      g_printerr ("\n\007 XXXX det: %f\n", det);
 
216
#endif
 
217
      return 0;
 
218
    }
 
219
 
 
220
  dest[0][0] /= det;
 
221
  dest[0][1] /= det;
 
222
  dest[0][2] /= det;
 
223
  dest[1][0] /= det;
 
224
  dest[1][1] /= det;
 
225
  dest[1][2] /= det;
 
226
  dest[2][0] /= det;
 
227
  dest[2][1] /= det;
 
228
  dest[2][2] /= det;
 
229
 
 
230
  return 1;
 
231
}
 
232
 
 
233
 
 
234
static void
 
235
rgbxyzrgb_init(void)
 
236
{
 
237
  init_powtable (ASSUMED_GAMMA);
 
238
 
 
239
  xnn = lxn / lyn;
 
240
  /* ynn taken as 1.0 */
 
241
  znn = (1.0F - (lxn + lyn)) / lyn;
 
242
 
 
243
  {
 
244
    CMatrix MRC, MRCi;
 
245
    double C1,C2,C3;
 
246
 
 
247
    MRC[0][0] = pxr;
 
248
    MRC[0][1] = pxg;
 
249
    MRC[0][2] = pxb;
 
250
    MRC[1][0] = pyr;
 
251
    MRC[1][1] = pyg;
 
252
    MRC[1][2] = pyb;
 
253
    MRC[2][0] = 1.0F - (pxr + pyr);
 
254
    MRC[2][1] = 1.0F - (pxg + pyg);
 
255
    MRC[2][2] = 1.0F - (pxb + pyb);
 
256
 
 
257
    Minvert (MRC, MRCi);
 
258
 
 
259
    C1 = MRCi[0][0]*xnn + MRCi[0][1] + MRCi[0][2]*znn;
 
260
    C2 = MRCi[1][0]*xnn + MRCi[1][1] + MRCi[1][2]*znn;
 
261
    C3 = MRCi[2][0]*xnn + MRCi[2][1] + MRCi[2][2]*znn;
 
262
 
 
263
    Mrgb_to_xyz[0][0] = MRC[0][0] * C1;
 
264
    Mrgb_to_xyz[0][1] = MRC[0][1] * C2;
 
265
    Mrgb_to_xyz[0][2] = MRC[0][2] * C3;
 
266
    Mrgb_to_xyz[1][0] = MRC[1][0] * C1;
 
267
    Mrgb_to_xyz[1][1] = MRC[1][1] * C2;
 
268
    Mrgb_to_xyz[1][2] = MRC[1][2] * C3;
 
269
    Mrgb_to_xyz[2][0] = MRC[2][0] * C1;
 
270
    Mrgb_to_xyz[2][1] = MRC[2][1] * C2;
 
271
    Mrgb_to_xyz[2][2] = MRC[2][2] * C3;
 
272
 
 
273
    Minvert (Mrgb_to_xyz, Mxyz_to_rgb);
 
274
  }
 
275
}
 
276
 
 
277
 
 
278
static void
 
279
xyz_to_rgb (double *inx_outr,
 
280
            double *iny_outg,
 
281
            double *inz_outb)
 
282
{
 
283
  const double x = *inx_outr;
 
284
  const double y = *iny_outg;
 
285
  const double z = *inz_outb;
 
286
 
 
287
  *inx_outr = Mxyz_to_rgb[0][0]*x + Mxyz_to_rgb[0][1]*y + Mxyz_to_rgb[0][2]*z;
 
288
  *iny_outg = Mxyz_to_rgb[1][0]*x + Mxyz_to_rgb[1][1]*y + Mxyz_to_rgb[1][2]*z;
 
289
  *inz_outb = Mxyz_to_rgb[2][0]*x + Mxyz_to_rgb[2][1]*y + Mxyz_to_rgb[2][2]*z;
 
290
}
 
291
 
 
292
 
 
293
static void
 
294
rgb_to_xyz (double *inr_outx,
 
295
            double *ing_outy,
 
296
            double *inb_outz)
 
297
{
 
298
  const double r = *inr_outx;
 
299
  const double g = *ing_outy;
 
300
  const double b = *inb_outz;
 
301
 
 
302
  *inr_outx = Mrgb_to_xyz[0][0]*r + Mrgb_to_xyz[0][1]*g + Mrgb_to_xyz[0][2]*b;
 
303
  *ing_outy = Mrgb_to_xyz[1][0]*r + Mrgb_to_xyz[1][1]*g + Mrgb_to_xyz[1][2]*b;
 
304
  *inb_outz = Mrgb_to_xyz[2][0]*r + Mrgb_to_xyz[2][1]*g + Mrgb_to_xyz[2][2]*b;
 
305
}
 
306
 
 
307
 
 
308
static inline double
 
309
ffunc(const double t)
 
310
{
 
311
  if (t > 0.008856F)
 
312
    {
 
313
      return (cbrt(t));
 
314
    }
 
315
  else
 
316
    {
 
317
      return (7.787F * t + 16.0F/116.0F);
 
318
    }
 
319
}
 
320
 
 
321
 
 
322
static inline double
 
323
ffunc_inv(const double t)
 
324
{
 
325
  if (t > 0.206893F)
 
326
    {
 
327
      return (t * t * t);
 
328
    }
 
329
  else
 
330
    {
 
331
      return ((t - 16.0F/116.0F) / 7.787F);
 
332
    }
 
333
}
 
334
 
 
335
 
 
336
static void
 
337
xyz_to_lab (double *inx,
 
338
            double *iny,
 
339
            double *inz)
 
340
{
 
341
  double L,a,b;
 
342
  double ffuncY;
 
343
  const double X = *inx;
 
344
  const double Y = *iny;
 
345
  const double Z = *inz;
 
346
 
 
347
  if (Y > 0.0F)
 
348
    {
 
349
      if (Y > 0.008856F)
 
350
        {
 
351
          L = (116.0F * cbrt(Y)) - 16.0F;
 
352
        }
 
353
      else
 
354
        {
 
355
          L = (Y * 903.3F);
 
356
        }
 
357
 
 
358
#ifdef SANITY
 
359
      if (L < 0.0F)
 
360
        {
 
361
          g_printerr (" <eek1>%f \007",(float)L);
 
362
        }
 
363
 
 
364
      if (L > 100.0F)
 
365
        {
 
366
          g_printerr (" <eek2>%f \007",(float)L);
 
367
        }
 
368
#endif
 
369
    }
 
370
  else
 
371
    {
 
372
      L = 0.0;
 
373
    }
 
374
 
 
375
  ffuncY = ffunc(Y);
 
376
  a = 500.0F * (ffunc(X/xnn) - ffuncY);
 
377
  b = 200.0F * (ffuncY - ffunc(Z/znn));
 
378
 
 
379
  *inx = L;
 
380
  *iny = a;
 
381
  *inz = b;
 
382
}
 
383
 
 
384
 
 
385
static void
 
386
lab_to_xyz (double *inl,
 
387
            double *ina,
 
388
            double *inb)
 
389
{
 
390
  double X,Y,Z;
 
391
  double P;
 
392
  const double L = *inl;
 
393
  const double a = *ina;
 
394
  const double b = *inb;
 
395
 
 
396
  if (L > LRAMP)
 
397
    {
 
398
      P = Y = (L + 16.0F) / 116.0F;
 
399
      Y = Y * Y * Y;
 
400
    }
 
401
  else
 
402
    {
 
403
      Y = L / 903.3F;
 
404
      P = 7.787F * Y + 16.0F/116.0F;
 
405
    }
 
406
 
 
407
  X = (P + a / 500.0F);
 
408
  X = xnn * ffunc_inv(X);
 
409
  Z = (P - b / 200.0F);
 
410
  Z = znn * ffunc_inv(Z);
 
411
 
 
412
#ifdef SANITY
 
413
  if (X<-0.00000F)
 
414
    {
 
415
      if (X<-0.0001F)
 
416
        g_printerr ("{badX %f {%f,%f,%f}}",X,L,a,b);
 
417
      X = 0.0F;
 
418
    }
 
419
  if (Y<-0.00000F)
 
420
    {
 
421
      if (Y<-0.0001F)
 
422
        g_printerr ("{badY %f}",Y);
 
423
      Y = 0.0F;
 
424
    }
 
425
  if (Z<-0.00000F)
 
426
    {
 
427
      if (Z<-0.1F)
 
428
        g_printerr ("{badZ %f}",Z);
 
429
      Z = 0.0F;
 
430
    }
 
431
#endif
 
432
 
 
433
  *inl = X;
 
434
  *ina = Y;
 
435
  *inb = Z;
 
436
}
 
437
 
 
438
 
 
439
 
 
440
/* call this before using the CPercep function */
 
441
void
 
442
cpercep_init (void)
 
443
{
 
444
  static gboolean initialized = FALSE;
 
445
 
 
446
  if (! initialized)
 
447
    {
 
448
      rgbxyzrgb_init();
 
449
      initialized = TRUE;
 
450
    }
 
451
}
 
452
 
 
453
void
 
454
cpercep_rgb_to_space (double  inr,
 
455
                      double  ing,
 
456
                      double  inb,
 
457
                      double *outr,
 
458
                      double *outg,
 
459
                      double *outb)
 
460
{
 
461
#ifdef APPROX
 
462
#ifdef SANITY
 
463
  /* ADM extra sanity */
 
464
  if ((inr) > 255.0F ||
 
465
      (ing) > 255.0F ||
 
466
      (inb) > 255.0F ||
 
467
      (inr) < -0.0F ||
 
468
      (ing) < -0.0F ||
 
469
      (inb) < -0.0F
 
470
      )
 
471
    abort();
 
472
#endif /* SANITY */
 
473
  inr = powtable[(int)inr];
 
474
  ing = powtable[(int)ing];
 
475
  inb = powtable[(int)inb];
 
476
#else
 
477
#ifdef SRGB
 
478
  /* sRGB gamma curve */
 
479
  if (inr <= (0.03928F * 255.0F))
 
480
      inr = inr / (255.0F * 12.92F);
 
481
  else
 
482
      inr = pow( (inr + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
 
483
 
 
484
  if (ing <= (0.03928F * 255.0F))
 
485
      ing = ing / (255.0F * 12.92F);
 
486
  else
 
487
      ing = pow( (ing + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
 
488
 
 
489
  if (inb <= (0.03928F * 255.0F))
 
490
      inb = inb / (255.0F * 12.92F);
 
491
  else
 
492
      inb = pow( (inb + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
 
493
#else
 
494
  /* pure gamma function */
 
495
  inr = pow((inr)/255.0F, ASSUMED_GAMMA);
 
496
  ing = pow((ing)/255.0F, ASSUMED_GAMMA);
 
497
  inb = pow((inb)/255.0F, ASSUMED_GAMMA);
 
498
#endif /* SRGB */
 
499
#endif /* APPROX */
 
500
 
 
501
#ifdef SANITY
 
502
  /* ADM extra sanity */
 
503
  if ((inr) > 1.0F ||
 
504
      (ing) > 1.0F ||
 
505
      (inb) > 1.0F ||
 
506
      (inr) < 0.0F ||
 
507
      (ing) < 0.0F ||
 
508
      (inb) < 0.0F
 
509
      )
 
510
    {
 
511
      g_printerr ("%%");
 
512
      /* abort(); */
 
513
    }
 
514
#endif /* SANITY */
 
515
 
 
516
  rgb_to_xyz(&inr, &ing, &inb);
 
517
 
 
518
#ifdef SANITY
 
519
  if (inr < 0.0F || ing < 0.0F || inb < 0.0F)
 
520
    {
 
521
      g_printerr (" [BAD2 XYZ: %f,%f,%f]\007 ",
 
522
              inr,ing,inb);
 
523
    }
 
524
#endif /* SANITY */
 
525
 
 
526
  xyz_to_lab(&inr, &ing, &inb);
 
527
 
 
528
  *outr = inr;
 
529
  *outg = ing;
 
530
  *outb = inb;
 
531
}
 
532
 
 
533
 
 
534
void
 
535
cpercep_space_to_rgb (double  inr,
 
536
                      double  ing,
 
537
                      double  inb,
 
538
                      double *outr,
 
539
                      double *outg,
 
540
                      double *outb)
 
541
{
 
542
  lab_to_xyz(&inr, &ing, &inb);
 
543
 
 
544
#ifdef SANITY
 
545
  if (inr<-0.0F || ing<-0.0F || inb<-0.0F)
 
546
    {
 
547
      g_printerr (" [BAD1 XYZ: %f,%f,%f]\007 ",
 
548
              inr,ing,inb);
 
549
    }
 
550
#endif
 
551
 
 
552
  xyz_to_rgb(&inr, &ing, &inb);
 
553
 
 
554
  /* yes, essential.  :( */
 
555
  inr = CLAMP(inr,0.0F,1.0F);
 
556
  ing = CLAMP(ing,0.0F,1.0F);
 
557
  inb = CLAMP(inb,0.0F,1.0F);
 
558
 
 
559
#ifdef SRGB
 
560
  if (inr <= 0.0030402477F)
 
561
    inr = inr * (12.92F * 255.0F);
 
562
  else
 
563
    inr = pow(inr, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
 
564
 
 
565
  if (ing <= 0.0030402477F)
 
566
    ing = ing * (12.92F * 255.0F);
 
567
  else
 
568
    ing = pow(ing, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
 
569
 
 
570
  if (inb <= 0.0030402477F)
 
571
    inb = inb * (12.92F * 255.0F);
 
572
  else
 
573
    inb = pow(inb, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
 
574
#else
 
575
  inr = 255.0F * pow(inr, REV_GAMMA);
 
576
  ing = 255.0F * pow(ing, REV_GAMMA);
 
577
  inb = 255.0F * pow(inb, REV_GAMMA);
 
578
#endif
 
579
 
 
580
  *outr = inr;
 
581
  *outg = ing;
 
582
  *outb = inb;
 
583
}
 
584
 
 
585
 
 
586
#if 0
 
587
/* EXPERIMENTAL SECTION */
 
588
 
 
589
const double
 
590
xscaler(const double start, const double end,
 
591
        const double me, const double him)
 
592
{
 
593
  return start + ((end-start) * him) / (me + him);
 
594
}
 
595
 
 
596
 
 
597
void
 
598
mix_colours (const double L1, const double a1, const double b1,
 
599
             const double L2, const double a2, const double b2,
 
600
             double *rtnL, double *rtna, double *rtnb,
 
601
             double mass1, double mass2)
 
602
{
 
603
  double w1, w2;
 
604
 
 
605
#if 0
 
606
  *rtnL = xscaler (L1, L2, mass1, mass2);
 
607
  *rtna = xscaler (a1, a2, mass1, mass2);
 
608
  *rtnb = xscaler (b1, b2, mass1, mass2);
 
609
#else
 
610
 
 
611
#if 1
 
612
  w1 = mass1 * L1;
 
613
  w2 = mass2 * L2;
 
614
#else
 
615
  w1 = mass1 * (L1*L1*L1);
 
616
  w2 = mass2 * (L2*L2*L2);
 
617
#endif
 
618
 
 
619
  *rtnL = xscaler (L1, L2, mass1, mass2);
 
620
 
 
621
  if (w1 <= 0.0 &&
 
622
      w2 <= 0.0)
 
623
    {
 
624
      *rtna =
 
625
        *rtnb = 0.0;
 
626
#ifdef SANITY
 
627
      /* g_printerr ("\007OUCH. "); */
 
628
#endif
 
629
    }
 
630
  else
 
631
    {
 
632
      *rtna = xscaler(a1, a2, w1, w2);
 
633
      *rtnb = xscaler(b1, b2, w1, w2);
 
634
    }
 
635
#endif
 
636
}
 
637
#endif /* EXPERIMENTAL SECTION */