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 }