/ source / tools / src / mkpalette.cpp
mkpalette.cpp
  1  #include "compat.h"
  2  
  3  struct hsv {
  4      float h, s, v;
  5  };
  6  
  7  struct rgb {
  8      float r, g, b;
  9  };
 10  
 11  struct gradient {
 12      int start, len, chompends;
 13      struct hsv startcolour, endcolour;
 14  };
 15  
 16  float min2(float x, float y);
 17  float max2(float x, float y);
 18  void convertHSVtoRGB(struct hsv *hsv, struct rgb *rgb);
 19  int showusage(void);
 20  int readscript(char *fn);
 21  
 22  struct gradient ramps[256];
 23  int nramps = 0;
 24  
 25  int main(int argc, char **argv)
 26  {
 27      struct hsv palette[256], lerpstep, lerped;
 28      struct rgb rgbidx;
 29      unsigned char rgbout[3];
 30      int idx, step, rampnum;
 31      FILE* fh;
 32      char const * outfile = "palette.dat";
 33  
 34      memset(palette,0,sizeof(palette));
 35  
 36      if (argc < 2) return showusage();
 37      if (readscript(argv[1])) return 1;
 38      if (argc >= 3) outfile = argv[2];
 39  
 40      for (rampnum = 0; rampnum < nramps; rampnum++) {
 41          idx = ramps[rampnum].start;
 42          step = ramps[rampnum].len;
 43          if (ramps[rampnum].chompends & 1) step++;
 44          if (ramps[rampnum].chompends & 2) step++;
 45          lerpstep.h = (ramps[rampnum].endcolour.h - ramps[rampnum].startcolour.h) / (float)step;
 46          lerpstep.s = (ramps[rampnum].endcolour.s - ramps[rampnum].startcolour.s) / (float)step;
 47          lerpstep.v = (ramps[rampnum].endcolour.v - ramps[rampnum].startcolour.v) / (float)step;
 48          lerped = ramps[rampnum].startcolour;
 49          if (ramps[rampnum].chompends & 1) {
 50              step--;
 51              lerped.h += lerpstep.h;
 52              lerped.s += lerpstep.s;
 53              lerped.v += lerpstep.v;
 54          }
 55          if (ramps[rampnum].chompends & 2) step--;
 56  
 57          for (; step > 0; step--,idx++) {
 58              palette[idx].h = lerped.h;
 59              palette[idx].s = lerped.s;
 60              palette[idx].v = lerped.v;
 61              lerped.h += lerpstep.h;
 62              lerped.s += lerpstep.s;
 63              lerped.v += lerpstep.v;
 64          }
 65      }
 66  
 67      fh = fopen(outfile,"wb");
 68      if (!fh) return 1;
 69  
 70      for (idx=0; idx<256; idx++) {
 71          convertHSVtoRGB(&palette[idx], &rgbidx);
 72          //printf("Index %d: r=%g g=%g b=%g\n",idx,rgbidx.r,rgbidx.g,rgbidx.b);
 73          rgbout[0] = (unsigned char)min2(255,max2(0,(int)(rgbidx.r * 255.0))) >> 2;
 74          rgbout[1] = (unsigned char)min2(255,max2(0,(int)(rgbidx.g * 255.0))) >> 2;
 75          rgbout[2] = (unsigned char)min2(255,max2(0,(int)(rgbidx.b * 255.0))) >> 2;
 76          fwrite(rgbout,3,1,fh);
 77      }
 78  
 79      fclose(fh);
 80  
 81      return 0;
 82  }
 83  
 84  float min2(float x, float y)
 85  {
 86      return x < y ? x : y;
 87  }
 88  
 89  float max2(float x, float y)
 90  {
 91      return x > y ? x : y;
 92  }
 93  
 94  // http://www.cs.rit.edu/~ncs/color/t_convert.html
 95  void convertHSVtoRGB(struct hsv *hsv, struct rgb *rgb)
 96  {
 97      int i;
 98      float f, p, q, t;
 99      if( hsv->s == 0 ) {
100          // achromatic (grey)
101          rgb->r = rgb->g = rgb->b = hsv->v;
102          return;
103      }
104      hsv->h /= 60;            // sector 0 to 5
105      i = floor( hsv->h );
106      f = hsv->h - i;            // factorial part of h
107      p = hsv->v * ( 1 - hsv->s );
108      q = hsv->v * ( 1 - hsv->s * f );
109      t = hsv->v * ( 1 - hsv->s * ( 1 - f ) );
110      switch( i ) {
111          case 0:
112              rgb->r = hsv->v;
113              rgb->g = t;
114              rgb->b = p;
115              break;
116          case 1:
117              rgb->r = q;
118              rgb->g = hsv->v;
119              rgb->b = p;
120              break;
121          case 2:
122              rgb->r = p;
123              rgb->g = hsv->v;
124              rgb->b = t;
125              break;
126          case 3:
127              rgb->r = p;
128              rgb->g = q;
129              rgb->b = hsv->v;
130              break;
131          case 4:
132              rgb->r = t;
133              rgb->g = p;
134              rgb->b = hsv->v;
135              break;
136          default:        // case 5:
137              rgb->r = hsv->v;
138              rgb->g = p;
139              rgb->b = q;
140              break;
141      }
142  }
143  
144  int showusage(void)
145  {
146      puts("mkpalette <palettescript.txt> [outputfile]");
147      puts("If outputfile is not given, palette.dat is assumed");
148  
149      puts("\nPalette script format:\n"
150      "  A line beginning with # is a comment, otherwise each line contains none\n"
151      "values separated by spaces defining the gradient:\n"
152      "\n"
153      "  startindex rangesize skip starthue startsat startval endhue endsat endval\n"
154      "\n"
155      "Any text after the end of a gradient description is ignored, so may use it\n"
156      "to describe the colour.\n"
157      "\n"
158      "* 'startindex' specifies the first palette index to write to\n"
159      "* 'rangesize' specifies the length of the gradient\n"
160      "* 'skip' specifies whether the first and/or last elements of the range should\n"
161      "  be ignored and with 'rangesize' elements interpolated between. This is so\n"
162      "  you can have a gradient starting at (potentially) pure black and ending at\n"
163      "  (potentially) pure white but without wasting a palette index on those colours\n"
164      "  if they already exist, eg. in a grey ramp.\n"
165      "  Legal values are 0 (no skipping), 1 (skip start), 2 (skip end),\n"
166      "  or 3 (skip start and end).\n"
167      "* 'starthue', 'startsat', 'startval' are integers specifying the beginning\n"
168      "  colour in Hue-Saturation-Value format.\n"
169      "  'starthue' should be in the range 0-360 indicating a degrees value\n"
170      "  'startsat' should be in the range 0-100 indicating a saturation percentage\n"
171      "  'startval' should be in the range 0-100 indicating an intensity percentage\n"
172      "* 'endhue', 'endsat', 'endval' specify the ending colour."
173      );
174      return 0;
175  }
176  
177  int readscript(char *fn)
178  {
179      int start, len, skip, shue, ssat, sval, ehue, esat, eval;
180      FILE *fp;
181      char line[1024];
182  
183      fp = fopen(fn,"rt");
184      if (!fp) {
185          puts("Error opening palette script");
186          return 1;
187      }
188  
189      while (fgets(line,sizeof(line),fp)) {
190          {
191              // test for comment
192              char *p = line;
193              while (*p && (*p == ' ' || *p == '\t')) p++;
194              if (*p == '#') continue;
195          }
196  
197          if (sscanf(line, "%d %d %d %d %d %d %d %d %d", &start,&len,&skip,&shue,&ssat,&sval,&ehue,&esat,&eval) < 9)
198              continue;
199  
200          if (start < 0 || start > 255) {
201              printf("start index of %d is out of range 0-255\n", start);
202              continue;
203          }
204          if (len < 1 || len > 255) {
205              printf("length %d is out of range 1-255\n", len);
206              continue;
207          }
208          if (skip != (skip&3)) {
209              printf("skip value of %d is out of range 0-3\n", skip);
210              continue;
211          }
212          if (shue < 0 || shue > 360) {
213              printf("start hue %d is out of range 0-360\n", shue);
214              continue;
215          }
216          if (ssat < 0 || ssat > 100) {
217              printf("start saturation %d is out of range 0-100\n", ssat);
218              continue;
219          }
220          if (sval < 0 || sval > 100) {
221              printf("start value %d is out of range 0-100\n", sval);
222              continue;
223          }
224          if (ehue < 0 || ehue > 360) {
225              printf("end hue %d is out of range 0-360\n", shue);
226              continue;
227          }
228          if (esat < 0 || esat > 100) {
229              printf("end saturation %d is out of range 0-100\n", ssat);
230              continue;
231          }
232          if (eval < 0 || eval > 100) {
233              printf("end value %d is out of range 0-100\n", sval);
234              continue;
235          }
236  
237          ramps[nramps].start = start;
238          ramps[nramps].len = len;
239          ramps[nramps].chompends = skip;
240          ramps[nramps].startcolour.h = (float)shue;
241          ramps[nramps].startcolour.s = (float)ssat / 100.0;
242          ramps[nramps].startcolour.v = (float)sval / 100.0;
243          ramps[nramps].endcolour.h = (float)ehue;
244          ramps[nramps].endcolour.s = (float)esat / 100.0;
245          ramps[nramps].endcolour.v = (float)eval / 100.0;
246          nramps++;
247      }
248  
249      fclose(fp);
250      return 0;
251  }