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

  1. /************************************************************************
  2.  *                                                                      *
  3.  * process.c                                                            *
  4.  * =========                                                            *
  5.  *                                                                      *
  6.  * RISCOS sprite style bitmap processing library                        *
  7.  * Uses spr_info generic bitmap interface from sprite.c library         *
  8.  *                                                                      *
  9.  * Supports scaling, depth (colour) expansion/reduction                 *
  10.  * with limited image processing features.                              *
  11.  * Uses Floyd-Steinburg Integer (FSI) error distrubution dithering      *
  12.  *                                                                      *
  13.  * Version 0.01 (18-Jan-1993)                                           *
  14.  *         0.02 (24-Feb-1993)                                           *
  15.  *         0.03 (15-Mar-1993)                                           *
  16.  *         0.04 (28-Apr-1993)                                           *
  17.  *         0.05 (10-May-1993) Split from spr_fsi.c                      *
  18.  *         0.06 (16-Jun-1993)                                           *
  19.  *         0.07 (01-Sep-1993)                                           *
  20.  *         0.08 (09-Sep-1993) closest_rgb() optimizations added         *
  21.  *         0.09 (13-Sep-1993)                                           *
  22.  *         0.10 (13-Oct-1993)                                           *
  23.  *         1.00 (13-Jan-1994)                                           *
  24.  *         1.10 (20-Apr-1994) filters added                *
  25.  *         1.15 (05-May-1994) closest_rgb moved to colours.c        *
  26.  *         1.22 (11-May-1994) pix_sum interpolation addded        *
  27.  *                                                                      *
  28.  * (C) 1993/1994 DEEJ Technology PLC                                    *
  29.  *                                                                      *
  30.  ************************************************************************/
  31.  
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <math.h>
  36. #include "sprite.h"
  37. #include "colours.h"
  38. #include "palette.h"
  39. #include "process.h"
  40.  
  41. /****************************************************************************/
  42.  
  43. /*
  44.  * return intensity of RGB value
  45.  * to 16 bit, using fixed coding
  46.  */
  47.  
  48. uint intensity(uint rgb)
  49. {
  50.         return( ( ((rgb >> 8)  & 0xFF) * RED_WEIGHT   +
  51.                   ((rgb >> 16) & 0xFF) * GREEN_WEIGHT +
  52.                   ((rgb >> 24) )       * BLUE_WEIGHT ) );
  53. }
  54.  
  55. /*
  56.  * check for any excess colour components
  57.  * (<0 or >255) and calculate an excess intensity
  58.  * to be added to to all three components
  59.  */
  60.  
  61. void excess_rgb(pix_str *rgb)
  62. {
  63.         int excess = 0;
  64.  
  65.         if(rgb->red < 0)
  66.         {
  67.                 excess   = rgb->red * RED_WEIGHT;
  68.                 rgb->red = 0;
  69.         }
  70.         if(rgb->red > 255)
  71.         {
  72.                 excess   = (rgb->red - 255) * RED_WEIGHT;
  73.                 rgb->red = 255;
  74.         }
  75.         if(rgb->green < 0)
  76.         {
  77.                 excess    += rgb->green * GREEN_WEIGHT;
  78.                 rgb->green = 0;
  79.         }
  80.         if(rgb->green > 255)
  81.         {
  82.                 excess    += (rgb->green - 255) * GREEN_WEIGHT;
  83.                 rgb->green = 255;
  84.         }
  85.         if(rgb->blue < 0)
  86.         {
  87.                 excess   += rgb->blue  * BLUE_WEIGHT;
  88.                 rgb->blue = 0;
  89.         }
  90.         if(rgb->blue > 255)
  91.         {
  92.                 excess   += (rgb->blue - 255) * BLUE_WEIGHT;
  93.                 rgb->blue = 255;
  94.         }
  95.  
  96.         if(excess != 0)
  97.         {
  98.                 rgb->red   += (excess >> 16);
  99.                 rgb->green += (excess >> 16);
  100.                 rgb->blue  += (excess >> 16);
  101.         }
  102. }
  103.  
  104. /*
  105.  * Invert a sprite
  106.  * using palette translation if possible
  107.  */
  108.  
  109. void invert(spr_info_str *s)
  110. {
  111.         int x,y,x1,y1;
  112.         uint mask;
  113.  
  114.         if(s->has_palette)
  115.         {
  116.                 x1   = s->cols;
  117.                 y1   = 1;
  118.                 mask = 0xFFFFFF00;
  119.         }
  120.         else
  121.         {
  122.                 x1   = s->X;
  123.                 y1   = s->Y;
  124.  
  125.                 switch(s->bpp)
  126.                 {
  127.                         case  8: mask = 0x000000FF; break;
  128.                         case 15: mask = 0x00007FFF; break;
  129.                         case 24: mask = 0xFFFFFF00; break;
  130.                         default: break;
  131.                 }
  132.         }
  133.  
  134.     progress_start("Inverting   :");
  135.  
  136.         for(y=0; y<y1; y++)
  137.     {
  138.             for(x=0; x<x1; x++)
  139.             {
  140.                 if(s->has_palette)
  141.                 {
  142.                         s->palette[x] = (~s->palette[x]) & mask;
  143.                     progress(x, x1);
  144.                 }
  145.                 else
  146.                 {
  147.                         s->write_pixel_val(s, x, y,
  148.                                            ~s->read_pixel_val(s,x,y) & mask);
  149.                 }
  150.         }
  151.             if(!s->has_palette)
  152.                 progress(y, y1);
  153.         }
  154.  
  155.     progress_finish();
  156. }
  157.  
  158. /*
  159.  * Expand dynamic range of a sprite
  160.  * using palette translation if possible
  161.  */
  162.  
  163. void expand(spr_info_str *s)
  164. {
  165.         int   i,x,y,x1,y1;
  166.         uint  value,min,max;
  167.         uint  r,g,b;
  168.         uchar table[256];
  169.  
  170.         if(s->has_palette)
  171.         {
  172.                 x1 = s->cols;
  173.                 y1 = 1;
  174.         }
  175.         else
  176.         {
  177.                 x1 = s->X;
  178.                 y1 = s->Y;
  179.         }
  180.  
  181.         /* find min and max values */
  182.  
  183.         min = 255;
  184.         max = 0;
  185.  
  186.     progress_start("Find limits :");
  187.  
  188.         for(y=0; y<y1; y++)
  189.     {
  190.             for(x=0; x<x1; x++)
  191.             {
  192.                 if(s->has_palette)
  193.         {
  194.                         value = s->palette[x];
  195.                     progress(x, x1);
  196.         }
  197.                 else
  198.         {
  199.                         value = s->read_pixel_val(s,x,y);
  200.         }
  201.  
  202.                 SPLIT_RGB(value)
  203.  
  204.                 if(r < min) min = r;
  205.                 if(g < min) min = g;
  206.                 if(b < min) min = b;
  207.                 if(r > max) max = r;
  208.                 if(g > max) max = g;
  209.                 if(b > max) max = b;
  210.         }
  211.  
  212.             if(!s->has_palette)
  213.                 progress(y, y1);
  214.         }
  215.  
  216.     progress_finish();
  217.     progress_start("Expanding   :");
  218.  
  219.         for(i=0; i<256; i++)
  220.         {
  221.                 table[i] = ((i-min)*255)/(max-min);
  222.         }
  223.  
  224.         table_lookup(s, table);
  225.  
  226.     progress_finish();
  227. }
  228.  
  229. /*
  230.  * correct gamma of a sprite
  231.  * using palette translation if possible
  232.  */
  233.  
  234. void gamma_cr(spr_info_str *s, float gamma)
  235. {
  236.         int  i;
  237.         uchar table[256];
  238.  
  239.     progress_start("Gamma corrct:");
  240.  
  241.         for(i=0; i<256; i++)
  242.         {
  243.             table[i] = (char)(pow((double)i/255.0, 1.0/(double)gamma)*255.0);
  244.         }
  245.         table_lookup(s, table);
  246.  
  247.     progress_finish();
  248. }
  249.  
  250. /*
  251.  * perform table lookup on on r,g,b components
  252.  * on a sprites palette, or pixels if paletteless
  253.  */
  254.  
  255. void table_lookup(spr_info_str *s, uchar *table)
  256. {
  257.         int x,y,x1,y1;
  258.         uint value, r,g,b;
  259.         pix_str rgb;
  260.  
  261.         if(s->has_palette)
  262.         {
  263.                 x1 = s->cols;
  264.                 y1 = 1;
  265.         }
  266.         else
  267.         {
  268.                 x1 = s->X;
  269.                 y1 = s->Y;
  270.         }
  271.  
  272.         for(y=0; y<y1; y++)
  273.     {
  274.             for(x=0; x<x1; x++)
  275.             {
  276.                 if(s->has_palette)
  277.         {
  278.                         value = s->palette[x];
  279.                     progress(x, x1);
  280.         }
  281.                 else
  282.         {
  283.                         value = s->read_pixel_val(s,x,y);
  284.         }
  285.  
  286.                 SPLIT_RGB(value);
  287.  
  288.                 rgb.red   = table[r];
  289.                 rgb.green = table[g];
  290.                 rgb.blue  = table[b];
  291.  
  292.                 if(s->has_palette)
  293.         {
  294.             rgb.value     = (rgb.blue  << 24) |
  295.                         (rgb.green << 16) |
  296.                         (rgb.red   <<  8);
  297.                         s->palette[x] =  rgb.value;
  298.         }
  299.                 else
  300.         {
  301.                         s->write_pixel_val(s,x,y,s->closest_rgb(s,&rgb)->value);
  302.         }
  303.         }
  304.             if(!s->has_palette)
  305.                 progress(y, y1);
  306.         }
  307. }
  308.  
  309. /*
  310.  * Apply a filter to a sprite
  311.  * should really only be used on 15/24 bpp
  312.  * as no error diffusion will be done on
  313.  * closest values used on substution
  314.  */
  315.  
  316. void filter(spr_info_str *s, filter_str *f)
  317. {
  318.         int i, x,y, x2,y2;
  319.     int     sum[3],mul;
  320.     uint    *buffer[3];
  321.         uint    val;
  322.     pix_str pix;
  323.  
  324.     /* get a three line buffer */
  325.  
  326.     if((buffer[0] = malloc(s->X*4))==0 ||
  327.        (buffer[1] = malloc(s->X*4))==0 ||
  328.        (buffer[2] = malloc(s->X*4))==0)
  329.     {
  330.                 fprintf(stderr,"Error: Failed to allocate filter buffer");
  331.                 fprintf(stderr,"- unable to continue\n");
  332.                 exit(1);
  333.         }
  334.  
  335.     progress_start("Filtering   :");
  336.  
  337.     /* read first three lines into buffer */
  338.  
  339.     for(y=0; y<3; y++)
  340.     for(x=0; x<s->X; x++)
  341.     {
  342.         buffer[y][x] = s->read_pixel_rgb(s, x, y);
  343.     }
  344.  
  345.         for(y=1; y<s->Y-1; y++)
  346.     {
  347.             for(x=1; x<s->X-1; x++)
  348.             {
  349.         /* sum weighted pixel component values in 3x3 matrix */
  350.  
  351.         sum[0] = sum[1] = sum[2] = 0;
  352.  
  353.         for(y2=0; y2<3; y2++)
  354.         for(x2=0; x2<3; x2++)
  355.         {
  356.             if((mul = f->matrix[y2][x2])!=0)
  357.             {
  358.                 val     = buffer[y2][x+x2-1];
  359.                 sum[0] += (((val>>8)  & 0xFF) * mul);
  360.                 sum[1] += (((val>>16) & 0xFF) * mul);
  361.                 sum[2] += (((val>>24) & 0xFF) * mul);
  362.             }
  363.         }
  364.  
  365.         if(f->diff != 0)
  366.             val    = s->read_pixel_rgb(s, x, y);
  367.  
  368.         /* filter each component seperately */
  369.  
  370.         for(i=0; i<3; i++)
  371.         {
  372.             /* multiply, divide and add constant to sum */
  373.  
  374.             if(f->mul != 1) sum[i] *= f->mul;
  375.             if(f->div != 1) sum[i] /= f->div;
  376.                     sum[i] += f->add;
  377.  
  378.             /* check for differencing (noise) filter */
  379.  
  380.             if(f->diff != 0)
  381.             {
  382.                 int diff = ((val >> ((i+1)*8)) & 0xFF) - sum[i];
  383.  
  384.                 if(diff<0) diff = -diff;
  385.  
  386.                 /* use centre value if diff in range */
  387.  
  388.                 if(diff <= f->diff)
  389.                     sum[i] = (val >> ((i+1)*8)) & 0xFF;
  390.             }
  391.             RANGE_RGB(sum[i]);
  392.         }
  393.  
  394.         /* write new value to centre pixel */
  395.  
  396.         pix.red   = sum[0];
  397.         pix.green = sum[1];
  398.         pix.blue  = sum[2];
  399.         s->write_pixel_val(s, x,y, s->closest_rgb(s, &pix)->value);
  400.         }
  401.  
  402.         /* copy lines up buffer and read next */
  403.  
  404.         memcpy(buffer[0], buffer[1], s->X*4);
  405.         memcpy(buffer[1], buffer[2], s->X*4);
  406.         for(x=0; x<s->X; x++)
  407.         {
  408.         buffer[2][x] = s->read_pixel_rgb(s, x, y+1);
  409.         }
  410.             progress(y, s->Y-2);
  411.         }
  412.  
  413.     progress_finish();
  414.  
  415.     free((void*)buffer[0]);
  416.     free((void*)buffer[1]);
  417.     free((void*)buffer[2]);
  418. }
  419.  
  420. /*
  421.  * diffuses fraction of RGB error to pixel
  422.  * parameters are the address of an R,G,B integer triplet
  423.  * the r,g,b error values as integers and a 16 bit
  424.  * fixed point fraction
  425.  */
  426.  
  427. void err_diff(pix_str *pixel, pix_str *err, int factor)
  428. {
  429.         pixel->red   += (err->red   * factor);
  430.         pixel->green += (err->green * factor);
  431.         pixel->blue  += (err->blue  * factor);
  432. }
  433.  
  434. /*
  435.  * sums pixels along a row, used by pix_sum
  436.  * averages pixels for contraction and
  437.  * interploates for expansion
  438.  * x1i,x1f = start for sum, pixel centre for interpolation
  439.  * x2i,x2f = end for sum, unused for interploation
  440.  */
  441.  
  442. static void pix_sum_row(spr_info_str *in, pix_str *sumX,
  443.                         int x1i, int x1f,
  444.                         int x2i, int x2f,
  445.                         int y, int div,
  446.             BOOL interpX)
  447. {
  448.         REGISTER int  x;
  449.         REGISTER uint rgb;
  450.     REGISTER int  r,g,b;
  451.  
  452.     if(interpX)
  453.     {
  454.         /* interploate between pixels centers */
  455.  
  456.             rgb         = in->read_pixel_rgb(in, x1i, y);
  457.         sumX->red   = (rgb >>  8) & 0xFF;
  458.         sumX->green = (rgb >> 16) & 0xFF;
  459.         sumX->blue  = (rgb >> 24) & 0xFF;
  460.  
  461.         if(x1f<0x8000 && x1i>0)
  462.         {
  463.             /* left of x center so add proportion */
  464.                         /* of previous pixel (0 to 0.5)       */
  465.  
  466.                 rgb = in->read_pixel_rgb(in, x1i-1, y);
  467.             SPLIT_RGB(rgb);
  468.  
  469.             sumX->red   += ((r - sumX->red  )*(0x8000-x1f)) >> 16;
  470.             sumX->green += ((g - sumX->green)*(0x8000-x1f)) >> 16;
  471.             sumX->blue  += ((b - sumX->blue )*(0x8000-x1f)) >> 16;
  472.         }
  473.         else if(x1f>0x8000 && x1i<(in->X-1))
  474.         {
  475.             /* right of x center so add proportion */
  476.                         /* of next pixel (0 to 0.5)            */
  477.  
  478.                 rgb = in->read_pixel_rgb(in, x1i+1, y);
  479.             SPLIT_RGB(rgb);
  480.  
  481.             sumX->red   += ((r - sumX->red  )*(x1f-0x8000)) >> 16;
  482.             sumX->green += ((g - sumX->green)*(x1f-0x8000)) >> 16;
  483.             sumX->blue  += ((b - sumX->blue )*(x1f-0x8000)) >> 16;
  484.         }
  485.     }
  486.     else
  487.     {
  488.             sumX->red = sumX->green = sumX->blue = 0;
  489.  
  490.             /* read first pixel */
  491.  
  492.             rgb = in->read_pixel_rgb(in, x1i, y);
  493.             SPLIT_RGB(rgb);
  494.  
  495.             /* if start and end in same pixel, average is pixel value */
  496.  
  497.             if(x1i==x2i)
  498.             {
  499.                     sumX->red   = r;
  500.                     sumX->green = g;
  501.                     sumX->blue  = b;
  502.             }
  503.             else
  504.             {
  505.                     /* sum fraction of first pixel if any */
  506.  
  507.                     if(x1f > 0)
  508.                     {
  509.                             sumX->red   = r * (0x10000-x1f);
  510.                             sumX->green = g * (0x10000-x1f);
  511.                             sumX->blue  = b * (0x10000-x1f);
  512.                     }
  513.                     else
  514.                     {
  515.                             sumX->red   = (r<<16);
  516.                             sumX->green = (g<<16);
  517.                             sumX->blue  = (b<<16);
  518.                     }
  519.  
  520.                     /* sum whole pixels between x1+1 & x2 */
  521.  
  522.                     if((x1i+1) < x2i)
  523.                     {
  524.                         for(x=x1i+1; x<x2i; x++)
  525.                         {
  526.                             rgb = in->read_pixel_rgb(in, x, y);
  527.                             SPLIT_RGB(rgb);
  528.  
  529.                             sumX->red   += (r<<16);
  530.                             sumX->green += (g<<16);
  531.                             sumX->blue  += (b<<16);
  532.                         }
  533.                     }
  534.  
  535.                     /* sum fractaction of last pixel if any */
  536.  
  537.                     if(x2f > 0)
  538.                     {
  539.                             rgb = in->read_pixel_rgb(in, x2i, y);
  540.                             SPLIT_RGB(rgb);
  541.  
  542.                             sumX->red   += r * x2f;
  543.                             sumX->green += g * x2f;
  544.                             sumX->blue  += b * x2f;
  545.                     }
  546.  
  547.                     /* average over number of whole & part pixels */
  548.  
  549.                     sumX->red   = sumX->red   / div;
  550.                     sumX->green = sumX->green / div;
  551.                     sumX->blue  = sumX->blue  / div;
  552.             }
  553.     }
  554. }
  555.  
  556. /*
  557.  * Averages an area of pixel fragments for contraction
  558.  * and interpolates between pixel centers for expansion
  559.  *
  560.  * Parameters are 16 bit fixed point positions
  561.  * of pixel area to be summed in source bitmaps
  562.  * x1,y1 = top left (inclusive)
  563.  * x2,y2 = bottom right (exclusive)
  564.  * (top left = 0,0)
  565.  *
  566.  * NOTE: fixed point fails if summing > 128 pixels in either direction
  567.  *       fractions are round fractions of pixels to prevent stepping
  568.  *       inaccuracies causing small fractions of pixels
  569.  *       to be summed, <1/256 can be ignored with no effect
  570.  */
  571.  
  572. pix_str pix_sum(spr_info_str *in, int x1, int y1, int x2, int y2)
  573. {
  574.         REGISTER int y;
  575.         REGISTER int x1i,y1i, x1f,y1f;
  576.         REGISTER int x2i,y2i, x2f,y2f;
  577.              int div;
  578.         pix_str  sumX, sumY;
  579.     BOOL     interpX = (x2-x1) < 0x10000;    /* interplate if expanding */
  580.         BOOL     interpY = (y2-y1) < 0x10000;    /* average if contracting  */
  581.  
  582.     if(interpX)
  583.     {
  584.         /* find pixel centre for interpolation */
  585.  
  586.             x1  = (x1+x2)>>1;
  587.             x1i = (x1 >> 16);
  588.             x1f = (x1 & 0xFFFF);
  589.  
  590.         /* round pixel fractions */
  591.  
  592.             if(x1f < 256) x1f=0;   if(x1f > 65280) { x1f=0; x1i++; }
  593.  
  594.             /* ensure original coords match new values */
  595.  
  596.             x1 = (x1i << 16)+x1f;
  597.     }
  598.     else
  599.     {
  600.         /* make integer and fractional parts for start/end */
  601.  
  602.             x1i = (x1 >> 16);
  603.             x1f = (x1 & 0xFFFF);
  604.             x2i = (x2 >> 16);
  605.             x2f = (x2 & 0xFFFF);
  606.  
  607.         /* round pixel fractions */
  608.  
  609.             if(x1f < 256) x1f=0;    if(x1f > 65280) { x1f=0; x1i++; }
  610.             if(x2f < 256) x2f=0;    if(x2f > 65280) { x2f=0; x2i++; }
  611.  
  612.             /* ensure original coords match new values */
  613.  
  614.             x1 = (x1i << 16)+x1f;
  615.             x2 = (x2i << 16)+x2f;
  616.  
  617.         /* pixel row sum divisor */
  618.  
  619.             div = (x2-x1);
  620.     }
  621.  
  622.     if(interpY)
  623.     {
  624.         /*
  625.          * interpolate between (sum/interpolation) of pixel rows
  626.          */
  627.             pix_str sumYn;
  628.  
  629.         /* find pixel centre for interpolation */
  630.  
  631.         y1  = (y1+y2)>>1;
  632.         y1i = (y1 >> 16);
  633.         y1f = (y1 & 0xFFFF);
  634.  
  635.         /* round pixel fractions */
  636.  
  637.             if(y1f < 256) y1f=0;    if(y1f > 65280) { y1f=0; y1i++; }
  638.  
  639.             /* ensure original coords match new values */
  640.  
  641.             y1 = (y1i << 16)+y1f;
  642.  
  643.         /* interpolate between centers of pixel rows if expanding */
  644.  
  645.             pix_sum_row(in, &sumY, x1i,x1f, x2i,x2f, y1i,div, interpX);
  646.  
  647.         if(y1f<0x08000 && y1i>0)
  648.         {
  649.             /* above y1 center so add proportion */
  650.                 /* of previous row (0 to 0.5)        */
  651.  
  652.             pix_sum_row(in, &sumYn, x1i,x1f,
  653.                         x2i,x2f, y1i-1, div, interpX);
  654.  
  655.             sumY.red   += ((sumYn.red   - sumY.red)   *
  656.                     (0x8000-y1f)) >> 16;
  657.             sumY.green += ((sumYn.green - sumY.green) *
  658.                     (0x8000-y1f)) >> 16;
  659.             sumY.blue  += ((sumYn.blue  - sumY.blue)  *
  660.                     (0x8000-y1f)) >> 16;
  661.         }
  662.         else if(y1f>0x08000 && y1i>(in->Y-1))
  663.         {
  664.             /* below y1 center so add proportion */
  665.                 /* of next row (0 to 0.5)            */
  666.  
  667.             pix_sum_row(in, &sumYn, x1i,x1f,
  668.                         x2i,x2f, y1i+1, div, interpX);
  669.  
  670.             sumY.red   += ((sumYn.red   - sumY.red)   *
  671.                     (y1f-0x8000)) >> 16;
  672.             sumY.green += ((sumYn.green - sumY.green) *
  673.                     (y1f-0x8000)) >> 16;
  674.             sumY.blue  += ((sumYn.blue  - sumY.blue)  *
  675.                     (y1f-0x8000)) >> 16;
  676.         }
  677.         return(sumY);
  678.     }
  679.  
  680.     /*
  681.          * sum whole and partial pixel rows
  682.      */
  683.  
  684.     sumY.red = sumY.green = sumY.blue = 0;
  685.  
  686.     /* make integer and fractional parts for start/end */
  687.  
  688.         y1i = (y1 >> 16);
  689.         y1f = (y1 & 0xFFFF);
  690.         y2i = (y2 >> 16);
  691.         y2f = (y2 & 0xFFFF);
  692.  
  693.     /* round pixel fractions */
  694.  
  695.         if(y1f < 256) y1f=0;    if(y1f > 65280) { y1f=0; y1i++; }
  696.         if(y2f < 256) y2f=0;    if(y2f > 65280) { y2f=0; y2i++; }
  697.  
  698.         /* ensure original coords match new values */
  699.  
  700.         y1 = (y1i << 16)+y1f;
  701.         y2 = (y2i << 16)+y2f;
  702.  
  703.         /* correct looping for whole last pixel row */
  704.  
  705.         if(y2f==0) y2i--;
  706.  
  707.         for(y=y1i; y<=y2i; y++)
  708.         {
  709.         /* sum or interpolate along pixel row */
  710.  
  711.         pix_sum_row(in, &sumX, x1i,x1f, x2i,x2f, y,div, interpX);
  712.  
  713.                 /* sum fraction of pixel row if not whole pixel high */
  714.  
  715.                 if((y==y1i) && (y!=y2i) && (y1f>0))
  716.                 {
  717.                         sumY.red   = sumX.red   * (0x10000-y1f);
  718.                         sumY.green = sumX.green * (0x10000-y1f);
  719.                         sumY.blue  = sumX.blue  * (0x10000-y1f);
  720.                 }
  721.                 else
  722.                 {
  723.                         /* sum faction of last pixel row if not whole */
  724.  
  725.                         if((y!=y1i) && (y==y2i) && (y2f>0))
  726.                         {
  727.                                 sumY.red   += sumX.red   * y2f;
  728.                                 sumY.green += sumX.green * y2f;
  729.                                 sumY.blue  += sumX.blue  * y2f;
  730.                         }
  731.                         else
  732.                         {
  733.                                 /* sum whole pixel rows */
  734.  
  735.                                 sumY.red   += (sumX.red   << 16);
  736.                                 sumY.green += (sumX.green << 16);
  737.                                 sumY.blue  += (sumX.blue  << 16);
  738.                         }
  739.                 }
  740.         }
  741.  
  742.         /*
  743.          * average over whole & part number of pixel rows
  744.          * fixed point is automatically converted to integer
  745.          * if start & end on the same row divid by 1
  746.          */
  747.  
  748.         div = (y2i==y1i) ? (1<<16) : (y2-y1);
  749.  
  750.         sumY.red   = sumY.red   / div;
  751.         sumY.green = sumY.green / div;
  752.         sumY.blue  = sumY.blue  / div;
  753.  
  754.         return(sumY);
  755. }
  756.  
  757. /*
  758.  * main sprite FSI processing routine
  759.  *
  760.  * if file valid write each processed line out immediately
  761.  * otherwise build destination sprite in memory
  762.  */
  763.  
  764. void process(process_str *p)
  765. {
  766.         REGISTER int inX, inY, outX, outY;
  767.         int Xinc, Yinc, Xdir, Ydir, x1, x2, y;
  768.         pix_str *line1, *line2;
  769.         pix_str sum, *new, err;
  770.  
  771.     /* get best function for finding closest RGB values */
  772.  
  773.     closest_rgb_func(p->in);
  774.  
  775.         /* do any preprocessing of the image */
  776.  
  777.     if(p->filter)      filter(p->in, &p->data.filter);
  778.         if(p->invert)      invert(p->in);
  779.         if(p->expand)      expand(p->in);
  780.         if(p->gamma)       gamma_cr(p->in,p->data.gamma);
  781.  
  782.         /* calculate optimized palette after preprocessing */
  783.  
  784.         if(p->palette_opt) optimize_palette(p->in, p->out);
  785.  
  786.     /* get best function for finding closest RGB values */
  787.  
  788.     closest_rgb_func(p->out);
  789.  
  790.     /* write sprite header to file if given */
  791.  
  792.     if(p->outf != 0) write_sprite_header(p->out, p->outf);
  793.  
  794.         /* allocate memory for two lines of the sprite 32+32+32 bpp (r,g,b) */
  795.  
  796.         if((line1=(pix_str*)malloc(p->out->X*sizeof(pix_str)))==0 ||
  797.            (line2=(pix_str*)malloc(p->out->X*sizeof(pix_str)))==0)
  798.         {
  799.                 /* should really free line1 if <>0, but exiting anyway */
  800.                 fprintf(stderr,"Error: Failed to allocate working buffer");
  801.                 fprintf(stderr,"- unable to continue\n");
  802.                 exit(1);
  803.         }
  804.         memset((void*)line1, 0, p->out->X*sizeof(pix_str));
  805.         memset((void*)line2, 0, p->out->X*sizeof(pix_str));
  806.  
  807.     progress_start("Processing  :");
  808.  
  809.         /* main Floyd Steinburg Integer code */
  810.  
  811.         Xdir = 1;                                 /* X direction for zig-zag */
  812.         Ydir = 1;                                 /* Y direction fixed (down)*/
  813.         Xinc = (p->in->X * 0x10000) / p->out->X;  /* 16.16 bit fixed point   */
  814.         Yinc = (p->in->Y * 0x10000) / p->out->Y;  /* increment through input */
  815.         inY  = 0;
  816.  
  817.         for(outY=0; outY<=p->out->Y-1; outY+=Ydir)
  818.         {
  819.                 /* X position is always top left of pixel regradless of dir */
  820.  
  821.                 if(Xdir==1)
  822.                 {
  823.                         x1  = 0;
  824.                         x2  = p->out->X;
  825.                         inX = 0;
  826.                 }
  827.                 else
  828.                 {
  829.                         x1  = p->out->X-1;
  830.                         x2  = -1;
  831.                         inX = (p->in->X<<16)+Xinc;
  832.                 }
  833.  
  834.                 for(outX=x1; outX!=x2; outX+=Xdir)
  835.                 {
  836.                         /* ensure that x1 is less than x2 and  */
  837.                         /* that y1 is less than y2 for pix_sum */
  838.  
  839.             if(p->nointerp)
  840.             {
  841.                 sum.value = p->in->read_pixel_rgb(p->in,
  842.                                                               inX>>16,
  843.                                                               inY>>16);
  844.                 sum.red   = (sum.value >>  8) & 0xFF;
  845.                 sum.green = (sum.value >> 16) & 0xFF;
  846.                 sum.blue  = (sum.value >> 24) & 0xFF;
  847.             }
  848.             else
  849.             {
  850.                             if(Xdir==1)
  851.                             {
  852.                                 sum = pix_sum(p->in, inX,      inY,
  853.                                                      inX+Xinc, inY+Yinc);
  854.                             }
  855.                             else
  856.                             {
  857.                                 sum = pix_sum(p->in, inX,      inY,
  858.                                                      inX-Xinc, inY+Yinc);
  859.                             }
  860.             }
  861.  
  862.                         if(!p->nodither)
  863.                         {
  864.                             /* add any error distributed to this pixel */
  865.  
  866.                             sum.red   += (line1[outX].red   >> 8);
  867.                             sum.green += (line1[outX].green >> 8);
  868.                             sum.blue  += (line1[outX].blue  >> 8);
  869.  
  870.                             excess_rgb(&sum);
  871.  
  872.                             new = p->out->closest_rgb(p->out, &sum);
  873.  
  874.                             line1[outX].value = new->value;
  875.  
  876.                             /* use full sum+line1 values for error calc */
  877.  
  878.                             err.red   = sum.red   - new->red;
  879.                             err.green = sum.green - new->green;
  880.                             err.blue  = sum.blue  - new->blue;
  881.  
  882.                             /* distribute error:    , pixel*1 , err*7/16, */
  883.                             /*              err*3/16, err*5/16, err*1/16, */
  884.  
  885.                             err_diff(&line1[outX], new, (16*0x100)/16);
  886.  
  887.                             /* speedup check for exact match */
  888.  
  889.                             if(err.red!=0 || err.green!=0 || err.blue!=0)
  890.                             {
  891.                                 if((Xdir == 1  && outX < (x2-1)) ||
  892.                                    (Xdir == -1 && outX > 0))
  893.                                 {
  894.                                     err_diff(&line1[outX+Xdir],
  895.                                              &err, (7*0x100)/16); /* 7/16 */
  896.                                 }
  897.                                 if(outY < (p->out->Y-1))
  898.                                 {
  899.                                     err_diff(&line2[outX],
  900.                                              &err, (5*0x100)/16); /* 5/16 */
  901.  
  902.                                     if((Xdir == 1  && outX < (x2-1)) ||
  903.                                        (Xdir == -1 && outX > 0))
  904.                                     {
  905.                                         err_diff(&line2[outX-Xdir],
  906.                                                  &err, (1*0x100)/16); /*1/16*/
  907.                                     }
  908.                                     if((Xdir == 1  && outX > 0) ||
  909.                                        (Xdir == -1 && outX < (x2-1)))
  910.                                     {
  911.                                         err_diff(&line2[outX+Xdir],
  912.                                                  &err, (3*0x100)/16); /*3/16*/
  913.                                     }
  914.                                 }
  915.                             }
  916.                         }
  917.                         else
  918.                         {
  919.                             /* no dither, so just find nearest colour */
  920.  
  921.                             new = p->out->closest_rgb(p->out, &sum);
  922.                             line1[outX].value = new->value;
  923.                         }
  924.                         inX += Xinc;
  925.                 }
  926.  
  927.                 Xdir = -Xdir;     /* reverse Xdir for zigzag */
  928.                 Xinc = -Xinc;
  929.                 inY += Yinc;
  930.  
  931.                 /*
  932.          * make one line of output sprite
  933.          * use y=0 if file is valid as only one line of data has been
  934.                  * allocated, otherwise place line in correct y position to
  935.                  * make whole sprite in memory
  936.          */
  937.  
  938.         if(p->outf==0)
  939.             y = outY;
  940.         else
  941.             y = 0;
  942.  
  943.                 for(outX=0; outX<p->out->X; outX++)
  944.                 {
  945.                         p->out->write_pixel_val(p->out, outX, y,
  946.                                                 line1[outX].value);
  947.                 }
  948.  
  949.                 /* write pixel line to file immediately if required */
  950.  
  951.         if(p->outf != 0)
  952.         {
  953.             fwrite(p->out->spr_data, p->out->line_size, 1, p->outf);
  954.         }
  955.  
  956.                 /* copy up second line of buffer, and clear */
  957.  
  958.                 memcpy(line1, line2, p->out->X*sizeof(pix_str));
  959.                 memset(line2, 0, p->out->X*sizeof(pix_str));
  960.  
  961.         progress(outY, p->out->Y);
  962.         }
  963.  
  964.     progress_finish();
  965.  
  966. /* #### run time heap problem under RISC OS */
  967. #ifndef RISCOS
  968.         free((void*)line1);
  969.     free((void*)line2);
  970. #endif
  971. }
  972.