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

« back to all changes in this revision

Viewing changes to app/core/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 <stdlib.h>
58
 
#include <math.h>
59
 
 
60
 
#ifndef __GLIBC__
61
 
/* cbrt() is a GNU extension */
62
 
#define cbrt(x) (pow(x, 1.0/3.0)) 
63
 
#endif
64
 
 
65
 
#ifdef GIMP_COMPILATION
66
 
#include <glib.h> /* to get working 'inline' */
67
 
#endif
68
 
 
69
 
/* defines:
70
 
 
71
 
   SANITY: emits warnings when passed non-sane colours (and usually
72
 
   corrects them) -- useful when debugging.
73
 
 
74
 
   APPROX: speeds up the conversion from RGB to the colourspace by
75
 
   assuming that the RGB values passed in are integral and definitely
76
 
   in the range 0->255
77
 
 
78
 
   SRGB: assumes that the RGB values being passed in (and out) are
79
 
   destined for an sRGB-alike display device (a typical modern monitor)
80
 
   -- if you change this then you'll probably want to change ASSUMED_GAMMA,
81
 
   the phosphor colours and the white point definition.
82
 
*/
83
 
 
84
 
/* #define SANITY */
85
 
#define APPROX
86
 
#define SRGB
87
 
 
88
 
 
89
 
#include "cpercep.h"
90
 
 
91
 
 
92
 
#ifdef SRGB
93
 
#define ASSUMED_GAMMA (2.2F)
94
 
#else
95
 
/*#define ASSUMED_GAMMA (2.591F)*/
96
 
#define ASSUMED_GAMMA (2.2F)
97
 
#endif
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
 
/* call this before using the CPercep function */
309
 
void
310
 
cpercep_init_conversions(void)
311
 
{
312
 
  rgbxyzrgb_init();
313
 
}
314
 
 
315
 
 
316
 
 
317
 
static inline double
318
 
ffunc(const double t)
319
 
{
320
 
  if (t > 0.008856F)
321
 
    {
322
 
      return (cbrt(t));
323
 
    }
324
 
  else
325
 
    {
326
 
      return (7.787F * t + 16.0F/116.0F);
327
 
    }
328
 
}
329
 
 
330
 
 
331
 
static inline double
332
 
ffunc_inv(const double t)
333
 
{
334
 
  if (t > 0.206893F)
335
 
    {
336
 
      return (t * t * t);
337
 
    }
338
 
  else
339
 
    {
340
 
      return ((t - 16.0F/116.0F) / 7.787F);
341
 
    }
342
 
}
343
 
 
344
 
 
345
 
static void
346
 
xyz_to_lab (double *inx,
347
 
            double *iny,
348
 
            double *inz)
349
 
{
350
 
  double L,a,b;
351
 
  double ffuncY;
352
 
  const double X = *inx;
353
 
  const double Y = *iny;
354
 
  const double Z = *inz;
355
 
 
356
 
  if (Y > 0.0F)
357
 
    {
358
 
      if (Y > 0.008856F)
359
 
        {
360
 
          L = (116.0F * cbrt(Y)) - 16.0F;
361
 
        }
362
 
      else
363
 
        {
364
 
          L = (Y * 903.3F);
365
 
        }
366
 
 
367
 
#ifdef SANITY
368
 
      if (L < 0.0F)
369
 
        {
370
 
          g_printerr (" <eek1>%f \007",(float)L);
371
 
        }
372
 
      
373
 
      if (L > 100.0F)
374
 
        {
375
 
          g_printerr (" <eek2>%f \007",(float)L);
376
 
        }
377
 
#endif
378
 
    }
379
 
  else
380
 
    {
381
 
      L = 0.0;
382
 
    }
383
 
 
384
 
  ffuncY = ffunc(Y);
385
 
  a = 500.0F * (ffunc(X/xnn) - ffuncY);
386
 
  b = 200.0F * (ffuncY - ffunc(Z/znn));
387
 
 
388
 
  *inx = L;
389
 
  *iny = a;
390
 
  *inz = b;
391
 
}
392
 
 
393
 
 
394
 
static void
395
 
lab_to_xyz (double *inl,
396
 
            double *ina,
397
 
            double *inb)
398
 
