home *** CD-ROM | disk | FTP | other *** search
/ hobbes.nmsu.edu 2008 / 2008-06-02_hobbes.nmsu.edu.zip / new / scummc-0.2.0-os2.zip / ScummC / src / code.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-11-09  |  11.2 KB  |  530 lines

  1. /* ScummC
  2.  * Copyright (C) 2004-2006  Alban Bedel
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17.  *
  18.  */
  19.  
  20. /**
  21.  * @file code.c
  22.  * @ingroup scumm
  23.  * @brief SCUMM image encoders
  24.  */
  25.  
  26. #include "config.h"
  27.  
  28. #include <inttypes.h>
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <stdio.h>
  32. #include <errno.h>
  33. #include <string.h>
  34.  
  35. #include "scc_fd.h"
  36. #include "scc_util.h"
  37.  
  38. static int compute_shr(uint8_t* src,int src_stride,
  39.                int width,int height) {
  40.   int l,c,shr = 4,mask = 0xFF >> (8 -shr);
  41.  
  42.   for(l = 0 ; l < height ; l++) {
  43.     for(c = (l>0?0:1) ; c < width ; c++) {
  44.       while((src[c] & mask) != src[c]) {
  45.     shr++;
  46.     mask = 0xFF >> (8 -shr);
  47.     if(shr == 8) return 8;
  48.       }
  49.     }
  50.     src += src_stride;
  51.   }
  52.   return shr;    
  53. }
  54.  
  55. #define WRITE_BITS while(cl >= 8) {  \
  56.     *dst=bits & 0xFF;            \
  57.      bits >>= 8;                  \
  58.     cl -= 8;                     \
  59.     len++;                       \
  60.     dst++;                       \
  61. }
  62.  
  63. #define FLUSH_BITS WRITE_BITS \
  64.    if(cl > 0) {       \
  65.     *dst=bits & (0xFF >> (8-cl)); \
  66.     cl = bits = 0;                \
  67.     len++;                        \
  68.         dst++;                        \
  69. }
  70.  
  71. #define WRITE_BIT(b) {       \
  72.     bits |= (b & 1)<<cl; \
  73.     cl++;                \
  74.     WRITE_BITS           \
  75. }
  76.  
  77. #define WRITE_8(b) {            \
  78.     bits |= (b & 0xFF)<<cl; \
  79.     cl+=8;                  \
  80.     WRITE_BITS              \
  81. }
  82.  
  83. #define WRITE_NBIT(b,n) {                 \
  84.     bits |= ((b) & (0xff >> (8-n)))<<cl;  \
  85.     cl += n;                          \
  86.     WRITE_BITS                        \
  87. }
  88.  
  89. int unkCodeA(uint8_t* dst,uint8_t* src,int src_stride,
  90.              int width,int height,int shr) {
  91.   uint32_t bits = 0;
  92.   uint32_t cl = 0;
  93.   uint32_t len = 0;
  94.   int l,c,inc,rep = 0,color = -1;
  95.  
  96.   for(l = 0 ; l < height ; l++) {
  97.     for(c = 0 ; c < width ; c++) {
  98.       // Write the first color as is
  99.       if(color < 0) {
  100.     //    printf("Start color: %x %x %x\n",src[c],src[c+1],src[c+2]);
  101.     color = src[c];
  102.     WRITE_8(color);
  103.     continue;
  104.       }
  105.       if(src[c] == color) {
  106.     rep++;
  107.     if(rep < 255) continue;
  108.       }
  109.  
  110.       // Repeating
  111.       //      if(rep >= 5+8) {
  112.       if(rep >= 13) {
  113.     WRITE_BIT(1);
  114.     WRITE_BIT(1);
  115.  
  116.     WRITE_NBIT(4,3);
  117.     WRITE_8(rep);
  118.       } else if(rep > 0) {
  119.     while(rep) {
  120.       WRITE_BIT(0);
  121.       rep--;
  122.     }
  123.       }
  124.       rep = 0;
  125.       if(src[c] == color) continue;
  126.  
  127.       // If we are near enouh use an inc
  128.       inc = src[c]-color;
  129.       if(inc >= -4 && inc < 4) {
  130.     WRITE_BIT(1);
  131.     WRITE_BIT(1);
  132.  
  133.     WRITE_NBIT(inc+4,3);
  134.       } else { // Otherwise write the color
  135.     WRITE_BIT(1);
  136.     WRITE_BIT(0);
  137.     
  138.     WRITE_NBIT(src[c],shr);
  139.       }
  140.       color = src[c];
  141.     }
  142.     src += src_stride;
  143.   }
  144.  
  145.   // Write the last pixel
  146.   // Repeating
  147.   if(rep >= 5+8) {
  148.     WRITE_BIT(1);
  149.     WRITE_BIT(1);
  150.     
  151.     WRITE_NBIT(4,3);
  152.     WRITE_8(rep);
  153.   } else if(rep > 0) {
  154.     while(rep) {
  155.       WRITE_BIT(0);
  156.       rep--;
  157.     }
  158.   }
  159.  
  160.   FLUSH_BITS;
  161.   
  162.  
  163.   return len;
  164. }
  165.  
  166.  
  167. int unkCodeA6(uint8_t* dst,uint8_t* src,int src_stride,
  168.              int width,int height,int shr) {
  169.   uint32_t bits = 0;
  170.   uint32_t cl = 0;
  171.   uint32_t len = 0;
  172.   int l,c,inc,color = -1;
  173.  
  174.   for(l = 0 ; l < height ; l++) {
  175.     for(c = 0 ; c < width ; c++) {
  176.       // Write the first color as is
  177.       if(color < 0) {
  178.     //    printf("Start color: %x %x %x\n",src[c],src[c+1],src[c+2]);
  179.     color = src[c];
  180.     WRITE_8(color);
  181.     continue;
  182.       }
  183.  
  184.       if(src[c] == color) {
  185.     WRITE_BIT(0);
  186.     continue;
  187.       }
  188.  
  189.       // If we are near enouh use an inc
  190.       inc = src[c]-color;
  191.       if(inc >= -4 && inc < 4) {
  192.     WRITE_BIT(1);
  193.     WRITE_BIT(1);
  194.  
  195.     WRITE_NBIT(inc+4,3);
  196.       } else { // Otherwise write the color
  197.     WRITE_BIT(1);
  198.     WRITE_BIT(0);
  199.     
  200.     WRITE_NBIT(src[c],shr);
  201.       }
  202.       color = src[c];
  203.     }
  204.     src += src_stride;
  205.   }
  206.  
  207.   FLUSH_BITS;
  208.   
  209.  
  210.   return len;
  211. }
  212.  
  213. int unkCodeB(uint8_t* dst,uint8_t* src,int src_stride,
  214.             int width,int height,int shr) {
  215.   uint32_t bits = 0;
  216.   uint32_t cl = 0;
  217.   uint32_t len = 0;
  218.   int l,c,inc = -1,color = -1;
  219.  
  220.   for(l = 0 ; l < height ; l++) {
  221.     for(c = 0 ; c < width ; c++) {
  222.       if(color < 0) {
  223.     color = src[c];
  224.     WRITE_8(color);
  225.     continue;
  226.       }
  227.       if(src[c] == color) {
  228.     WRITE_BIT(0);
  229.     continue;
  230.       }
  231.       WRITE_BIT(1);
  232.      
  233.       if(src[c] == color + inc) {
  234.     WRITE_BIT(1);
  235.     WRITE_BIT(0);
  236.     color += inc;
  237.       } else if(src[c] == color -inc) {
  238.     WRITE_BIT(1);
  239.     WRITE_BIT(1);
  240.     inc = -inc;
  241.     color += inc;
  242.       } else {
  243.     WRITE_BIT(0);
  244.     WRITE_NBIT(src[c],shr);
  245.     color = src[c];
  246.     inc = -1;
  247.       }
  248.     }
  249.     src += src_stride;
  250.   }
  251.   FLUSH_BITS;
  252.   return len;
  253. }
  254.  
  255. int unkCodeC(uint8_t* dst,uint8_t* src,int src_stride,
  256.             int width,int height,int shr) {
  257.   uint32_t bits = 0;
  258.   uint32_t cl = 0;
  259.   uint32_t len = 0;
  260.   int l,c,inc = -1,color = -1;
  261.  
  262.   for(c = 0 ; c < width ; c++) {
  263.     for(l = 0 ; l < height ; l++) {
  264.       if(color < 0) {
  265.     color = src[l];
  266.     WRITE_8(color);
  267.     continue;
  268.       }
  269.       if(src[l*src_stride] == color) {
  270.     WRITE_BIT(0);
  271.     continue;
  272.       }
  273.       WRITE_BIT(1);
  274.      
  275.       if(src[l*src_stride] == color + inc) {
  276.     WRITE_BIT(1);
  277.     WRITE_BIT(0);
  278.     color += inc;
  279.       } else if(src[l*src_stride] == color -inc) {
  280.     WRITE_BIT(1);
  281.     WRITE_BIT(1);
  282.     inc = -inc;
  283.     color += inc;
  284.       } else {
  285.     color = src[l*src_stride];
  286.     inc = -1;
  287.     WRITE_BIT(0);
  288.     WRITE_NBIT(color,shr);
  289.       }
  290.     }
  291.     src++;
  292.   }
  293.   FLUSH_BITS;
  294.  
  295.   return len;
  296. }
  297.  
  298. typedef int (*unkCode_f)(uint8_t* dst,uint8_t* src,int src_stride,
  299.              int width,int height,int shr);
  300. struct scc_img_coder_st {
  301.   unkCode_f code;
  302.   int opaque,trans;
  303. } coders[] = {
  304.   { unkCodeA,100,120 },
  305.   { unkCodeA6,60,80 },
  306.   { unkCodeB,20,40 },
  307.   { unkCodeC,10,30 },
  308.   { NULL, 0, 0, },
  309. };
  310.  
  311. int scc_code_image(uint8_t* src, int src_stride,
  312.            int width,int height,int transparentColor,
  313.            uint8_t** smap_p) {
  314.   int stripes = width/8;
  315.   int codecs[stripes];
  316.   int len = 0,slen,c,pos,i,j;
  317.   int shr;
  318.   uint8_t *tbuf,*smap;
  319.  
  320.   if(stripes*8 != width) {
  321.     printf("Can't encode image with width %% 8 != 0 !!!!\n");
  322.     return 0;
  323.   }
  324.  
  325.   // should be enouth
  326.   tbuf = malloc(height*8*2);
  327.  
  328.   // find the best codec for each stripe
  329.   for(i = 0 ; i < stripes ; i++) {
  330.     // compute the shr
  331.     shr = compute_shr(&src[8*i],src_stride,8,height);
  332.     // and try
  333.     slen = coders[0].code(tbuf,&src[8*i],src_stride,8,height,shr);
  334.     for(c = 0, j = 1 ; coders[j].code ; j++) {
  335.       int l = coders[j].code(tbuf,&src[8*i],src_stride,8,height,shr);
  336.       if(l < slen) {
  337.     c = j;
  338.     slen = l;
  339.       }
  340.     }
  341.     codecs[i] = shr+c*10;
  342.     len += slen+1;
  343.   }
  344.   free(tbuf);
  345.  
  346.   pos = stripes*4;
  347.   len += pos;
  348.   len = ((len+1)/2)*2;
  349.   smap = malloc(len);
  350.   
  351.   for(i = 0 ; i < stripes ; i++) {
  352.     // get the shr back
  353.     shr = codecs[i] % 10;
  354.     // put the offset table entry
  355.     SCC_SET_32LE(smap,i*4,pos+8);
  356.     // code
  357.     smap[pos] = ((transparentColor >= 0) ? coders[codecs[i]/10].trans :
  358.          coders[codecs[i]/10].opaque) + shr;
  359.     pos++;
  360.     pos += coders[codecs[i]/10].code(&smap[pos],&src[8*i],src_stride,8,height,shr);
  361.     if(pos > len) {
  362.       printf("Big problem %d > %d !!!!\n",pos,len+stripes*4);
  363.       free(smap);
  364.       return 0;
  365.     }
  366.   }
  367.  
  368.   if(pos < len) memset(smap+pos,0,len-pos);
  369.  
  370.   smap_p[0] = smap;
  371.  
  372.   return len;
  373. }
  374.  
  375.  
  376. int check_coder(uint8_t* dec, int dec_stride,
  377.         uint8_t* ref,int ref_size,int height,
  378.         int (*unkCode)(uint8_t* dst,uint8_t* src,int src_stride,
  379.                    int width,int height,int shr),
  380.         void (*unkDecode)(uint8_t *dst, int dst_stride,
  381.                   uint8_t *src, int height,
  382.                   uint32_t palette_mod,
  383.                   uint32_t decomp_mask,uint32_t decomp_shr)
  384.         ) {
  385.   uint8_t* test = calloc(1,8*height*3/2);
  386.   uint8_t* final = calloc(1,18*height);
  387.   int i,j,len,shr = compute_shr(dec,dec_stride,8,height);
  388.   int c = 0;
  389.   //printf("Computed shr: %d\n",shr);
  390.  
  391.   for(j = 0,i = 0 ; coders[i].code ; i++) {
  392.     len = coders[i].code(test,dec,dec_stride,8,height,shr);
  393.     if(!j) j = len;
  394.     else if(len < j) j = len, c = i;
  395.     //    printf("%soder %c: %d\n",(coders[i] == unkCode ? "Selectec c" : "C"),
  396.     //                  i+'A',len);
  397.     if(coders[i].code == unkCode) printf("Testing codec: %c\n",i+'A');
  398.   }
  399.  
  400.   len = unkCode(test,dec,dec_stride,8,height,shr);
  401.  
  402.   if(coders[c].code != unkCode) printf("It wasn't the best codec (%d > %d (%d: %d %%)) ??\n",len,j,c,len*100/j);
  403.  
  404.   unkDecode(final,18,test,height,0,0xFF >> (8-shr),shr);
  405.  
  406.   if(len != ref_size) printf("Stripe size mismatch: %d instead of %d\n",len,ref_size);
  407.   else printf("Stripe size match\n");
  408.   for(i = 0 ; i < len ; i++) {
  409.     if(test[i] != ref[i]) { 
  410.       printf("Mismatch at 0x%x/0x%x : 0x%x 0x%x\n",
  411.          i,len,test[i],ref[i]);
  412.       printf("Ref data: %0x %0x %0x %0x\n",ref[i-1],ref[i],ref[i+1],ref[i+230]);
  413.       printf("Our data: %0x %0x %0x %0x\n",test[i-1],test[i],test[i+1],test[i+2]);
  414.       break;
  415.     }
  416.   }
  417.  
  418.  
  419.   for(j = 0 ; j < height ; j++) {
  420.     for(i = 0 ; i < 8 ; i++) {
  421.       if(final[i+j*18] != dec[i+j*dec_stride]) {
  422.     printf("First mismatch at 0x%x/0x%x : %x %x %x <=> %x %x %x %x\n",i,8*height,
  423.            final[i+j*18-1],final[i+j*18],final[i+j*18+1],
  424.            dec[i+j*dec_stride-1],dec[i+j*dec_stride],dec[i+j*dec_stride+1],dec[i+j*dec_stride+2]);
  425.     free(test);
  426.     return 0;
  427.       }
  428.     }
  429.   }
  430.     
  431.   free(test);
  432.   free(final);
  433.   return 1;
  434. }
  435.  
  436.  
  437.  
  438. static int compMask(uint8_t *dst, 
  439.             uint8_t *src, int src_stride,
  440.             int height) {
  441.   uint8_t buf[height];
  442.   int ds = -1,rs = -1,r = 0;
  443.   int l;
  444.   int len = 0;
  445.  
  446.   
  447.   for(l = 0 ; l < height ; l++)
  448.     buf[l] = src[l*src_stride];
  449.  
  450.   for(l = 0 ; l < height ; l++) {
  451.  
  452.     if(l+1 < height && buf[l+1] == buf[l]) {
  453.       if(rs < 0) rs = l, r = 1;
  454.       r++;
  455.       continue;
  456.     }
  457.  
  458.     if(r > 2) {
  459.       if(ds >= 0) {
  460.     *dst = rs-ds;
  461.     memcpy(dst+1,&buf[ds],dst[0]);
  462.     len += dst[0]+1;
  463.     dst += dst[0]+1;
  464.       } 
  465.       //else if(r >= height && buf[l] == 0) return 0;
  466.       // scummvm have no pb with this, but not the original engine.
  467.       while(r > 0) {
  468.     uint8_t v = (r > 0x7f) ? 0x7f : r;
  469.     *dst = v | 0x80; dst++;
  470.     *dst = buf[l]; dst++;
  471.     len += 2;
  472.     r -= v;
  473.       }
  474.       ds = rs = -1;
  475.       continue;
  476.     }
  477.  
  478.     if(ds < 0) {
  479.       if(rs >= 0) ds = rs;
  480.       else ds = l;
  481.     }
  482.  
  483.     r = 0;
  484.     rs = -1;
  485.  
  486.  
  487.  
  488.     if(l+1 < height && l+1-ds < 0x7f) continue;
  489.     
  490.     *dst = l+1-ds;
  491.     memcpy(dst+1,&buf[ds],dst[0]);
  492.     len += dst[0]+1;
  493.     dst += dst[0]+1;
  494.     ds = -1;
  495.   }
  496.  
  497.   return len;  
  498. }
  499.  
  500.  
  501. int scc_code_zbuf(uint8_t* src, int src_stride,
  502.           int width,int height,
  503.           uint8_t** smap_p) {
  504.   int strides = width/8;
  505.   int slen,len,i,pos = strides*2;
  506.   uint8_t tmp[2*height];
  507.   uint8_t* smap;
  508.  
  509.   *smap_p = NULL;
  510.  
  511.   for(len = i = 0 ; i < strides ; i++)
  512.     len += compMask(tmp,&src[i],src_stride,height);
  513.  
  514.   len += pos;
  515.   smap = malloc(len);
  516.  
  517.   for(i = 0 ; i < strides ; i++) {
  518.     slen = compMask(&smap[pos],&src[i],src_stride,height);
  519.     SCC_SET_16LE(smap,i*2,(slen) ? pos+8 : 0);
  520.     pos += slen;
  521.     if(pos > len) {
  522.       printf("Big problem while coding zplane\n");
  523.       break;
  524.     }
  525.   }
  526.  
  527.   *smap_p = smap;
  528.   return len;
  529. }
  530.