home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 2 / RISC_DISC_2.iso / pd_share / program / sprtools / c / spr_fsi < prev    next >
Encoding:
Text File  |  1994-07-18  |  31.2 KB  |  1,087 lines

  1. /************************************************************************
  2.  *                                                                      *
  3.  * spr_fsi.c                                                            *
  4.  * =========                                                            *
  5.  *                                                                      *
  6.  * RISCOS sprite manipulation utility                                   *
  7.  * Supports scaling, depth (colour) expansion/reduction                 *
  8.  * with image processing features.                                      *
  9.  * Uses Floyd-Steinburg Integer (FSI) error distrubution dithering      *
  10.  *                                                                      *
  11.  * Version 0.01 (18-Jan-1993)                                           *
  12.  *         0.02 (24-Feb-1993)                                           *
  13.  *         0.03 (15-Mar-1993)                                           *
  14.  *         0.04 (28-Apr-1993)                                           *
  15.  *         0.05 (10-May-1993) Split to form process.c                   *
  16.  *         0.06 (16-Jun-1993)                                           *
  17.  *         0.07 (13-Aug-1993)                                           *
  18.  *         0.08 (31-Aug-1993)                                           *
  19.  *         0.09 (13-Sep-1993)                                           *
  20.  *         0.10 (13-Oct-1993)                                           *
  21.  *         1.00 (13-Jan-1994)                                           *
  22.  *         1.10 (20-Apr-1994) filters added                             *
  23.  *                                                                      *
  24.  * (C) 1993-4 DEEJ Technology PLC                                         *
  25.  *                                                                      *
  26.  ************************************************************************/
  27.  
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include "io.h"
  32. #include "sprite.h"
  33. #include "process.h"
  34. #include "palette.h"
  35.  
  36. /******************************** Constants ********************************/
  37.  
  38. typedef enum
  39. {
  40.     PAL_INPUT = 0,
  41.     PAL_DESK  = 1,
  42.     PAL_WIN3  = 2,
  43.     PAL_RGB      = 3,
  44.     PAL_GREY  = 4,
  45.     PAL_FIX   = 5,
  46.     PAL_OPT   = 6,
  47.     PAL_NONE  = -1
  48. } palette_type;
  49.  
  50. const char *palette_names[] =
  51. {
  52.         "input",
  53.         "desktop",
  54.         "win3",
  55.         "rgb",
  56.         "grey",
  57.         "fix",
  58.     "opt",
  59.     ""
  60. };
  61.  
  62. typedef enum
  63. {
  64.     FILTER_user     = 0,
  65.     FILTER_sharpen1 = 1,
  66.     FILTER_sharpen2 = 2,
  67.     FILTER_sharpen3 = 3,
  68.     FILTER_smooth1  = 4,
  69.     FILTER_smooth2  = 5,
  70.     FILTER_smooth3  = 6,
  71.     FILTER_average  = 7,
  72.     FILTER_noise1   = 8,
  73.     FILTER_noise2   = 9,
  74.     FILTER_noise3   = 10,
  75.     FILTER_edge     = 11,
  76.     FILTER_edgeV    = 12,
  77.     FILTER_edgeH    = 13,
  78.     FILTER_edgeNW   = 14,
  79.     FILTER_edgeNE   = 15,
  80.     FILTER_edgeSW   = 16,
  81.     FILTER_edgeSE   = 17,
  82.     FILTER_emboss1  = 18,
  83.     FILTER_emboss2  = 19,
  84.     FILTER_none     = -1
  85. } filter_type;
  86.  
  87. const char *filter_names[] =
  88. {
  89.     "user",
  90.     "sharpen1",
  91.     "sharpen2",
  92.     "sharpen3",
  93.     "smooth1",
  94.     "smooth2",
  95.     "smooth3",
  96.     "average",
  97.     "noise1",
  98.     "noise2",
  99.     "noise3",
  100.     "edge",
  101.     "edgeV",
  102.     "edgeH",
  103.     "edgeNW",
  104.     "edgeNE",
  105.     "edgeSW",
  106.     "edgeSE",
  107.     "emboss1",
  108.     "emboss2",
  109.     ""
  110. };
  111.  
  112. /******************************** structures ********************************/
  113.  
  114. typedef struct
  115. {
  116.     int    Xmul;
  117.     int    Xdiv;
  118.     int    Ymul;
  119.     int    Ydiv;
  120. } scale_str;
  121.  
  122. typedef struct
  123. {
  124.     process_str    pro;
  125.     scale_str    scale;
  126.         palette_type    palette;
  127.     filter_type     filter;
  128.     BOOL            aspect;
  129.     BOOL        quiet;
  130. }  options_str;
  131.  
  132. /*************************** Function prototypes ****************************/
  133.  
  134. void error(char*);
  135. void syntax(char*);
  136. void info(void);
  137. void palette_setup(char*);
  138. void filter_setup(char*);
  139. void scale_setup(char*);
  140. void calc_output_info(spr_info_str*, spr_info_str*);
  141.  
  142. /*********************************** Data ***********************************/
  143.  
  144. /* Program parameter globals */
  145.  
  146. options_str opts;
  147.  
  148. /* main program data globals */
  149.  
  150. FILE *inf, *outf, *errf;
  151. spr_info_str in,out;
  152.  
  153. /* general globals */
  154.  
  155. char progname[256];
  156.  
  157. /* externals */
  158.  
  159. #ifdef CACHE_STAT
  160. extern int cache_calls;
  161. extern int cache_hits;
  162. extern int cache_misses;
  163. extern int cache_used;
  164. #endif
  165.  
  166. /****************************************************************************/
  167.  
  168. /*
  169.  * report non continuable error condition
  170.  */
  171.  
  172. void error(char *err)
  173. {
  174.         fprintf(errf,"Error: %s - %s unable to continue\n",err,progname);
  175.         exit(1);
  176. }
  177.  
  178. /*
  179.  * explain command syntax
  180.  */
  181.  
  182. void syntax(char *info)
  183. {
  184.         fprintf(errf,"%s\n",info);
  185.         fprintf(errf,"Syntax:\n");
  186.         fprintf(errf,     "%s [-scale {<Xsize>,<Ysize>} |\n",progname);
  187.         fprintf(errf,"                {<XYmul>:<XYdiv>} |\n");
  188.         fprintf(errf,"                {<Xmul>:<Xdiv>,<Ymul>:<Ydiv>}]\n");
  189.         fprintf(errf,"        [-bpp <1|2|4|8|15|24>]\n");
  190.         fprintf(errf,"        [-palette <rgb|grey|desktop|win3|fix|opt>]\n");
  191.     fprintf(errf,"        [-filter {<name>}|{<matrix>[,<mul>][,<div>],[<add>],[<min>,<max>]]\n");
  192.         fprintf(errf,"        [-invert] [-expand] [-gamma <gamma>] [-aspect]\n");
  193.         fprintf(errf,"        [-nodither] [-nointerp] [-quiet] [-help]\n");
  194.         fprintf(errf,"        [-in <in_file>] [-out <out_file>] [-err <err_file>]\n");
  195.         fprintf(errf,"\n");
  196.  
  197.  
  198.     /* #### add palette and filter names here */
  199.  
  200.         fprintf(errf,"Input defaults to stdin, output to stdout and\n");
  201.         fprintf(errf,"errors/progress indication to stderr\n");
  202. }
  203.  
  204. void info(void)
  205. {
  206.     int  xres, yres, type;
  207.  
  208.     type = (unsigned)out.mode >> 27;
  209.         xres = (out.mode >>  1) & 0xFFF;
  210.         yres = (out.mode >> 14) & 0xFFF;
  211.  
  212.         fprintf(errf,"Scale       : %d:%d,%d:%d\n",opts.scale.Xmul,
  213.                            opts.scale.Xdiv,
  214.                            opts.scale.Ymul,
  215.                            opts.scale.Ydiv);
  216.         fprintf(errf,"Pixel aspect: %s\n",opts.aspect       ? "TRUE":"FALSE");
  217.         fprintf(errf,"No dither   : %s\n",opts.pro.nodither ? "TRUE":"FALSE");
  218.         fprintf(errf,"No interpol.: %s\n",opts.pro.nointerp ? "TRUE":"FALSE");
  219.  
  220.     if(opts.pro.gamma)
  221.             fprintf(errf,"Gamma       : %f\n",opts.pro.data.gamma);
  222.     else
  223.             fprintf(errf,"Gamma       : None\n");
  224.  
  225.         fprintf(errf,"Palette     : %s\n",palette_names[opts.palette]);
  226.  
  227.     if(opts.pro.filter)
  228.     {
  229.             fprintf(errf,"Filter      : %s\n",filter_names[opts.filter]);
  230.             fprintf(errf,"              %2d,%2d,%2d  *%d /%d\n",
  231.                     opts.pro.data.filter.matrix[0][0],
  232.                     opts.pro.data.filter.matrix[0][1],
  233.                     opts.pro.data.filter.matrix[0][2],
  234.                     opts.pro.data.filter.mul,
  235.                     opts.pro.data.filter.div);
  236.             fprintf(errf,"              %2d,%2d,%2d  +%d\n",
  237.                     opts.pro.data.filter.matrix[1][0],
  238.                     opts.pro.data.filter.matrix[1][1],
  239.                     opts.pro.data.filter.matrix[1][2],
  240.                     opts.pro.data.filter.add);
  241.             fprintf(errf,"              %2d,%2d,%2d  >%d\n",
  242.                     opts.pro.data.filter.matrix[2][0],
  243.                     opts.pro.data.filter.matrix[2][1],
  244.                     opts.pro.data.filter.matrix[2][2],
  245.                     opts.pro.data.filter.diff);
  246.         
  247.     }
  248.         fprintf(errf,"Size        : %d,%d\n",out.X,out.Y);
  249.         fprintf(errf,"BPP (cols)  : %d/%d (%d)\n",out.bpp,out.pix,out.cols);
  250.  
  251.     if(type == 0)
  252.             fprintf(errf,"Mode        : %d (0x%X)\n",out.mode,out.mode);
  253.     else
  254.             fprintf(errf,"Mode (deep) : 0x%X (%d:%dx%d)\n", out.mode,
  255.                                                                 type,xres,yres);
  256. }
  257.  
  258. /*
  259.  * find palette type for argument
  260.  */
  261.  
  262. void palette_setup(char *arg)
  263. {
  264.     int i = 0;
  265.  
  266.     while(strcmp(palette_names[i],"")!=0 && strcmp(palette_names[i],arg)!=0)
  267.         i++;
  268.  
  269.     if(i==0 || strcmp(palette_names[i],"")==0)
  270.     {
  271.         syntax("Error: unrecognised palette type");
  272.         exit(1);
  273.     }
  274.  
  275.     opts.palette = i;
  276. }
  277.  
  278. /*
  279.  * find palette type for argument
  280.  */
  281.  
  282. void filter_setup(char *arg)
  283. {
  284.     int i = 0;
  285.  
  286.     while(strcmp(filter_names[i],"")!=0 && strcmp(filter_names[i],arg)!=0)
  287.         i++;
  288.  
  289.     if(i==0 || strcmp(filter_names[i],"")==0)
  290.     {
  291.         if(!((arg[0]>='0' && arg[0]<='9') ||
  292.                      (arg[0]=='-' && arg[1]>='0' && arg[1]<='9')))
  293.         {
  294.             syntax("Error: unrecognised filter type/format");
  295.             exit(1);
  296.         }
  297.  
  298.         memset(&opts.pro.data.filter, 0, sizeof(filter_str));
  299.         sscanf(arg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
  300.                 &opts.pro.data.filter.matrix[0][0],
  301.                 &opts.pro.data.filter.matrix[0][1],
  302.                 &opts.pro.data.filter.matrix[0][2],
  303.                 &opts.pro.data.filter.matrix[1][0],
  304.                 &opts.pro.data.filter.matrix[1][1],
  305.                 &opts.pro.data.filter.matrix[1][2],
  306.                 &opts.pro.data.filter.matrix[2][0],
  307.                 &opts.pro.data.filter.matrix[2][1],
  308.                 &opts.pro.data.filter.matrix[2][2],
  309.                 &opts.pro.data.filter.mul,
  310.                 &opts.pro.data.filter.div,
  311.                 &opts.pro.data.filter.add,
  312.                 &opts.pro.data.filter.diff);
  313.  
  314.         if(opts.pro.data.filter.mul==0 || opts.pro.data.filter.div==0)
  315.         {
  316.             int j,k;
  317.  
  318.             opts.pro.data.filter.mul = 1;
  319.             opts.pro.data.filter.div = 0;
  320.  
  321.             for(j=0; j<3; j++)
  322.             for(k=0; k<3; k++)
  323.                 opts.pro.data.filter.div +=
  324.                     opts.pro.data.filter.matrix[j][k];
  325.  
  326.             if(opts.pro.data.filter.div == 0)
  327.                 opts.pro.data.filter.div = 1;
  328.             if(opts.pro.data.filter.div < 0)
  329.                 opts.pro.data.filter.div =
  330.                         -opts.pro.data.filter.div;
  331.         }
  332.  
  333.         opts.pro.filter = TRUE;
  334.         opts.filter     = FILTER_user;
  335.     }
  336.     else
  337.     {
  338.         opts.pro.filter = TRUE;
  339.         opts.filter     = i;
  340.  
  341.         switch(opts.filter)
  342.         {
  343.             case FILTER_sharpen1:
  344.             {
  345.                 filter_str f = { -1, -2, -1,
  346.                          -2, 19, -2,
  347.                          -1, -2, -1,
  348.                                                  1,7, 0, 0 };
  349.                 opts.pro.data.filter = f;
  350.             }
  351.             break;
  352.                 
  353.             case FILTER_sharpen2:
  354.             {
  355.                 filter_str f = { -1, -2, -1,
  356.                          -2, 13, -2,
  357.                          -1, -2, -1,
  358.                                                  1,1, 0, 0 };
  359.                 opts.pro.data.filter = f;
  360.             }
  361.             break;
  362.                 
  363.             case FILTER_sharpen3:
  364.             {
  365.                 filter_str f = {  0, -1,  0,
  366.                          -1,  5, -1,
  367.                           0, -1,  0,
  368.                                                  1,1, 0, 0 };
  369.                 opts.pro.data.filter = f;
  370.             }
  371.             break;
  372.                 
  373.             case FILTER_smooth1:
  374.             {
  375.                 filter_str f = {  1,  1,  1,
  376.                           1, 24,  1,
  377.                           1,  1,  1,
  378.                                                  1,32, 0, 0 };
  379.                 opts.pro.data.filter = f;
  380.             }
  381.             break;
  382.                 
  383.             case FILTER_smooth2:
  384.             {
  385.                 filter_str f = {  1,  2,  1,
  386.                           2,  4,  2,
  387.                           1,  2,  1,
  388.                                                  1,16, 0, 0 };
  389.                 opts.pro.data.filter = f;
  390.             }
  391.             break;
  392.                 
  393.             case FILTER_smooth3:
  394.             {
  395.                 filter_str f = {  1,  1,  1,
  396.                           1,  2,  1,
  397.                           1,  1,  1,
  398.                                                  1,10, 0, 0 };
  399.                 opts.pro.data.filter = f;
  400.             }
  401.             break;
  402.                 
  403.             case FILTER_average:
  404.             {
  405.                 filter_str f = {  1,  1,  1,
  406.                           1,  1,  1,
  407.                           1,  1,  1,
  408.                                                  1,9, 0, 0 };
  409.                 opts.pro.data.filter = f;
  410.             }
  411.             break;
  412.                 
  413.             case FILTER_noise1:
  414.             {
  415.                 filter_str f = {  1,  1,  1,
  416.                           1,  0,  1,
  417.                           1,  1,  1,
  418.                                                  1,8, 0, 150 };
  419.                 opts.pro.data.filter = f;
  420.             }
  421.             break;
  422.                 
  423.             case FILTER_noise2:
  424.             {
  425.                 filter_str f = {  1,  1,  1,
  426.                           1,  0,  1,
  427.                           1,  1,  1,
  428.                                                  1,8, 0, 100 };
  429.                 opts.pro.data.filter = f;
  430.             }
  431.             break;
  432.                 
  433.             case FILTER_noise3:
  434.             {
  435.                 filter_str f = {  1,  1,  1,
  436.                           1,  0,  1,
  437.                           1,  1,  1,
  438.                                                  1,8, 0, 50 };
  439.                 opts.pro.data.filter = f;
  440.             }
  441.             break;
  442.                 
  443.             case FILTER_edge:
  444.             {
  445.                 filter_str f = {  0, -2,  0,
  446.                          -2,  8, -2,
  447.                           0, -2,  0,
  448.                                                  1,1, 0, 0 };
  449.                 opts.pro.data.filter = f;
  450.             }
  451.             break;
  452.                 
  453.             case FILTER_edgeV:
  454.             {
  455.                 filter_str f = {  1,  0, -1,
  456.                           2,  0, -2,
  457.                           1,  0, -1,
  458.                                                  1,1, 0, 0 };
  459.                 opts.pro.data.filter = f;
  460.             }
  461.             break;
  462.                 
  463.             case FILTER_edgeH:
  464.             {
  465.                 filter_str f = {  1,  2,  1,
  466.                           0,  0,  0,
  467.                          -1, -2, -1,
  468.                                                  1,1, 0, 0 };
  469.                 opts.pro.data.filter = f;
  470.             }
  471.             break;
  472.                 
  473.             case FILTER_edgeNW:
  474.             {
  475.                 filter_str f = {  2,  1,  0,
  476.                           1,  0, -1,
  477.                           0, -1, -2,
  478.                                                  1,1, 0, 0 };
  479.                 opts.pro.data.filter = f;
  480.             }
  481.             break;
  482.                 
  483.             case FILTER_edgeNE:
  484.             {
  485.                 filter_str f = {  0,  1,  2,
  486.                          -1,  0,  1,
  487.                          -2, -1,  0,
  488.                                                  1,1, 0, 0 };
  489.                 opts.pro.data.filter = f;
  490.             }
  491.             break;
  492.                 
  493.             case FILTER_edgeSW:
  494.             {
  495.                 filter_str f = {  0, -1, -2,
  496.                           1,  0, -1,
  497.                           2,  1,  0,
  498.                                                  1,1, 0, 0 };
  499.                 opts.pro.data.filter = f;
  500.             }
  501.             break;
  502.                 
  503.             case FILTER_edgeSE:
  504.             {
  505.                 filter_str f = { -2, -1,  0,
  506.                          -1,  0,  1,
  507.                           0,  1,  2,
  508.                                                  1,1, 0, 0 };
  509.                 opts.pro.data.filter = f;
  510.             }
  511.             break;
  512.                 
  513.             case FILTER_emboss1:
  514.             {
  515.                 filter_str f = { -1,  0,  0,
  516.                           0,  1,  0,
  517.                           0,  0,  0,
  518.                                                  1,1, 128, 0 };
  519.                 opts.pro.data.filter = f;
  520.             }
  521.             break;
  522.                 
  523.             case FILTER_emboss2:
  524.             {
  525.                 filter_str f = {  0,  0,  0,
  526.                           0,  1,  0,
  527.                           0,  0, -1,
  528.                                                  1,1, 128, 0 };
  529.                 opts.pro.data.filter = f;
  530.             }
  531.             break;
  532.                 
  533.             default:
  534.             break;
  535.         }
  536.     } 
  537. }
  538.  
  539. /*
  540.  * decode -scale argument
  541.  */
  542.  
  543. void scale_setup(char *arg)
  544. {
  545.         int a,b,c,d  = -1;
  546.         char *comma  = strchr(arg, ',');
  547.         char *colon1 = strchr(arg, ':');
  548.         char *colon2 = strrchr(arg,':');
  549.  
  550.         /* Xmul:Xdiv,Ymul:Ydiv */
  551.  
  552.         if(colon1!=0 && colon2!=0 && colon1!=colon2 && comma!=0)
  553.         {
  554.                 sscanf(arg,"%d:%d,%d:%d",&a,&b,&c,&d);
  555.                 if(a>0 && b>0 && c>0 && d>0)
  556.                 {
  557.                         opts.scale.Xmul = a;
  558.                         opts.scale.Xdiv = b;
  559.                         opts.scale.Ymul = c;
  560.                         opts.scale.Ydiv = d;
  561.                         return;
  562.                 }
  563.                 else
  564.                 {
  565.                         syntax("Error: Bad scale factors");
  566.                         exit(1);
  567.                 }
  568.         }
  569.  
  570.         /* XYmul:XYdiv */
  571.  
  572.         if(colon1!=0 && colon2!=0 && colon1==colon2 && comma==0)
  573.         {
  574.                 sscanf(arg,"%d:%d",&a,&b);
  575.                 if(a>0 && b>0)
  576.                 {
  577.                         opts.scale.Xmul = opts.scale.Ymul = a;
  578.                         opts.scale.Xdiv = opts.scale.Ydiv = b;
  579.                         return;
  580.                 }
  581.                 else
  582.                 {
  583.                         syntax("Error: Bad scale factors");
  584.                         exit(1);
  585.                 }
  586.         }
  587.  
  588.         /* Xsize,Ysize */
  589.  
  590.         if(colon1==0 && colon2==0 && comma!=0)
  591.         {
  592.                 sscanf(arg,"%d,%d",&a,&b);
  593.                 if(a>0 && b>0)
  594.                 {
  595.                         if(a > in.X)
  596.                         {
  597.                                 opts.scale.Xmul = a;
  598.                                 opts.scale.Xdiv = in.X;
  599.                         }
  600.                         else
  601.                         {
  602.                                 opts.scale.Xmul = in.X;
  603.                                 opts.scale.Xdiv = a;
  604.                         }
  605.                         if(b > in.Y)
  606.                         {
  607.                                 opts.scale.Ymul = b;
  608.                                 opts.scale.Ydiv = in.Y;
  609.                         }
  610.                         else
  611.                         {
  612.                                 opts.scale.Ymul = in.Y;
  613.                                 opts.scale.Ydiv = b;
  614.                         }
  615.                         return;
  616.                 }
  617.                 else
  618.                 {
  619.                         syntax("Error: Bad scale factors");
  620.                         exit(1);
  621.                 }
  622.         }
  623.  
  624.         syntax("Error: Bad scale expression");
  625.         exit(1);
  626. }
  627.  
  628. /*
  629.  * calculate spr_info structure for output sprite
  630.  * allocate 24 bit partial buffer for FSI routine 
  631.  */
  632.  
  633. void calc_output_info(spr_info_str *in, spr_info_str *out)
  634. {
  635.         int i,j,r,g,b;
  636.  
  637.         /* check for preservation of pixel aspect ratio (using global) */
  638.  
  639.         if(opts.aspect)
  640.         {
  641.                 out->Xasp = in->Xasp;
  642.                 out->Yasp = in->Yasp;
  643.         }
  644.         else
  645.         {
  646.                 out->Xasp = 1;
  647.                 out->Yasp = 1;
  648.         }
  649.  
  650.         if(opts.scale.Xmul==-1 || opts.scale.Xdiv==-1)
  651.         {
  652.                 /* fix up mul or div depending on source image size */
  653.  
  654.                 if(opts.scale.Xmul == -1) opts.scale.Xmul = in->X;
  655.                 if(opts.scale.Xdiv == -1) opts.scale.Xdiv = in->X;
  656.         }
  657.         else
  658.         {
  659.                 /* account for differing pixel aspect ratios in scale factors */
  660.  
  661.                 if(in->Xasp > out->Xasp)
  662.                 {
  663.                         opts.scale.Xmul *= in->Xasp;
  664.                         opts.scale.Xdiv *= out->Xasp;
  665.                 }
  666.                 else
  667.                 {
  668.                         opts.scale.Xmul *= out->Xasp;
  669.                         opts.scale.Xdiv *= in->Xasp;
  670.                 }
  671.         }
  672.         if(opts.scale.Ymul==-1 || opts.scale.Ydiv==-1)
  673.         {
  674.                 /* fix up mul or div depending on source image size */
  675.  
  676.                 if(opts.scale.Ymul == -1) opts.scale.Ymul = in->Y;
  677.                 if(opts.scale.Ydiv == -1) opts.scale.Ydiv = in->Y;
  678.         }
  679.         else
  680.         {
  681.                 /* account for differing pixel aspect ratios in scale factors */
  682.  
  683.                 if(in->Yasp > out->Yasp)
  684.                 {
  685.                         opts.scale.Ymul *= in->Yasp;
  686.                         opts.scale.Ydiv *= out->Yasp;
  687.                 }
  688.                 else
  689.                 {
  690.                         opts.scale.Ymul *= out->Yasp;
  691.                         opts.scale.Ydiv *= in->Yasp;
  692.                 }
  693.         }
  694.  
  695.         /* check for scale factors * or / greater than 128 */
  696.  
  697.         if((opts.scale.Xmul/opts.scale.Xdiv)>=128 ||
  698.        (opts.scale.Xdiv/opts.scale.Xmul)>=128)
  699.                 error("X scale factors too large");
  700.         if((opts.scale.Ymul/opts.scale.Ydiv)>=128 ||
  701.        (opts.scale.Ydiv/opts.scale.Ymul)>=128)
  702.                 error("Y scale factors too large");
  703.  
  704.         /* calculate output sprites sizes */
  705.  
  706.         out->X = (in->X * opts.scale.Xmul) / opts.scale.Xdiv;
  707.         out->Y = (in->Y * opts.scale.Ymul) / opts.scale.Ydiv;
  708.  
  709.         if(out->X<4 || out->Y<4)
  710.                 error("Ridiculously small output sprite with this scale");
  711.  
  712.         if(out->X>32767 || out->Y>32767)
  713.                 error("Output sprite is too large for fixed point maths");
  714.  
  715.     if(out->X==in->X && out->Y==in->Y)
  716.         opts.pro.nointerp = TRUE;
  717.  
  718.     if(out->bpp == 24)
  719.         opts.pro.nodither = TRUE;
  720.  
  721.         /* fill out palette and pix spacing */
  722.  
  723.         out->cols = (1<<out->bpp);
  724.  
  725.         switch(opts.palette)
  726.         {
  727.             case PAL_INPUT:
  728.                 /* copy palettes if same bpp, else make defaults */
  729.                 if((in->cols==out->cols) && in->cols<=256)
  730.                 {
  731.             memcpy((void*)out->palette,
  732.                    (void*)in->palette,
  733.                 out->cols*sizeof(uint));
  734.                 }
  735.                 else
  736.                 {
  737.                         default_palette(out);
  738.                 }
  739.                 break;
  740.  
  741.             case PAL_DESK:          /* RISCOS desktop palette */
  742.                 if(out->bpp == 4)
  743.                 {
  744.                         out->palette[0]  = 0xFFFFFF00;
  745.                         out->palette[1]  = 0xDDDDDD00;
  746.                         out->palette[2]  = 0xBBBBBB00;
  747.                         out->palette[3]  = 0x99999900;
  748.                         out->palette[4]  = 0x77777700;
  749.                         out->palette[5]  = 0x55555500;
  750.                         out->palette[6]  = 0x33333300;
  751.                         out->palette[7]  = 0x00000000;
  752.                         out->palette[8]  = 0x99440000;
  753.                         out->palette[9]  = 0x00EEEE00;
  754.                         out->palette[10] = 0x00CC0000;
  755.                         out->palette[11] = 0x0000DD00;
  756.                         out->palette[12] = 0xBBEEEE00;
  757.                         out->palette[13] = 0x00885500;
  758.                         out->palette[14] = 0x00BBFF00;
  759.                         out->palette[15] = 0xFFBB0000;
  760.                 }
  761.                 else
  762.         {
  763.                     if(out->bpp == 8)
  764.             default_palette(out);
  765.             else
  766.                         error("Desktop palette only available with 4 BPP");
  767.         }
  768.                 break;
  769.  
  770.             case PAL_WIN3:          /* Microsoft Windows 3 palette */
  771.                 switch(out->bpp)
  772.                 {
  773.                     case 2:
  774.                         out->palette[0]  = 0x00000000;
  775.                         out->palette[1]  = 0x80808000;
  776.                         out->palette[2]  = 0xC0C0C000;
  777.                         out->palette[3]  = 0xFFFFFF00;
  778.                         break;
  779.  
  780.                     case 4:
  781.                         out->palette[0]  = 0x00000000;
  782.                         out->palette[1]  = 0x00008000;
  783.                         out->palette[2]  = 0x00800000;
  784.                         out->palette[3]  = 0x00808000;
  785.                         out->palette[4]  = 0x80000000;
  786.                         out->palette[5]  = 0x80008000;
  787.                         out->palette[6]  = 0x80800000;
  788.                         out->palette[7]  = 0x80808000;
  789.                         out->palette[8]  = 0xC0C0C000;
  790.                         out->palette[9]  = 0x0000FF00;
  791.                         out->palette[10] = 0x00FF0000;
  792.                         out->palette[11] = 0x00FFFF00;
  793.                         out->palette[12] = 0xFF000000;
  794.                         out->palette[13] = 0xFF00FF00;
  795.                         out->palette[14] = 0xFFFF0000;
  796.                         out->palette[15] = 0xFFFFFF00;
  797.                         break;
  798.  
  799.                                 /* not a windows 3 palette,                   */
  800.                                 /*but I wanted to use it somewhere            */
  801.                     case 8:     /* 176 greys, 62 2 bpp cube, 18 RGYBMC shades */
  802.  
  803.                         for(i=0; i<176; i++)
  804.                         {
  805.                                 j = (i * 255) / 175;
  806.                                 out->palette[i] = (j<<24) | (j<<16) | (j<<8);
  807.                         }
  808.                         for(i=1; i<63; i++)
  809.                         {
  810.                                 r =  (i &  3)       * 0x55;
  811.                                 g = ((i & 12) >> 2) * 0x55;
  812.                                 b = ((i & 48) >> 4) * 0x55;
  813.  
  814.                                 out->palette[i+175] = (b<<24)|(g<<16)|(r<<8);
  815.                         }
  816.                         for(i=0; i<18; i++)
  817.                         {
  818.                                 switch(i%6)
  819.                                 {
  820.                                         case 0: j=0x0000FF00; break;
  821.                                         case 1: j=0x00FF0000; break;
  822.                                         case 2: j=0x00FFFF00; break;
  823.                                         case 3: j=0xFF000000; break;
  824.                                         case 4: j=0xFF00FF00; break;
  825.                                         case 5: j=0xFFFF0000; break;
  826.                                 }
  827.                                 switch(i/6)
  828.                                 {
  829.                                         case 0: j = 0x33333300 & j; break;
  830.                                         case 1: j = 0x88888800 & j; break;
  831.                                         case 2: j = 0xDDDDDD00 & j; break;
  832.                                 }
  833.                                 out->palette[i+238] = j;
  834.                         }
  835.                         break;
  836.  
  837.                     default:
  838.                         error("Windows 3 palette only available with 4 BPP");
  839.                         break;
  840.                 }
  841.                 break;
  842.  
  843.             case PAL_RGB:
  844.                 switch(out->bpp)
  845.                 {
  846.                     case 1:
  847.                     case 2:
  848.                         error("RGB palette only available with >= 4 BPP");
  849.                         break;
  850.  
  851.                     case  4:        /* 9 greys + 6 full satuarated colours */
  852.                         out->palette[0]  = 0xFFFFFF00;
  853.                         out->palette[1]  = 0xDDDDDD00;
  854.                         out->palette[2]  = 0xBBBBBB00;
  855.                         out->palette[3]  = 0x99999900;
  856.                         out->palette[4]  = 0x77777700;
  857.                         out->palette[5]  = 0x55555500;
  858.                         out->palette[6]  = 0x33333300;
  859.                         out->palette[7]  = 0x00000000;
  860.                         out->palette[8]  = 0xFF000000;
  861.                         out->palette[9]  = 0x00FFFF00;
  862.                         out->palette[10] = 0x00FF0000;
  863.                         out->palette[11] = 0x0000FF00;
  864.                         out->palette[12] = 0xEEEEEE00;
  865.                         out->palette[13] = 0x007FFF00;
  866.                         out->palette[14] = 0xFF00FF00;
  867.                         out->palette[15] = 0xFFFF0000;
  868.                         break;
  869.  
  870.                     case 8:         /* 6x6x6 r,g,b (minus greys) + 46 greys */
  871.                         for(i=0; i<46; i++)
  872.                         {
  873.                                 j = (i * 255) / 45;
  874.                                 out->palette[i] = (j<<24) | (j<<16) | (j<<8);
  875.                         }
  876.                         for(r=0; r<6; r++)
  877.                         for(g=0; g<6; g++)
  878.                         for(b=0; b<6; b++)
  879.                         {
  880.                                 if( !((r==g) && (r==b) && (g==b)) )
  881.                                         out->palette[i++] = ((r*255/5)<<24) |
  882.                                                             ((g*255/5)<<16) |
  883.                                                             ((b*255/5)<<8);
  884.                         }
  885.                         break;
  886.  
  887.                     case 24:    /* RGB_PAL used to select 24 bpp or 24/32 bpp */
  888.                         out->pix = 24;
  889.  
  890.                     default:
  891.                         break;
  892.                 }
  893.                 break;
  894.                         
  895.             case PAL_GREY:  /* maximum span grey level palettes */
  896.                 if(out->bpp <= 8)
  897.                 {
  898.                         for(i=0; i<out->cols; i++)
  899.                         {
  900.                                 j = (i * 255) / (out->cols-1);
  901.                                 out->palette[i] = (j<<24) | (j<<16) | (j<<8);
  902.                         }
  903.                 }
  904.                 else
  905.                         error("Grey palette only available with <= 8 BPP");
  906.                 break;
  907.  
  908.             case PAL_FIX:
  909.                 /*
  910.                  * fix input palette by copying
  911.                  * upper to lower nibbles
  912.                  * if lower nibble is zero
  913.                  */
  914.                 for(i=0; i<in->cols; i++)
  915.                 {
  916.                         if((in->palette[i] & 0x0F) == 0)
  917.                                 in->palette[i] |= (in->palette[i]>>4);
  918.                 }
  919.  
  920.                 /* copy palettes if same bpp, else make defaults */
  921.  
  922.                 if((in->cols==out->cols) && in->cols<=256)
  923.                 {
  924.                         for(i=0; i<out->cols; i++)
  925.                         {
  926.                                 out->palette[i] = in->palette[i];
  927.                         }
  928.                 }
  929.                 else
  930.                 {
  931.                         default_palette(out);
  932.                 }
  933.                 break;
  934.  
  935.         case PAL_OPT:
  936.         if(out->bpp<4 || out->bpp>8)
  937.                     error("Optomized palette only available with 4 & 8 BPP");
  938.  
  939.         out->has_palette = out->cols;
  940.  
  941.         /*
  942.          * leave calculating optimised palette until after palette or
  943.          * image altering operations such as invert/expand/gamma
  944.                  */
  945.         opts.pro.palette_opt = TRUE;
  946.         break;
  947.  
  948.             default:
  949.                 break;          /* should be checked by arg processor */
  950.         }
  951.  
  952.         /* select mode from output bpp           */
  953.         /* also selects best pixel r/w functions */
  954.  
  955.         fill_info(out);
  956.  
  957.         /* allocate memory for one line of the output image */
  958.  
  959.         alloc_spr_line(out);
  960. }
  961.  
  962. int main(int argc, char **argv)
  963. {
  964.         opts.scale.Xmul   = 1;
  965.         opts.scale.Xdiv   = 1;
  966.         opts.scale.Ymul   = 1;
  967.         opts.scale.Ydiv   = 1;
  968.         opts.palette      = PAL_INPUT;
  969.         opts.pro.invert   = FALSE;
  970.         opts.pro.expand   = FALSE;
  971.         opts.pro.gamma    = FALSE;
  972.     opts.pro.filter   = FALSE;
  973.         opts.pro.nodither = FALSE;
  974.         opts.pro.nointerp = FALSE;
  975.         opts.aspect       = FALSE;
  976.         opts.quiet        = FALSE;
  977.         in.X  = in.Y      = -1;
  978.         out.X = out.Y     = -1;
  979.         out.bpp           = 24;
  980.         
  981.         strcpy(progname,argv[0]);
  982.  
  983.         file_args(argc, argv, &inf, &outf, &errf);
  984.  
  985.         argc--; argv++;
  986.  
  987.         while(argc>0 && (**argv==0 || **argv=='-'))
  988.         {
  989.             if(**argv=='-')
  990.             {
  991.                 (*argv)++;
  992.  
  993.                 switch(**argv)
  994.                 {
  995.                     case 's':
  996.                         argc--; argv++;
  997.                         scale_setup(*argv);
  998.                         break;
  999.  
  1000.                     case 'i':
  1001.                         opts.pro.invert = TRUE;
  1002.                         break;
  1003.  
  1004.                     case 'b':
  1005.                         argc--; argv++;
  1006.                         out.bpp = atoi(*argv);
  1007.                         if(out.bpp!=1  && out.bpp!=2 &&
  1008.                            out.bpp!=4  && out.bpp!=8 &&
  1009.                            out.bpp!=15 && out.bpp!=24)
  1010.                         {
  1011.                                 syntax("Error: Bad bits per pixel");
  1012.                                 exit(1);
  1013.                         }
  1014.                         /* 24/24 bpp mode by specifing PAL_RGB */
  1015.                         break;
  1016.  
  1017.                     case 'p':
  1018.                         argc--; argv++;
  1019.             palette_setup(*argv);
  1020.                         break;
  1021.  
  1022.                     case 'f':
  1023.                         argc--; argv++;
  1024.             filter_setup(*argv);
  1025.                         break;
  1026.  
  1027.                     case 'e':
  1028.                         opts.pro.expand = TRUE;
  1029.                         break;
  1030.  
  1031.                     case 'g':
  1032.                         argc--; argv++;
  1033.             opts.pro.gamma      = TRUE;
  1034.                         opts.pro.data.gamma = (float)atof(*argv);
  1035.                         break;
  1036.  
  1037.                     case 'a':
  1038.                         opts.aspect = TRUE;  /* preserve pixel aspect ratio */
  1039.                         break;
  1040.  
  1041.                     case 'n':
  1042.             if(strncmp(*argv, "nod", 3)==0)
  1043.                             opts.pro.nodither = TRUE;
  1044.             else if(strncmp(*argv, "noi", 3)==0)
  1045.                             opts.pro.nointerp = TRUE;
  1046.             else
  1047.                 syntax("Unrecognided -n...");
  1048.                         break;
  1049.  
  1050.                     case 'q':
  1051.                         opts.quiet = TRUE;
  1052.                         break;
  1053.  
  1054.                     case 'h':
  1055.                         syntax("Sprite processing with FSI dithering");
  1056.                         exit(0);
  1057.                         break;
  1058.  
  1059.                     default:
  1060.                         syntax("Error: Unrecognised parameter");
  1061.                         exit(1);
  1062.                         break;
  1063.                 }
  1064.             }
  1065.             argc--; argv++;
  1066.         }
  1067.  
  1068.         read_sprite(&in, inf);
  1069.         calc_output_info(&in, &out);
  1070.  
  1071.         if(!opts.quiet) info();
  1072.  
  1073.     /* main scaling, preprocessing and FSI routine */
  1074.  
  1075.     opts.pro.in   = ∈
  1076.     opts.pro.out  = &out;
  1077.     opts.pro.outf = outf;
  1078.         process(&opts.pro);
  1079.  
  1080. #ifdef CACHE_STAT
  1081.         fprintf(errf,"Cache calls : %d\n", cache_calls);
  1082.         fprintf(errf,"Cache hits  : %d\n", cache_hits);
  1083.         fprintf(errf,"Cache miss  : %d\n", cache_misses);
  1084.         fprintf(errf,"Cache used  : %d\n", cache_used);
  1085. #endif
  1086. }
  1087.