{
399
 
  double X,Y,Z;
400
 
  double P;
401
 
  const double L = *inl;
402
 
  const double a = *ina;
403
 
  const double b = *inb;
404
 
 
405
 
  if (L > LRAMP)
406
 
    {
407
 
      P = Y = (L + 16.0F) / 116.0F;
408
 
      Y = Y * Y * Y;
409
 
    }
410
 
  else
411
 
    {
412
 
      Y = L / 903.3F;
413
 
      P = 7.787F * Y + 16.0F/116.0F;
414
 
    }
415
 
 
416
 
  X = (P + a / 500.0F);
417
 
  X = xnn * ffunc_inv(X);
418
 
  Z = (P - b / 200.0F);
419
 
  Z = znn * ffunc_inv(Z);
420
 
 
421
 
#ifdef SANITY
422
 
  if (X<-0.00000F)
423
 
    {
424
 
      if (X<-0.0001F)
425
 
        g_printerr ("{badX %f {%f,%f,%f}}",X,L,a,b);
426
 
      X = 0.0F;
427
 
    }
428
 
  if (Y<-0.00000F)
429
 
    {
430
 
      if (Y<-0.0001F)
431
 
        g_printerr ("{badY %f}",Y);
432
 
      Y = 0.0F;
433
 
    }
434
 
  if (Z<-0.00000F)
435
 
    {
436
 
      if (Z<-0.1F)
437
 
        g_printerr ("{badZ %f}",Z);
438
 
      Z = 0.0F;
439
 
    }
440
 
#endif
441
 
 
442
 
  *inl = X;
443
 
  *ina = Y;
444
 
  *inb = Z;
445
 
}
446
 
 
447
 
 
448
 
 
449
 
 
450
 
void
451
 
cpercep_rgb_to_space (double inr, double ing, double inb,
452
 
                      double* outr, double* outg, double* outb)
453
 
