home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * process.c *
- * ========= *
- * *
- * RISCOS sprite style bitmap processing library *
- * Uses spr_info generic bitmap interface from sprite.c library *
- * *
- * Supports scaling, depth (colour) expansion/reduction *
- * with limited image processing features. *
- * Uses Floyd-Steinburg Integer (FSI) error distrubution dithering *
- * *
- * Version 0.01 (18-Jan-1993) *
- * 0.02 (24-Feb-1993) *
- * 0.03 (15-Mar-1993) *
- * 0.04 (28-Apr-1993) *
- * 0.05 (10-May-1993) Split from spr_fsi.c *
- * 0.06 (16-Jun-1993) *
- * 0.07 (01-Sep-1993) *
- * 0.08 (09-Sep-1993) closest_rgb() optimizations added *
- * 0.09 (13-Sep-1993) *
- * 0.10 (13-Oct-1993) *
- * 1.00 (13-Jan-1994) *
- * 1.10 (20-Apr-1994) filters added *
- * 1.15 (05-May-1994) closest_rgb moved to colours.c *
- * 1.22 (11-May-1994) pix_sum interpolation addded *
- * *
- * (C) 1993/1994 DEEJ Technology PLC *
- * *
- ************************************************************************/
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #include "sprite.h"
- #include "colours.h"
- #include "palette.h"
- #include "process.h"
-
- /****************************************************************************/
-
- /*
- * return intensity of RGB value
- * to 16 bit, using fixed coding
- */
-
- uint intensity(uint rgb)
- {
- return( ( ((rgb >> 8) & 0xFF) * RED_WEIGHT +
- ((rgb >> 16) & 0xFF) * GREEN_WEIGHT +
- ((rgb >> 24) ) * BLUE_WEIGHT ) );
- }
-
- /*
- * check for any excess colour components
- * (<0 or >255) and calculate an excess intensity
- * to be added to to all three components
- */
-
- void excess_rgb(pix_str *rgb)
- {
- int excess = 0;
-
- if(rgb->red < 0)
- {
- excess = rgb->red * RED_WEIGHT;
- rgb->red = 0;
- }
- if(rgb->red > 255)
- {
- excess = (rgb->red - 255) * RED_WEIGHT;
- rgb->red = 255;
- }
- if(rgb->green < 0)
- {
- excess += rgb->green * GREEN_WEIGHT;
- rgb->green = 0;
- }
- if(rgb->green > 255)
- {
- excess += (rgb->green - 255) * GREEN_WEIGHT;
- rgb->green = 255;
- }
- if(rgb->blue < 0)
- {
- excess += rgb->blue * BLUE_WEIGHT;
- rgb->blue = 0;
- }
- if(rgb->blue > 255)
- {
- excess += (rgb->blue - 255) * BLUE_WEIGHT;
- rgb->blue = 255;
- }
-
- if(excess != 0)
- {
- rgb->red += (excess >> 16);
- rgb->green += (excess >> 16);
- rgb->blue += (excess >> 16);
- }
- }
-
- /*
- * Invert a sprite
- * using palette translation if possible
- */
-
- void invert(spr_info_str *s)
- {
- int x,y,x1,y1;
- uint mask;
-
- if(s->has_palette)
- {
- x1 = s->cols;
- y1 = 1;
- mask = 0xFFFFFF00;
- }
- else
- {
- x1 = s->X;
- y1 = s->Y;
-
- switch(s->bpp)
- {
- case 8: mask = 0x000000FF; break;
- case 15: mask = 0x00007FFF; break;
- case 24: mask = 0xFFFFFF00; break;
- default: break;
- }
- }
-
- progress_start("Inverting :");
-
- for(y=0; y<y1; y++)
- {
- for(x=0; x<x1; x++)
- {
- if(s->has_palette)
- {
- s->palette[x] = (~s->palette[x]) & mask;
- progress(x, x1);
- }
- else
- {
- s->write_pixel_val(s, x, y,
- ~s->read_pixel_val(s,x,y) & mask);
- }
- }
- if(!s->has_palette)
- progress(y, y1);
- }
-
- progress_finish();
- }
-
- /*
- * Expand dynamic range of a sprite
- * using palette translation if possible
- */
-
- void expand(spr_info_str *s)
- {
- int i,x,y,x1,y1;
- uint value,min,max;
- uint r,g,b;
- uchar table[256];
-
- if(s->has_palette)
- {
- x1 = s->cols;
- y1 = 1;
- }
- else
- {
- x1 = s->X;
- y1 = s->Y;
- }
-
- /* find min and max values */
-
- min = 255;
- max = 0;
-
- progress_start("Find limits :");
-
- for(y=0; y<y1; y++)
- {
- for(x=0; x<x1; x++)
- {
- if(s->has_palette)
- {
- value = s->palette[x];
- progress(x, x1);
- }
- else
- {
- value = s->read_pixel_val(s,x,y);
- }
-
- SPLIT_RGB(value)
-
- if(r < min) min = r;
- if(g < min) min = g;
- if(b < min) min = b;
- if(r > max) max = r;
- if(g > max) max = g;
- if(b > max) max = b;
- }
-
- if(!s->has_palette)
- progress(y, y1);
- }
-
- progress_finish();
- progress_start("Expanding :");
-
- for(i=0; i<256; i++)
- {
- table[i] = ((i-min)*255)/(max-min);
- }
-
- table_lookup(s, table);
-
- progress_finish();
- }
-
- /*
- * correct gamma of a sprite
- * using palette translation if possible
- */
-
- void gamma_cr(spr_info_str *s, float gamma)
- {
- int i;
- uchar table[256];
-
- progress_start("Gamma corrct:");
-
- for(i=0; i<256; i++)
- {
- table[i] = (char)(pow((double)i/255.0, 1.0/(double)gamma)*255.0);
- }
- table_lookup(s, table);
-
- progress_finish();
- }
-
- /*
- * perform table lookup on on r,g,b components
- * on a sprites palette, or pixels if paletteless
- */
-
- void table_lookup(spr_info_str *s, uchar *table)
- {
- int x,y,x1,y1;
- uint value, r,g,b;
- pix_str rgb;
-
- if(s->has_palette)
- {
- x1 = s->cols;
- y1 = 1;
- }
- else
- {
- x1 = s->X;
- y1 = s->Y;
- }
-
- for(y=0; y<y1; y++)
- {
- for(x=0; x<x1; x++)
- {
- if(s->has_palette)
- {
- value = s->palette[x];
- progress(x, x1);
- }
- else
- {
- value = s->read_pixel_val(s,x,y);
- }
-
- SPLIT_RGB(value);
-
- rgb.red = table[r];
- rgb.green = table[g];
- rgb.blue = table[b];
-
- if(s->has_palette)
- {
- rgb.value = (rgb.blue << 24) |
- (rgb.green << 16) |
- (rgb.red << 8);
- s->palette[x] = rgb.value;
- }
- else
- {
- s->write_pixel_val(s,x,y,s->closest_rgb(s,&rgb)->value);
- }
- }
- if(!s->has_palette)
- progress(y, y1);
- }
- }
-
- /*
- * Apply a filter to a sprite
- * should really only be used on 15/24 bpp
- * as no error diffusion will be done on
- * closest values used on substution
- */
-
- void filter(spr_info_str *s, filter_str *f)
- {
- int i, x,y, x2,y2;
- int sum[3],mul;
- uint *buffer[3];
- uint val;
- pix_str pix;
-
- /* get a three line buffer */
-
- if((buffer[0] = malloc(s->X*4))==0 ||
- (buffer[1] = malloc(s->X*4))==0 ||
- (buffer[2] = malloc(s->X*4))==0)
- {
- fprintf(stderr,"Error: Failed to allocate filter buffer");
- fprintf(stderr,"- unable to continue\n");
- exit(1);
- }
-
- progress_start("Filtering :");
-
- /* read first three lines into buffer */
-
- for(y=0; y<3; y++)
- for(x=0; x<s->X; x++)
- {
- buffer[y][x] = s->read_pixel_rgb(s, x, y);
- }
-
- for(y=1; y<s->Y-1; y++)
- {
- for(x=1; x<s->X-1; x++)
- {
- /* sum weighted pixel component values in 3x3 matrix */
-
- sum[0] = sum[1] = sum[2] = 0;
-
- for(y2=0; y2<3; y2++)
- for(x2=0; x2<3; x2++)
- {
- if((mul = f->matrix[y2][x2])!=0)
- {
- val = buffer[y2][x+x2-1];
- sum[0] += (((val>>8) & 0xFF) * mul);
- sum[1] += (((val>>16) & 0xFF) * mul);
- sum[2] += (((val>>24) & 0xFF) * mul);
- }
- }
-
- if(f->diff != 0)
- val = s->read_pixel_rgb(s, x, y);
-
- /* filter each component seperately */
-
- for(i=0; i<3; i++)
- {
- /* multiply, divide and add constant to sum */
-
- if(f->mul != 1) sum[i] *= f->mul;
- if(f->div != 1) sum[i] /= f->div;
- sum[i] += f->add;
-
- /* check for differencing (noise) filter */
-
- if(f->diff != 0)
- {
- int diff = ((val >> ((i+1)*8)) & 0xFF) - sum[i];
-
- if(diff<0) diff = -diff;
-
- /* use centre value if diff in range */
-
- if(diff <= f->diff)
- sum[i] = (val >> ((i+1)*8)) & 0xFF;
- }
- RANGE_RGB(sum[i]);
- }
-
- /* write new value to centre pixel */
-
- pix.red = sum[0];
- pix.green = sum[1];
- pix.blue = sum[2];
- s->write_pixel_val(s, x,y, s->closest_rgb(s, &pix)->value);
- }
-
- /* copy lines up buffer and read next */
-
- memcpy(buffer[0], buffer[1], s->X*4);
- memcpy(buffer[1], buffer[2], s->X*4);
- for(x=0; x<s->X; x++)
- {
- buffer[2][x] = s->read_pixel_rgb(s, x, y+1);
- }
- progress(y, s->Y-2);
- }
-
- progress_finish();
-
- free((void*)buffer[0]);
- free((void*)buffer[1]);
- free((void*)buffer[2]);
- }
-
- /*
- * diffuses fraction of RGB error to pixel
- * parameters are the address of an R,G,B integer triplet
- * the r,g,b error values as integers and a 16 bit
- * fixed point fraction
- */
-
- void err_diff(pix_str *pixel, pix_str *err, int factor)
- {
- pixel->red += (err->red * factor);
- pixel->green += (err->green * factor);
- pixel->blue += (err->blue * factor);
- }
-
- /*
- * sums pixels along a row, used by pix_sum
- * averages pixels for contraction and
- * interploates for expansion
- * x1i,x1f = start for sum, pixel centre for interpolation
- * x2i,x2f = end for sum, unused for interploation
- */
-
- static void pix_sum_row(spr_info_str *in, pix_str *sumX,
- int x1i, int x1f,
- int x2i, int x2f,
- int y, int div,
- BOOL interpX)
- {
- REGISTER int x;
- REGISTER uint rgb;
- REGISTER int r,g,b;
-
- if(interpX)
- {
- /* interploate between pixels centers */
-
- rgb = in->read_pixel_rgb(in, x1i, y);
- sumX->red = (rgb >> 8) & 0xFF;
- sumX->green = (rgb >> 16) & 0xFF;
- sumX->blue = (rgb >> 24) & 0xFF;
-
- if(x1f<0x8000 && x1i>0)
- {
- /* left of x center so add proportion */
- /* of previous pixel (0 to 0.5) */
-
- rgb = in->read_pixel_rgb(in, x1i-1, y);
- SPLIT_RGB(rgb);
-
- sumX->red += ((r - sumX->red )*(0x8000-x1f)) >> 16;
- sumX->green += ((g - sumX->green)*(0x8000-x1f)) >> 16;
- sumX->blue += ((b - sumX->blue )*(0x8000-x1f)) >> 16;
- }
- else if(x1f>0x8000 && x1i<(in->X-1))
- {
- /* right of x center so add proportion */
- /* of next pixel (0 to 0.5) */
-
- rgb = in->read_pixel_rgb(in, x1i+1, y);
- SPLIT_RGB(rgb);
-
- sumX->red += ((r - sumX->red )*(x1f-0x8000)) >> 16;
- sumX->green += ((g - sumX->green)*(x1f-0x8000)) >> 16;
- sumX->blue += ((b - sumX->blue )*(x1f-0x8000)) >> 16;
- }
- }
- else
- {
- sumX->red = sumX->green = sumX->blue = 0;
-
- /* read first pixel */
-
- rgb = in->read_pixel_rgb(in, x1i, y);
- SPLIT_RGB(rgb);
-
- /* if start and end in same pixel, average is pixel value */
-
- if(x1i==x2i)
- {
- sumX->red = r;
- sumX->green = g;
- sumX->blue = b;
- }
- else
- {
- /* sum fraction of first pixel if any */
-
- if(x1f > 0)
- {
- sumX->red = r * (0x10000-x1f);
- sumX->green = g * (0x10000-x1f);
- sumX->blue = b * (0x10000-x1f);
- }
- else
- {
- sumX->red = (r<<16);
- sumX->green = (g<<16);
- sumX->blue = (b<<16);
- }
-
- /* sum whole pixels between x1+1 & x2 */
-
- if((x1i+1) < x2i)
- {
- for(x=x1i+1; x<x2i; x++)
- {
- rgb = in->read_pixel_rgb(in, x, y);
- SPLIT_RGB(rgb);
-
- sumX->red += (r<<16);
- sumX->green += (g<<16);
- sumX->blue += (b<<16);
- }
- }
-
- /* sum fractaction of last pixel if any */
-
- if(x2f > 0)
- {
- rgb = in->read_pixel_rgb(in, x2i, y);
- SPLIT_RGB(rgb);
-
- sumX->red += r * x2f;
- sumX->green += g * x2f;
- sumX->blue += b * x2f;
- }
-
- /* average over number of whole & part pixels */
-
- sumX->red = sumX->red / div;
- sumX->green = sumX->green / div;
- sumX->blue = sumX->blue / div;
- }
- }
- }
-
- /*
- * Averages an area of pixel fragments for contraction
- * and interpolates between pixel centers for expansion
- *
- * Parameters are 16 bit fixed point positions
- * of pixel area to be summed in source bitmaps
- * x1,y1 = top left (inclusive)
- * x2,y2 = bottom right (exclusive)
- * (top left = 0,0)
- *
- * NOTE: fixed point fails if summing > 128 pixels in either direction
- * fractions are round fractions of pixels to prevent stepping
- * inaccuracies causing small fractions of pixels
- * to be summed, <1/256 can be ignored with no effect
- */
-
- pix_str pix_sum(spr_info_str *in, int x1, int y1, int x2, int y2)
- {
- REGISTER int y;
- REGISTER int x1i,y1i, x1f,y1f;
- REGISTER int x2i,y2i, x2f,y2f;
- int div;
- pix_str sumX, sumY;
- BOOL interpX = (x2-x1) < 0x10000; /* interplate if expanding */
- BOOL interpY = (y2-y1) < 0x10000; /* average if contracting */
-
- if(interpX)
- {
- /* find pixel centre for interpolation */
-
- x1 = (x1+x2)>>1;
- x1i = (x1 >> 16);
- x1f = (x1 & 0xFFFF);
-
- /* round pixel fractions */
-
- if(x1f < 256) x1f=0; if(x1f > 65280) { x1f=0; x1i++; }
-
- /* ensure original coords match new values */
-
- x1 = (x1i << 16)+x1f;
- }
- else
- {
- /* make integer and fractional parts for start/end */
-
- x1i = (x1 >> 16);
- x1f = (x1 & 0xFFFF);
- x2i = (x2 >> 16);
- x2f = (x2 & 0xFFFF);
-
- /* round pixel fractions */
-
- if(x1f < 256) x1f=0; if(x1f > 65280) { x1f=0; x1i++; }
- if(x2f < 256) x2f=0; if(x2f > 65280) { x2f=0; x2i++; }
-
- /* ensure original coords match new values */
-
- x1 = (x1i << 16)+x1f;
- x2 = (x2i << 16)+x2f;
-
- /* pixel row sum divisor */
-
- div = (x2-x1);
- }
-
- if(interpY)
- {
- /*
- * interpolate between (sum/interpolation) of pixel rows
- */
- pix_str sumYn;
-
- /* find pixel centre for interpolation */
-
- y1 = (y1+y2)>>1;
- y1i = (y1 >> 16);
- y1f = (y1 & 0xFFFF);
-
- /* round pixel fractions */
-
- if(y1f < 256) y1f=0; if(y1f > 65280) { y1f=0; y1i++; }
-
- /* ensure original coords match new values */
-
- y1 = (y1i << 16)+y1f;
-
- /* interpolate between centers of pixel rows if expanding */
-
- pix_sum_row(in, &sumY, x1i,x1f, x2i,x2f, y1i,div, interpX);
-
- if(y1f<0x08000 && y1i>0)
- {
- /* above y1 center so add proportion */
- /* of previous row (0 to 0.5) */
-
- pix_sum_row(in, &sumYn, x1i,x1f,
- x2i,x2f, y1i-1, div, interpX);
-
- sumY.red += ((sumYn.red - sumY.red) *
- (0x8000-y1f)) >> 16;
- sumY.green += ((sumYn.green - sumY.green) *
- (0x8000-y1f)) >> 16;
- sumY.blue += ((sumYn.blue - sumY.blue) *
- (0x8000-y1f)) >> 16;
- }
- else if(y1f>0x08000 && y1i>(in->Y-1))
- {
- /* below y1 center so add proportion */
- /* of next row (0 to 0.5) */
-
- pix_sum_row(in, &sumYn, x1i,x1f,
- x2i,x2f, y1i+1, div, interpX);
-
- sumY.red += ((sumYn.red - sumY.red) *
- (y1f-0x8000)) >> 16;
- sumY.green += ((sumYn.green - sumY.green) *
- (y1f-0x8000)) >> 16;
- sumY.blue += ((sumYn.blue - sumY.blue) *
- (y1f-0x8000)) >> 16;
- }
- return(sumY);
- }
-
- /*
- * sum whole and partial pixel rows
- */
-
- sumY.red = sumY.green = sumY.blue = 0;
-
- /* make integer and fractional parts for start/end */
-
- y1i = (y1 >> 16);
- y1f = (y1 & 0xFFFF);
- y2i = (y2 >> 16);
- y2f = (y2 & 0xFFFF);
-
- /* round pixel fractions */
-
- if(y1f < 256) y1f=0; if(y1f > 65280) { y1f=0; y1i++; }
- if(y2f < 256) y2f=0; if(y2f > 65280) { y2f=0; y2i++; }
-
- /* ensure original coords match new values */
-
- y1 = (y1i << 16)+y1f;
- y2 = (y2i << 16)+y2f;
-
- /* correct looping for whole last pixel row */
-
- if(y2f==0) y2i--;
-
- for(y=y1i; y<=y2i; y++)
- {
- /* sum or interpolate along pixel row */
-
- pix_sum_row(in, &sumX, x1i,x1f, x2i,x2f, y,div, interpX);
-
- /* sum fraction of pixel row if not whole pixel high */
-
- if((y==y1i) && (y!=y2i) && (y1f>0))
- {
- sumY.red = sumX.red * (0x10000-y1f);
- sumY.green = sumX.green * (0x10000-y1f);
- sumY.blue = sumX.blue * (0x10000-y1f);
- }
- else
- {
- /* sum faction of last pixel row if not whole */
-
- if((y!=y1i) && (y==y2i) && (y2f>0))
- {
- sumY.red += sumX.red * y2f;
- sumY.green += sumX.green * y2f;
- sumY.blue += sumX.blue * y2f;
- }
- else
- {
- /* sum whole pixel rows */
-
- sumY.red += (sumX.red << 16);
- sumY.green += (sumX.green << 16);
- sumY.blue += (sumX.blue << 16);
- }
- }
- }
-
- /*
- * average over whole & part number of pixel rows
- * fixed point is automatically converted to integer
- * if start & end on the same row divid by 1
- */
-
- div = (y2i==y1i) ? (1<<16) : (y2-y1);
-
- sumY.red = sumY.red / div;
- sumY.green = sumY.green / div;
- sumY.blue = sumY.blue / div;
-
- return(sumY);
- }
-
- /*
- * main sprite FSI processing routine
- *
- * if file valid write each processed line out immediately
- * otherwise build destination sprite in memory
- */
-
- void process(process_str *p)
- {
- REGISTER int inX, inY, outX, outY;
- int Xinc, Yinc, Xdir, Ydir, x1, x2, y;
- pix_str *line1, *line2;
- pix_str sum, *new, err;
-
- /* get best function for finding closest RGB values */
-
- closest_rgb_func(p->in);
-
- /* do any preprocessing of the image */
-
- if(p->filter) filter(p->in, &p->data.filter);
- if(p->invert) invert(p->in);
- if(p->expand) expand(p->in);
- if(p->gamma) gamma_cr(p->in,p->data.gamma);
-
- /* calculate optimized palette after preprocessing */
-
- if(p->palette_opt) optimize_palette(p->in, p->out);
-
- /* get best function for finding closest RGB values */
-
- closest_rgb_func(p->out);
-
- /* write sprite header to file if given */
-
- if(p->outf != 0) write_sprite_header(p->out, p->outf);
-
- /* allocate memory for two lines of the sprite 32+32+32 bpp (r,g,b) */
-
- if((line1=(pix_str*)malloc(p->out->X*sizeof(pix_str)))==0 ||
- (line2=(pix_str*)malloc(p->out->X*sizeof(pix_str)))==0)
- {
- /* should really free line1 if <>0, but exiting anyway */
- fprintf(stderr,"Error: Failed to allocate working buffer");
- fprintf(stderr,"- unable to continue\n");
- exit(1);
- }
- memset((void*)line1, 0, p->out->X*sizeof(pix_str));
- memset((void*)line2, 0, p->out->X*sizeof(pix_str));
-
- progress_start("Processing :");
-
- /* main Floyd Steinburg Integer code */
-
- Xdir = 1; /* X direction for zig-zag */
- Ydir = 1; /* Y direction fixed (down)*/
- Xinc = (p->in->X * 0x10000) / p->out->X; /* 16.16 bit fixed point */
- Yinc = (p->in->Y * 0x10000) / p->out->Y; /* increment through input */
- inY = 0;
-
- for(outY=0; outY<=p->out->Y-1; outY+=Ydir)
- {
- /* X position is always top left of pixel regradless of dir */
-
- if(Xdir==1)
- {
- x1 = 0;
- x2 = p->out->X;
- inX = 0;
- }
- else
- {
- x1 = p->out->X-1;
- x2 = -1;
- inX = (p->in->X<<16)+Xinc;
- }
-
- for(outX=x1; outX!=x2; outX+=Xdir)
- {
- /* ensure that x1 is less than x2 and */
- /* that y1 is less than y2 for pix_sum */
-
- if(p->nointerp)
- {
- sum.value = p->in->read_pixel_rgb(p->in,
- inX>>16,
- inY>>16);
- sum.red = (sum.value >> 8) & 0xFF;
- sum.green = (sum.value >> 16) & 0xFF;
- sum.blue = (sum.value >> 24) & 0xFF;
- }
- else
- {
- if(Xdir==1)
- {
- sum = pix_sum(p->in, inX, inY,
- inX+Xinc, inY+Yinc);
- }
- else
- {
- sum = pix_sum(p->in, inX, inY,
- inX-Xinc, inY+Yinc);
- }
- }
-
- if(!p->nodither)
- {
- /* add any error distributed to this pixel */
-
- sum.red += (line1[outX].red >> 8);
- sum.green += (line1[outX].green >> 8);
- sum.blue += (line1[outX].blue >> 8);
-
- excess_rgb(&sum);
-
- new = p->out->closest_rgb(p->out, &sum);
-
- line1[outX].value = new->value;
-
- /* use full sum+line1 values for error calc */
-
- err.red = sum.red - new->red;
- err.green = sum.green - new->green;
- err.blue = sum.blue - new->blue;
-
- /* distribute error: , pixel*1 , err*7/16, */
- /* err*3/16, err*5/16, err*1/16, */
-
- err_diff(&line1[outX], new, (16*0x100)/16);
-
- /* speedup check for exact match */
-
- if(err.red!=0 || err.green!=0 || err.blue!=0)
- {
- if((Xdir == 1 && outX < (x2-1)) ||
- (Xdir == -1 && outX > 0))
- {
- err_diff(&line1[outX+Xdir],
- &err, (7*0x100)/16); /* 7/16 */
- }
- if(outY < (p->out->Y-1))
- {
- err_diff(&line2[outX],
- &err, (5*0x100)/16); /* 5/16 */
-
- if((Xdir == 1 && outX < (x2-1)) ||
- (Xdir == -1 && outX > 0))
- {
- err_diff(&line2[outX-Xdir],
- &err, (1*0x100)/16); /*1/16*/
- }
- if((Xdir == 1 && outX > 0) ||
- (Xdir == -1 && outX < (x2-1)))
- {
- err_diff(&line2[outX+Xdir],
- &err, (3*0x100)/16); /*3/16*/
- }
- }
- }
- }
- else
- {
- /* no dither, so just find nearest colour */
-
- new = p->out->closest_rgb(p->out, &sum);
- line1[outX].value = new->value;
- }
- inX += Xinc;
- }
-
- Xdir = -Xdir; /* reverse Xdir for zigzag */
- Xinc = -Xinc;
- inY += Yinc;
-
- /*
- * make one line of output sprite
- * use y=0 if file is valid as only one line of data has been
- * allocated, otherwise place line in correct y position to
- * make whole sprite in memory
- */
-
- if(p->outf==0)
- y = outY;
- else
- y = 0;
-
- for(outX=0; outX<p->out->X; outX++)
- {
- p->out->write_pixel_val(p->out, outX, y,
- line1[outX].value);
- }
-
- /* write pixel line to file immediately if required */
-
- if(p->outf != 0)
- {
- fwrite(p->out->spr_data, p->out->line_size, 1, p->outf);
- }
-
- /* copy up second line of buffer, and clear */
-
- memcpy(line1, line2, p->out->X*sizeof(pix_str));
- memset(line2, 0, p->out->X*sizeof(pix_str));
-
- progress(outY, p->out->Y);
- }
-
- progress_finish();
-
- /* #### run time heap problem under RISC OS */
- #ifndef RISCOS
- free((void*)line1);
- free((void*)line2);
- #endif
- }
-