Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
rle_putrow.c
Go to the documentation of this file.
1 /*
2  * This software is copyrighted as noted below. It may be freely copied,
3  * modified, and redistributed, provided that the copyright notice is
4  * preserved on all copies.
5  *
6  * There is no warranty or other guarantee of fitness for this software,
7  * it is provided solely "as is". Bug reports or fixes may be sent
8  * to the author, who may or may not act on them as he desires.
9  *
10  * You may not include this software in a program or other software product
11  * without supplying the source, or without informing the end-user that the
12  * source is available for no extra charge.
13  *
14  * If you modify this software, you should include a notice giving the
15  * name of the person performing the modification, the date of modification,
16  * and the reason for such modification.
17  *
18  * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
19  * to have all "void" functions so declared.
20  */
21 /*
22  * rle_putrow.c - Save a row of the fb to a file.
23  *
24  * Author: Spencer W. Thomas
25  * Computer Science Dept.
26  * University of Utah
27  * Date: 1 April 1981
28  * Copyright (c) 1981,1986 Spencer W. Thomas
29  *
30  * $Id: rle_putrow.c,v 3.0.1.2 1992/01/28 18:29:22 spencer Exp $
31  */
32 
33 #include "stdio.h"
34 #include "rle_put.h"
35 #include "rle.h"
36 
37 static int findruns();
38 
39 #define FASTRUNS /* Faster run finding */
40 #ifdef vax
41 #define LOCC /* Use vax instructions for more speed */
42 #endif
43 
44 #define FALSE 0
45 #define TRUE 1
46 
47 /* Save some typing. */
48 #define PBRUN the_hdr->priv.put.brun
49 
50 /*****************************************************************
51  * TAG( rle_putrow )
52  * Write a scanline to the output file.
53  *
54  * Inputs:
55  * rows: Pointer to vector of pointers to
56  * rle_pixel arrays containing the pixel information.
57  * If NULL, rowlen scanlines are skipped.
58  * rowlen: The number of pixels in the scanline, or the
59  * number of scanlines to skip (see above).
60  * Outputs:
61  * Run length encoded information is written to the_hdr.rle_file.
62  * Assumptions:
63  * I'm sure there are lots of assumptions in here.
64  * Algorithm:
65  * There are two parts:
66  * 1. Find all "sufficiently long" runs of background
67  * color. These will not be saved at all.
68  * 2. For each run of non-background, for each color
69  * channel, find runs of identical pixel values
70  * between "data" segments (of differing pixel
71  * values).
72  * For part 1, "sufficiently long" is 2 pixels, if the following
73  * data is less than 256 pixels long, otherwise it is 4 pixels.
74  * This is enforced by a post-process merge.
75  *
76  * Part 1 can be done in two different ways, depending on whether
77  * FASTRUNS is defined or not. With FASTRUNS defined, it finds
78  * runs of the background pixel value in each channel
79  * independently, and then merges the results. With FASTRUNS not
80  * defined, it scans all channels in parallel.
81  *
82  * Part 2 uses a state machine. For each run of non-background
83  * data, it searches for sufficiently long sequences of a single
84  * value (in each channel independently). Sufficiently long is 4
85  * pixels if the following data is < 256 pixels, 6 pixels
86  * otherwise. This is because the startup cost for the run is 2
87  * bytes, and the startup cost for a data segment is 2 bytes if
88  * it is < 256 pixels long, 4 bytes otherwise. Thus a run
89  * shorter than 4 or 6 pixels (respectively) would actually make
90  * the output longer. An additional pixel is required if the
91  * preceding data is an odd number of pixels long (because a
92  * filler byte will be output at the end of it.)
93  */
94 
95 void
97 register rle_pixel *rows[];
98 int rowlen;
99 register rle_hdr * the_hdr;
100 {
101  register int i, j;
102  int nrun;
103  register rle_pixel *row;
104  int mask;
105  char bits[256];
106  short state, /* State of run-finding state machine. */
107  dstart, /* Starting point for current data segment. */
108  dend, /* Ending point of current data segment. */
109  rstart = 0, /* Starting point of current run. */
110  runval = 0; /* Data value for current run. */
111 
112  if (rows == NULL)
113  {
114  the_hdr->priv.put.nblank += rowlen;
115  return;
116  }
117  /*
118  * If not done already, allocate space to remember runs of
119  * non-background color. A run of bg color must be at least 2
120  * bytes long to count, so there can be at most rowlen/3 of them.
121  */
122  if ( PBRUN == NULL )
123  {
124  PBRUN = (short (*)[2])malloc(
125  (unsigned)((rowlen/3 + 1) * 2 * sizeof(short)) );
126  if ( PBRUN == NULL )
127  {
128  fprintf( stderr, "%s: Malloc failed in rle_putrow, writing %s\n",
129  the_hdr->cmd, the_hdr->file_name );
130  exit(1);
131  }
132  }
133  /* Unpack bitmask in the_hdr struct */
134  for ( i=0; i < the_hdr->ncolors; i++ )
135  bits[i] = RLE_BIT( *the_hdr, i );
136  bits[255] = RLE_BIT( *the_hdr, -1 );
137 
138  /*
139  * If saving only non-background pixels, find runs of them. Note
140  * that the alpha channel is considered to be background iff it is
141  * zero.
142  */
143 #ifdef FASTRUNS
144  if ( the_hdr->background )
145  {
146  /*
147  * Find runs in each color individually, merging them as we go.
148  */
149  nrun = 0; /* start out with no runs */
150  /* Alpha channel first */
151  if ( the_hdr->alpha )
152  nrun = findruns( rows[-1], rowlen, 0, nrun, PBRUN );
153  /* Now the color channels */
154  for ( i = 0; i < the_hdr->ncolors; i++ )
155  if ( bits[i] )
156  nrun = findruns( rows[i], rowlen, the_hdr->bg_color[i],
157  nrun, PBRUN );
158  }
159  else
160  {
161  PBRUN[0][0] = 0;
162  PBRUN[0][1] = rowlen-1;
163  nrun = 1;
164  }
165 #else /* FASTRUNS */
166  if (the_hdr->background) /* find non-background runs */
167  {
168  j = 0;
169  for (i=0; i<rowlen; i++)
170  if (!same_color( i, rows, the_hdr->bg_color,
171  the_hdr->ncolors, bits ) ||
172  (the_hdr->alpha && rows[-1][i] != 0))
173  {
174  if (j > 0 && i - PBRUN[j-1][1] <= 2)
175  j--;
176  else
177  PBRUN[j][0] = i; /* start of run */
178  for ( i++;
179  i < rowlen &&
180  ( !same_color( i, rows, the_hdr->bg_color,
181  the_hdr->ncolors, bits ) ||
182  (the_hdr->alpha && rows[-1][i] != 0) );
183  i++)
184  ; /* find the end of this run */
185  PBRUN[j][1] = i-1; /* last in run */
186  j++;
187  }
188  nrun = j;
189  }
190  else
191  {
192  PBRUN[0][0] = 0;
193  PBRUN[0][1] = rowlen-1;
194  nrun = 1;
195  }
196 #endif /* FASTRUNS */
197  /* One final pass merges runs with fewer than 4 intervening pixels
198  * if the second run is longer than 255 pixels. This is because
199  * the startup cost for such a run is 4 bytes.
200  */
201  if ( nrun > 1 )
202  {
203  for ( i = nrun - 1; i > 0; i-- )
204  {
205  if ( PBRUN[i][1] - PBRUN[i][0] > 255 &&
206  PBRUN[i-1][1] + 4 > PBRUN[i][0] )
207  {
208  PBRUN[i-1][1] = PBRUN[i][1];
209  for ( j = i; j < nrun - 1; j++ )
210  {
211  PBRUN[j][0] = PBRUN[j+1][0];
212  PBRUN[j][1] = PBRUN[j+1][1];
213  }
214  nrun--;
215  }
216  }
217  }
218 
219  if (nrun > 0)
220  {
221  if (the_hdr->priv.put.nblank > 0)
222  {
223  SkipBlankLines(the_hdr->priv.put.nblank);
224  the_hdr->priv.put.nblank = 0;
225  }
226  for ( mask = (the_hdr->alpha ? -1 : 0);
227  mask < the_hdr->ncolors;
228  mask++) /* do all colors */
229  {
230  if ( ! bits[mask & 0xff] )
231  {
232  continue;
233  }
234  row = rows[mask];
235  SetColor(mask);
236  if (PBRUN[0][0] > 0)
237  {
238  SkipPixels(PBRUN[0][0], FALSE, FALSE);
239  }
240  for (j=0; j<nrun; j++)
241  {
242  state = DATA;
243  dstart = PBRUN[j][0];
244  dend = PBRUN[j][1];
245  for (i=dstart; i<=dend; i++)
246  {
247  switch(state)
248  {
249  case DATA:
250  if (i > dstart && runval == row[i])
251  {
252  /* 2 in a row may be a run. */
253  /* If odd data length, start with RUN1 */
254  if ( ((i - dstart) % 2) == 0)
255  state = RUN1;
256  else
257  state = RUN2;
258  }
259  else
260  {
261  runval = row[i]; /* maybe a run starts here? */
262  rstart = i;
263  }
264  break;
265 
266  case RUN4:
267  if (runval == row[i])
268  {
269  /* If the following data might be longer
270  * than 255 pixels then look for 8 in a
271  * row, otherwise, 6 in a row is
272  * sufficient. Fake this by skipping to
273  * state RUN5.
274  */
275  if ( dend - i > 255 )
276  state = RUN5; /* Need some more. */
277  else
278  state = RUN7; /* Next one makes a run. */
279 
280  }
281  else
282  {
283  state = DATA; /* Nope, back to data */
284  runval = row[i]; /* but maybe a new run here? */
285  rstart = i;
286  }
287  break;
288 
289  case RUN1:
290  case RUN2:
291  case RUN3:
292  case RUN5:
293  case RUN6:
294  if (runval == row[i])
295  {
296  /* Move to the next state. */
297  state++;
298  }
299  else
300  {
301  state = DATA; /* Nope, back to data */
302  runval = row[i]; /* but maybe a new run here? */
303  rstart = i;
304  }
305  break;
306 
307 
308  case RUN7:
309  if (runval == row[i]) /* enough in a row for a run */
310  {
311  state = INRUN;
312  putdata(row + dstart, rstart - dstart);
313 #ifdef FASTRUNS
314 #ifdef LOCC
315  /* Shortcut to find end of run! */
316  i = dend - skpc( (char *)row + i, dend + 1 - i,
317  runval );
318 #else
319  while ( row[++i] == runval && i <= dend)
320  ; /* not quite so good, but not bad */
321  i--;
322 #endif /* LOCC */
323 #endif /* FASTRUNS */
324  }
325  else
326  {
327  state = DATA; /* not a run, */
328  runval = row[i]; /* but may this starts one */
329  rstart = i;
330  }
331  break;
332 
333  case INRUN:
334  if (runval != row[i]) /* if run out */
335  {
336  state = DATA;
337  putrun(runval, i - rstart, FALSE);
338  runval = row[i]; /* who knows, might be more */
339  rstart = i;
340  dstart = i; /* starting a new 'data' run */
341  }
342  break;
343  }
344  }
345  if (state == INRUN)
346  putrun(runval, i - rstart, TRUE); /* last bit */
347  else
348  putdata(row + dstart, i - dstart);
349 
350  if (j < nrun-1)
351  SkipPixels(
352  PBRUN[j+1][0] - dend - 1,
353  FALSE, state == INRUN);
354  else
355  {
356  if (rowlen - dend > 0)
357  SkipPixels(
358  rowlen - dend - 1,
359  TRUE, state == INRUN);
360  }
361  }
362 
363  if ( mask != the_hdr->ncolors - 1 )
365  }
366  }
367 
368  /* Increment to next scanline */
369  the_hdr->priv.put.nblank++;
370 
371  /* flush every scanline */
372  fflush( the_hdr->rle_file );
373 }
374 
375 
376 /*****************************************************************
377  * TAG( rle_skiprow )
378  *
379  * Skip rows in RLE file.
380  * Inputs:
381  * the_hdr: Header struct for RLE output file.
382  * nrow: Number of rows to skip.
383  * Outputs:
384  * Increments the nblank field in the the_hdr struct, so that a Skiplines
385  * code will be output the next time rle_putrow or rle_putraw is called.
386  * Assumptions:
387  * Only effective when called between rle_putrow or rle_putraw calls (or
388  * some other routine that follows the same conventions.
389  * Algorithm:
390  * [None]
391  */
392 void
394 rle_hdr *the_hdr;
395 int nrow;
396 {
397  the_hdr->priv.put.nblank += nrow;
398 }
399 
400 
401 /*****************************************************************
402  * TAG( rle_put_init )
403  *
404  * Initialize the header structure for writing scanlines.
405  * Inputs:
406  * [None]
407  * Outputs:
408  * the_hdr: Private portions initialized for output.
409  * Assumptions:
410  * [None]
411  * Algorithm:
412  * [None]
413  */
414 void
416 register rle_hdr *the_hdr;
417 {
418  the_hdr->dispatch = RUN_DISPATCH;
419 
420  if ( the_hdr->is_init != RLE_INIT_MAGIC )
421  {
422  the_hdr->cmd = "Urt";
423  the_hdr->file_name = "some file";
424  }
425  the_hdr->priv.put.nblank = 0; /* Reinit static vars */
426  /* Would like to be able to free previously allocated storage,
427  * but can't count on a non-NULL value being a valid pointer.
428  */
429  PBRUN = NULL;
430  the_hdr->priv.put.fileptr = 0;
431 
432  /* Only save alpha if alpha AND alpha channel bit are set. */
433  if ( the_hdr->alpha )
434  the_hdr->alpha = (RLE_BIT( *the_hdr, -1 ) != 0);
435  else
436  RLE_CLR_BIT( *the_hdr, -1 );
437 }
438 
439 /*****************************************************************
440  * TAG( rle_put_setup )
441  *
442  * Initialize for writing RLE, and write header to output file.
443  * Inputs:
444  * the_hdr: Describes output image.
445  * Outputs:
446  * the_hdr: Initialized.
447  * Assumptions:
448  * Lots of them.
449  * Algorithm:
450  * [None]
451  */
452 void
454 register rle_hdr * the_hdr;
455 {
456  rle_put_init( the_hdr );
457  the_hdr->img_num++; /* Count output images. */
458  Setup();
459 }
460 
461 /*ARGSUSED*/
462 void
464 rle_hdr * the_hdr;
465 {
466  /* Do nothing */
467 }
468 
469 /*****************************************************************
470  * TAG( rle_puteof )
471  * Write an EOF code into the output file.
472  */
473 void
475 register rle_hdr * the_hdr;
476 {
477  /* Don't puteof twice. */
478  if ( the_hdr->dispatch == NO_DISPATCH )
479  return;
480  PutEof();
481  fflush( the_hdr->rle_file );
482  /* Free storage allocated by rle_put_init. */
483  if ( PBRUN != NULL )
484  {
485  free( PBRUN );
486  PBRUN = NULL;
487  }
488  /* Signal that puteof has been called. */
489  the_hdr->dispatch = NO_DISPATCH;
490 }
491 
492 #ifndef FASTRUNS
493 /*****************************************************************
494  * TAG( same_color )
495  *
496  * Determine if the color at the given index position in the scan rows
497  * is the same as the background color.
498  * Inputs:
499  * index: Index to the pixel position in each row.
500  * rows: array of pointers to the scanlines
501  * bg_color: the background color
502  * ncolors: number of color elements/pixel
503  * Outputs:
504  * TRUE if the color at row[*][i] is the same as bg_color[*].
505  * Assumptions:
506  * [None]
507  * Algorithm:
508  * [None]
509  */
510 static int
511 same_color( index, rows, bg_color, ncolors, bits )
512 register rle_pixel *rows[];
513 register int bg_color[];
514 char *bits;
515 {
516  register int i;
517 
518  for ( i = 0; i < ncolors; i++, bits++ )
519  if ( *bits &&
520  rows[i][index] != bg_color[i] )
521  return 0;
522  return 1; /* all the same */
523 }
524 #endif /* !FASTRUNS */
525 
526 /*****************************************************************
527  * TAG( findruns )
528  *
529  * Find runs not a given color in the row.
530  * Inputs:
531  * row: Row of pixel values
532  * rowlen: Number of pixels in the row.
533  * color: Color to compare against.
534  * nrun: Number of runs already found (in different colors).
535  * brun: Runs found in other color channels already.
536  * Outputs:
537  * brun: Modified to reflect merging of runs in this color.
538  * Returns number of runs in brun.
539  * Assumptions:
540  *
541  * Algorithm:
542  * Search for occurences of pixels not of the given color outside
543  * the runs already found. When some are found, add a new run or
544  * extend an existing one. Adjacent runs with fewer than two
545  * pixels intervening are merged.
546  */
547 static int
549 register rle_pixel *row;
550 int rowlen, color, nrun;
551 short (*brun)[2];
552 {
553  int i = 0, lower, upper;
554  register int s, j;
555 
556 #ifdef DEBUG
557  fprintf( stderr, "findruns( " );
558  for ( s = 0; s < rowlen; s++ )
559  fprintf( stderr, "%2x.%s", row[s], (s % 20 == 19) ? "\n\t" : "" );
560  if ( s % 20 != 0 )
561  fprintf( stderr, "\n\t" );
562  fprintf( stderr, "%d, %d, %d, \n\t", rowlen, color, nrun );
563  for ( j = 0; j < nrun; j++ )
564  fprintf( stderr, "(%3d,%3d) %s", brun[j][0], brun[j][1],
565  (j % 6 == 5) ? "\n\t" : "" );
566  fprintf( stderr, ")\n" );
567 #endif
568 
569  while ( i <= nrun )
570  {
571  /* Assert: 0 <= i <= rowlen
572  * brun[i] is the run following the "blank" space being
573  * searched. If i == rowlen, search after brun[i-1].
574  */
575 
576  /* get lower and upper bounds of search */
577 
578  if ( i == 0 )
579  lower = 0;
580  else
581  lower = brun[i-1][1] + 1;
582 
583  if ( i == nrun )
584  upper = rowlen - 1;
585  else
586  upper = brun[i][0] - 1;
587 
588 #ifdef DEBUG
589  fprintf( stderr, "Searching before run %d from %d to %d\n",
590  i, lower, upper );
591 #endif
592  /* Search for beginning of run != color */
593 #if defined(LOCC)&defined(vax)
594  s = upper - skpc( (char *)row + lower, upper - lower + 1, color ) + 1;
595 #else
596  for ( s = lower; s <= upper; s++ )
597  if ( row[s] != color )
598  break;
599 #endif
600 
601  if ( s <= upper ) /* found a new run? */
602  {
603  if ( s > lower + 1 || i == 0 ) /* disjoint from preceding run? */
604  {
605 #ifdef DEBUG
606  fprintf( stderr, "Found new run starting at %d\n", s );
607 #endif
608  /* Shift following runs up */
609  for ( j = nrun; j > i; j-- )
610  {
611  brun[j][0] = brun[j-1][0];
612  brun[j][1] = brun[j-1][1];
613  }
614  brun[i][0] = s;
615  nrun++;
616  }
617  else
618  {
619  i--; /* just add to preceding run */
620 #ifdef DEBUG
621  fprintf( stderr, "Adding to previous run\n" );
622 #endif
623  }
624 
625 #if defined(LOCC)&defined(vax)
626  s = upper - locc( (char *)row + s, upper - s + 1, color ) + 1;
627 #else
628  for ( ; s <= upper; s++ )
629  if ( row[s] == color )
630  break;
631 #endif
632  brun[i][1] = s - 1;
633 
634 #ifdef DEBUG
635  fprintf( stderr, "Ends at %d", s - 1 );
636 #endif
637  if ( s >= upper && i < nrun - 1 ) /* merge with following run */
638  {
639  brun[i][1] = brun[i+1][1];
640  /* move following runs back down */
641  for ( j = i + 2; j < nrun; j++ )
642  {
643  brun[j-1][0] = brun[j][0];
644  brun[j-1][1] = brun[j][1];
645  }
646  nrun--;
647 #ifdef DEBUG
648  fprintf( stderr, ", add to next run" );
649 #endif
650  }
651 #ifdef DEBUG
652  putc( '\n', stderr );
653 #endif
654  }
655 
656  /* Search in next space */
657  i++;
658  }
659 
660  return nrun;
661 }
662 
663 
664 /*****************************************************************
665  * TAG( rgb_to_bw )
666  *
667  * Perform the NTSC Y transform on RGB data to get B&W data.
668  * Inputs:
669  * red_row, green_row, blue_row: Given RGB pixel data.
670  * rowlen: Number of pixels in the rows.
671  * Outputs:
672  * bw_row: Output B&W data. May coincide with one of the
673  * inputs.
674  * Assumptions:
675  * [None]
676  * Algorithm:
677  * BW = .30*R + .59*G + .11*B
678  */
679 void
681 rle_pixel *red_row;
682 rle_pixel *green_row;
683 rle_pixel *blue_row;
684 rle_pixel *bw_row;
685 int rowlen;
686 {
687  register int x, bw;
688 
689  for (x=0; x<rowlen; x++)
690  {
691  /* 68000 won't store float > 127 into byte? */
692  /* HP compiler blows it */
693  bw = 0.5 + .30*red_row[x] + .59*green_row[x] + .11*blue_row[x];
694  bw_row[x] = bw;
695  }
696 }
697 
698 #ifdef LOCC
699 /*ARGSUSED*/
700 locc( p, l, c )
701 register char *p;
702 register int l;
703 register int c;
704 {
705  asm( "locc r9,r10,(r11)" );
706 #ifdef lint
707  c = (int) p; /* why doesn't ARGSUSED work? */
708  l = c;
709  return l; /* Needs return value, at least */
710 #endif
711 }
712 
713 /*ARGSUSED*/
714 skpc( p, l, c )
715 register char *p;
716 register int l;
717 register int c;
718 {
719  asm( "skpc r9,r10,(r11)" );
720 #ifdef lint
721  c = (int) p; /* why doesn't ARGSUSED work? */
722  l = c;
723  return l; /* Needs return value, at least */
724 #endif
725 }
726 #endif
#define DATA
Definition: rle_put.h:88
#define PutEof()
Definition: rle_put.h:83
#define SkipPixels(n, l, r)
Definition: rle_put.h:78
#define RUN6
Definition: rle_put.h:94
static int findruns(rle_pixel *row, int rowlen, int color, int nrun, short *brun)
Definition: rle_putrow.c:548
#define FALSE
Definition: giftorle.c:39
#define RUN1
Definition: rle_put.h:89
#define putrun(val, len, f)
Definition: rle_put.h:81
int * bg_color
Definition: rle.h:100
long int is_init
Definition: rle.h:131
#define SetColor(c)
Definition: rle_put.h:77
void rgb_to_bw(rle_pixel *red_row, rle_pixel *green_row, rle_pixel *blue_row, rle_pixel *bw_row, int rowlen)
Definition: rle_putrow.c:680
#define RUN2
Definition: rle_put.h:90
const char * cmd
Definition: rle.h:133
void rle_puteof(rle_hdr *the_hdr)
Definition: rle_putrow.c:474
void rle_putrow(rows, int rowlen, rle_hdr *the_hdr)
Definition: rle_putrow.c:96
enum rle_dispatch dispatch
Definition: rle.h:99
int img_num
Definition: rle.h:135
#define RLE_INIT_MAGIC
Definition: rle.h:79
#define FASTRUNS
Definition: rle_putrow.c:39
void DefaultBlockHook(rle_hdr *the_hdr)
Definition: rle_putrow.c:463
#define RUN4
Definition: rle_put.h:92
#define SkipBlankLines(n)
Definition: rle_put.h:76
#define TRUE
Definition: giftorle.c:38
#define NewScanLine(flag)
Definition: rle_put.h:79
void rle_skiprow(rle_hdr *the_hdr, int nrow)
Definition: rle_putrow.c:393
int background
Definition: rle.h:100
#define RLE_CLR_BIT(glob, bit)
Definition: rle.h:124
void rle_put_init(rle_hdr *the_hdr)
Definition: rle_putrow.c:415
unsigned char rle_pixel
Definition: rle.h:56
void rle_put_setup(rle_hdr *the_hdr)
Definition: rle_putrow.c:453
#define putdata(buf, len)
Definition: rle_put.h:80
#define RUN7
Definition: rle_put.h:95
int alpha
Definition: rle.h:100
#define RUN3
Definition: rle_put.h:91
const char * file_name
Definition: rle.h:134
#define Setup()
Definition: rle_put.h:75
#define PBRUN
Definition: rle_putrow.c:48
#define RUN5
Definition: rle_put.h:93
#define INRUN
Definition: rle_put.h:96
FILE * rle_file
Definition: rle.h:114
int ncolors
Definition: rle.h:100
#define RLE_BIT(glob, bit)
Definition: rle.h:126