{
454
 
#ifdef APPROX
455
 
#ifdef SANITY
456
 
  /* ADM extra sanity */
457
 
  if ((inr) > 255.0F ||
458
 
      (ing) > 255.0F ||
459
 
      (inb) > 255.0F ||
460
 
      (inr) < -0.0F ||
461
 
      (ing) < -0.0F ||
462
 
      (inb) < -0.0F
463
 
      )
464
 
    abort();
465
 
#endif /* SANITY */
466
 
  inr = powtable[(int)inr];
467
 
  ing = powtable[(int)ing];
468
 
  inb = powtable[(int)inb];
469
 
#else
470
 
#ifdef SRGB
471
 
  /* sRGB gamma curve */
472
 
  if (inr <= (0.03928F * 255.0F))
473
 
      inr = inr / (255.0F * 12.92F);
474
 
  else
475
 
      inr = pow( (inr + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
476
 
 
477
 
  if (ing <= (0.03928F * 255.0F))
478
 
      ing = ing / (255.0F * 12.92F);
479
 
  else
480
 
      ing = pow( (ing + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
481
 
 
482
 
  if (inb <= (0.03928F * 255.0F))
483
 
      inb = inb / (255.0F * 12.92F);
484
 
  else
485
 
      inb = pow( (inb + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
486
 
#else
487
 
  /* pure gamma function */
488
 
  inr = pow((inr)/255.0F, ASSUMED_GAMMA);
489
 
  ing = pow((ing)/255.0F, ASSUMED_GAMMA);
490
 
  inb = pow((inb)/255.0F, ASSUMED_GAMMA);
491
 
#endif /* SRGB */
492
 
#endif /* APPROX */
493
 
 
494
 
#ifdef SANITY
495
 
  /* ADM extra sanity */
496
 
  if ((inr) > 1.0F ||
497
 
      (ing) > 1.0F ||
498
 
      (inb) > 1.0F ||
499
 
      (inr) < 0.0F ||
500
 
      (ing) < 0.0F ||
501
 
      (inb) < 0.0F
502
 
      )
503
 
    {
504
 
      g_printerr ("%%");
505
 
      /* abort(); */
506
 
    }
507
 
#endif /* SANITY */
508
 
 
509
 
  rgb_to_xyz(&inr, &ing, &inb);
510
 
 
511
 
#ifdef SANITY
512
 
  if (inr < 0.0F || ing < 0.0F || inb < 0.0F)
513
 
    {
514
 
      g_printerr (" [BAD2 XYZ: %f,%f,%f]\007 ",
515
 
              inr,ing,inb);
516
 
    }
517
 
#endif /* SANITY */
518
 
 
519
 
  xyz_to_lab(&inr, &ing, &inb);
520
 
 
521
 
  *outr = inr;
522
 
  *outg = ing;
523
 
  *outb = inb;
524
 
}
525
 
 
526
 
 
527
 
void
528
 
cpercep_space_to_rgb (double inr, double ing, double inb,
529
 
                      double* outr, double* outg, double* outb)
530
 
{
531
 
  lab_to_xyz(&inr, &ing, &inb);
532
 
 
533
 
#ifdef SANITY
534
 
  if (inr<-0.0F || ing<-0.0F || inb<-0.0F)
535
 
    {
536
 
      g_printerr (" [BAD1 XYZ: %f,%f,%f]\007 ",
537
 
              inr,ing,inb);
538
 
    }
539
 
#endif
540
 
 
541
 
  xyz_to_rgb(&inr, &ing, &inb);
542
 
 
543
 
  /* yes, essential.  :( */
544
 
  inr = CLAMP(inr,0.0F,1.0F);
545
 
  ing = CLAMP(ing,0.0F,1.0F);
546
 
  inb = CLAMP(inb,0.0F,1.0F);
547
 
 
548
 
#ifdef SRGB
549
 
  if (inr <= 0.0030402477F)
550
 
    inr = inr * (12.92F * 255.0F);
551
 
  else
552
 
    inr = pow(inr, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
553
 
 
554
 
  if (ing <= 0.0030402477F)
555
 
    ing = ing * (12.92F * 255.0F);
556
 
  else
557
 
    ing = pow(ing, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
558
 
 
559
 
  if (inb <= 0.0030402477F)
560
 
    inb = inb * (12.92F * 255.0F);
561
 
  else
562
 
    inb = pow(inb, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
563
 
#else
564
 
  inr = 255.0F * pow(inr, REV_GAMMA);
565
 
  ing = 255.0F * pow(ing, REV_GAMMA);
566
 
  inb = 255.0F * pow(inb, REV_GAMMA);
567
 
#endif
568
 
 
569
 
  *outr = inr;
570
 
  *outg = ing;
571
 
  *outb = inb;
572
 
}
573
 
 
574
 
 
575
 
#if 0
576
 
/* EXPERIMENTAL SECTION */
577
 
 
578
 
const double
579
 
xscaler(const double start, const double end,
580
 
        const double me, const double him)
581
 
{
582
 
  return start + ((end-start) * him) / (me + him);
583
 
}
584
 
 
585
 
 
586
 
void
587
 
mix_colours (const double L1, const double a1, const double b1,
588
 
             const double L2, const double a2, const double b2,
589
 
             double *rtnL, double *rtna, double *rtnb,
590
 
             double mass1, double mass2)
591
 
{
592
 
  double w1, w2;
593
 
  
594
 
#if 0
595
 
  *rtnL = xscaler (L1, L2, mass1, mass2);
596
 
  *rtna = xscaler (a1, a2, mass1, mass2);
597
 
  *rtnb = xscaler (b1, b2, mass1, mass2);
598
 
#else
599
 
 
600
 
#if 1
601
 
  w1 = mass1 * L1;
602
 
  w2 = mass2 * L2;
603
 
#else
604
 
  w1 = mass1 * (L1*L1*L1);
605
 
  w2 = mass2 * (L2*L2*L2);
606
 
#endif
607
 
  
608
 
  *rtnL = xscaler (L1, L2, mass1, mass2);
609
 
 
610
 
  if (w1 <= 0.0 &&
611
 
      w2 <= 0.0)
612
 
    {
613
 
      *rtna =
614
 
        *rtnb = 0.0;
615
 
#ifdef SANITY
616
 
      /* g_printerr ("\007OUCH. "); */
617
 
#endif
618
 
    }
619
 
  else
620
 
    {
621
 
      *rtna = xscaler(a1, a2, w1, w2);
622
 
      *rtnb = xscaler(b1, b2, w1, w2);
623
 
    }
624
 
#endif
625
 
}
626
 
#endif /* EXPERIMENTAL SECTION */