earlybrowserreborn - Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 roytam 1 /*
2  *      Utah RLE Toolkit library routines.
3  *
4  *      Read image support only.
5  *
6  *      Cobbled from Utah RLE include and library source files.
7  *
8  *      By Graeme Gill
9  *      30/5/90
10  *
11  */
12  
13 #include <stdio.h>
14 #include <math.h>
4 roytam 15 //#include <varargs.h>
1 roytam 16 #include <ctype.h>
17  
18 #include "image.h"              /* need ZFILE definition */
19 #include "rle.h"
20  
21 /* SUPPRESS 530y */
22 /* SUPPRESS 558 */
23 /* SUPPRESS 590 */
24  
25 #define zeof(zfp) feof((zfp)->stream)
26 #define zclearerr(zfp) clearerr((zfp)->stream)
27  
28 /*
29  * This software is copyrighted as noted below.  It may be freely copied,
30  * modified, and redistributed, provided that the copyright notice is
31  * preserved on all copies.
32  *
33  * There is no warranty or other guarantee of fitness for this software,
34  * it is provided solely "as is".  Bug reports or fixes may be sent
35  * to the author, who may or may not act on them as he desires.
36  *
37  * You may not include this software in a program or other software product
38  * without supplying the source, or without informing the end-user that the
39  * source is available for no extra charge.
40  *
41  * If you modify this software, you should include a notice giving the
42  * name of the person performing the modification, the date of modification,
43  * and the reason for such modification.
44  */
45 /*
46  * Runsv.h - Definitions for Run Length Encoding.
47  *
48  * Author:      Spencer W. Thomas
49  *              Computer Science Dept.
50  *              University of Utah
51  * Date:        Mon Aug  9 1982
52  * Copyright (c) 1982 Spencer W. Thomas
53  */
54  
55 #ifndef XTNDRUNSV
56 #define XTNDRUNSV
57  
58 /*
59  * Opcode definitions
60  */
61  
62 #define     LONG                0x40
63 #define     RSkipLinesOp        1
64 #define     RSetColorOp         2
65 #define     RSkipPixelsOp       3
66 #define     RByteDataOp         5
67 #define     RRunDataOp          6
68 #define     REOFOp              7
69  
70 #define     H_CLEARFIRST        0x1     /* clear framebuffer flag */
71 #define     H_NO_BACKGROUND     0x2     /* if set, no bg color supplied */
72 #define     H_ALPHA             0x4   /* if set, alpha channel (-1) present */
73 #define     H_COMMENT           0x8     /* if set, comments present */
74  
75 struct XtndRsetup
76 {
77     short   h_xpos,
78             h_ypos,
79             h_xlen,
80             h_ylen;
81     char    h_flags,
82             h_ncolors,
83             h_pixelbits,
84             h_ncmap,
85             h_cmaplen;
86 };
87 #define     SETUPSIZE   ((4*2)+5)
88  
89 /* "Old" RLE format magic numbers */
90 #define     RMAGIC      ('R' << 8)      /* top half of magic number */
91 #define     WMAGIC      ('W' << 8)      /* black&white rle image */
92  
93 #define     XtndRMAGIC  ((short)0xcc52) /* RLE file magic number */
94  
95 #endif /* XTNDRUNSV */
96  
97 /*  "svfb.h" */
98 /*
99  * This software is copyrighted as noted below.  It may be freely copied,
100  * modified, and redistributed, provided that the copyright notice is
101  * preserved on all copies.
102  *
103  * There is no warranty or other guarantee of fitness for this software,
104  * it is provided solely "as is".  Bug reports or fixes may be sent
105  * to the author, who may or may not act on them as he desires.
106  *
107  * You may not include this software in a program or other software product
108  * without supplying the source, or without informing the end-user that the
109  * source is available for no extra charge.
110  *
111  * If you modify this software, you should include a notice giving the
112  * name of the person performing the modification, the date of modification,
113  * and the reason for such modification.
114  */
115 /*
116  * svfb.h - Definitions and a few global variables for svfb.
117  *
118  * Author:      Spencer W. Thomas
119  *              Computer Science Dept.
120  *              University of Utah
121  * Date:        Mon Aug  9 1982
122  * Copyright (c) 1982 Spencer W. Thomas
123  */
124  
125 /* ****************************************************************
126  * Dispatch table for different output types.
127  */
128 typedef void sv_fn();
129 struct sv_dispatch_tab {
130     char   *magic;                      /* magic type flags */
131     sv_fn  *setup,                      /* startup function */
132            *skipBlankLines,
133            *setColor,
134            *skipPixels,
135            *newScanLine,
136            *putdat,                     /* put a set of differing pixels */
137            *putrn,                      /* put a run all the same */
138            *blockHook,                  /* hook called at start of new */
139                                         /* output block */
140            *putEof;             /* write EOF marker (if possible) */
141 };
142  
143 struct sv_dispatch_tab sv_DTable[];
144  
145 /*
146  * These definitions presume the existence of a variable called
147  * "fileptr", declared "long * fileptr".  *fileptr should be
148  * initialized to 0 before calling Setup().
149  * A pointer "globals" declared "struct sv_globals * globals" is also
150  * presumed to exist.
151  */
152 #define     sv_magic            (sv_DTable[(int)globals->sv_dispatch].magic)
153 #define     Setup()             (*sv_DTable[(int)globals->sv_dispatch].setup)(globals)
154 #define     SkipBlankLines(n)   (*sv_DTable[(int)globals->sv_dispatch].skipBlankLines)(n, globals)
155 #define     SetColor(c)         (*sv_DTable[(int)globals->sv_dispatch].setColor)(c, globals)
156 #define     SkipPixels(n, l, r) (*sv_DTable[(int)globals->sv_dispatch].skipPixels)(n,l,r, globals)
157 #define     NewScanLine(flag)   (*sv_DTable[(int)globals->sv_dispatch].newScanLine)(flag, globals)
158 #define     putdata(buf, len)   (*sv_DTable[(int)globals->sv_dispatch].putdat)(buf, len, globals)
159 #define     putrun(val, len, f) (*sv_DTable[(int)globals->sv_dispatch].putrn)(val,len,f, globals)
160 #define     BlockHook()         (*sv_DTable[(int)globals->sv_dispatch].blockHook)(globals)
161 #define     PutEof()            (*sv_DTable[(int)globals->sv_dispatch].putEof)(globals)
162  
163 /*
164  * States for run detection
165  */
166 #define DATA    0
167 #define RUN2    1
168 #define RUN3    2
169 #define RUN4    3
170 #define INRUN   -1
171  
172 /*
173  * This software is copyrighted as noted below.  It may be freely copied,
174  * modified, and redistributed, provided that the copyright notice is
175  * preserved on all copies.
176  *
177  * There is no warranty or other guarantee of fitness for this software,
178  * it is provided solely "as is".  Bug reports or fixes may be sent
179  * to the author, who may or may not act on them as he desires.
180  *
181  * You may not include this software in a program or other software product
182  * without supplying the source, or without informing the end-user that the
183  * source is available for no extra charge.
184  *
185  * If you modify this software, you should include a notice giving the
186  * name of the person performing the modification, the date of modification,
187  * and the reason for such modification.
188  *
189  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
190  *  to have all "void" functions so declared.
191  */
192 /*
193  * svfb_global.c - Global variable initialization for svfb routines.
194  *
195  * Author:      Spencer W. Thomas
196  *              Computer Science Dept.
197  *              University of Utah
198  * Date:        Thu Apr 25 1985
199  * Copyright (c) 1985,1986 Spencer W. Thomas
200  */
201  
202  
203 void    RunSetup(),
204                 RunSkipBlankLines(),
205                 RunSetColor(),
206                 RunSkipPixels(),
207                 RunNewScanLine(),
208                 Runputdata(),
209                 Runputrun(),
210                 RunputEof();
211  
212 void    DefaultBlockHook();
213 void    NullputEof();
214  
215 struct sv_dispatch_tab sv_DTable[] = {
216     {
217         " OB",
218         RunSetup,
219         RunSkipBlankLines,
220         RunSetColor,
221         RunSkipPixels,
222         RunNewScanLine,
223         Runputdata,
224         Runputrun,
225         DefaultBlockHook,
226         RunputEof
227     },
228 };
229  
230 static int sv_bg_color[3] = { 0, 0, 0 };
231  
232 struct sv_globals sv_globals = {
233     RUN_DISPATCH,               /* dispatch value */
234     3,                          /* 3 colors */
235     sv_bg_color,                /* background color */
236     0,                          /* (alpha) if 1, save alpha channel */
237     2,                          /* (background) 0->just save pixels, */
238                                 /* 1->overlay, 2->clear to bg first */
239     0, 511,                     /* (xmin, xmax) X bounds to save */
240     0, 479,                     /* (ymin, ymax) Y bounds to save */
241     0,                          /* ncmap (if != 0, save color map) */
242     8,                          /* cmaplen (log2 of length of color map) */
243     NULL,                       /* pointer to color map */
244     NULL,                       /* pointer to comment strings */
245     NULL,                       /* output file */
246     { 7 }                       /* RGB channels only */
247     /* Can't initialize the union */
248 };
249  
250 /* ARGSUSED */
251 void
252 NullputEof(globals)
253 struct sv_globals * globals;
254 {
255                                 /* do nothing */
256 }
257  
258 /*
259  * This software is copyrighted as noted below.  It may be freely copied,
260  * modified, and redistributed, provided that the copyright notice is
261  * preserved on all copies.
262  *
263  * There is no warranty or other guarantee of fitness for this software,
264  * it is provided solely "as is".  Bug reports or fixes may be sent
265  * to the author, who may or may not act on them as he desires.
266  *
267  * You may not include this software in a program or other software product
268  * without supplying the source, or without informing the end-user that the
269  * source is available for no extra charge.
270  *
271  * If you modify this software, you should include a notice giving the
272  * name of the person performing the modification, the date of modification,
273  * and the reason for such modification.
274  *
275  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
276  *  to have all "void" functions so declared.
277  */
278 /*
279  * Runsv.c - General purpose Run Length Encoding for svfb.
280  *
281  * Author:      Spencer W. Thomas
282  *              Computer Science Dept.
283  *              University of Utah
284  * Date:        Mon Aug  9 1982
285  * Copyright (c) 1982,1986 Spencer W. Thomas
286  */
287  
288 /* THIS IS WAY OUT OF DATE.  See rle.5.
289  * The output file format is:
290  *
291  * Word 0:      A "magic" number.  The top byte of the word contains
292  *              the letter 'R' or the letter 'W'.  'W' indicates that
293  *              only black and white information was saved.  The bottom
294  *              byte is one of the following:
295  *      ' ':    Means a straight "box" save, -S flag was given.
296  *      'B':    Image saved with background color, clear screen to
297  *              background before restoring image.
298  *      'O':    Image saved in overlay mode.
299  *
300  * Words 1-6:   The structure
301  * {   short   xpos,                    * Lower left corner
302  *             ypos,
303  *             xsize,                   * Size of saved box
304  *             ysize;
305  *     char    rgb[3];                  * Background color
306  *     char    map;                     * flag for map presence
307  * }
308  *
309  * If the map flag is non-zero, then the color map will follow as
310  * 3*256 16 bit words, first the red map, then the green map, and
311  * finally the blue map.
312  *
313  * Following the setup information is the Run Length Encoded image.
314  * Each instruction consists of a 4-bit opcode, a 12-bit datum and
315  * possibly one or more following words (all words are 16 bits).  The
316  * instruction opcodes are:
317  *
318  * SkipLines (1):   The bottom 10 bits are an unsigned number to be added to
319  *                  current Y position.
320  *
321  * SetColor (2):    The datum indicates which color is to be loaded with
322  *                  the data described by the following ByteData and
323  *                  RunData instructions.  0->red, 1->green, 2->blue.  The
324  *                  operation also resets the X position to the initial
325  *                  X (i.e. a carriage return operation is performed).
326  *
327  * SkipPixels (3):  The bottom 10 bits are an unsigned number to be
328  *                  added to the current X position.
329  *
330  * ByteData (5):    The datum is one less than the number of bytes of
331  *                  color data following.  If the number of bytes is
332  *                  odd, a filler byte will be appended to the end of
333  *                  the byte string to make an integral number of 16-bit
334  *                  words.  The bytes are in PDP-11 order.  The X
335  *                  position is incremented to follow the last byte of
336  *                  data.
337  *
338  * RunData (6):     The datum is one less than the run length.  The
339  *                  following word contains (in its lower 8 bits) the
340  *                  color of the run.  The X position is incremented to
341  *                  follow the last byte in the run.
342  */
343  
344 #define UPPER 255                       /* anything bigger ain't a byte */
345  
346 /* Predefine LITTLE_ENDIAN for vax and pdp11 machines */
347 #if defined(vax) || defined(pdp11)
348 #define LITTLE_ENDIAN
349 #endif
350  
351 /*
352  * Macros to make writing instructions with correct byte order easier.
353  */
354 union { short s; char c[2]; } arg;
355 #ifdef LITTLE_ENDIAN
356 #define put16(a)    arg.s=a,putc(arg.c[0],sv_fd), putc(arg.c[1],sv_fd)
357 #else
358 #define put16(a)    arg.s=a,putc(arg.c[1],sv_fd), putc(arg.c[0],sv_fd)
359 #endif
360  
361 /* short instructions */
362 #define mk_short_1(oper,a1)             /* one argument short */ \
363     putc(oper,sv_fd), putc((char)a1,sv_fd)
364  
365 #define mk_short_2(oper,a1,a2)          /* two argument short */ \
366     putc(oper,sv_fd), putc((char)a1,sv_fd), put16(a2)
367  
368 /* long instructions */
369 #define mk_long_1(oper,a1)              /* one argument long */ \
370     putc((char)(LONG|oper),sv_fd), putc('\0', sv_fd), put16(a1)
371  
372 #define mk_long_2(oper,a1,a2)           /* two argument long */ \
373     putc((char)(LONG|oper),sv_fd), putc('\0', sv_fd), \
374     put16(a1), put16(a2)
375  
376 /* choose between long and short format instructions */
377 /* NOTE: these macros can only be used where a STATEMENT is legal */
378  
379 #define mk_inst_1(oper,a1)              /* one argument inst */ \
380     if (a1>UPPER) (mk_long_1(oper,a1)); else (mk_short_1(oper,a1))
381  
382 #define mk_inst_2(oper,a1,a2)           /* two argument inst */ \
383     if (a1>UPPER) (mk_long_2(oper,a1,a2)); else (mk_short_2(oper,a1,a2))
384  
385 /*
386  * Opcode definitions
387  */
388 #define     RSkipLines(n)           mk_inst_1(RSkipLinesOp,(n))
389  
390 #define     RSetColor(c)            mk_short_1(RSetColorOp,(c))
391                                     /* has side effect of performing */
392                                     /* "carriage return" action */
393  
394 #define     RSkipPixels(n)          mk_inst_1(RSkipPixelsOp,(n))
395  
396 #define     RNewLine                RSkipLines(1)
397  
398 #define     RByteData(n)            mk_inst_1(RByteDataOp,n)
399                                         /* followed by ((n+1)/2)*2 bytes */
400                                         /* of data.  If n is odd, last */
401                                         /* byte will be ignored */
402                                         /* "cursor" is left at pixel */
403                                         /* following last pixel written */
404  
405 #define     RRunData(n,c)           mk_inst_2(RRunDataOp,(n),(c))
406                                         /* next word contains color data */
407                                         /* "cursor" is left at pixel after */
408                                         /* end of run */
409  
410 #define     REOF                    mk_inst_1(REOFOp,0)
411                                         /* Really opcode only */
412  
413 /*****************************************************************
414  * TAG( RunSetup )
415  * Put out initial setup data for RLE svfb files.
416  */
417 void
418 RunSetup(globals)
419 register struct sv_globals * globals;
420 {
421 }
422  
423 /*****************************************************************
424  * TAG( RunSkipBlankLines )
425  * Skip one or more blank lines in the RLE file.
426  */
427 void
428 RunSkipBlankLines(nblank, globals)
429 register struct sv_globals * globals;
430 {
431 }
432  
433 /*****************************************************************
434  * TAG( RunSetColor )
435  * Select a color and do carriage return.
436  * color: 0 = Red, 1 = Green, 2 = Blue.
437  */
438 void
439 RunSetColor(c, globals)
440 register struct sv_globals * globals;
441 {
442 }
443  
444 /*****************************************************************
445  * TAG( RunSkipPixels )
446  * Skip a run of background.
447  */
448  
449 /* ARGSUSED */
450 void
451 RunSkipPixels(nskip, last, wasrun, globals)
452 register struct sv_globals * globals;
453 {
454 }
455  
456 /*****************************************************************
457  * TAG( RunNewScanLine )
458  * Perform a newline action.  Since CR is implied by the Set Color
459  * operation, only generate code if the newline flag is true.
460  */
461 void
462 RunNewScanLine(flag, globals)
463 register struct sv_globals * globals;
464 {
465 }
466  
467 /*****************************************************************
468  * TAG( Runputdata )
469  * Put one or more pixels of byte data into the output file.
470  */
471 void
472 Runputdata(buf, n, globals)
473 rle_pixel * buf;
474 register struct sv_globals * globals;
475 {
476 }
477  
478 /*****************************************************************
479  * TAG( Runputrun )
480  * Output a single color run.
481  */
482  
483 /* ARGSUSED */
484 void
485 Runputrun(color, n, last, globals)
486 register struct sv_globals * globals;
487 {
488 }
489  
490  
491 /*****************************************************************
492  * TAG( RunputEof )
493  * Output an EOF opcode
494  */
495 void
496 RunputEof( globals )
497 register struct sv_globals * globals;
498 {
499 }
500  
501 /*ARGSUSED*/
502 void
503 DefaultBlockHook(globals)
504 struct sv_globals * globals;
505 {
506 }
507  
508  
509 /*
510  * This software is copyrighted as noted below.  It may be freely copied,
511  * modified, and redistributed, provided that the copyright notice is
512  * preserved on all copies.
513  *
514  * There is no warranty or other guarantee of fitness for this software,
515  * it is provided solely "as is".  Bug reports or fixes may be sent
516  * to the author, who may or may not act on them as he desires.
517  *
518  * You may not include this software in a program or other software product
519  * without supplying the source, or without informing the end-user that the
520  * source is available for no extra charge.
521  *
522  * If you modify this software, you should include a notice giving the
523  * name of the person performing the modification, the date of modification,
524  * and the reason for such modification.
525  */
526 /*
527  * buildmap.c - Build a color map from the RLE file color map.
528  *
529  * Author:      Spencer W. Thomas
530  *              Computer Science Dept.
531  *              University of Utah
532  * Date:        Sat Jan 24 1987
533  * Copyright (c) 1987, University of Utah
534  */
535  
536 /*****************************************************************
537  * TAG( buildmap )
538  *
539  * Returns a color map that can easily be used to map the pixel values in
540  * an RLE file.  Map is built from the color map in the input file.
541  * Inputs:
542  *      globals:        sv_globals structure containing color map.
543  *      minmap:         Minimum number of channels in output map.
544  *      gamma:          Adjust color map for this image gamma value
545  *                      (1.0 means no adjustment).
546  * Outputs:
547  *      Returns an array of pointers to arrays of rle_pixels.  The array
548  *      of pointers contains max(sv_ncolors, sv_ncmap) elements, each
549  *      array of pixels contains 2^sv_cmaplen elements.  The pixel arrays
550  *      should be considered read-only.
551  * Assumptions:
552  *      [None]
553  * Algorithm:
554  *      Ensure that there are at least sv_ncolors rows in the map, and
555  *      that each has at least 256 elements in it (largest map that can
556  *      be addressed by an rle_pixel).
557  */
558 rle_pixel **
559 buildmap( globals, minmap, gamma )
560 struct sv_globals *globals;
561 int minmap;
562 double gamma;
563 {
564     rle_pixel ** cmap, * gammap;
565     register int i, j;
566     int maplen, cmaplen, ncmap, nmap;
567  
568     if ( globals->sv_ncmap == 0 )       /* make identity map */
569     {
570         nmap = (minmap < globals->sv_ncolors) ? globals->sv_ncolors : minmap;
571         cmap = (rle_pixel **)lmalloc( nmap * sizeof(rle_pixel *) );
572         cmap[0] = (rle_pixel *)lmalloc( 256 * sizeof(rle_pixel) );
573         for ( i = 0; i < 256; i++ )
574             cmap[0][i] = i;
575         for ( i = 1; i < nmap; i++ )
576             cmap[i] = cmap[0];
577         maplen = 256;
578         ncmap = 1;              /* number of unique rows */
579     }
580     else                        /* make map from globals */
581     {
582         /* Map is at least 256 long */
583         cmaplen = (1 << globals->sv_cmaplen);
584         if ( cmaplen < 256 )
585             maplen = 256;
586         else
587             maplen = cmaplen;
588  
589         if ( globals->sv_ncmap == 1 )   /* make "b&w" map */
590         {
591             nmap = (minmap < globals->sv_ncolors) ?
592                 globals->sv_ncolors : minmap;
593             cmap = (rle_pixel **)lmalloc( nmap * sizeof(rle_pixel *) );
594             cmap[0] = (rle_pixel *)lmalloc( maplen * sizeof(rle_pixel) );
595             for ( i = 0; i < maplen; i++ )
596                 if ( i < cmaplen )
597                     cmap[0][i] = globals->sv_cmap[i] >> 8;
598                 else
599                     cmap[0][i] = i;
600             for ( i = 1; i < nmap; i++ )
601                 cmap[i] = cmap[0];
602             ncmap = 1;
603         }
604         else if ( globals->sv_ncolors <= globals->sv_ncmap )
605         {
606             nmap = (minmap < globals->sv_ncmap) ? globals->sv_ncmap : minmap;
607             cmap = (rle_pixel **)lmalloc( nmap * sizeof(rle_pixel *) );
608             for ( j = 0; j < globals->sv_ncmap; j++ )
609             {
610                 cmap[j] = (rle_pixel *)lmalloc( maplen * sizeof(rle_pixel) );
611                 for ( i = 0; i < maplen; i++ )
612                     if ( i < cmaplen )
613                         cmap[j][i] = globals->sv_cmap[j*cmaplen + i] >> 8;
614                     else
615                         cmap[j][i] = i;
616             }
617             for ( i = j, j--; i < nmap; i++ )
618                 cmap[i] = cmap[j];
619             ncmap = globals->sv_ncmap;
620         }
621         else                    /* ncolors > ncmap */
622         {
623             nmap = (minmap < globals->sv_ncolors) ?
624                 globals->sv_ncolors : minmap;
625             cmap = (rle_pixel **)lmalloc( nmap * sizeof(rle_pixel *) );
626             for ( j = 0; j < globals->sv_ncmap; j++ )
627             {
628                 cmap[j] = (rle_pixel *)lmalloc( maplen * sizeof(rle_pixel) );
629                 for ( i = 0; i < maplen; i++ )
630                     if ( i < cmaplen )
631                         cmap[j][i] = globals->sv_cmap[j*cmaplen + i] >> 8;
632                     else
633                         cmap[j][i] = i;
634             }
635             for( i = j, j--; i < nmap; i++ )
636                 cmap[i] = cmap[j];
637             ncmap = globals->sv_ncmap;
638         }
639     }
640  
641     /* Gamma compensate if requested */
642     if ( gamma != 1.0 )
643     {
644         gammap = (rle_pixel *)lmalloc( 256 * sizeof(rle_pixel) );
645         for ( i = 0; i < 256; i++ )
646                 {
647 #ifdef BYTEBUG
648                 int byteb1;
649                 byteb1 = (int)(0.5 + 255.0 * pow( i / 255.0, gamma ));
650                 gammap[i] = byteb1;
651 #else
652             gammap[i] = (int)(0.5 + 255.0 * pow( i / 255.0, gamma ));
653 #endif
654                 }
655         for ( i = 0; i < ncmap; i++ )
656             for ( j = 0; j < maplen; j++ )
657                 cmap[i][j] = gammap[cmap[i][j]];
658     }
659  
660     return cmap;
661 }
662  
663 /*
664  * This software is copyrighted as noted below.  It may be freely copied,
665  * modified, and redistributed, provided that the copyright notice is
666  * preserved on all copies.
667  *
668  * There is no warranty or other guarantee of fitness for this software,
669  * it is provided solely "as is".  Bug reports or fixes may be sent
670  * to the author, who may or may not act on them as he desires.
671  *
672  * You may not include this software in a program or other software product
673  * without supplying the source, or without informing the end-user that the
674  * source is available for no extra charge.
675  *
676  * If you modify this software, you should include a notice giving the
677  * name of the person performing the modification, the date of modification,
678  * and the reason for such modification.
679  */
680 /*
681  * rle_getcom.c - Get specific comments from globals structure.
682  *
683  * Author:      Spencer W. Thomas
684  *              Computer Science Dept.
685  *              University of Utah
686  * Date:        Sun Jan 25 1987
687  * Copyright (c) 1987, University of Utah
688  */
689  
690 /*****************************************************************
691  * TAG( match )
692  *
693  * Match a name against a test string for "name=value" or "name".
694  * If it matches name=value, return pointer to value part, if just
695  * name, return pointer to NUL at end of string.  If no match, return NULL.
696  *
697  * Inputs:
698  *      n:      Name to match.  May also be "name=value" to make it easier
699  *              to replace comments.
700  *      v:      Test string.
701  * Outputs:
702  *      Returns pointer as above.
703  * Assumptions:
704  *      [None]
705  * Algorithm:
706  *      [None]
707  */
708 static char *
709 match( n, v )
710 register char *n;
711 register char *v;
712 {
713     for ( ; *n != '\0' && *n != '=' && *n == *v; n++, v++ )
714         ;
715     if (*n == '\0' || *n == '=')
716         if ( *v == '\0' )
717             return v;
718         else if ( *v == '=' )
719             return ++v;
720  
721     return NULL;
722 }
723  
724 /*****************************************************************
725  * TAG( rle_getcom )
726  *
727  * Return a pointer to the value part of a name=value pair in the comments.
728  * Inputs:
729  *      name:           Name part of the comment to search for.
730  *      globals:        sv_globals structure.
731  * Outputs:
732  *      Returns pointer to value part of comment or NULL if no match.
733  * Assumptions:
734  *      [None]
735  * Algorithm:
736  *      [None]
737  */
738 char *
739 rle_getcom( name, globals )
740 char *name;
741 struct sv_globals *globals;
742 {
743     char ** cp;
744     char * v;
745  
746     if ( globals->sv_comments == NULL )
747         return NULL;
748  
749     for ( cp = globals->sv_comments; *cp; cp++ )
750         if ( (v = match( name, *cp )) != NULL )
751             return v;
752  
753     return NULL;
754 }
755  
756 /*
757  * This software is copyrighted as noted below.  It may be freely copied,
758  * modified, and redistributed, provided that the copyright notice is
759  * preserved on all copies.
760  *
761  * There is no warranty or other guarantee of fitness for this software,
762  * it is provided solely "as is".  Bug reports or fixes may be sent
763  * to the author, who may or may not act on them as he desires.
764  *
765  * You may not include this software in a program or other software product
766  * without supplying the source, or without informing the end-user that the
767  * source is available for no extra charge.
768  *
769  * If you modify this software, you should include a notice giving the
770  * name of the person performing the modification, the date of modification,
771  * and the reason for such modification.
772  *
773  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
774  *  to have all "void" functions so declared.
775  */
776 /*
777  * rle_getrow.c - Read an RLE file in.
778  *
779  * Author:      Spencer W. Thomas
780  *              Computer Science Dept.
781  *              University of Utah
782  * Date:        Wed Apr 10 1985
783  * Copyright (c) 1985 Spencer W. Thomas
784  *
785  */
786 /*
787  * Automatically define LITTLE_ENDIAN on vax and pdp11 machines
788  */
789 #if defined(vax) || defined(pdp11)
790 #define LITTLE_ENDIAN
791 #endif
792  
793 struct inst {
794   unsigned opcode:8, datum:8;
795 };
796  
797 #define BREAD(type, var, len)\
798             zread( infile, (byte *)&var,len )
799 #define OPCODE(inst) (inst.opcode & ~LONG)
800 #define LONGP(inst) (inst.opcode & LONG)
801 #define DATUM(inst) (0x00ff & inst.datum)
802  
803 static int         debug_f;             /* if non-zero, print debug info */
804 static void     bfill();
805  
806 /*****************************************************************
807  * TAG( rle_get_setup )
808  *
809  * Read the initialization information from an RLE file.
810  * Inputs:
811  *      globals:    Contains pointer to the input file.
812  * Outputs:
813  *      globals:    Initialized with information from the
814  *                  input file.
815  *      Returns 0 on success, -1 if the file is not an RLE file,
816  *      -2 if malloc of the color map failed, -3 if an immediate EOF
817  *      is hit (empty input file), and -4 if an EOF is encountered reading
818  *      the setup information.
819  * Assumptions:
820  *      infile points to the "magic" number in an RLE file (usually
821  * byte 0 in the file).
822  * Algorithm:
823  *      Read in the setup info and fill in sv_globals.
824  */
825 rle_get_setup( globals )
826 struct sv_globals * globals;
827 {
828     struct XtndRsetup setup;
829     short magic;                        /* assume 16 bits */
830     register ZFILE *infile = globals->svfb_fd;
831     rle_pixel * bg_color;
832     register int i;
833     char * comment_buf;
834  
835     zclearerr(infile);
836     BREAD( short, magic, sizeof magic );
837     SWAB(magic);
838     if ( zeof( infile ) )
839         return -3;
840     if ( magic != XtndRMAGIC )
841         return -1;
842     BREAD( struct XtndRsetup, setup, SETUPSIZE );  /* assume VAX packing */
843     if ( zeof( infile ) )
844         return -4;
845     SWAB( setup.h_xpos );
846     SWAB( setup.h_ypos );
847     SWAB( setup.h_xlen );
848     SWAB( setup.h_ylen );
849  
850     /* Extract information from setup */
851     globals->sv_ncolors = setup.h_ncolors;
852     for ( i = 0; i < globals->sv_ncolors; i++ )
853         SV_SET_BIT( *globals, i );
854  
855     if ( !(setup.h_flags & H_NO_BACKGROUND) )
856     {
857         globals->sv_bg_color = (int *)lmalloc(
858             (unsigned)(sizeof(int) * setup.h_ncolors) );
859         bg_color = (rle_pixel *)lmalloc(
860             (unsigned)(1 + (setup.h_ncolors / 2) * 2) );
861         zread( infile, (byte *)bg_color, 1 + (setup.h_ncolors / 2) * 2 );
862         for ( i = 0; i < setup.h_ncolors; i++ )
863             globals->sv_bg_color[i] = bg_color[i];
864         lfree( bg_color );
865     }
866     else
867         zgetc( infile );                        /* skip filler byte */
868  
869     if ( setup.h_flags & H_NO_BACKGROUND )
870         globals->sv_background = 0;
871     else if ( setup.h_flags & H_CLEARFIRST )
872         globals->sv_background = 2;
873     else
874         globals->sv_background = 1;
875     if ( setup.h_flags & H_ALPHA )
876     {
877         globals->sv_alpha = 1;
878         SV_SET_BIT( *globals, SV_ALPHA );
879     }
880     else
881         globals->sv_alpha = 0;
882  
883     globals->sv_xmin = setup.h_xpos;
884     globals->sv_ymin = setup.h_ypos;
885     globals->sv_xmax = globals->sv_xmin + setup.h_xlen - 1;
886     globals->sv_ymax = globals->sv_ymin + setup.h_ylen - 1;
887  
888     globals->sv_ncmap = setup.h_ncmap;
889     globals->sv_cmaplen = setup.h_cmaplen;
890     if ( globals->sv_ncmap > 0 )
891     {
892         register int maplen =
893                      globals->sv_ncmap * (1 << globals->sv_cmaplen);
894         globals->sv_cmap = (rle_map *)lmalloc(
895             (unsigned)(sizeof(rle_map) * maplen) );
896         if ( globals->sv_cmap == NULL )
897         {
898             fprintf( stderr,
899                 "Malloc failed for color map of size %d*%d in rle_get_setup\n",
900                 globals->sv_ncmap, (1 << globals->sv_cmaplen) );
901             return -2;
902         }
903         zread( infile, (byte *)globals->sv_cmap, sizeof(short) * maplen );
904 #ifndef LITTLE_ENDIAN
905         /* Swap bytes on bigendian machines
906          */
907         for ( i = 0; i < maplen; i++ )
908             SWAB( globals->sv_cmap[i] );
909 #endif
910     }
911  
912     /* Check for comments */
913     if ( setup.h_flags & H_COMMENT )
914     {
915         short comlen, evenlen;
916         register char * cp;
917  
918         BREAD( short, comlen, sizeof comlen );  /* get comment length */
919         SWAB( comlen );
920         evenlen = (comlen + 1) & ~1;    /* make it even */
921         comment_buf = (char *)lmalloc( (unsigned) evenlen );
922         if ( comment_buf == NULL )
923         {
924             fprintf( stderr,
925                      "Malloc failed for comment buffer of size %d in rle_get_setup\n",
926                      comlen );
927             return -2;
928         }
929         zread( infile, (byte *)comment_buf, evenlen );
930         /* Count the comments */
931         for ( i = 0, cp = comment_buf; cp < comment_buf + comlen; cp++ )
932             if ( *cp == 0 )
933                 i++;
934         i++;                    /* extra for NULL pointer at end */
935         /* Get space to put pointers to comments */
936         globals->sv_comments =
937             (char **)lmalloc( (unsigned)(i * sizeof(char *)) );
938         if ( globals->sv_comments == NULL )
939         {
940             fprintf( stderr,
941                     "Malloc failed for %d comment pointers in rle_get_setup\n",
942                      i );
943             return -2;
944         }
945         /* Get pointers to the comments */
946         *globals->sv_comments = comment_buf;
947         for ( i = 1, cp = comment_buf + 1; cp < comment_buf + comlen; cp++ )
948             if ( *(cp - 1) == 0 )
949                 globals->sv_comments[i++] = cp;
950         globals->sv_comments[i] = NULL;
951     }
952     else
953         globals->sv_comments = NULL;
954  
955     /* Initialize state for rle_getrow */
956     globals->sv_private.get.scan_y = globals->sv_ymin;
957     globals->sv_private.get.vert_skip = 0;
958     globals->sv_private.get.is_eof = 0;
959     globals->sv_private.get.is_seek = 0;        /* Can't do seek on zfile */
960     debug_f = 0;
961  
962     if ( !zeof( infile ) )
963         return 0;                       /* success! */
964     else
965     {
966         globals->sv_private.get.is_eof = 1;
967         return -4;
968     }
969 }
970  
971  
972 /*****************************************************************
973  * TAG( rle_get_error )
974  *
975  * Print an error message for the return code from rle_get_setup
976  * Inputs:
977  *      code:           The return code from rle_get_setup.
978  *      pgmname:        Name of this program (argv[0]).
979  *      fname:          Name of the input file.
980  * Outputs:
981  *      Prints an error message on standard output.
982  *      Returns code.
983  */
984  
985 rle_get_error( code, pgmname, fname )
986 char *pgmname;
987 char *fname;
988 {
989     switch( code )
990     {
991     case 0:                     /* success */
992         break;
993  
994     case -1:                    /* Not an RLE file */
995         fprintf( stderr, "%s: %s is not an RLE file\n",
996                  pgmname, fname );
997         break;
998  
999     case -2:                    /* malloc failed */
1000         fprintf( stderr,
1001                  "%s: Malloc failed reading header of file %s\n",
1002                  pgmname, fname );
1003         break;
1004  
1005     case -3:
1006         fprintf( stderr, "%s: %s is an empty file\n", pgmname, fname );
1007         break;
1008  
1009     case -4:
1010         fprintf( stderr,
1011                  "%s: RLE header of %s is incomplete (premature EOF)\n",
1012                  pgmname, fname );
1013         break;
1014  
1015     default:
1016         fprintf( stderr, "%s: Error encountered reading header of %s\n",
1017                  pgmname, fname );
1018         break;
1019     }
1020     return code;
1021 }
1022  
1023  
1024 /*****************************************************************
1025  * TAG( rle_get_setup_ok )
1026  *
1027  * Read the initialization information from an RLE file.
1028  * Inputs:
1029  *      globals:    Contains pointer to the input file.
1030  *      prog_name:  Program name to be printed in the error message.
1031  *      file_name:  File name to be printed in the error message.
1032  *                  If NULL, the string "stdin" is generated.
1033  * Outputs:
1034  *      globals:    Initialized with information from the
1035  *                  input file.
1036  *      If reading the globals fails, it prints an error message
1037  *      and exits with the appropriate status code.
1038  * Algorithm:
1039  *      sv_get_setup does all the work.
1040  */
1041 void
1042 rle_get_setup_ok( globals, prog_name, file_name )
1043 struct sv_globals * globals;
1044 char *prog_name;
1045 char *file_name;
1046 {
1047     int code;
1048  
1049     if (! file_name)
1050         file_name = "stdin";
1051  
1052     code = rle_get_error( rle_get_setup( globals ), prog_name, file_name );
1053     if (code)
1054         exit( code );
1055 }
1056  
1057  
1058 /*****************************************************************
1059  * TAG( rle_debug )
1060  *
1061  * Turn RLE debugging on or off.
1062  * Inputs:
1063  *      on_off:         if 0, stop debugging, else start.
1064  * Outputs:
1065  *      Sets internal debug flag.
1066  * Assumptions:
1067  *      [None]
1068  * Algorithm:
1069  *      [None]
1070  */
1071 void
1072 rle_debug( on_off )
1073 int on_off;
1074 {
1075     debug_f = on_off;
1076 }
1077  
1078  
1079 /*****************************************************************
1080  * TAG( rle_getrow )
1081  *
1082  * Get a scanline from the input file.
1083  * Inputs:
1084  *      globals:    sv_globals structure containing information about
1085  *                  the input file.
1086  * Outputs:
1087  *      scanline:   an array of pointers to the individual color
1088  *                  scanlines.  Scanline is assumed to have
1089  *                  globals->sv_ncolors pointers to arrays of rle_pixel,
1090  *                  each of which is at least globals->sv_xmax+1 long.
1091  *      Returns the current scanline number.
1092  * Assumptions:
1093  *      rle_get_setup has already been called.
1094  * Algorithm:
1095  *      If a vertical skip is being executed, and clear-to-background is
1096  *      specified (globals->sv_background is true), just set the
1097  *      scanlines to the background color.  If clear-to-background is
1098  *      not set, just increment the scanline number and return.
1099  *
1100  *      Otherwise, read input until a vertical skip is encountered,
1101  *      decoding the instructions into scanline data.
1102  */
1103  
1104 rle_getrow( globals, scanline )
1105 struct sv_globals * globals;
1106 rle_pixel *scanline[];
1107 {
1108     register rle_pixel * scanc;
1109     register int nc;
1110     register ZFILE *infile = globals->svfb_fd;
1111     int scan_x = globals->sv_xmin,      /* current X position */
1112            channel = 0;                 /* current color channel */
1113     short word, long_data;
1114     struct inst inst;
1115  
1116     /* Clear to background if specified */
1117     if ( globals->sv_background == 2 )
1118     {
1119         if ( globals->sv_alpha && SV_BIT( *globals, -1 ) )
1120             bfill( (char *)scanline[-1], globals->sv_xmax + 1, 0 );
1121         for ( nc = 0; nc < globals->sv_ncolors; nc++ )
1122             if ( SV_BIT( *globals, nc ) )
1123                 bfill( (char *)scanline[nc], globals->sv_xmax+1,
1124                         globals->sv_bg_color[nc] );
1125     }
1126  
1127     /* If skipping, then just return */
1128     if ( globals->sv_private.get.vert_skip > 0 )
1129     {
1130         globals->sv_private.get.vert_skip--;
1131         globals->sv_private.get.scan_y++;
1132         if ( globals->sv_private.get.vert_skip > 0 )
1133             return globals->sv_private.get.scan_y;
1134     }
1135  
1136     /* If EOF has been encountered, return also */
1137     if ( globals->sv_private.get.is_eof )
1138         return ++globals->sv_private.get.scan_y;
1139  
1140     /* Otherwise, read and interpret instructions until a skipLines
1141      * instruction is encountered.
1142      */
1143     if ( SV_BIT( *globals, channel ) )
1144         scanc = scanline[channel] + scan_x;
1145     else
1146         scanc = NULL;
1147     for (;;)
1148     {
1149         BREAD(struct inst, inst, 2 );
1150         if ( zeof(infile) )
1151         {
1152             globals->sv_private.get.is_eof = 1;
1153             break;              /* <--- one of the exits */
1154         }
1155  
1156         switch( OPCODE(inst) )
1157         {
1158         case RSkipLinesOp:
1159             if ( LONGP(inst) )
1160             {
1161                 BREAD( short, long_data, sizeof long_data );
1162                 SWAB( long_data );
1163                 globals->sv_private.get.vert_skip = long_data;
1164             }
1165             else
1166                 globals->sv_private.get.vert_skip = DATUM(inst);
1167             if (debug_f)
1168                 fprintf(stderr, "Skip %d Lines (to %d)\n",
1169                         globals->sv_private.get.vert_skip,
1170                         globals->sv_private.get.scan_y +
1171                             globals->sv_private.get.vert_skip );
1172  
1173             break;                      /* need to break for() here, too */
1174  
1175         case RSetColorOp:
1176             channel = DATUM(inst);      /* select color channel */
1177             if ( channel == 255 )
1178                 channel = -1;
1179             scan_x = globals->sv_xmin;
1180             if ( SV_BIT( *globals, channel ) )
1181                 scanc = scanline[channel]+scan_x;
1182             if ( debug_f )
1183                 fprintf( stderr, "Set color to %d (reset x to %d)\n",
1184                          channel, scan_x );
1185             break;
1186  
1187         case RSkipPixelsOp:
1188             if ( LONGP(inst) )
1189             {
1190                 BREAD( short, long_data, sizeof long_data );
1191                 SWAB( long_data );
1192                 scan_x += long_data;
1193                 scanc += long_data;
1194                 if ( debug_f )
1195                     fprintf( stderr, "Skip %d pixels (to %d)\n",
1196                             long_data, scan_x );
1197  
1198             }
1199             else
1200             {
1201                 scan_x += DATUM(inst);
1202                 scanc += DATUM(inst);
1203                 if ( debug_f )
1204                     fprintf( stderr, "Skip %d pixels (to %d)\n",
1205                             DATUM(inst), scan_x );
1206             }
1207             break;
1208  
1209         case RByteDataOp:
1210             if ( LONGP(inst) )
1211             {
1212                 BREAD( short, long_data, sizeof long_data );
1213                 SWAB( long_data );
1214                 nc = (int)long_data;
1215             }
1216             else
1217                 nc = DATUM(inst);
1218             nc++;
1219             if ( SV_BIT( *globals, channel ) )
1220             {
1221                 zread( infile, (byte *)scanc, nc );
1222                 if ( nc & 1 )
1223                     (void)zgetc( infile );      /* throw away odd byte */
1224             }
1225             else
1226                 {               /* Emulate a forward fseek */
1227                     register int ii;
1228                     for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
1229                         (void) zgetc( infile ); /* discard it */
1230                 }
1231  
1232             scanc += nc;
1233             scan_x += nc;
1234             if ( debug_f )
1235                 if ( SV_BIT( *globals, channel ) )
1236                 {
1237                     rle_pixel * cp = scanc - nc;
1238                     fprintf( stderr, "Pixel data %d (to %d):", nc, scan_x );
1239                     for ( ; nc > 0; nc-- )
1240                         fprintf( stderr, "%02x", *cp++ );
1241                     putc( '\n', stderr );
1242                 }
1243             else
1244                 fprintf( stderr, "Pixel data %d (to %d)\n", nc, scan_x );
1245             break;
1246  
1247         case RRunDataOp:
1248             if ( LONGP(inst) )
1249             {
1250                 BREAD( short, long_data, sizeof long_data );
1251                 SWAB( long_data );
1252                 nc = long_data;
1253             }
1254             else
1255                 nc = DATUM(inst);
1256             scan_x += nc + 1;
1257  
1258             BREAD( short, word, sizeof(short) );
1259             SWAB( word );
1260             if ( debug_f )
1261                 fprintf( stderr, "Run length %d (to %d), data %02x\n",
1262                             nc + 1, scan_x, word );
1263             if ( SV_BIT( *globals, channel ) )
1264             {
1265                 if ( nc >= 10 )         /* break point for 785, anyway */
1266                 {
1267                     bfill( (char *)scanc, nc + 1, word );
1268                     scanc += nc + 1;
1269                 }
1270                 else
1271                     for ( ; nc >= 0; nc--, scanc++ )
1272                         *scanc = word;
1273             }
1274             break;
1275  
1276         case REOFOp:
1277             globals->sv_private.get.is_eof = 1;
1278             break;
1279  
1280         default:
1281             fprintf( stderr,
1282                      "rle_getrow: Unrecognized opcode: %d\n", inst.opcode );
1283             exit(1);
1284         }
1285         if ( OPCODE(inst) == RSkipLinesOp || OPCODE(inst) == REOFOp )
1286             break;                      /* <--- the other loop exit */
1287     }
1288  
1289     return globals->sv_private.get.scan_y;
1290 }
1291  
1292  
1293 /* Fill buffer at s with n copies of character c.  N must be <= 65535*/
1294 /* ARGSUSED */
1295 static void bfill( s, n, c )
1296 char *s;
1297 int n, c;
1298 {
1299 #ifdef vax
1300     asm("   movc5   $0,*4(ap),12(ap),8(ap),*4(ap)");
1301 #else
1302     while ( n-- > 0 )
1303         *s++ = c;
1304 #endif
1305 }
1306  
1307 /*
1308  * This software is copyrighted as noted below.  It may be freely copied,
1309  * modified, and redistributed, provided that the copyright notice is
1310  * preserved on all copies.
1311  *
1312  * There is no warranty or other guarantee of fitness for this software,
1313  * it is provided solely "as is".  Bug reports or fixes may be sent
1314  * to the author, who may or may not act on them as he desires.
1315  *
1316  * You may not include this software in a program or other software product
1317  * without supplying the source, or without informing the end-user that the
1318  * source is available for no extra charge.
1319  *
1320  * If you modify this software, you should include a notice giving the
1321  * name of the person performing the modification, the date of modification,
1322  * and the reason for such modification.
1323  *
1324  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
1325  *  to have all "void" functions so declared.
1326  *
1327  * Modified to generate an apropriate size dither map (ie 2x2, 4x4, 8x8
1328  * or 16x16) rather than use fixed 16x16 map. Use a large enough map
1329  * to give a minimum of 128 effective levels rather than aiming for 256.
1330  * This should give less grainy pictures.
1331  * Two global variables can modify this:
1332  * dith_levels = 128 (default)
1333  * dith_np2 = 0 (default). Nonzero to enable non power of 2 dither mapping.
1334  * dith_size = actual dither matrix size chosen.
1335  *
1336  * Graeme Gill  3 June 88
1337  */
1338  
1339 /*
1340  * dither.c - Functions for RGB color dithering.
1341  *
1342  * Author:      Spencer W. Thomas
1343  *              Computer Science Dept.
1344  *              University of Utah
1345  * Date:        Mon Feb  2 1987
1346  * Copyright (c) 1987, University of Utah
1347  */
1348  
1349 void    make_square();
1350  
1351 /* dither globals */
1352 int dith_levels = 128;
1353 int dith_np2 = 0;
1354 int dith_size = 16;
1355  
1356 /* basic dithering macro */
1357 #define DMAP(v,x,y)     (modN[v]>magic[x][y] ? divN[v] + 1 : divN[v])
1358  
1359 /*****************************************************************
1360  * TAG( dithermap )
1361  *
1362  * Create a color dithering map with a specified number of intensity levels.
1363  * Inputs:
1364  *      levels:         Intensity levels per primary.
1365  *      gamma:          Display gamma value.
1366  * Outputs:
1367  *      rgbmap:         Generated color map.
1368  *      divN:           "div" function for dithering.
1369  *      modN:           "mod" function for dithering.
1370  * Assumptions:
1371  *      rgbmap will hold levels^3 entries.
1372  * Algorithm:
1373  *      Compute gamma compensation map.
1374  *      N = 255.0 / (levels - 1) is number of pixel values per level.
1375  *      Compute rgbmap with red ramping fastest, green slower, and blue
1376  *      slowest (treat it as if it were rgbmap[levels][levels][levels][3]).
1377  *      Call make_square to get divN, modN, and magic
1378  *
1379  * Note:
1380  *      Call dithergb( x, y, r, g, b, levels, divN, modN, magic ) to get index
1381  *      into rgbmap for a given color/location pair, or use
1382  *          row = y % 16; col = x % 16;
1383  *          DMAP(v,col,row) =def (divN[v] + (modN[v]>magic[col][row] ? 1 : 0))
1384  *          DMAP(r,col,row) + DMAP(g,col,row)*levels + DMAP(b,col,row)*levels^2
1385  *      if you don't want function call overhead.
1386  */
1387 void
1388 dithermap( levels, gamma, rgbmap, divN, modN, magic )
1389 double gamma;
1390 int rgbmap[][3];
1391 int divN[256];
1392 int modN[256];
1393 int magic[16][16];
1394 {
1395     double N;
1396     register int i;
1397     int levelsq, levelsc;
1398     int gammamap[256];
1399  
1400         make_gamma(gamma,gammamap);
1401  
1402     levelsq = levels*levels;    /* squared */
1403     levelsc = levels*levelsq;   /* and cubed */
1404  
1405     N = 255.0 / (levels - 1);    /* Get size of each step */
1406  
1407     /*
1408      * Set up the color map entries.
1409      */
1410     for(i = 0; i < levelsc; i++) {
1411         rgbmap[i][0] = gammamap[(int)(0.5 + (i%levels) * N)];
1412         rgbmap[i][1] = gammamap[(int)(0.5 + ((i/levels)%levels) * N)];
1413         rgbmap[i][2] = gammamap[(int)(0.5 + ((i/levelsq)%levels) * N)];
1414     }
1415  
1416     make_square( N, divN, modN, magic );
1417 }
1418  
1419  
1420 /*****************************************************************
1421  * TAG( bwdithermap )
1422  *
1423  * Create a color dithering map with a specified number of intensity levels.
1424  * Inputs:
1425  *      levels:         Intensity levels.
1426  *      gamma:          Display gamma value.
1427  * Outputs:
1428  *      bwmap:          Generated black & white map.
1429  *      divN:           "div" function for dithering.
1430  *      modN:           "mod" function for dithering.
1431  * Assumptions:
1432  *      bwmap will hold levels entries.
1433  * Algorithm:
1434  *      Compute gamma compensation map.
1435  *      N = 255.0 / (levels - 1) is number of pixel values per level.
1436  *      Compute bwmap for levels entries.
1437  *      Call make_square to get divN, modN, and magic.
1438  * Note:
1439  *      Call ditherbw( x, y, val, divN, modN, magic ) to get index into
1440  *      bwmap for a given color/location pair, or use
1441  *          row = y % 16; col = x % 16;
1442  *          divN[val] + (modN[val]>magic[col][row] ? 1 : 0)
1443  *      if you don't want function call overhead.
1444  *      On a 1-bit display, use
1445  *          divN[val] > magic[col][row] ? 1 : 0
1446  */
1447 void
1448 bwdithermap( levels, gamma, bwmap, divN, modN, magic )
1449 double gamma;
1450 int bwmap[];
1451 int divN[256];
1452 int modN[256];
1453 int magic[16][16];
1454 {
1455     double N;
1456     register int i;
1457     int gammamap[256];
1458  
1459         make_gamma(gamma,gammamap);
1460  
1461     N = 255.0 / (levels - 1);    /* Get size of each step */
1462  
1463     /*
1464      * Set up the color map entries.
1465      */
1466     for(i = 0; i < levels; i++)
1467         bwmap[i] = gammamap[(int)(0.5 + i * N)];
1468  
1469     make_square( N, divN, modN, magic );
1470 }
1471  
1472  
1473 /*****************************************************************
1474  * TAG( make_square )
1475  *
1476  * Build the magic square for a given number of levels.
1477  * Inputs:
1478  *      N:              Pixel values per level (255.0 / (levels-1)).
1479  * (global) dith_levels = 128 (default) - number of effective levels to aim for
1480  * (global) dith_np2 = 0 (default) - non-zero if non power of two size is permissable.
1481  * Outputs:
1482  *      divN:           Integer value of pixval / N
1483  *      modN:           Integer remainder between pixval and divN[pixval]*N
1484  *      magic:          Magic square for dithering to N sublevels.
1485  * (global) dith_size = magic square size chosen.
1486  * Assumptions:
1487  *      
1488  * Algorithm:
1489  *      divN[pixval] = (int)(pixval / N) maps pixval to its appropriate level.
1490  *      modN[pixval] = pixval - (int)(N * divN[pixval]) maps pixval to
1491  *      its sublevel, and is used in the dithering computation.
1492  */
1493 void
1494 make_square( N, divN, modN, magic )
1495 double N;
1496 int divN[256];
1497 int modN[256];
1498 int magic[16][16] ;
1499 {
1500     register int i, j, k, l;
1501     double magicfact;
1502  
1503     for ( i = 0; i < 256; i++ )
1504     {
1505         divN[i] = (int)(i / N);
1506         modN[i] = i - (int)(N * divN[i]);
1507     }
1508     modN[255] = 0;              /* always */
1509  
1510         /* figure out how big a square will give */
1511         /* the desired number of levels */
1512         if(dith_np2)
1513                 for(dith_size= 2;((dith_size * dith_size)+1)<((N*dith_levels)/256);dith_size++ );
1514         else
1515                 for(dith_size= 2;((dith_size * dith_size)+1)<((N*dith_levels)/256);dith_size *=2);
1516  
1517         /* make the basic square up */
1518         /* ( will have numbers 0 - size * size ) */
1519         make_magic(dith_size,magic);
1520  
1521         /* divN gives 0 - levels-1 */
1522         /* modN gives 0 - N-1 */
1523         /* dither is if(modN(pix) > magic[][] so */
1524         /* scale magic it to have levels 0 to N-2 */
1525         /* (ie takes account of magic square size allows size * size +1 levels */
1526  
1527         magicfact = (N-2)/((double)((dith_size * dith_size)-1));
1528         for(i=0;i<dith_size;i++)
1529         {
1530                 for(j=0;j<dith_size;j++)
1531                 {
1532                         magic[i][j] = (int)(0.5 + magic[i][j] * magicfact);
1533                 }
1534         }
1535  
1536         if(!dith_np2)   /* if we have power of 2 */
1537         {
1538                 /* now replicate the size square we've chosen */  
1539                 /* (and use a brick pattern) */
1540                 for(k=0;k<16;k += dith_size)
1541                 {
1542                         for(l=k>0?0:dith_size;l<16;l += dith_size)
1543                         {
1544                                 for(i=0;i<dith_size;i++)
1545                                 {
1546                                         for(j=0;j<dith_size;j++)
1547                                         {
1548                                                 magic[k+i][((l+k/2)+j)%16] = magic[i][j];
1549                                         }
1550                                 }
1551                         }
1552                 }
1553         }
1554 }
1555  
1556 int magic16x16[16][16] =
1557         {
1558                 {0,128,32,160,8,136,40,168,2,130,34,162,10,138,42,170},
1559                 {192,64,224,96,200,72,232,104,194,66,226,98,202,74,234,106},
1560                 {48,176,16,144,56,184,24,152,50,178,18,146,58,186,26,154},
1561                 {240,112,208,80,248,120,216,88,242,114,210,82,250,122,218,90},
1562                 {12,140,44,172,4,132,36,164,14,142,46,174,6,134,38,166},
1563                 {204,76,236,108,196,68,228,100,206,78,238,110,198,70,230,102},
1564                 {60,188,28,156,52,180,20,148,62,190,30,158,54,182,22,150},
1565                 {252,124,220,92,244,116,212,84,254,126,222,94,246,118,214,86},
1566                 {3,131,35,163,11,139,43,171,1,129,33,161,9,137,41,169},
1567                 {195,67,227,99,203,75,235,107,193,65,225,97,201,73,233,105},
1568                 {51,179,19,147,59,187,27,155,49,177,17,145,57,185,25,153},
1569                 {243,115,211,83,251,123,219,91,241,113,209,81,249,121,217,89},
1570                 {15,143,47,175,7,135,39,167,13,141,45,173,5,133,37,165},
1571                 {207,79,239,111,199,71,231,103,205,77,237,109,197,69,229,101},
1572                 {63,191,31,159,55,183,23,151,61,189,29,157,53,181,21,149},
1573                 {255,127,223,95,247,119,215,87,253,125,221,93,245,117,213,85}
1574         };
1575  
1576 /*****************************************************************
1577  * TAG( make_magic )
1578      *
1579  * Create the magic square.
1580  * Inputs:
1581  *      size:           Order of the square
1582  *  magic:              Address of 16 x 16 magic square.
1583  * Outputs:
1584  *      Fills in the 16 x 16 magic square.
1585  * Assumptions:
1586  *      size is between 2 and 16
1587  * Algorithm:
1588  *      Chose sub cell of 16 by 16 magic square
1589      */
1590 make_magic( size, magic )
1591 int size;
1592 int magic[16][16];
1593 {
1594         int j,i,li,bi,bx,by;
1595         int xx,yy;
1596         int total;
1597  
1598         total = size * size;
1599  
1600         i = 0;
1601         li = -1;
1602         for(j=0;j<total;j++)   
1603         {
1604                 bi = 256;
1605  
1606                 for(xx=0;xx<size;xx++)
1607                 {
1608                         for(yy=0;yy<size;yy++)
1609                         {
1610                                 if(magic16x16[xx][yy] >li && magic16x16[xx][yy] < bi)
1611                                 {
1612                                         bx = xx;
1613                                         by = yy;
1614                                         bi = magic16x16[xx][yy];
1615                                 }
1616                         }
1617                 }
1618                 magic[bx][by] = i;
1619                 i++;
1620                 li = bi;
1621         }
1622 }
1623  
1624 /*****************************************************************
1625  * TAG( make_gamma )
1626  *
1627  * Makes a gamma compenstation map.
1628  * Inputs:
1629  *  gamma:                      desired gamma
1630  *      gammamap:               gamma mapping array
1631  * Outputs:
1632  *  Changes gamma array entries.
1633  */
1634 make_gamma( gamma, gammamap )
1635 double gamma;
1636 int gammamap[256];
1637 {
1638         register int i;
1639  
1640     for ( i = 0; i < 256; i++ )
1641                 {
1642 #ifdef BYTEBUG
1643                 int byteb1;
1644  
1645                 byteb1 = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
1646                 gammamap[i] = byteb1;
1647 #else
1648                 gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
1649 #endif
1650                 }
1651 }
1652  
1653 /*****************************************************************
1654  * TAG( dithergb )
1655  *
1656  * Return dithered RGB value.
1657  * Inputs:
1658  *      x:              X location on screen of this pixel.
1659  *      y:              Y location on screen of this pixel.
1660  *      r, g, b:        Color at this pixel (0 - 255 range).
1661  *      levels:         Number of levels in this map.
1662  *      divN, modN:     From dithermap.
1663  *      magic:          Magic square from dithermap.
1664  * Outputs:
1665  *      Returns color map index for dithered pixelv value.
1666  * Assumptions:
1667  *      divN, modN, magic were set up properly.
1668  * Algorithm:
1669  *      see "Note:" in dithermap comment.
1670  */
1671 dithergb( x, y, r, g, b, levels, divN, modN, magic )
1672 int divN[256];
1673 int modN[256];
1674 int magic[16][16];
1675 {
1676     int col = x % 16, row = y % 16;
1677  
1678     return DMAP(r, col, row) +
1679         DMAP(g, col, row) * levels +
1680             DMAP(b, col, row) * levels*levels;
1681 }
1682  
1683  
1684 /*****************************************************************
1685  * TAG( ditherbw )
1686  *
1687  * Return dithered black & white value.
1688  * Inputs:
1689  *      x:              X location on screen of this pixel.
1690  *      y:              Y location on screen of this pixel.
1691  *      val:            Intensity at this pixel (0 - 255 range).
1692  *      divN, modN:     From dithermap.
1693  *      magic:          Magic square from dithermap.
1694  * Outputs:
1695  *      Returns color map index for dithered pixel value.
1696  * Assumptions:
1697  *      divN, modN, magic were set up properly.
1698  * Algorithm:
1699  *      see "Note:" in bwdithermap comment.
1700  */
1701 ditherbw( x, y, val, divN, modN, magic )
1702 int divN[256];
1703 int modN[256];
1704 int magic[16][16];
1705 {
1706     int col = x % 16, row = y % 16;
1707  
1708     return DMAP(val, col, row);
1709 }