1 /* Copyright (C) 1992 Nathan Sidwell */ 2 /* RCS $Id: scram.c,v 4.7 1993/11/09 16:27:47 nathan Stable $ */ 3 /*{{{ about me*/ 4 /* a simple program to compress the monochrome, mask & color sprites 5 * together into one set of planes. This is done by color separation 6 * overlay. Not particularly well written or documented, but then 7 * its not supposed to be a general tool. 8 * If anybody wants to make it more general, they are welcome 9 * args 10 * -n invert noswap 11 * +n add edge to noswap 12 * -s swap is ~noswap 13 * +s swap is same as noswap 14 * -m mask is solid (and therefore not present) 15 * -c insert noswap as first color plane 16 * -0 no monochrome 17 * -[1-9] no monochrome, set color planes 18 */ 19 /*}}}*/ 20 #include "ansiknr.h" 21 /*{{{ includes*/ 22 #include <assert.h> 23 #include <stdio.h> 24 #include <stddef.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <ctype.h> 28 #ifdef TRANSPUTER 29 #include <iocntrl.h> 30 #else 31 #include <unistd.h> 32 #endif /* TRANSPUTER */ 33 /*}}}*/ 34 #define SUFFIXMONO ".bw" 35 #define SUFFIXCOLOR ".rgb" 36 #define MAX_PLANES 5 37 #define MAX_COLORS (1 << MAX_PLANES) 38 /*{{{ typedef struct Coord*/ 39 typedef struct Coord 40 /* general coordinate store */ 41 { 42 int x; 43 int y; 44 } COORD; 45 /*}}}*/ 46 /*{{{ typedef struct Size*/ 47 typedef struct Size 48 /* general size store */ 49 { 50 unsigned x; 51 unsigned y; 52 } SIZE; 53 /*}}}*/ 54 /*{{{ typedef struct Bitmap*/ 55 typedef struct Bitmap 56 { 57 char *bits; /* bit pattern */ 58 SIZE size; /* size in pixels */ 59 COORD hot; /* hot spot */ 60 unsigned scan; /* scan line */ 61 } BITMAP; 62 /*}}}*/ 63 static BITMAP source; 64 static BITMAP current; 65 static BITMAP scratch; 66 static SIZE size; 67 static BITMAP color_bitmap; 68 static int color_planes = 0; 69 static unsigned long mono_noswap; 70 static unsigned long mono_swap; 71 static BITMAP bitmaps[MAX_COLORS]; 72 static char *noswap_colors[MAX_COLORS]; 73 static char *swap_colors[MAX_COLORS]; 74 static int colors; 75 static char *filename; 76 static int error = 0; 77 #define GC_COPY 0 78 #define GC_AND 1 79 #define GC_XOR 2 80 #define GC_OR 3 81 #define GC_CLEAR 4 82 /*{{{ void *smalloc(size)*/ 83 static VOID *smalloc 84 FUNCARG((size), 85 size_t size 86 ) 87 { 88 VOID *ptr; 89 90 ptr = malloc(size); 91 if(!ptr) 92 { 93 fprintf(stderr, "Malloc failed\n"); 94 exit(1); 95 } 96 return ptr; 97 } 98 /*}}}*/ 99 /*{{{ unsigned read_bitmap(name, bitmap)*/ 100 static unsigned read_bitmap 101 FUNCARG((name, bitmap), 102 char CONST *name /* name of file */ 103 ARGSEP BITMAP *bitmap /* bitmap ptr */ 104 ) 105 /* state 0 new block 106 * state 1 comment 107 * state 2 { 108 * state 3 reading 109 * state 4 done 110 */ 111 { 112 unsigned error; 113 FILE *stream; 114 unsigned state; 115 char line[128]; 116 SIZE place; 117 unsigned extra; 118 119 stream = fopen(name, "r"); 120 if(!stream) 121 return 1; 122 error = 0; 123 extra = 0; 124 bitmap->size.x = bitmap->size.y = bitmap->scan = 0; 125 bitmap->hot.x = bitmap->hot.y = -1; 126 bitmap->bits = NULL; 127 state = 0; 128 while(fgets(line, sizeof(line), stream)) 129 { 130 char *ptr; 131 132 ptr = line; 133 while(*ptr == ' ' || *ptr == '\t') 134 ptr++; 135 if(*ptr == '\n') 136 continue; 137 /*{{{ new state?*/ 138 if(state == 0) 139 { 140 if(ptr[0] == '/' && ptr[1] == '*') 141 { 142 ptr += 2; 143 state = 1; 144 } 145 else if(!strncmp(ptr, "#define", 7)) 146 /*{{{ define*/ 147 { 148 /* some poor saps don't have offsetof */ 149 /*{{{ static char CONST *table[] =*/ 150 static char CONST *table[] = 151 { 152 "width", "height", "x_hot", "y_hot" 153 }; 154 /*}}}*/ 155 size_t length; 156 unsigned ix; 157 char CONST **tptr; 158 159 ptr += 8; 160 while(*ptr == ' ' || *ptr == '\t') 161 ptr++; 162 for(length = 0; ptr[length] != ' ' && ptr[length] != '\t' && 163 ptr[length]; length++) 164 /* EMPTY */; 165 for(tptr = table, ix = 4; ix--; tptr++) 166 { 167 size_t len; 168 169 len = strlen(*tptr); 170 if(length >= len && !strncmp(&ptr[length - len], *tptr, len)) 171 { 172 int value; 173 174 ptr += length; 175 while(*ptr == ' ' || *ptr == '\t') 176 ptr++; 177 value = strtol(ptr, &ptr, 0); 178 switch(ix) 179 { 180 case 3: 181 bitmap->size.x = value; 182 break; 183 case 2: 184 bitmap->size.y = value; 185 break; 186 case 1: 187 bitmap->hot.x = value; 188 break; 189 case 0: 190 bitmap->hot.y = value; 191 break; 192 } 193 bitmap->scan = (bitmap->size.x + 7) / 8; 194 break; 195 } 196 } 197 } 198 /*}}}*/ 199 else 200 { 201 char *bptr; 202 203 bptr = strchr(ptr, '['); 204 if(bptr && bptr - ptr > 3 && !strncmp(bptr - 4, "bits", 4) && 205 bptr[1] == ']') 206 { 207 state = 2; 208 ptr = bptr; 209 } 210 } 211 } 212 /*}}}*/ 213 /*{{{ in comment?*/ 214 if(state == 1) 215 { 216 while(*ptr && state) 217 { 218 while(*ptr && *ptr != '*') 219 ptr++; 220 if(*ptr) 221 { 222 if(ptr[1] == '/') 223 { 224 ptr += 2; 225 state = 0; 226 break; 227 } 228 else 229 ptr++; 230 } 231 } 232 } 233 /*}}}*/ 234 /*{{{ {?*/ 235 if(state == 2) 236 { 237 ptr = strchr(ptr, '{'); 238 if(ptr) 239 { 240 int count; 241 242 state = 3; 243 ptr++; 244 if(!bitmap->size.x || !bitmap->size.y) 245 { 246 error = 1; 247 break; 248 } 249 count = bitmap->scan * bitmap->size.y; 250 bitmap->bits = smalloc(count); 251 place.x = place.y = 0; 252 for(; count--;) 253 bitmap->bits[count] = 0; 254 } 255 } 256 /*}}}*/ 257 /*{{{ reading?*/ 258 if(state == 3) 259 { 260 while(state != 4 && *ptr && *ptr != '\n') 261 { 262 while(*ptr == ' ' || *ptr == '\t') 263 ptr++; 264 if(*ptr == '}') 265 state = 4; 266 else 267 /*{{{ item*/ 268 { 269 unsigned val; 270 271 val = strtol(ptr, &ptr, 0); 272 if(*ptr == ',') 273 ptr++; 274 if(place.y != bitmap->size.y) 275 { 276 bitmap->bits[place.y * bitmap->scan + place.x] = val; 277 place.x++; 278 if(place.x == bitmap->scan) 279 { 280 place.x = 0; 281 place.y++; 282 } 283 } 284 else if(!extra) 285 { 286 fprintf(stderr, "Warning: Extra on end of bitmap '%s'\n", 287 name); 288 extra = 1; 289 } 290 } 291 /*}}}*/ 292 } 293 } 294 /*}}}*/ 295 } 296 error |= ferror(stream) || !bitmap->bits; 297 fclose(stream); 298 return error; 299 } 300 /*}}}*/ 301 /*{{{ void malloc_bitmap(bitmap, x, y)*/ 302 static VOIDFUNC malloc_bitmap 303 FUNCARG((bitmap, x, y), 304 BITMAP *bitmap 305 ARGSEP unsigned x 306 ARGSEP unsigned y 307 ) 308 { 309 unsigned ix; 310 311 bitmap->size.x = x; 312 bitmap->size.y = y; 313 bitmap->hot.x = bitmap->hot.y = -1; 314 bitmap->scan = (x + 7) / 8; 315 ix = bitmap->scan * y; 316 bitmap->bits = smalloc(ix); 317 while(ix--) 318 bitmap->bits[ix] = 0; 319 return; 320 } 321 /*}}}*/ 322 /*{{{ unsigned is_blank(bitmap)*/ 323 static unsigned is_blank 324 FUNCARG((bitmap), 325 BITMAP *bitmap 326 ) 327 { 328 unsigned ix; 329 unsigned bits; 330 331 bits = 0; 332 for(ix = bitmap->scan * bitmap->size.y; ix--;) 333 bits |= bitmap->bits[ix] & 0xFF; 334 return !bits; 335 } 336 /*}}}*/ 337 /*{{{ void fill_area(bitmap, gc, x, y, w, h)*/ 338 static VOIDFUNC fill_area 339 FUNCARG((bitmap, gc, x, y, w, h), 340 BITMAP *bitmap 341 ARGSEP unsigned gc 342 ARGSEP int x 343 ARGSEP int y 344 ARGSEP unsigned w 345 ARGSEP unsigned h 346 ) 347 { 348 unsigned ix; 349 unsigned iy; 350 int count; 351 352 assert(!(x & 7) && w && h); 353 assert(x >= 0 && y >= 0 && x + w <= bitmap->size.x && 354 y + h <= bitmap->size.y); 355 for(iy = 0; h--; iy++) 356 { 357 char *bptr; 358 359 bptr = &bitmap->bits[iy * bitmap->scan]; 360 for(ix = x / 8, count = w; count > 0; ix++, count -= 8) 361 { 362 unsigned mask; 363 364 mask = count > 7 ? 0xFF : 0xFF >> (8 - count); 365 switch(gc) 366 { 367 case GC_COPY: 368 bptr[ix] |= mask; 369 break; 370 case GC_CLEAR: 371 bptr[ix] &= ~mask; 372 break; 373 case GC_XOR: 374 bptr[ix] ^= mask; 375 break; 376 case GC_OR: 377 bptr[ix] |= mask; 378 break; 379 } 380 } 381 } 382 return; 383 } 384 /*}}}*/ 385 /*{{{ void copy_area(source, dest, gc, sx, sy, w, h, dx, dy)*/ 386 static VOIDFUNC copy_area 387 FUNCARG((source, dest, gc, sx, sy, w, h, dx, dy), 388 BITMAP *source 389 ARGSEP BITMAP *dest 390 ARGSEP unsigned gc 391 ARGSEP int sx 392 ARGSEP int sy 393 ARGSEP unsigned w 394 ARGSEP unsigned h 395 ARGSEP int dx 396 ARGSEP int dy 397 ) 398 { 399 unsigned ix; 400 unsigned iy; 401 char *sptr; 402 char *dptr; 403 char line[16]; 404 int count; 405 406 assert(sx >= 0 && sy >= 0 && sx + w <= source->size.x && 407 sy + h <= source->size.y); 408 assert(dx >= 0 && dy >= 0 && dx + w <= dest->size.x && 409 dy + h <= dest->size.y); 410 assert(w < sizeof(line) * 8); 411 for(iy = h; iy--;) 412 { 413 sptr = &source->bits[(sy + iy) * source->scan + sx / 8]; 414 /*{{{ set source pointer*/ 415 if(sx & 7) 416 { 417 for(ix = 0, count = w; count > 0; ix++, count -= 8) 418 { 419 line[ix] = (sptr[ix] & 0xFF) >> (sx & 7); 420 if(ix) 421 line[ix - 1] |= (sptr[ix] & 0xFF) << (8 - (sx & 7)); 422 else 423 count += (sx & 7); 424 } 425 sptr = line; 426 } 427 /*}}}*/ 428 dptr = &dest->bits[(dy + iy) * dest->scan + dx / 8]; 429 for(ix = 0, count = w; count > 0; ix++) 430 { 431 unsigned mask; 432 unsigned shift; 433 434 shift = dx & 7; 435 mask = (0xFF << shift) & 0xFF; 436 if(count < 8 - shift) 437 mask &= 0xFF >> ((8 - shift) - count); 438 /*{{{ first half*/ 439 switch(gc) 440 { 441 case GC_COPY: 442 dptr[ix] &= ~mask; 443 dptr[ix] |= ((sptr[ix] & 0xFF) << shift) & mask; 444 break; 445 case GC_AND: 446 dptr[ix] &= (((sptr[ix] & 0xFF) << shift) & mask) | ~mask; 447 break; 448 case GC_OR: 449 dptr[ix] |= ((sptr[ix] & 0xFF) << shift) & mask; 450 break; 451 case GC_XOR: 452 dptr[ix] ^= ((sptr[ix] & 0xFF) << shift) & mask; 453 break; 454 } 455 /*}}}*/ 456 count -= 8 - shift; 457 if(shift && count > 0) 458 { 459 mask = count >= 8 ? 0xFF : 0xFF >> (8 - count); 460 mask >>= 8 - shift; 461 /*{{{ second half*/ 462 switch(gc) 463 { 464 case GC_COPY: 465 dptr[ix + 1] &= ~mask; 466 dptr[ix + 1] |= ((sptr[ix] & 0xFF) >> (8 - shift)) & mask; 467 break; 468 case GC_AND: 469 dptr[ix + 1] &= (((sptr[ix] & 0xFF) >> (8 - shift)) & 470 mask) | ~mask; 471 break; 472 case GC_OR: 473 dptr[ix + 1] |= ((sptr[ix] & 0xFF) >> (8 - shift)) & mask; 474 break; 475 case GC_XOR: 476 dptr[ix + 1] ^= ((sptr[ix] & 0xFF) >> (8 - shift)) & mask; 477 break; 478 } 479 /*}}}*/ 480 count -= shift; 481 } 482 } 483 } 484 return; 485 } 486 /*}}}*/ 487 /*{{{ void draw_rectangle(bitmap, gc, x, y, w, h)*/ 488 static VOIDFUNC draw_rectangle 489 FUNCARG((bitmap, gc, x, y, w, h), 490 BITMAP *bitmap 491 ARGSEP unsigned gc 492 ARGSEP int x 493 ARGSEP int y 494 ARGSEP unsigned w 495 ARGSEP unsigned h 496 ) 497 { 498 unsigned ix; 499 unsigned iy; 500 int count; 501 char *bptr; 502 unsigned mask; 503 504 assert(w & h && !(x & 7)); 505 assert(x >= 0 && y >= 0 && x + w < bitmap->size.x && y + h < bitmap->size.y); 506 bptr = &bitmap->bits[y * bitmap->scan]; 507 /*{{{ top and bottom edges*/ 508 for(ix = x / 8, count = w + 1; count > 0; ix++, count -= 8) 509 { 510 mask = count > 7 ? 0xFF : 0xFF >> (8 - count); 511 /*{{{ edge*/ 512 switch(gc) 513 { 514 case GC_COPY: 515 case GC_OR: 516 bptr[ix] |= mask; 517 bptr[ix + h * bitmap->scan] |= mask; 518 break; 519 case GC_CLEAR: 520 bptr[ix] &= ~mask; 521 bptr[ix + h * bitmap->scan] &= ~mask; 522 break; 523 case GC_XOR: 524 bptr[ix] ^= mask; 525 bptr[ix + h * bitmap->scan] ^= mask; 526 break; 527 case GC_AND: 528 break; 529 } 530 /*}}}*/ 531 } 532 /*}}}*/ 533 /*{{{ left and right edges*/ 534 for(iy = y + 1, count = h - 2; count > 0; iy++, count--) 535 { 536 bptr = &bitmap->bits[iy * bitmap->scan + x / 8]; 537 mask = 1 << (x & 7); 538 /*{{{ left edge*/ 539 switch(gc) 540 { 541 case GC_OR: 542 case GC_COPY: 543 *bptr |= mask; 544 break; 545 case GC_XOR: 546 *bptr ^= mask; 547 break; 548 case GC_AND: 549 break; 550 case GC_CLEAR: 551 *bptr &= ~mask; 552 break; 553 } 554 /*}}}*/ 555 bptr = &bitmap->bits[iy * bitmap->scan + (x + w) / 8]; 556 mask = 1 << ((x + w) & 7); 557 /*{{{ right edge*/ 558 switch(gc) 559 { 560 case GC_OR: 561 case GC_COPY: 562 *bptr |= mask; 563 break; 564 case GC_XOR: 565 *bptr ^= mask; 566 break; 567 case GC_AND: 568 break; 569 case GC_CLEAR: 570 *bptr &= ~mask; 571 break; 572 } 573 /*}}}*/ 574 } 575 /*}}}*/ 576 return; 577 } 578 /*}}}*/ 579 /*{{{ void make_color_pixmaps(char **name, BITMAP *bitmaps, char CONST *title)*/ 580 static VOIDFUNC make_color_pixmaps 581 FUNCARG((name, bitmaps, title), 582 char **name 583 ARGSEP BITMAP *bitmaps 584 ARGSEP char CONST *title 585 ) 586 { 587 unsigned ix; 588 589 for(ix = 0; name[ix]; ix++) 590 if(ix >= (1 << color_planes)) 591 fill_area(&bitmaps[ix], GC_CLEAR, 0, 0, size.x, size.y); 592 else 593 { 594 unsigned bit; 595 596 copy_area(&source, &bitmaps[ix], GC_COPY, 0, 0, size.x, size.y, 0, 0); 597 for(bit = 0; bit != color_planes; bit++) 598 if((1 << bit) & ix) 599 { 600 copy_area(&color_bitmap, &bitmaps[ix], GC_AND, 601 0, (int)(size.y * bit), size.x, size.y, 0, 0); 602 } 603 else 604 { 605 copy_area(&color_bitmap, ¤t, GC_COPY, 606 0, (int)(size.y * bit), size.x, size.y, 0, 0); 607 fill_area(¤t, GC_XOR, 0, 0, size.x, size.y); 608 copy_area(¤t, &bitmaps[ix], GC_AND, 609 0, 0, size.x, size.y, 0, 0); 610 } 611 } 612 copy_area(&source, ¤t, GC_COPY, 0, 0, size.x, size.y, 0, 0); 613 for(ix = 0; name[ix]; ix++) 614 copy_area(&bitmaps[ix], ¤t, GC_XOR, 0, 0, size.x, size.y, 0, 0); 615 if(!is_blank(¤t)) 616 { 617 unsigned x, y; 618 619 error = 1; 620 fprintf(stderr, "%s: Error on %s at", filename, title); 621 for(y = 0; y != size.y; y++) 622 for(x = 0; x != size.x; x++) 623 if(current.bits[y * current.scan + x / 8] & 1 << (x & 7)) 624 fprintf(stderr, " (%d, %d)", x, y); 625 fprintf(stderr, "\n"); 626 } 627 return; 628 } 629 /*}}}*/ 630 /*{{{ void add_edge(unsigned ix, BITMAP *bitmaps)*/ 631 static VOIDFUNC add_edge 632 FUNCARG((ix, bitmaps), 633 unsigned ix 634 ARGSEP BITMAP *bitmaps 635 ) 636 { 637 copy_area(&source, ¤t, GC_COPY, 0, 0, size.x, size.y, 0, 0); 638 copy_area(&source, ¤t, GC_AND, 0, 0, size.x, size.y - 1, 0, 1); 639 copy_area(&source, ¤t, GC_AND, 0, 1, size.x, size.y - 1, 0, 0); 640 copy_area(&source, ¤t, GC_AND, 0, 0, size.x - 1, size.y, 1, 0); 641 copy_area(&source, ¤t, GC_AND, 1, 0, size.x - 1, size.y, 0, 0); 642 draw_rectangle(¤t, GC_CLEAR, 0, 0, size.x - 1, size.y - 1); 643 copy_area(&source, ¤t, GC_XOR, 0, 0, size.x, size.y, 0, 0); 644 copy_area(¤t, &bitmaps[ix], GC_COPY, 0, 0, size.x, size.y, 0, 0); 645 fill_area(¤t, GC_XOR, 0, 0, size.x, size.y); 646 while(ix--) 647 copy_area(¤t, &bitmaps[ix], GC_AND, 0, 0, size.x, size.y, 0, 0); 648 return; 649 } 650 /*}}}*/ 651 /*{{{ void compress_colors(char **name, BITMAP *bitmaps, char CONST *title)*/ 652 static VOIDFUNC compress_colors 653 FUNCARG((name, bitmaps, title), 654 char **name 655 ARGSEP BITMAP *bitmaps 656 ARGSEP char CONST *title 657 ) 658 { 659 unsigned ix, j; 660 661 for(ix = 0; name[ix + 1]; ix++) 662 { 663 for(j = ix + 1; name[j]; j++) 664 if(!strcmp(name[ix], name[j])) 665 { 666 copy_area(&bitmaps[j], &bitmaps[ix], GC_OR, 667 0, 0, size.x, size.y, 0, 0); 668 fill_area(&bitmaps[j], GC_CLEAR, 0, 0, size.x, size.y); 669 name[j] = (char *)"-"; 670 } 671 } 672 for(ix = 0; name[ix]; ix++) 673 { 674 if(is_blank(&bitmaps[ix])) 675 { 676 BITMAP old; 677 678 if(strcmp(name[ix], "-")) 679 fprintf(stderr, "Warning: %s color '%s' has no pixels\n", 680 title, name[ix]); 681 memcpy(&old, &bitmaps[ix], sizeof(BITMAP)); 682 for(j = ix; name[j + 1]; j++) 683 { 684 name[j] = name[j+1]; 685 memcpy(&bitmaps[j], &bitmaps[j+1], sizeof(BITMAP)); 686 } 687 name[j] = NULL; 688 memcpy(&bitmaps[j], &old, sizeof(BITMAP)); 689 ix--; 690 } 691 else if(!strcmp(name[ix], "-")) 692 { 693 unsigned x, y; 694 695 error = 1; 696 fprintf(stderr, "%s: Void color on %s at", filename, title); 697 for(y = 0; y != size.y; y++) 698 for(x = 0; x != size.x; x++) 699 if(bitmaps[ix].bits[y * bitmaps[ix].scan + x / 8] & (1 << x & 7)) 700 fprintf(stderr, " (%d, %d)", x, y); 701 fprintf(stderr, "\n"); 702 } 703 } 704 return; 705 } 706 /*}}}*/ 707 /*{{{ void merge_mono()*/ 708 static VOIDFUNC merge_mono FUNCARGVOID 709 { 710 unsigned ix; 711 712 for(ix = 1; ix != colors; ix++) 713 { 714 if(is_blank(&source)) 715 break; 716 copy_area(&source, ¤t, GC_COPY, 0, 0, size.x, size.y, 0, 0); 717 copy_area(&bitmaps[ix], ¤t, GC_AND, 0, 0, size.x, size.y, 0, 0); 718 if(!is_blank(¤t)) 719 { 720 mono_swap |= (unsigned long)1 << ix; 721 copy_area(¤t, &scratch, GC_COPY, 722 0, 0, size.x, size.y, 0, 0); 723 copy_area(&bitmaps[ix], &scratch, GC_XOR, 724 0, 0, size.x, size.y, 0, 0); 725 if(!is_blank(&scratch)) 726 { 727 copy_area(&bitmaps[ix], &bitmaps[colors], GC_COPY, 728 0, 0, size.x, size.y, 0, 0); 729 copy_area(¤t, &bitmaps[colors], GC_XOR, 730 0, 0, size.x, size.y, 0, 0); 731 noswap_colors[colors] = noswap_colors[ix]; 732 swap_colors[colors] = swap_colors[ix]; 733 mono_noswap = mono_noswap | 734 (((mono_noswap >> ix) & 1) << colors); 735 copy_area(¤t, &bitmaps[ix], GC_COPY, 736 0, 0, size.x, size.y, 0, 0); 737 colors++; 738 } 739 copy_area(&bitmaps[ix], &source, GC_XOR, 740 0, 0, size.x, size.y, 0, 0); 741 } 742 } 743 return; 744 } 745 /*}}}*/ 746 /*{{{ int main(int argc, char **argv)*/ 747 int main 748 FUNCARG((argc, argv), 749 int argc 750 ARGSEP char **argv 751 ) 752 { 753 BITMAP mono_bitmap; 754 BITMAP mono_source; 755 int planes; 756 char *edge = NULL; 757 char *noswap[MAX_COLORS + 1]; 758 char *swap[MAX_COLORS + 1]; 759 BITMAP noswap_bitmaps[MAX_COLORS]; 760 BITMAP swap_bitmaps[MAX_COLORS]; 761 int status; 762 unsigned ix; 763 BITMAP output_bitmap; 764 unsigned noswap_edge = 0; 765 unsigned noswap_invert = 0; 766 unsigned swap_invert = 0; 767 unsigned swap_copy = 0; 768 unsigned no_mono = 0; 769 unsigned mono_planes; 770 unsigned color_copy = 0; 771 unsigned solid_mask = 0; 772 773 /*{{{ slurp up the arguments*/ 774 { 775 filename = argv[1]; 776 if(argc > 2) 777 { 778 argv += 2; 779 argc -= 2; 780 for(; argc; argc--, argv++) 781 { 782 if(argv[0][0] == '+') 783 { 784 if(argv[0][2]) 785 error = 1; 786 else if(argv[0][1] == 's') 787 swap_copy = 1; 788 else if(argv[0][1] == 'n') 789 noswap_edge = 1; 790 else 791 error = 1; 792 } 793 else if(argv[0][0] == '-') 794 { 795 if(!argv[0][1]) 796 break; 797 else if(argv[0][2]) 798 error = 1; 799 else if(argv[0][1] == 's') 800 swap_invert = 1; 801 else if(argv[0][1] == 'n') 802 noswap_invert = 1; 803 else if(argv[0][1] == 'c') 804 color_copy = 1; 805 else if(argv[0][1] == 'm') 806 solid_mask = 1; 807 else if(argv[0][1] == '0') 808 no_mono = 1; 809 else if(isdigit(argv[0][1])) 810 { 811 no_mono = 1; 812 color_planes = argv[0][1] - '0'; 813 } 814 else 815 error = 1; 816 } 817 else 818 break; 819 if(error) 820 { 821 fprintf(stderr, "'%s' not a flag\n", argv[0]); 822 argc = 0; 823 break; 824 } 825 } 826 } 827 for(ix = 0; argc && strcmp(*argv, "+"); argc--, argv++) 828 noswap[ix++] = *argv; 829 if(argc) 830 argv++, argc--; 831 while(ix != MAX_COLORS + 1) 832 noswap[ix++] = NULL; 833 for(ix = 0; argc && strcmp(*argv, "+"); argc--, argv++) 834 swap[ix++] = *argv; 835 if(argc) 836 argv++, argc--; 837 while(ix != MAX_COLORS + 1) 838 swap[ix++] = NULL; 839 if(argc) 840 { 841 edge = *argv; 842 argv++, argc--; 843 } 844 if(argc || !filename || (no_mono && 845 (noswap_edge || noswap_invert || swap_invert || swap_copy))) 846 { 847 fprintf(stderr, 848 "Usage: scram <name> [-<n>|[+n][+s][-n][-s]] <noswap> + <swap> + [<edge>]\n"); 849 return 1; 850 } 851 } 852 /*}}}*/ 853 if(no_mono) 854 mono_planes = 1; 855 else 856 { 857 mono_planes = noswap_edge | noswap_invert | swap_copy | swap_invert ? 858 2 : 3; 859 if(solid_mask) 860 mono_planes--; 861 } 862 /*{{{ read files*/ 863 { 864 char *name; 865 866 name = smalloc(strlen(filename) + 7); 867 strcpy(name, filename); 868 strcat(name, SUFFIXMONO); 869 status = read_bitmap(name, &mono_source); 870 size.x = mono_source.size.x; 871 size.y = mono_source.size.y; 872 if(status || size.y % mono_planes) 873 { 874 fprintf(stderr, "Cannot read monochrome '%s'\n", name); 875 return 1; 876 } 877 size.y /= mono_planes; 878 strcpy(name, filename); 879 strcat(name, SUFFIXCOLOR); 880 status = read_bitmap(name, &color_bitmap); 881 if(status) 882 { 883 fprintf(stderr, "Cannot read colour '%s'\n", name); 884 return 1; 885 } 886 if(color_planes) 887 size.y = color_bitmap.size.y / color_planes; 888 else 889 color_planes = color_bitmap.size.y / size.y; 890 if(color_bitmap.size.y % size.y || color_bitmap.size.x != size.x) 891 { 892 fprintf(stderr, "Bitmaps are incompatible sizes\n"); 893 return 1; 894 } 895 free(name); 896 } 897 /*}}}*/ 898 /*{{{ alloc some bitmaps*/ 899 { 900 malloc_bitmap(&source, size.x, size.y); 901 malloc_bitmap(¤t, size.x, size.y); 902 malloc_bitmap(&scratch, size.x, size.y); 903 malloc_bitmap(&mono_bitmap, size.x, size.y * 2); 904 } 905 /*}}}*/ 906 /*{{{ solid mask?*/ 907 if(solid_mask) 908 { 909 BITMAP temp; 910 911 if(!no_mono) 912 mono_planes++; 913 malloc_bitmap(&temp, size.x, size.y * mono_planes); 914 copy_area(&mono_source, &temp, GC_COPY, 0, 0, 915 size.x, size.y * (mono_planes - 1), 0, size.y); 916 fill_area(&temp, GC_COPY, 0, 0, size.x, size.y); 917 memcpy(&temp.hot, &mono_source.hot, sizeof(COORD)); 918 memcpy(&mono_source, &temp, sizeof(BITMAP)); 919 } 920 /*}}}*/ 921 /*{{{ copy color?*/ 922 if(color_copy) 923 { 924 BITMAP temp; 925 926 color_planes++; 927 malloc_bitmap(&temp, size.x, size.y * color_planes); 928 copy_area(&color_bitmap, &temp, GC_COPY, 0, 0, 929 size.x, size.y * (color_planes - 1), 0, size.y); 930 copy_area(&mono_source, &temp, GC_COPY, 931 0, size.y, size.x, size.y, 0, 0); 932 memcpy(&color_bitmap, &temp, sizeof(BITMAP)); 933 } 934 /*}}}*/ 935 /*{{{ alloc a pile of bitmaps*/ 936 { 937 for(ix = 0; ix < MAX_COLORS; ix++) 938 { 939 malloc_bitmap(&bitmaps[ix], size.x, size.y); 940 fill_area(&bitmaps[ix], GC_CLEAR, 0, 0, size.x, size.y); 941 } 942 for(ix = 0; ix < MAX_COLORS; ix++) 943 { 944 malloc_bitmap(&noswap_bitmaps[ix], size.x, size.y); 945 fill_area(&noswap_bitmaps[ix], GC_CLEAR, 0, 0, size.x, size.y); 946 } 947 for(ix = 0; ix < MAX_COLORS; ix++) 948 { 949 malloc_bitmap(&swap_bitmaps[ix], size.x, size.y); 950 fill_area(&swap_bitmaps[ix], GC_CLEAR, 0, 0, size.x, size.y); 951 } 952 } 953 /*}}}*/ 954 colors = !no_mono; 955 if(!no_mono) 956 { 957 /*{{{ fiddle mono noswap*/ 958 { 959 copy_area(&mono_source, &source, GC_COPY, 960 0, (int)size.y, size.x, size.y, 0, 0); 961 if(noswap_invert) 962 fill_area(&source, GC_XOR, 0, 0, size.x, size.y); 963 if(noswap_edge) 964 { 965 copy_area(&mono_source, ¤t, GC_COPY, 0, 0, 966 size.x, size.y, 0, 0); 967 copy_area(&mono_source, ¤t, GC_AND, 0, 0, 968 size.x, size.y - 1, 0, 1); 969 copy_area(&mono_source, ¤t, GC_AND, 0, 1, 970 size.x, size.y - 1, 0, 0); 971 copy_area(&mono_source, ¤t, GC_AND, 0, 0, 972 size.x - 1, size.y, 1, 0); 973 copy_area(&mono_source, ¤t, GC_AND, 1, 0, 974 size.x - 1, size.y, 0, 0); 975 draw_rectangle(¤t, GC_CLEAR, 0, 0, size.x - 1, size.y - 1); 976 fill_area(¤t, GC_XOR, 0, 0, size.x, size.y); 977 copy_area(¤t, &source, GC_OR, 0, 0, size.x, size.y, 0, 0); 978 } 979 copy_area(&mono_source, &source, GC_AND, 0, 0, size.x, size.y, 0, 0); 980 copy_area(&source, &mono_bitmap, GC_COPY, 981 0, 0, size.x, size.y, 0, 0); 982 } 983 /*}}}*/ 984 /*{{{ fiddle mono swap*/ 985 { 986 copy_area(&mono_source, &source, GC_COPY, 987 0, (int)(size.y * (mono_planes - 1)), size.x, size.y, 0, 0); 988 if(swap_invert) 989 fill_area(&source, GC_XOR, 0, 0, size.x, size.y); 990 copy_area(&mono_source, &source, GC_AND, 991 0, 0, size.x, size.y, 0, 0); 992 copy_area(&source, &mono_bitmap, GC_COPY, 993 0, 0, size.x, size.y, 0, (int)size.y); 994 } 995 /*}}}*/ 996 } 997 copy_area(&mono_source, &source, GC_COPY, 0, 0, size.x, size.y, 0, 0); 998 make_color_pixmaps(noswap, noswap_bitmaps, "Noswap"); 999 if(edge) 1000 { 1001 for(ix = 0; noswap[ix]; ix++) 1002 /*EMPTY*/; 1003 add_edge(ix, noswap_bitmaps); 1004 noswap[ix] = edge; 1005 } 1006 copy_area(&mono_source, &source, GC_COPY, 0, 0, size.x, size.y, 0, 0); 1007 make_color_pixmaps(swap, swap_bitmaps, "Swap"); 1008 compress_colors(noswap, noswap_bitmaps, "Noswap"); 1009 compress_colors(swap, swap_bitmaps, "Swap"); 1010 /*{{{ merge the noswap colors*/ 1011 { 1012 for(ix = 0; noswap[ix]; ix++) 1013 { 1014 copy_area(&noswap_bitmaps[ix], &bitmaps[ix + colors], GC_COPY, 1015 0, 0, size.x, size.y, 0, 0); 1016 noswap_colors[ix + colors] = noswap[ix]; 1017 } 1018 colors = ix + colors; 1019 } 1020 /*}}}*/ 1021 /*{{{ merge the swap colors*/ 1022 for(ix = 0; swap[ix]; ix++) 1023 { 1024 unsigned j; 1025 1026 for(j = 0; j != colors; j++) 1027 { 1028 if(is_blank(&swap_bitmaps[ix])) 1029 break; 1030 copy_area(&swap_bitmaps[ix], ¤t, GC_COPY, 1031 0, 0, size.x, size.y, 0, 0); 1032 copy_area(&bitmaps[j], ¤t, GC_AND, 1033 0, 0, size.x, size.y, 0, 0); 1034 if(!is_blank(¤t)) 1035 { 1036 swap_colors[j] = swap[ix]; 1037 copy_area(¤t, &scratch, GC_COPY, 1038 0, 0, size.x, size.y, 0, 0); 1039 copy_area(&bitmaps[j], &scratch, GC_XOR, 1040 0, 0, size.x, size.y, 0, 0); 1041 if(!is_blank(&scratch)) 1042 { 1043 copy_area(&bitmaps[j], &bitmaps[colors], GC_COPY, 1044 0, 0, size.x, size.y, 0, 0); 1045 copy_area(¤t, &bitmaps[colors], GC_XOR, 1046 0, 0, size.x, size.y, 0, 0); 1047 noswap_colors[colors] = noswap_colors[j]; 1048 copy_area(¤t, &bitmaps[j], GC_COPY, 1049 0, 0, size.x, size.y, 0, 0); 1050 colors++; 1051 } 1052 copy_area(&bitmaps[j], &swap_bitmaps[ix], GC_XOR, 1053 0, 0, size.x, size.y, 0, 0); 1054 } 1055 } 1056 } 1057 /*}}}*/ 1058 if(!no_mono) 1059 { 1060 /*{{{ merge the noswap mono*/ 1061 { 1062 copy_area(&mono_bitmap, &source, GC_COPY, 0, 0, size.x, size.y, 0, 0); 1063 merge_mono(); 1064 mono_noswap = mono_swap; 1065 mono_swap = 0; 1066 } 1067 /*}}}*/ 1068 /*{{{ merge the swap mono*/ 1069 { 1070 copy_area(&mono_bitmap, &source, GC_COPY, 1071 0, (int)size.y, size.x, size.y, 0, 0); 1072 merge_mono(); 1073 } 1074 /*}}}*/ 1075 /*{{{ add mono color masks*/ 1076 { 1077 char st[20]; 1078 1079 sprintf(st, "0x%lx", mono_noswap); 1080 noswap_colors[0] = strcpy(smalloc(strlen(st) + 1), st); 1081 sprintf(st, "0x%lx", mono_swap); 1082 swap_colors[0] = strcpy(smalloc(strlen(st) + 1), st); 1083 } 1084 /*}}}*/ 1085 } 1086 /*{{{ create the output bitmap*/ 1087 { 1088 unsigned mask; 1089 1090 for(mask = 1, planes = 0; mask < colors; mask <<= 1) 1091 planes++; 1092 fprintf(stderr, "Creating %s.%s with %d colors on %d planes\n", filename, 1093 no_mono ? "packed" : "h", colors, planes); 1094 malloc_bitmap(&output_bitmap, size.x, size.y * planes); 1095 fill_area(&output_bitmap, GC_CLEAR, 0, 0, size.x, size.y * planes); 1096 for(ix = 0; ix != colors; ix++) 1097 { 1098 int bit; 1099 1100 for(bit = 0; bit != planes; bit++) 1101 if(ix & (1 << bit)) 1102 copy_area(&bitmaps[ix], &output_bitmap, GC_OR, 1103 0, 0, size.x, size.y, 0, (int)(bit * size.y)); 1104 } 1105 } 1106 /*}}}*/ 1107 /*{{{ write the file*/ 1108 { 1109 char *name; 1110 FILE *stream; 1111 char *ptr; 1112 unsigned x, y; 1113 unsigned count; 1114 unsigned ix; 1115 1116 name = smalloc(strlen(filename) + 8); 1117 strcpy(name, filename); 1118 strcat(name, no_mono ? ".packed" : ".h"); 1119 ptr = strrchr(filename, '/'); 1120 if(!ptr) 1121 ptr = filename; 1122 else 1123 ptr++; 1124 stream = fopen(name, "w"); 1125 if(!stream) 1126 { 1127 fprintf(stderr, "Cannot write file\n"); 1128 return 1; 1129 } 1130 fprintf(stream, "#define %s_width %d\n", ptr, (int)size.x); 1131 fprintf(stream, "#define %s_height %d\n", ptr, (int)(size.y * planes)); 1132 if(mono_source.hot.x >= 0) 1133 { 1134 fprintf(stream, "#define %s_x_hot %d\n", ptr, mono_source.hot.x); 1135 fprintf(stream, "#define %s_y_hot %d\n", ptr, mono_source.hot.y); 1136 } 1137 if(!no_mono) 1138 fprintf(stream, "#define %s_depth %d\n", ptr, (int)planes); 1139 fprintf(stream, "static unsigned char %s_bits[] =\n{\n ", ptr); 1140 count = 10; 1141 for(y = 0; y < output_bitmap.size.y; y++) 1142 { 1143 for(x = 0; x < (output_bitmap.size.x + 7) / 8; x++) 1144 { 1145 if(!count--) 1146 { 1147 count = 9; 1148 fputs("\n ", stream); 1149 } 1150 fprintf(stream, " 0x%02x,", ((size.x - x * 8) > 7 ? 1151 0xFF : 0xFF >> (8 - (size.x - x * 8))) & 1152 output_bitmap.bits[y * output_bitmap.scan + x]); 1153 } 1154 } 1155 fprintf(stream, "\n};\n"); 1156 if(no_mono) 1157 { 1158 fputs(" ", stdout); 1159 for(ix = 0; ix != colors; ix++) 1160 fprintf(stdout, "%s ", noswap_colors[ix]); 1161 fputs("+ \\\n", stdout); 1162 fputs(" ", stdout); 1163 for(ix = 0; ix != colors; ix++) 1164 fprintf(stdout, "%s ", swap_colors[ix]); 1165 fputs("+\n", stdout); 1166 } 1167 else 1168 { 1169 fprintf(stream, "static unsigned long %s_noswap[] =\n{\n", ptr); 1170 for(ix = 0; ix != colors; ix++) 1171 fprintf(stream, " %s,\n", noswap_colors[ix]); 1172 while(ix++ < 1 << planes) 1173 fprintf(stream, " ~(unsigned long)0,\n"); 1174 fprintf(stream, "};\n"); 1175 fprintf(stream, "static unsigned long %s_swap[] =\n{\n", ptr); 1176 for(ix = 0; ix != colors; ix++) 1177 fprintf(stream, " %s,\n", swap_colors[ix]); 1178 while(ix++ < 1 << planes) 1179 fprintf(stream, " ~(unsigned long)0,\n"); 1180 fprintf(stream, "};\n"); 1181 } 1182 if(ferror(stream)) 1183 { 1184 fprintf(stderr, "Error writing file"); 1185 error = 1; 1186 } 1187 fclose(stream); 1188 if(error) 1189 unlink(name); 1190 free(name); 1191 } 1192 /*}}}*/ 1193 return error; 1194 } 1195 /*}}}*/ 1196