home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1997 Miloslaw Smyk
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Miloslaw Smyk
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- #define REVISION "40.2"
- #define AUTHOR "Miloslaw Smyk"
- #define VERNUM 40
- #define REVNUM 2
-
- #define DT_FS 0
- #define DT_ORDERED 1
- #define DT_NONE 2
-
- /* some useful includes */
-
- #include <string.h>
-
- int dither_type = DT_NONE;
-
- struct R3DHandle
- {
- UBYTE depth;
- UWORD size_x, size_y;
- SHORT *line;
- int line_width;
- };
-
-
- /*
- ** 4x4 4-bit dispersed dot ordered dither pattern, which is the base
- ** for final dither pattern, calculated as soon as screen depth
- ** is known.
- */
-
- const UBYTE dithBase[4][4] = {
- 1, 15, 2, 12,
- 9, 5, 10, 7,
- 3, 13, 0, 14,
- 11, 7, 8, 4
- };
-
- static struct dith
- {
- UBYTE r, g, b, g2;
- } dith[4][4];
-
- struct dither_val
- {
- UBYTE r[2], g[2], b[2], g2[2];
- } dither[256];
-
- int red5[256], green5[256], blue5[256], green6[256];
-
- enum {COL_ORIGINAL, COL_SHIFTED};
-
- /* macros we use to get fractions with integer math */
- #define SCALING_FACTOR 4
- #define HALF 8
- #define DESCALE(expr) (((expr) + HALF) >> SCALING_FACTOR)
-
-
- void LIBInitDithering(void)
- {
- int i,j;
-
- /* calculate errors for every possible pixel value. */
- for(i = 0; i < 256; i++)
- {
- red5[i] = i - ((i + 4) & ~0x07);
- green5[i] = i - ((i + 4) & ~0x07);
- green6[i] = i - ((i + 2) & ~0x03);
- blue5[i] = i - ((i + 4) & ~0x07);
- }
-
- for(i = 0; i < 256; i++)
- {
- dither[i].r[COL_ORIGINAL] = i & ~0x07;
- dither[i].g[COL_ORIGINAL] = i & ~0x07;
- dither[i].g2[COL_ORIGINAL] = i & ~0x03;
- dither[i].b[COL_ORIGINAL] = i & ~0x07;
-
- dither[i].r[COL_SHIFTED] = MIN(i + 8, 255);
- dither[i].g[COL_SHIFTED] = MIN (i + 8, 255);
- dither[i].g2[COL_SHIFTED] = MIN(i + 4,255);
- dither[i].b[COL_SHIFTED] = MIN(i + 8, 255);
- }
-
- for(j = 0; j < 4; j++)
- for(i = 0; i < 4; i++)
- {
- dith[i][j].r = (dithBase[i][j] * 16) / 32;
- dith[i][j].g = (dithBase[i][j] * 16) / 32;
- dith[i][j].g2 = (dithBase[i][j] * 16) / 64;
- dith[i][j].b = (dithBase[i][j] * 16) / 32;
- }
- }
-
- void LIBDitherLine(struct R3DHandle *handle, UBYTE *buf, int len, int x, int y)
- {
- int i;
- int bsame_r, bnext_r, next_r;
- int bsame_g, bnext_g, next_g;
- int bsame_b, bnext_b, next_b;
- UBYTE *inptr;
- SHORT *errptr;
- int delta;
- int temp;
-
- if(handle->depth == 15 || handle->depth == 16)
- {
- switch(dither_type)
- {
- case DT_FS:
- if(handle->line_width != len)
- {
- if(handle->line)
- FreeVec(handle->line);
-
- handle->line = AllocVec(sizeof(SHORT) * (len + 2) * 3, MEMF_ANY | MEMF_CLEAR);
- handle->line_width = len;
- }
-
- inptr = buf;
- errptr = handle->line + 3;
-
- /* make sure there is no error at the start of the line */
- for(i = 0; i < 3; i++)
- errptr[i] = 0;
-
- bsame_r = bnext_r = next_r = 0;
- bsame_g = bnext_g = next_g = 0;
- bsame_b = bnext_b = next_b = 0;
-
- for(i = 0; i < len; i++)
- {
- /* red component */
-
- temp = *inptr + DESCALE(next_r + bsame_r);
-
- if(temp < 0)
- *inptr = 0;
- else
- if(temp > 255)
- *inptr = 255;
- else
- *inptr = temp;
-
- /* right-down pixel gets 1/16 of error */
- bnext_r = red5[*inptr];
- delta = bnext_r << 1;
-
- /* left-down pixel gets 3/16 of error */
- next_r = bnext_r + delta;
- *(errptr - 3) += next_r;
-
- /* pixel below gets 5/16 of error */
- next_r += delta;
- *errptr += next_r;
-
- /* next pixel (to the right) gets 7/16 of error */
- next_r += delta;
-
- /* try to get closest match with color-gun */
- if(*inptr < 252)
- *inptr += 4;
-
- bsame_r = *(errptr);
- *(errptr) = bnext_r;
- errptr++;
- inptr++;
-
- /* green component */
-
- temp = *inptr + DESCALE(next_g + bsame_g);
-
- if(temp < 0)
- *inptr = 0;
- else
- if(temp > 255)
- *inptr = 255;
- else
- *inptr = temp;
-
- /* right-down pixel gets 1/16 of error */
- bnext_g = handle->depth == 15 ? green5[*inptr] : green6[*inptr];
- delta = bnext_g << 1;
-
- /* left-down pixel gets 3/16 of error */
- next_g = bnext_g + delta;
- *(errptr - 3) += next_g;
-
- /* pixel below gets 5/16 of error */
- next_g += delta;
- *errptr += next_g;
-
- /* next pixel (to the right) gets 7/16 of error */
- next_g += delta;
-
- /* try to get closest match with color-gun */
- if(handle->depth == 15)
- {
- if(*inptr < 252)
- *inptr += 4;
- }
- else
- {
- if(*inptr < 254)
- *inptr += 2;
- }
-
- bsame_g = *(errptr);
- *(errptr) = bnext_g;
- errptr++;
- inptr++;
-
- /* blue component */
-
- temp = *inptr + DESCALE(next_b + bsame_b);
-
- if(temp < 0)
- *inptr = 0;
- else
- if(temp > 255)
- *inptr = 255;
- else
- *inptr = temp;
-
- /* right-down pixel gets 1/16 of error */
- bnext_b = blue5[*inptr];
- delta = bnext_b << 1;
-
- /* left-down pixel gets 3/16 of error */
- next_b = bnext_b + delta;
- *(errptr - 3) += next_b;
-
- /* pixel below gets 5/16 of error */
- next_b += delta;
- *errptr += next_b;
-
- /* next pixel (to the right) gets 7/16 of error */
- next_b += delta;
-
- /* try to get closest match with color-gun */
- if(*inptr < 252)
- *inptr += 4;
-
- bsame_b = *(errptr);
- *(errptr) = bnext_b;
-
- errptr++;
-
- /* advance input pointer */
- inptr += 2;
- }
-
- break;
-
- case DT_ORDERED:
- if(handle->depth == 15)
- for(i = 0; i < len * 4; i += 4)
- {
- if(buf[i] - dither[buf[i]].r[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].r)
- buf[i] = dither[buf[i]].r[COL_SHIFTED];
- if(buf[i + 1] - dither[buf[i + 1]].g[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].g)
- buf[i + 1] = dither[buf[i + 1]].g[COL_SHIFTED];
- if(buf[i + 2] - dither[buf[i + 2]].b[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].b)
- buf[i + 2] = dither[buf[i + 2]].b[COL_SHIFTED];
- }
- else
- for(i = 0; i < len * 4; i += 4)
- {
- if(buf[i] - dither[buf[i]].r[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].r)
- buf[i] = dither[buf[i]].r[COL_SHIFTED];
- if(buf[i + 1] - dither[buf[i + 1]].g2[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].g2)
- buf[i + 1] = dither[buf[i + 1]].g2[COL_SHIFTED];
- if(buf[i + 2] - dither[buf[i + 2]].b[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].b)
- buf[i + 2] = dither[buf[i + 2]].b[COL_SHIFTED];
- }
- break;
- }
- }
- }
-