00001
00002
00003
00004 #include <OCOLTBL.H>
00005 #include <ALL.H>
00006 #include <math.h>
00007 #include <OVGA.H>
00008
00009
00010
00011
00012 #define MAX_COLOUR 255
00013 #define M_PI 3.14159265359L
00014 #define NEAREST_COLOR 8
00015 #define BRIGHTNESS_WEIGHTING 4.0
00016
00017 BYTE ColorTable::identity_table[MAX_COLOUR_TABLE_SIZE] = {
00018 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
00019 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
00020 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
00021 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
00022 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
00023 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
00024 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
00025 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
00026 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
00027 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
00028 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
00029 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
00030 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
00031 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
00032 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
00033 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
00034 };
00035
00036
00037
00038 inline int sq(int a) {
00039 return a*a;
00040 }
00041
00042
00043 ColorTable::ColorTable() {
00044 remap_table = NULL;
00045 remap_table_array = NULL;
00046 }
00047
00048 ColorTable::ColorTable(int absScale, int tableSize, WORD *customTable) {
00049 remap_table = NULL;
00050 remap_table_array = NULL;
00051 init(absScale, tableSize, customTable);
00052 }
00053
00054
00055
00056
00057 ColorTable::ColorTable(const ColorTable& ct) : abs_scale(ct.abs_scale),
00058 table_size(ct.table_size) {
00059 if( ct.remap_table ) {
00060 remap_table = (WORD *)mem_add(table_size * (2*abs_scale+1) * sizeof(WORD) );
00061 memcpy(remap_table, ct.remap_table, table_size * (2*abs_scale+1) * sizeof(WORD) );
00062 remap_table_array = (WORD **)mem_add(sizeof(WORD *) * (2*abs_scale+1) );
00063 create_table_array();
00064 }
00065 else {
00066 remap_table = NULL;
00067 remap_table_array = NULL;
00068 }
00069 }
00070
00071
00072
00073
00074 ColorTable::~ColorTable() {
00075 deinit();
00076 }
00077
00078
00079
00080
00081 void ColorTable::init() {
00082 deinit();
00083 abs_scale = 0;
00084 }
00085
00086
00087
00088
00089 void ColorTable::init(int absScale, int tableSize, WORD *customTable) {
00090 deinit();
00091
00092 abs_scale = absScale;
00093 table_size = table_size;
00094 remap_table = (WORD *)mem_add(table_size * (2*absScale+1) * sizeof(WORD) );
00095 memcpy(remap_table, customTable, tableSize * (2*absScale+1) * sizeof(WORD) );
00096 remap_table_array = (WORD **)mem_add(sizeof(WORD *) * (2*absScale+1) );
00097 create_table_array();
00098 }
00099
00100
00101
00102
00103 void ColorTable::deinit() {
00104 if( remap_table ) {
00105 mem_del( remap_table );
00106 remap_table = NULL;
00107 }
00108 if( remap_table_array) {
00109 mem_del( remap_table_array);
00110 remap_table_array = NULL;
00111 }
00112 }
00113
00114
00115
00116
00117 ColorTable& ColorTable::operator=(const ColorTable& ct) {
00118 deinit();
00119
00120 abs_scale = ct.abs_scale;
00121 table_size= ct.table_size;
00122
00123 if( ct.remap_table ) {
00124 remap_table = (WORD *)mem_add(table_size * (2*abs_scale+1) );
00125 memcpy(remap_table, ct.remap_table, table_size * (2*abs_scale+1) * sizeof(WORD) );
00126 remap_table_array = (WORD **)mem_add(sizeof(WORD *) * (2*abs_scale+1) );
00127 create_table_array();
00128 }
00129 else {
00130 remap_table = NULL;
00131 remap_table_array = NULL;
00132 }
00133
00134 return *this;
00135 }
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 void ColorTable::generate_table(int absScale, PalDesc & palD, RGBColor (*fp)(RGBColor, int, int)) {
00154 int palSize = palD.pal_size;
00155
00156 err_when(absScale < 0 || palD.reserved_count < 0 || palD.pal == NULL);
00157 err_when(palSize > MAX_COLOUR_TABLE_SIZE);
00158 deinit();
00159
00160 abs_scale = absScale;
00161 table_size = palSize;
00162 WORD *remapEntry = remap_table = (WORD *)mem_add(table_size * (2*absScale+1) * sizeof(WORD) );
00163 remap_table_array = (WORD **)mem_add(sizeof(WORD *) * (2*absScale+1) );
00164
00165 int scale, c;
00166
00167
00168 for( scale = -absScale; scale <= absScale; ++scale) {
00169 for( c=0; c < palSize; ++c, ++remapEntry) {
00170 RGBColor rgb = (*fp)(palD.get_rgb(c), scale, absScale);
00171 *remapEntry = vga.make_pixel(&rgb);
00172 }
00173 }
00174
00175 create_table_array();
00176 }
00177
00178
00179
00180
00181
00182 void ColorTable::generate_table_fast (int absScale, PalDesc &palD, RGBColor (*fp)(RGBColor, int, int)) {
00183 int palSize = palD.pal_size;
00184
00185 err_when(absScale < 0 || palD.reserved_count < 0 || palD.pal == NULL);
00186 err_when(palSize > MAX_COLOUR_TABLE_SIZE);
00187 deinit();
00188
00189 abs_scale = absScale;
00190 table_size = palSize;
00191 WORD *remapEntry = remap_table = (WORD *)mem_add(table_size * (2*absScale+1) * sizeof(WORD) );
00192 remap_table_array = (WORD **)mem_add(sizeof(WORD *) * (2*absScale+1) );
00193
00194 int scale, c;
00195
00196
00197 for( scale = -absScale; scale <= absScale; ++scale) {
00198 for( c=0; c < palSize; ++c, ++remapEntry) {
00199 RGBColor rgb = (*fp)(palD.get_rgb(c), scale, absScale);
00200 *remapEntry = vga.make_pixel(&rgb);
00201 }
00202 }
00203
00204 create_table_array();
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 void ColorTable::generate_table(PalDesc &sPalD, PalDesc &palD) {
00221 int sPalSize = sPalD.pal_size, palSize = palD.pal_size;
00222
00223 err_when(sPalD.pal == NULL || sPalSize <= 0 || sPalD.reserved_count < 0);
00224 err_when(palD.pal == NULL || palSize <= 0 || palD.reserved_count < 0);
00225 err_when(palSize > MAX_COLOUR_TABLE_SIZE || sPalSize > MAX_COLOUR_TABLE_SIZE);
00226 deinit();
00227
00228 abs_scale = 0;
00229 table_size = sPalSize;
00230 WORD *remapEntry = remap_table = (WORD *)mem_add(sPalSize);
00231 remap_table_array = (WORD **)mem_add(sizeof(WORD *));
00232
00233 int sReservedIndex = 0;
00234 for(int c=0; c < sPalSize; ++c, ++remapEntry) {
00235 *remapEntry = c;
00236
00237
00238 if( sPalD.is_reserved(c, sReservedIndex))
00239 continue;
00240
00241 RGBColor rgb = sPalD.get_rgb(c);
00242
00243
00244 int cc, dist[NEAREST_COLOR], thisDiff;
00245 BYTE closeColor[NEAREST_COLOR];
00246
00247 for( cc = 0; cc < NEAREST_COLOR; ++cc ) {
00248 closeColor[cc] = c;
00249 dist[cc] = 3*0xff*0xff+1;
00250 }
00251 int dReservedIndex = 0;
00252 for( int d=0; d < palSize; ++d) {
00253
00254 if( palD.is_reserved(d, dReservedIndex) )
00255 continue;
00256
00257
00258 thisDiff = color_dist(rgb, palD.get_rgb(d));
00259
00260 if( thisDiff < dist[NEAREST_COLOR-1]) {
00261 BYTE d1 = (BYTE) d;
00262 for( cc = 0; cc < NEAREST_COLOR; ++cc ) {
00263 if( thisDiff < dist[cc] ) {
00264
00265
00266 int tempd;
00267 BYTE tempc;
00268 tempd = dist[cc];
00269 dist[cc] = thisDiff;
00270 thisDiff = tempd;
00271
00272 tempc = closeColor[cc];
00273 closeColor[cc] = d1;
00274 d1 = tempc;
00275 }
00276 }
00277 }
00278 }
00279
00280
00281 d = closeColor[0];
00282 *remapEntry = d;
00283 int minDiff = color_dist_hsv(rgb, palD.get_rgb(d));
00284 for( cc = 1; cc < NEAREST_COLOR; ++cc) {
00285 d = closeColor[cc];
00286 thisDiff = color_dist_hsv(rgb, palD.get_rgb(d));
00287 if( thisDiff < minDiff ) {
00288 minDiff = thisDiff;
00289 *remapEntry = d;
00290 }
00291 }
00292 }
00293
00294 create_table_array();
00295 }
00296
00297
00298
00299
00300 WORD *ColorTable::get_table(int scale) {
00301 err_when( !remap_table );
00302 err_when( scale < -abs_scale || scale > abs_scale);
00303 return remap_table + table_size * (scale + abs_scale);
00304 }
00305
00306
00307
00308
00309 void ColorTable::create_table_array() {
00310 err_when( !remap_table );
00311 for( int j = 0; j < 2*abs_scale+1; ++j) {
00312 remap_table_array[j] = remap_table + table_size * j;
00313 }
00314 }
00315
00316
00317
00318
00319 RGBColor ColorTable::bright_func(RGBColor c, int scale, int absScale) {
00320 RGBColor ans;
00321 if( scale < 0) {
00322 double factor = sqrt(double(absScale + scale) / absScale);
00323 ans.red = BYTE(c.red * factor);
00324 ans.green = BYTE(c.green * factor);
00325 ans.blue = BYTE(c.blue * factor);
00326 }
00327 else {
00328 ans.red = c.red + (MAX_COLOUR - c.red) * scale / absScale;
00329 ans.green = c.green + (MAX_COLOUR - c.green) * scale / absScale;
00330 ans.blue = c.blue + (MAX_COLOUR - c.blue) * scale / absScale;
00331 }
00332 return ans;
00333 }
00334
00335
00336
00337
00338 void ColorTable::patch_table(BYTE from, WORD to) {
00339 err_when(from >= table_size);
00340 for(int s = -abs_scale; s <= abs_scale; ++s) {
00341 get_table(s)[from] = to;
00342 }
00343 }
00344
00345
00346
00347
00348 int ColorTable::color_dist(RGBColor c1, RGBColor c2) {
00349 return sq((int)c2.red-c1.red) + sq((int)c2.green-c1.green) + sq((int)c2.blue-c1.blue);
00350 }
00351
00352
00353
00354
00355 int ColorTable::color_dist_hsv(RGBColor c1, RGBColor c2) {
00356
00357
00358
00359
00360 HSVColor hsv1(rgb2hsv(c1));
00361 HSVColor hsv2(rgb2hsv(c2));;
00362
00363 double dx = hsv2.saturation * cos(hsv2.hue * M_PI / 3.0) - hsv1.saturation * cos(hsv1.hue * M_PI / 3.0);
00364 double dy = hsv2.saturation * sin(hsv2.hue * M_PI / 3.0) - hsv1.saturation * sin(hsv1.hue * M_PI / 3.0);
00365 double dv = hsv2.brightness - hsv1.brightness;
00366
00367 return int(10000 * ( dx*dx + dy*dy + dv*dv*BRIGHTNESS_WEIGHTING ));
00368 }
00369
00370
00371
00372
00373 HSVColor ColorTable::rgb2hsv(RGBColor &rgb) {
00374 if( rgb.red == rgb.green && rgb.red == rgb.blue) {
00375 return HSVColor(1.0, 0.0, rgb.red / 255.0);
00376 }
00377
00378
00379 if( rgb.red <= rgb.green && rgb.red <= rgb.blue) {
00380 if( rgb.green >= rgb.blue ) {
00381
00382 return HSVColor( 2.0 + (double) rgb.blue/ rgb.green,
00383 rgb.blue != 0 ? 1.0 - (double) rgb.red / rgb.blue : 1.0,
00384 rgb.green / 255.0);
00385 }
00386 else {
00387
00388 return HSVColor( 4.0 - (double) rgb.green / rgb.blue,
00389 rgb.green != 0 ? 1.0 - (double) rgb.red/ rgb.green : 1.0,
00390 rgb.blue / 255.0);
00391 }
00392 }
00393 else if( rgb.green <= rgb.red && rgb.green <= rgb.blue) {
00394 if( rgb.red >= rgb.blue) {
00395
00396 return HSVColor( 6.0 - (double)rgb.blue/rgb.red,
00397 rgb.blue!=0 ? 1.0 - (double)rgb.green/rgb.blue: 1.0,
00398 rgb.red / 255.0);
00399 }
00400 else {
00401
00402 return HSVColor( 4.0 + (double)rgb.red/rgb.blue,
00403 rgb.red!=0 ? 1.0 - (double)rgb.green/rgb.red: 1.0,
00404 rgb.blue / 255.0);
00405 }
00406 }
00407 else if( rgb.blue <= rgb.red && rgb.blue <= rgb.green) {
00408 if( rgb.red >= rgb.green) {
00409
00410 return HSVColor( (double)rgb.green/rgb.red,
00411 rgb.green!=0 ? 1.0 - (double)rgb.blue/rgb.green: 1.0,
00412 rgb.red / 255.0);
00413 }
00414 else {
00415
00416 return HSVColor( 2.0 - (double)rgb.red/rgb.green,
00417 rgb.red!=0 ? 1.0 - (double)rgb.blue/rgb.red: 1.0,
00418 rgb.green / 255.0);
00419 }
00420 }
00421 else {
00422 err_when(1);
00423 return HSVColor( 1.0, 0.0, rgb.red / 255.0);
00424 }
00425 }
00426
00427
00428
00429
00430 RGBColor ColorTable::hsv2rgb(HSVColor &hsv) {
00431 while( hsv.hue < 0.0)
00432 hsv.hue += 6.0;
00433 while(hsv.hue >= 6.0)
00434 hsv.hue -= 6.0;
00435 double p = hsv.brightness * 255.0;
00436 err_when( p >= 256.0);
00437
00438 RGBColor ans;
00439
00440 if( hsv.hue < 1.0) {
00441
00442 ans.red = BYTE(p);
00443 p *= hsv.hue;
00444 ans.green = BYTE(p);
00445 p *= 1.0 - hsv.saturation;
00446 ans.blue = BYTE(p);
00447 }
00448 else if( hsv.hue < 2.0) {
00449
00450 ans.green = BYTE(p);
00451 p *= 2.0 - hsv.hue;
00452 ans.red = BYTE(p);
00453 p *= 1.0 - hsv.saturation;
00454 ans.blue = BYTE(p);
00455 }
00456 else if( hsv.hue < 3.0) {
00457
00458 ans.green = BYTE(p);
00459 p *= hsv.hue - 2.0;
00460 ans.blue = BYTE(p);
00461 p *= 1.0 - hsv.saturation;
00462 ans.red = BYTE(p);
00463 }
00464 else if( hsv.hue < 4.0) {
00465
00466 ans.blue = BYTE(p);
00467 p *= 4.0 - hsv.hue;
00468 ans.green = BYTE(p);
00469 p *= 1.0 - hsv.saturation;
00470 ans.red = BYTE(p);
00471 }
00472 else if( hsv.hue < 5.0) {
00473
00474 ans.blue = BYTE(p);
00475 p *= hsv.hue - 4.0;
00476 ans.red = BYTE(p);
00477 p *= 1.0 - hsv.saturation;
00478 ans.green = BYTE(p);
00479 }
00480 else if( hsv.hue < 6.0) {
00481
00482 ans.red = BYTE(p);
00483 p *= 6.0 - hsv.hue;
00484 ans.blue = BYTE(p);
00485 p *= 1.0 - hsv.saturation;
00486 ans.green = BYTE(p);
00487 }
00488
00489 return ans;
00490 }
00491
00492
00493
00494
00495 int ColorTable::write_file(File *f) {
00496 return( f->file_put_long(abs_scale) && f->file_put_long(table_size)
00497 && f->file_write(remap_table, table_size * (2*abs_scale+1) * remap_table[0] ) );
00498 }
00499
00500
00501
00502
00503 int ColorTable::read_file(File *f) {
00504 deinit();
00505 abs_scale = f->file_get_long();
00506 table_size = f->file_get_long();
00507
00508 remap_table = (WORD *)mem_add(table_size * (2*abs_scale+1) * remap_table[0] );
00509 if(! f->file_read(remap_table, table_size * (2*abs_scale+1) * remap_table[0]) ) {
00510 mem_del(remap_table);
00511 remap_table = 0;
00512 return 0;
00513 }
00514 remap_table_array = (WORD **)mem_add(sizeof(remap_table_array[0]) * (2*abs_scale+1) );
00515 create_table_array();
00516 return 1;
00517 }
00518
00519