/*--------------------------------------------------------*/
/* File: LISTING1.C   By: Marv Luse, Autumn Hill Software */
/*                                                        */
/* Desc: Code for computing 4x4 dither cells with either  */
/*       16 linear steps or 8 logs steps, given a 4x4     */
/*       dither matrix as input.                          */
/*--------------------------------------------------------*/
#include "stdlib.h"
#include "stdio.h"
#include "math.h"

/* types applicable to 4x4 dithering */
typedef int DITHER_MATRIX[4][4];
typedef unsigned char DITHER_CELL[4];

/* dit_mat determines dot-order within cell */
DITHER_MATRIX dit_mat = {
   {  9,  5, 16, 12 }, { 13,  1,  4,  8 },
   {  6,  2,  3, 15 }, { 10, 14,  7, 11 },};

/* dit_cells contains 4x4 dither patterns */
DITHER_CELL dit_cells[16] = {
  { 0x00, 0x00, 0x00, 0x00 },{ 0x00, 0x00, 0x00, 0x00 }, /*  0,1  */
  { 0x00, 0x00, 0x00, 0x00 },{ 0x00, 0x00, 0x00, 0x00 }, /*  2,3  */
  { 0x00, 0x00, 0x00, 0x00 },{ 0x00, 0x00, 0x00, 0x00 }, /*  4,5  */
  { 0x00, 0x00, 0x00, 0x00 },{ 0x00, 0x00, 0x00, 0x00 }, /*  6,7  */
  { 0x00, 0x00, 0x00, 0x00 },{ 0x00, 0x00, 0x00, 0x00 }, /*  8,9  */
  { 0x00, 0x00, 0x00, 0x00 },{ 0x00, 0x00, 0x00, 0x00 }, /* 10,11 */
  { 0x00, 0x00, 0x00, 0x00 },{ 0x00, 0x00, 0x00, 0x00 }, /* 12,13 */
  { 0x00, 0x00, 0x00, 0x00 },{ 0x00, 0x00, 0x00, 0x00 }, /* 14,15 */
};
/*--------------------------------------------------------*/
/* determine dot count at each step of log intensity scl  */
/*--------------------------------------------------------*/
void compute_log_steps( int dot_cnt[], int nlvls, int ndots ) {
    int    i;
    double r, ri;

/* compute step intensity ratio */
    r = pow( ndots, 1.0/(nlvls-1.0) );

/* index 0 always has 0 dots on */
    dot_cnt[0] = 0;

/* compute number of dots in remaining levels */
    for( i=1, ri=r;  i<nlvls;  i++, ri*=r )
       dot_cnt[i] = (int) (ri + 0.5);
}
/*--------------------------------------------------------*/
/* create an 8-level 4x4 logarithmic intensity dither     */
/*--------------------------------------------------------*/
void log_4x4_dither(  DITHER_MATRIX dm, DITHER_CELL dc[] ) {
    int i, j, n, cnt[8];
    unsigned char mask;

/* determine dots/cell for each level */
    compute_log_steps( cnt, 8, 16 );
/* determine dither cells */
    for( n=0; n<8; n++ ) {            /* cell n           */
       for( i=0; i<4; i++ ) {         /* byte i of cell n */
          dc[n][i] = 0;
          for( j=0; j<4; j++ ) {      /* bit j of byte i  */
             mask = 0x08 >> j;
             if( dm[i][j] <= cnt[n] ) dc[n][i] |= mask;
          }
       }
    }
}
/*--------------------------------------------------------*/
/* create a 16-level 4x4 linear intensity dither          */
/*--------------------------------------------------------*/
void lin_4x4_dither(  DITHER_MATRIX dm, DITHER_CELL dc[] ) {
    int i, j, n;
    unsigned char mask;

/* determine dither cells */
    for( n=0; n<16; n++ ) {           /* cell n           */
       for( i=0; i<4; i++ ) {         /* byte i of cell n */
          dc[n][i] = 0;
          for( j=0; j<4; j++ ) {      /* bit j of byte i  */
             mask = 0x08 >> j;
             if( dm[i][j] <= n ) dc[n][i] |= mask;
          }
       }
    }
}
/*--------------------------------------------------------*/
/* print the data-initialization of a 4x4 dither set      */
/*--------------------------------------------------------*/
void print_dither(  char *name, DITHER_CELL dc[], int ncells ) {
    int i, j;

    printf( "DITHER_CELL %s[] =\n", name );
    printf( "{\n" );
    for( i=0; i<ncells; i++ ) {
       printf( "   {" );
       for( j=0; j<4; j++ ) printf( " 0x%02X,", dc[i][j] );
       printf( " },\n" );
    }
    printf( "};\n" );
}
/*--------------------------------------------------------*/
/* main to exercise the code...                           */
/*--------------------------------------------------------*/
void main( void ) {
     int i, j;

     printf( "4x4 Dither Matrix...\n" );
     printf( "\n" );
     for( i=0; i<4; i++ ) {
        printf( "  %c", 179 );
        for( j=0; j<4; j++ ) printf( " %2d", dit_mat[i][j] );
        printf( " %c\n", 179 );
     }
     printf( "\n" );
     printf( "4x4 16-level Linear Dither...\n" ); printf( "\n" );
     lin_4x4_dither( dit_mat, dit_cells );
     print_dither( "lin_4x4", dit_cells, 16 ); printf( "\n" );
     printf( "4x4 8-level Logarithmic Dither...\n" );
     printf( "\n" );
     log_4x4_dither( dit_mat, dit_cells );
     print_dither( "log_4x4", dit_cells, 8 ); printf( "\n" );
}
