buffer stores 2 channels of double; colour using both channels; default supersample...
[maximus:sft.git] / SuperFractalThing / source / SFTPalette.java
1 //      SFTPalette
2 //      Converts iteration counts into colours
3 //
4 //    Copyright 2013 Kevin Martin
5 //    Copyright 2013 Claude Heiland-Allen
6 //
7 //    This file is part of SuperFractalThing.
8 //
9 //    SuperFractalThing is free software: you can redistribute it and/or modify
10 //    it under the terms of the GNU General Public License as published by
11 //    the Free Software Foundation, either version 3 of the License, or
12 //    any later version.
13 //
14 //    SuperFractalThing is distributed in the hope that it will be useful,
15 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //    GNU General Public License for more details.
18 //
19 //    You should have received a copy of the GNU General Public License
20 //    along with SuperFractalThing.  If not, see <http://www.gnu.org/licenses/>.
21 //
22
23 import java.awt.Color;
24
25
26 interface IPaletteChangeNotify
27 {
28         void PaletteChanged();
29 }
30
31 public class SFTPalette implements IPalette
32 {
33
34         IPaletteChangeNotify mNotify;
35         double mPixelSpacing;
36
37         public SFTPalette(IPaletteChangeNotify aNotify)
38         {
39                 mNotify = aNotify;
40         }
41         public void SetPixelSpacing(double aPixelSpacing)
42         {
43                 mPixelSpacing = aPixelSpacing;
44         }
45
46         // linear interpolation by Robert Munafo mrob.com
47         float lin_interp
48                 ( float x
49                 , float domain_low
50                 , float domain_hi
51                 , float range_low
52                 , float range_hi
53                 ) {
54                 if ((x >= domain_low) && (x <= domain_hi)) {
55                         x = (x - domain_low) / (domain_hi - domain_low);
56                         x = range_low + x * (range_hi - range_low);
57                 }
58                 return x;
59         }
60
61         // perceptually balanced hue adjustment by Robert Munafo mrob.com
62         float pvp_adjust_3(float x) {
63                 x = x - (float) Math.floor(x);
64                 x = lin_interp(x, 0.00f, 0.125f, -0.050f, 0.090f);
65                 x = lin_interp(x, 0.125f, 0.25f,  0.090f, 0.167f);
66                 x = lin_interp(x, 0.25f, 0.375f,  0.167f, 0.253f);
67                 x = lin_interp(x, 0.375f, 0.50f,  0.253f, 0.383f);
68                 x = lin_interp(x, 0.50f, 0.625f,  0.383f, 0.500f);
69                 x = lin_interp(x, 0.625f, 0.75f,  0.500f, 0.667f);
70                 x = lin_interp(x, 0.75f, 0.875f,  0.667f, 0.800f);
71                 x = lin_interp(x, 0.875f, 1.00f,  0.800f, 0.950f);
72                 x = x - (float) Math.floor(x);
73                 return(x);
74         }
75
76         @Override
77         public int GetColour(double i, double d)
78         {
79                 if (i==0)
80                         return 0xffffffff;
81                 float h = (float) i / 256.0f;
82                 float s = 0.25f;
83                 float v = (float) Math.tanh(d / mPixelSpacing);
84                 float r, g, b;
85
86                 // hsv to rgb conversion
87                 float j, f, p, q, t;
88                 if (s == 0.0) {
89                         r = v;
90                         g = v;
91                         b = v;
92                 } else {
93                         h = pvp_adjust_3(h);
94                         h = h * 6.0f;
95                         j = (float) Math.floor(h);
96                         f = h - j;
97                         p = v*(1.0f - s);
98                         q = v*(1.0f - (s*f));
99                         t = v*(1.0f - (s*(1.0f - f)));
100                         if (j < 1.0f) { r = v; g = t; b = p; } else
101                         if (j < 2.0f) { r = q; g = v; b = p; } else
102                         if (j < 3.0f) { r = p; g = v; b = t; } else
103                         if (j < 4.0f) { r = p; g = q; b = v; } else
104                         if (j < 5.0f) { r = t; g = p; b = v; } else
105                                       { r = v; g = p; b = q; }
106                 }
107
108                 int red = (int)(r * 255.0f) & 255;
109                 int grn = (int)(g * 255.0f) & 255;
110                 int blu = (int)(b * 255.0f) & 255;
111
112                 return 0xff000000 + blu + (grn << 8) + (red << 16);
113         }
114
115
116         public int GetAverageColour(double i0, double i1, double i2, double i3, double d0, double d1, double d2, double d3)
117         {
118                 int c1,c2,c3,c4,c;
119
120                 c1 = GetColour(i0,d0);
121                 c2 = GetColour(i1,d1);
122                 c3 = GetColour(i2,d2);
123                 c4 = GetColour(i3,d3);
124
125                 c = ((c1&0xff)+(c2&0xff)+(c3&0xff)+(c4&0xff)+2)>>2;
126                 c += (((c1&0xff00)+(c2&0xff00)+(c3&0xff00)+(c4&0xff00)+2)>>2) & 0xff00;
127                 c += (((c1&0xff0000)+(c2&0xff0000)+(c3&0xff0000)+(c4&0xff0000)+2)>>2) & 0xff0000;
128                 c += 0xff000000;
129                 return c;
130         }
131
132         public int GetAverageColour(double i0, double i1, double i2, double i3,double i4, double i5, double i6, double i7, double i8, double d0, double d1, double d2, double d3,double d4, double d5, double d6, double d7, double d8)
133         {
134                 int c1,c2,c3,c4,c5,c6,c7,c8,c9,c;
135
136                 c1 = GetColour(i0,d0);
137                 c2 = GetColour(i1,d1);
138                 c3 = GetColour(i2,d2);
139                 c4 = GetColour(i3,d3);
140                 c5 = GetColour(i4,d4);
141                 c6 = GetColour(i5,d5);
142                 c7 = GetColour(i6,d6);
143                 c8 = GetColour(i7,d7);
144                 c9 = GetColour(i8,d8);
145
146                 c = ((c1&0xff)+(c2&0xff)+(c3&0xff)+(c4&0xff)+(c5&0xff)+(c6&0xff)+(c7&0xff)+(c8&0xff)+(c9&0xff)+4)/9;
147                 c += (((c1&0xff00)+(c2&0xff00)+(c3&0xff00)+(c4&0xff00)+(c5&0xff00)+(c6&0xff00)+(c7&0xff00)+(c8&0xff00)+(c9&0xff00)+4)/9) & 0xff00;
148                 c += (((c1&0xff0000)+(c2&0xff0000)+(c3&0xff0000)+(c4&0xff0000)+(c5&0xff0000)+(c6&0xff0000)+(c7&0xff0000)+(c8&0xff0000)+(c9&0xff0000)+4)/9) & 0xff0000;
149                 c += 0xff000000;
150                 return c;
151         }
152
153 }
154
155 /*
156 class SFTPaletteOld implements IPalette
157 {
158
159         @Override
160         public int GetColour(int i)
161         {
162                 return 0xff000000+i + ((i*7 & 255)<<8) + ((i*31 & 255)<<16);
163         }
164         public int GetAverageColour(int i0, int i1, int i2, int i3)
165         {
166                 return 0;
167         }
168         public int GetAverageColour(int i0, int i1, int i2, int i3,int i4, int i5, int i6, int i7, int i8)
169         {
170                 return 0;
171         }
172 }
173
174
175 class PaletteBand
176 {
177         int mFirst;
178         int mWidth;
179         int mPeriod;
180         int mRed_inc;
181         int     mGrn_inc;
182         int mBlu_inc;
183         int mRed_scale_int;
184         int mGrn_scale_int;
185         int mBlu_scale_int;
186         float mRed_scale;
187         float mGrn_scale;
188         float mBlu_scale;
189         
190         public PaletteBand(int aFirst, int aWidth, int aPeriod, int aRed_inc, int aGrn_inc, int aBlu_inc, int aRed_scale, int aGrn_scale, int aBlu_scale)
191         {
192                 mFirst=aFirst;
193                 mWidth=aWidth;
194                 mPeriod=aPeriod;
195                 mRed_inc=aRed_inc;
196                 mGrn_inc=aGrn_inc;
197                 mBlu_inc=aBlu_inc;
198                 mRed_scale_int=aRed_scale;
199                 mGrn_scale_int=aGrn_scale;
200                 mBlu_scale_int=aBlu_scale;
201
202                 UpdateScale();
203         }
204         
205         void UpdateScale()
206         {
207                 mRed_scale = mRed_scale_int*1.0f/255.0f * (255-mRed_inc)/255.0f;
208                 mGrn_scale = mGrn_scale_int*1.0f/255.0f * (255-mGrn_inc)/255.0f;
209                 mBlu_scale = mBlu_scale_int*1.0f/255.0f * (255-mBlu_inc)/255.0f;
210
211         }
212         
213         void Apply(int[] aColour, int i)
214         {
215                 if (mWidth==0)
216                         return;
217                 
218                 i -= mFirst;
219                 if (mPeriod!=0)
220                         i = i % mPeriod;
221
222                 if (i>0 && i<mWidth)
223                 {
224                         aColour[0] *= mRed_scale;
225                         aColour[1] *= mGrn_scale;
226                         aColour[2] *= mBlu_scale;
227                         
228                         aColour[0] += mRed_inc;
229                         aColour[1] += mGrn_inc;
230                         aColour[2] += mBlu_inc;
231                 }
232         }
233         
234         public int[] Get()
235         {
236                 int [] res = new int[9];
237                 
238                 res[0] = mFirst;
239                 res[1] = mWidth;
240                 res[2] = mPeriod;
241                 
242                 res[3] = mRed_inc;
243                 res[4] = mGrn_inc;
244                 res[5] = mBlu_inc;
245
246                 res[6] = mRed_scale_int;
247                 res[7] = mGrn_scale_int;
248                 res[8] = mBlu_scale_int;
249         
250                 return res;
251         }
252         public int[] Set(int[] aBand)
253         {
254                 int [] res = new int[9];
255                 
256                 mFirst=aBand[0];
257                 mWidth=aBand[1];
258                 mPeriod=aBand[2];
259                 
260                 mRed_inc=aBand[3];
261                 mGrn_inc=aBand[4];
262                 mBlu_inc=aBand[5];
263
264                 mRed_scale_int = aBand[6];
265                 mGrn_scale_int = aBand[7];
266                 mBlu_scale_int = aBand[8];
267                 
268                 UpdateScale();
269         
270                 return res;
271         }
272         
273         public String ToString()
274         {
275                 String str="";
276                 str+= mFirst;
277                 str+=",";
278                 str+= mWidth;
279                 str+=",";
280                 str+= mPeriod;
281                 str+=",";
282                 str+= mRed_inc;
283                 str+=",";
284                 str+=   mGrn_inc;
285                 str+=",";
286                 str+= mBlu_inc;
287                 str+=",";
288                 str+= mRed_scale_int;
289                 str+=",";
290                 str+= mGrn_scale_int;
291                 str+=",";
292                 str+= mBlu_scale_int;           
293                 str+="\n";
294                 return str;
295         }
296         public void ParseString(String aString)
297         {
298                 String numbers[] = aString.split(",");
299                 
300                 mFirst = Integer.parseInt(numbers[0]);
301                 mWidth = Integer.parseInt(numbers[1]);
302                 mPeriod = Integer.parseInt(numbers[2]);
303                 mRed_inc = Integer.parseInt(numbers[3]);
304                 mGrn_inc = Integer.parseInt(numbers[4]);
305                 mBlu_inc = Integer.parseInt(numbers[5]);
306                 mRed_scale_int = Integer.parseInt(numbers[6]);
307                 mGrn_scale_int = Integer.parseInt(numbers[7]);
308                 mBlu_scale_int = Integer.parseInt(numbers[8]);
309
310                 UpdateScale();
311         }
312 }
313
314
315 public class SFTPalette implements IPalette
316 {
317         public static int NUM_BANDS=6;
318         int mPalette[];
319         IPaletteChangeNotify mNotify;
320         int mEnd_colour;
321         
322         float mDr_di1;
323         float mDg_di1;
324         float mDb_di1;
325
326         float mDr_di2;
327         float mDg_di2;
328         float mDb_di2;
329         
330         float mDecay_r;
331         float mDecay_g;
332         float mDecay_b;
333         
334         int mStart_red;
335         int mStart_grn;
336         int mStart_blu;
337         
338         int mColour[];
339         PaletteBand mBands[];
340         
341         public SFTPalette(IPaletteChangeNotify aNotify)
342         {
343                 mNotify = aNotify;
344                 
345                 mPalette = new int[0x10000];
346                 
347                 mDr_di1 = 0.1230459405F;
348                 mDg_di1 = 0.0039432465F;
349                 mDb_di1 = 0.0274356756F;
350                 
351                 mDr_di2 = 0.0730459405F;
352                 mDg_di2 = 0.0079432465F;
353                 mDb_di2 = 0.0224356756F;
354                 
355                 mDecay_r = 5000;
356                 mDecay_g = 10000;
357                 mDecay_b = 20000;
358                 
359                 mEnd_colour = 0xff000000;
360                 
361                 mColour = new int[3];
362                 
363                 mBands = new PaletteBand[NUM_BANDS];
364                 mBands[0]=  new PaletteBand(5000, 256, 5000, 0,0,0,  208,255,255);
365                 mBands[1]=  new PaletteBand(3000, 256, 4444, 28,0,0,  255,191,191);
366                 mBands[2]=  new PaletteBand(7000, 512, 7777, 0,0,0,  255, 255, 224);
367                 mBands[3]=  new PaletteBand(8500, 256, 9532, 0,0,0,  221, 221, 255);
368                 mBands[4]=  new PaletteBand(0, 0, 0, 0,0,0,  255, 255, 255);
369                 mBands[5]=  new PaletteBand(0, 0, 0, 0,0,0,  255, 255, 255);
370         }
371 */
372
373 /*
374                 
375                 i &= 0xffff;
376                 if (mPalette[i]!=0)
377                         return mPalette[i];
378                 
379                 //int red = (int)(256*(i*(0.1230459405F + (0.05*(Math.exp(-i/5000.0)-1)) )));// + Math.sin(i*0.033)));
380                 //int blu = (int)(256*(i*(0.0039432465F - (0.004*(Math.exp(-i/10000.0)-1)) )));// + Math.sin(i*0.007)));
381                 //int grn = (int)(256*(i*(0.0274356756F + (0.005*(Math.exp(-i/20000.0)-1)) )));// + Math.sin(i*0.0073)));
382                 
383                 int red = mStart_red + (int)(256*(i*(mDr_di1 + (1-Math.exp(-i/mDecay_r))*(mDr_di2-mDr_di1) )));// + Math.sin(i*0.033)));
384                 int blu = mStart_blu + (int)(256*(i*(mDg_di1 + (1-Math.exp(-i/mDecay_g))*(mDg_di2-mDg_di1) )));// + Math.sin(i*0.007)));
385                 int grn = mStart_grn + (int)(256*(i*(mDb_di1 + (1-Math.exp(-i/mDecay_b))*(mDb_di2-mDb_di1) )));// + Math.sin(i*0.0073)));
386
387                 mColour[0] = red & 255;
388                 mColour[1] = grn & 255;
389                 mColour[2] = blu & 255;
390                 
391                 
392 */
393                 
394 /*              red *= 1-Math.pow(Math.sin(6.28*i/10000), 1000);
395                 
396                 double fraction = 0.5*Math.pow(Math.sin(6.28*i/11000), 1000);
397                 red = (int)(fraction * 255 + (1-fraction)*red);
398                 grn *= 1-fraction;
399                 blu *= 1-fraction;
400 */              
401 /*
402                 for (int j=0; j< mBands.length; j++)
403                 {
404                         mBands[j].Apply(mColour, i);
405                 }
406
407                 mPalette[i] = 0xff000000+mColour[2] + ((mColour[1])<<8) + (mColour[0]<<16);
408                 return mPalette[i];
409 */
410 /*
411         }
412
413         public void GetGradientValues(float pGradient[][], Color aColours[])
414         {
415                 pGradient[0][0]=mDr_di1;
416                 pGradient[0][1]=mDr_di2;
417                 pGradient[0][2]=mDecay_r;
418
419                 pGradient[1][0]=mDg_di1;
420                 pGradient[1][1]=mDg_di2;
421                 pGradient[1][2]=mDecay_g;
422         
423                 pGradient[2][0]=mDb_di1;
424                 pGradient[2][1]=mDb_di2;
425                 pGradient[2][2]=mDecay_b;
426                 
427                 aColours[0] = new Color( mStart_red, mStart_grn, mStart_blu);
428                 aColours[1] = new Color( (mEnd_colour>>16)&255, (mEnd_colour>>8)&255, (mEnd_colour>>0)&255);
429
430         }
431
432         public void SetGradientValues(float pGradient[][], Color aStart, Color aEnd)
433         {
434
435                 mDr_di1=pGradient[0][0];
436                 mDr_di2=pGradient[0][1];
437                 mDecay_r=pGradient[0][2];
438
439                 mDg_di1=pGradient[1][0];
440                 mDg_di2=pGradient[1][1];
441                 mDecay_g=pGradient[1][2];
442         
443                 mDb_di1=pGradient[2][0];
444                 mDb_di2=pGradient[2][1];
445                 mDecay_b=pGradient[2][2];
446                 
447                 
448                 mPalette = new int[0x10000];
449                 
450                 mEnd_colour = aEnd.getRGB() | 0xff000000;
451                 mStart_red = aStart.getRed();
452                 mStart_grn = aStart.getGreen();
453                 mStart_blu = aStart.getBlue();
454                 
455                 mNotify.PaletteChanged();
456         }
457         
458         public int[] GetBand(int index)
459         {
460                 return mBands[index].Get();
461         }
462         
463         public int[] SetBand(int index, int aBand[])
464         {               
465                 return mBands[index].Set(aBand);
466         }
467         
468         public String ToString()
469         {
470                 String str="sft_palette\n";
471                 str += mDr_di1;
472                 str += ",";
473                 str += mDr_di2;
474                 str += ",";
475                 str += mDecay_r;
476                 str += "\n";
477
478                 str += mDg_di1;
479                 str += ",";
480                 str += mDg_di2;
481                 str += ",";
482                 str += mDecay_g;
483                 str += "\n";
484
485                 str += mDb_di1;
486                 str += ",";
487                 str += mDb_di2;
488                 str += ",";
489                 str += mDecay_b;
490                 str += "\n";
491
492                 str += mStart_red;
493                 str += ",";
494                 str += mStart_grn;
495                 str += ",";
496                 str += mStart_blu;
497                 str += "\n";
498                 
499                 str += (mEnd_colour>>16) & 255;
500                 str += ",";
501                 str +=  (mEnd_colour>>8) & 255;
502                 str += ",";
503                 str +=  (mEnd_colour>>0) & 255;
504                 str += "\n";
505
506
507                 for (int i=0; i<NUM_BANDS; i++)
508                 {
509                         String s = mBands[i].ToString();
510                         str += s;
511                 }
512                 return str;
513         }
514         
515         public void ParseString(String aString)
516         {
517                 String[] lines = aString.split("\n");
518         
519                 if (!lines[0].contentEquals("sft_palette"))
520                         return;
521                 
522                 String[] numbers = lines[1].split(",");
523                 mDr_di1 = Float.parseFloat(numbers[0]); 
524                 mDr_di2 = Float.parseFloat(numbers[1]); 
525                 mDecay_r = Float.parseFloat(numbers[2]);        
526
527                 numbers = lines[2].split(",");
528                 mDg_di1 = Float.parseFloat(numbers[0]); 
529                 mDg_di2 = Float.parseFloat(numbers[1]); 
530                 mDecay_g = Float.parseFloat(numbers[2]);        
531                 
532                 numbers = lines[3].split(",");
533                 mDb_di1 = Float.parseFloat(numbers[0]); 
534                 mDb_di2 = Float.parseFloat(numbers[1]); 
535                 mDecay_b = Float.parseFloat(numbers[2]);        
536
537                 numbers = lines[4].split(",");
538                 mStart_red = Integer.parseInt(numbers[0]);      
539                 mStart_grn = Integer.parseInt(numbers[1]);      
540                 mStart_blu = Integer.parseInt(numbers[2]);      
541         
542                 numbers = lines[5].split(",");
543                 int r = Integer.parseInt(numbers[0]);   
544                 int g = Integer.parseInt(numbers[1]);   
545                 int b = Integer.parseInt(numbers[2]);   
546                 
547                 mEnd_colour  =(r<<16)+(g<<8)+b + 0xff000000;
548
549                 for (int i=0; i<NUM_BANDS; i++)
550                 {
551                         mBands[i].ParseString( lines[6+i]);
552                 }
553                 
554                 mPalette = new int[0x10000];
555                 mNotify.PaletteChanged();
556         }
557 }
558 */