home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / libs / gle / bmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-29  |  26.2 KB  |  1,203 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <math.h>
  7. #ifdef __TURBOC__
  8. #include <mem.h>
  9. #include <alloc.h>
  10. #else
  11. #define farcalloc calloc
  12. #define farcoreleft() (1200000)
  13. #endif
  14. #ifdef unix
  15. #define EXIT_FAILURE 1
  16. #endif
  17.  
  18. #include "bmp.h"
  19. #define CLIPSIZE ((long) PWIDTH* (long) sizeof(int)* (long) (b->ny+2))
  20. #define dbg if (gdebug==true)
  21.  
  22. #define false  0
  23. #define true !0
  24. extern int gdebug;
  25. int iscolor;
  26. extern int dev_noclip;
  27.  
  28. int row_show(char *s,Run *r,int y);
  29. int row_init(Run *r, int ny);
  30. int bmp_paintsort(int *p, int np);
  31. int row_free(Run *r, int ny);
  32. int row_grow(Run *r, int y, int v);
  33. int bmp_ink4(Bitmap *bb,unsigned int savem,int cindex);
  34. int bmp_ink16(Bitmap *bb,unsigned int newink[],int cindex);
  35. int bmpcheck(Bitmap *b);
  36.  
  37. /*
  38.     Filling routines to allow an arbitrary dimensioned
  39.     bitmap to be drawn into.
  40. */
  41.  
  42. /* General notes:
  43.     Color and pattern are the same thing, on a
  44.     color system the pattern array would have the
  45.     same depth as the bitmap itself.
  46.  
  47.     White bit = 1;
  48.     Black bit = 0;
  49. */
  50.  
  51.  
  52. /*    allocates the storage required.
  53.     initializes it
  54.     returns NULL if not enough memory
  55.     returns pointer to Bitmap structure
  56.     (ignoring depth at the moment)
  57.  
  58. */
  59.  
  60. /* FILE *fgle; */
  61. Bitmap *bmp_open(int xsize,int ysize,int depth, int bmp_compress)
  62. {
  63.     Bitmap *b;
  64.     int *p;
  65.     int i,j;
  66.  
  67. /*    fgle = fopen("test.gle","w");
  68.     fprintf(fgle,"size 15 15\n");
  69.     fprintf(fgle,"scale .3 .3 \n");
  70. */
  71.     b = (Bitmap *) calloc(1,sizeof(Bitmap));
  72.     if (b==NULL) bmp_die("No memory for Bitmap structure\n");
  73.     b->nx = xsize;
  74.     b->ny = ysize;
  75.         b->compress = bmp_compress;
  76.  
  77.     row_init(&b->clip,b->ny);
  78.     row_init(&b->paint,b->ny);
  79.     row_init(&b->horiz,b->ny);
  80.  
  81.     b->data = (char *(*)[]) calloc(1,sizeof(int *) * (ysize+3));
  82.     if (b->data == NULL) bmp_die("No memory for bitmap pointers \n");
  83.  
  84.     { long x;
  85.         if (iscolor) x=xsize/2;
  86.         else x=xsize/8;
  87.         x = x*ysize+80000L;
  88.         if (farcoreleft() < x) b->compress = true;
  89.     }
  90.     if (b->compress) printf("Compressing internal bitmap to save memory\n");
  91.  
  92.     if (b->compress==false) {
  93.       for (i=0; i<=ysize+1; i++) {
  94.         if (iscolor) {
  95.         if ( ((*b->data)[i] = calloc(1,xsize/2+2)) == NULL)
  96.             bmp_die("No memory for bitmap\n");
  97.         memset( (*b->data)[i], 255, xsize/2+2);
  98.         } else {
  99.         if ( ((*b->data)[i] = calloc(1,xsize/8+2)) == NULL)
  100.             bmp_die("No memory for bitmap\n");
  101.         memset( (*b->data)[i], 255, xsize/8+2);
  102.         }
  103.       }
  104.     }
  105.     b->painty1 = ysize;
  106.     b->lwidth = 1;
  107.     b->lstyle = 0x8000001e;
  108.     b->lstyle_mask = 0x80000000;
  109.         b->lstyle_dotlen = 1;
  110.         b->lstyle_dotpix = 0;
  111.     bmp_color(b,0);
  112. #ifdef __TURBOC__
  113. /*    printf("Free memory after bitmap allocated %ld \n",farcoreleft()); */
  114. #endif
  115.     return b;
  116. }
  117. row_init(Run *r, int ny)
  118. {
  119.     r->alloc = (unsigned char *) calloc(1,ny+3);
  120.     if (r->alloc == NULL) bmp_die("Not enough  memory for run counts \n");
  121.     r->used = (unsigned char *) calloc(1,ny+3);
  122.     if (r->used == NULL) bmp_die("Not enough  memory for run counts \n");
  123.     r->row = (typrow) calloc(sizeof(int *),ny+3);
  124.     if (r->row == NULL) bmp_die("Not enough  memory for run counts \n");
  125. }
  126. row_free(Run *r, int ny)
  127. {
  128.     int i,*rr;
  129.     for (i=0;i<=ny;i++) {
  130.         rr = (*r->row)[i];
  131.         if (rr!=NULL)  free(rr);
  132.     }
  133.     free(r->row);
  134.     free(r->used);
  135.     free(r->alloc);
  136. }
  137. int row_shrinkx(Run *r, int ny);
  138. int row_shrink(Bitmap *b);
  139. row_shrink(Bitmap *b)
  140. {
  141.     row_shrinkx(&b->paint,b->ny);
  142.     row_shrinkx(&b->horiz,b->ny);
  143. }
  144. row_shrinkx(Run *r, int ny)
  145. {
  146.     int i,*rr;
  147.     for (i=0;i<=ny;i++) {
  148.         rr = (*r->row)[i];
  149.         if (rr!=NULL)  free(rr);
  150.         (*r->row)[i] = NULL;
  151.         r->used[i] = 0;
  152.         r->alloc[i] = 0;
  153.     }
  154. }
  155. #define row_data(r,y)   ( (*r.row)[y] )
  156. #define row_used(r,y)   ( r.used[y] )
  157. #define row_setused(r,y,v) ( r.used[y] = v )
  158. row_grow(Run *r, int y, int v)
  159. {
  160.     int vv;
  161.     int *z;
  162.     v += r->used[y];
  163.     if (v<= r->alloc[y]) {
  164.         r->used[y] = v;
  165.         return;
  166.     }
  167.     vv = v;
  168.     if ((v&1)==1) vv++;
  169.     z = (*r->row)[y] ;
  170.     if (z==NULL) z = (int *) malloc(vv*sizeof(int));
  171.     else z = (int *) realloc((*r->row)[y],vv*sizeof(int));
  172. /*
  173.     if (z==NULL) z = malloc(vv*sizeof(int));
  174.     else {
  175.         z = malloc(vv*sizeof(int));
  176.         memcpy(z, (*r->row)[y] ,r->used[y]*sizeof(int));
  177.         free( (*r->row)[y] );
  178.     }
  179. */
  180.     (*r->row)[y] = z;
  181.         /* malloc(v);   */
  182.     if ((*r->row)[y] == NULL) bmp_die("Could not grow row count data \n");
  183.     r->alloc[y] = vv;
  184.     r->used[y] = v;
  185. }
  186.  
  187. /*    frees up all storage. */
  188. iffree(void *block)
  189. {
  190.     if (block!=NULL) free(block);
  191. }
  192. bmp_close(Bitmap *b)
  193. {
  194.     int i,j;
  195.     if (b==NULL) return;
  196.     for (i=0; i<=b->ny+2; i++) {
  197.         iffree((*b->data)[i]);
  198.     }
  199.     row_free(&b->paint,b->ny);
  200.     row_free(&b->clip,b->ny);
  201.     row_free(&b->horiz,b->ny);
  202. /*    fclose(fgle);  */
  203. }
  204.  
  205. /*
  206.     Draws line of current lwidth, lstyle,
  207.     and color/pattern
  208.  
  209.     Line is clipped using clip array.
  210. */
  211. #define sign(x) ((x) > 0 ? 1:  ((x) == 0 ? 0:  (-1)))
  212. bmp_line(Bitmap *b,int x1,int y1,int x2,int y2)
  213. {
  214.     int dx, dy, dxabs, dyabs, i, j, px, py, sdx, sdy;
  215.     register int x,y;
  216.     unsigned long int mask,pattern,lastpatbit;
  217.     int lwidth, dotlen,pix;
  218.  
  219.     lwidth = b->lwidth/2;
  220.     mask = b->lstyle_mask;
  221.     pattern = b->lstyle;
  222.     lastpatbit = 1l << (pattern & 0x1f);
  223.     dotlen = b->lstyle_dotlen;
  224.     pix = b->lstyle_dotpix;
  225.  
  226. /*     printf("lstyle %08lx, mask %08lx, dotlen %d, dotpix %d, lastpatbit %8lx pat= %lx \n",
  227.     pattern,mask,dotlen,pix,lastpatbit,pattern & 0x1f);
  228. */
  229.     if (bmp_clipline(b,&x1,&y1,&x2,&y2)) return;    /* clip to bitmap */
  230.     dx = x2 - x1;
  231.     dy = y2 - y1;
  232.     sdx = sign(dx);
  233.     sdy = sign(dy);
  234.     dxabs = abs(dx);
  235.     dyabs = abs(dy);
  236.     x = 0;
  237.     y = 0;
  238.     px = x1;
  239.     py = y1;
  240.  
  241.     if (dxabs >= dyabs) {
  242.        mask = (mask & lastpatbit) ? 0x80000000 : mask;
  243.        if (pattern & mask) {
  244.           for (j= -lwidth; j<=lwidth; j++)
  245.         bmp_pixel(b,px,py+j);
  246.        }
  247.        if ((++pix) >= dotlen)  {mask >>= 1; pix=0;}
  248.        for (i=0; i<dxabs; i++) {
  249.           mask = (mask & lastpatbit) ? 0x80000000 : mask;
  250.           y += dyabs;
  251.           if (y>=dxabs) {
  252.          y -= dxabs;
  253.          py += sdy;
  254.           }
  255.           px += sdx;
  256.           if (pattern & mask) {
  257.          for (j= -lwidth; j<=lwidth; j++)
  258.             bmp_pixel(b,px,py+j);
  259.           }
  260.           if ((++pix) >= dotlen)  {mask >>= 1; pix=0;}
  261.        }
  262.     } else {
  263.        mask = (mask & lastpatbit) ? 0x80000000 : mask;
  264.        if (pattern & mask) {
  265.           for (j= -lwidth; j<=lwidth; j++)
  266.          bmp_pixel(b,px+j,py);
  267.        }
  268.        if ((++pix) >= dotlen)  {mask >>= 1; pix=0;}
  269.        for (i=0; i<dyabs; i++) {
  270.           mask = (mask & lastpatbit) ? 0x80000000 : mask;
  271.           x += dxabs;
  272.           if (x>=dyabs) {
  273.          x -= dyabs;
  274.          px += sdx;
  275.           }
  276.           py += sdy;
  277.           if (pattern & mask) {
  278.          for (j= -lwidth; j<=lwidth; j++)
  279.             bmp_pixel(b,px+j,py);
  280.           }
  281.           if ((++pix) >= dotlen)  {mask >>= 1; pix=0;}
  282.        }
  283.     }
  284.  
  285.     b->lstyle_mask = mask;
  286.     b->lstyle_dotpix = pix;
  287. /*    printf("lstyle %08x, mask %08x, lastpatbix %08x, dotpix %d \n",
  288.            pattern, mask, lastpatbit, pix); */
  289.  
  290. }
  291.  
  292. /*
  293.     Apply clipping
  294.     Get bit from ink
  295.     Get row of bitmap
  296.     Place bit into row
  297. */
  298. static Bitmap *pr_lb;
  299. static int pr_ly;
  300. static char *pr_row;
  301. bmp_pixel(register Bitmap *b,register int x,register int y)
  302. {
  303.     static int i,spot;
  304.     int ry;
  305. /*    static char *row; */
  306.     unsigned char *k;
  307.  
  308.     if (b->clipping) if (bmp_invis(b,x,y)) return;
  309.     if (x> b->nx || x<0 || y>b->ny || y<0) return;
  310.     ry = y % 16;
  311.     if (pr_ly!=y || pr_lb!=b) {
  312.         pr_row = bmp_row(b,y);
  313.         pr_ly = y; pr_lb = b;
  314.     }
  315.  
  316.     k = (unsigned char *) &b->ink[ry%16][0];
  317.     spot = k[x%16];
  318.     if (iscolor) {
  319.         i = pr_row[x/2];
  320.         if (x % 2==0) {
  321.             i = (i & 0x0f) | (spot << 4);
  322.         } else {
  323.             i = (i & 0xf0) | spot;
  324.         }
  325.         pr_row[x/2] = i;
  326.         return;
  327.     }
  328.  
  329.  
  330.     if (k[x % 16] != 0) { /* a white spot */
  331.       *(pr_row + x/8) |= (1 << (x%8));
  332.     } else {
  333.       *(pr_row + x/8) &= (255-(1 << (x%8)));
  334.     }
  335. }
  336. bmp_paintrange(Bitmap *b,int y, register int x1, int x2)
  337. {
  338.     static int i,spot;
  339.     int ry;
  340. /*    static char *p;*/
  341.     unsigned char *k;
  342.  
  343. /* debugging stuff */
  344.     if (x1==-2 || x2==-2) {
  345.         printf("********Stuffed range on line %d, %d-->%d \n",y,x1,x2);
  346.         return;
  347.     }
  348.     dbg printf("Paint range %d, %d %d \n",y,x1,x2);
  349.  
  350. /* end debug */
  351. /*    printf("Paint range %d, %d %d \n",y,x1,x2);*/
  352.     ry = y % 16;
  353.     if (pr_ly!=y || pr_lb!=b) {
  354.         pr_row = bmp_row(b,y);
  355.         pr_ly = y; pr_lb = b;
  356.     }
  357.  
  358.  
  359.     k = (unsigned char  *) &b->ink[ry%16][0];
  360.  
  361.     if (iscolor) {
  362.       for (;x1<=x2;x1++) {
  363.         spot = k[x1%16];
  364.         i = pr_row[x1/2];
  365.         if (x1 % 2==0) {
  366.             i = (i & 0x0f) | (spot << 4);
  367.         } else {
  368.             i = (i & 0xf0) | spot;
  369.         }
  370.         pr_row[x1/2] = i;
  371.       }
  372.       return;
  373.     }
  374.  
  375.     for (;x1<=x2;x1++) {
  376.       if (k[x1 % 16] != 0) { /* a white spot */
  377.         *(pr_row + x1/8) |= (1 << (x1%8));
  378.       } else {
  379.         *(pr_row + x1/8) &= (255-(1 << (x1%8)));
  380.       }
  381.     }
  382. }
  383.  
  384. /* return true if pixel at that
  385.    location is clipped
  386. */
  387. int bmp_invis(Bitmap *b, int x, int y)
  388. {
  389.     int *c,nc,i;
  390.  
  391.     if (! b->clipping) return false; /* clipping os off */
  392.     c = row_data(b->clip,y);
  393.     if (*c==0) return true; /* clipping */
  394.     nc = row_used(b->clip,y);
  395.     for (i=0;i<nc-1;i+=2, c+=2) {
  396.          if ( (x>= *c) && (x<= *(c+1))) return false; /* is visible */
  397.     }
  398.     return true;
  399. }
  400.  
  401. /*
  402.     Adds x values at y crossings onto the paint[] array.
  403.     Doesn't add last crossing
  404.     Sets maxy,miny
  405.  
  406.     Special cases:
  407.  
  408. move
  409.     init lddy
  410.         sx,sy, x1,y1 ...
  411.  
  412.     * Change in sdy
  413.         put in double x value
  414.     * When end of line meets start of line.
  415.         remember start of line with bmp_pmove
  416.         remember start sdy
  417.         if sdy == enddy then don't put endx,endy
  418.         start new polygon.
  419.         (at fill check lines is closed, if not then close before fill)
  420.     * (WRONG) Start of Horizontal lines
  421.         put in start xvalue, (if not first line in path)
  422.     * Continued horizontal line
  423.         do nothing
  424.     * (WRONG) end of horizontal line
  425.         Put in last x(thisy) value
  426.  
  427.     * with horizontal lines or lines which have multiple x values
  428.     store the range of values into b->horiz[][] so they can
  429.     also be drawn in.  This gets the middle of an H or A or top
  430.     of a B drawn correctly if the bar is very thin.
  431. */
  432. bmp_pmove(Bitmap *b,int x1,int y1)
  433. {
  434.     bmp_clipline(b,&x1,&y1,&x1,&y1);    /* clip to bitmap */
  435.     /* fprintf(fgle,"amove %d %d \n",x1,y1); */
  436.     if (b->sx != b->x1 || b->sy != b->y1) {
  437.         printf("Closing path\n");
  438.         bmp_pline(b,b->sx,b->sy);
  439.     }
  440.     /* printf("pmove %d %d \n",x1,y1); */
  441.     b->sx = x1;    b->sy = y1;
  442.     b->x1 = x1;    b->y1 = y1;
  443.     b->sddy = -2;
  444.     b->lddy = -2;
  445. }
  446. bmp_pline(Bitmap *b,int x2,int y2)
  447. {
  448.     int dx, dy, dxabs, dyabs, i, j, px, py, sdx, sdy;
  449.     int endy,xwid;
  450.     register int x,y;
  451.     int x1=b->x1, y1=b->y1;    /* start of line */
  452.     int lddy=b->lddy;
  453.     int ddy,horizx;
  454.  
  455.     if (x1==x2 && y1==y2) return;    /* not going anywhere */
  456.  
  457.  
  458.  
  459.     if (bmp_clipline(b,&x1,&y1,&x2,&y2)) return;    /* clip to bitmap */
  460. /*    fprintf(fgle,"aline %d %d \n",x2,y2);
  461.     printf("CVector %d,%d  --- %d,%d \n",x1,y1,x2,y2);
  462. */
  463.     b->x1 = x2; b->y1 = y2;        /* remember end of line */
  464.     bmp_minmax(b,y1);
  465.     bmp_minmax(b,y2);     /* remember range of y paint values */
  466.  
  467.     dx = x2 - x1;
  468.     dy = y2 - y1;
  469.     xwid = dx/2;
  470.     sdx = sign(dx);
  471.     sdy = sign(dy);
  472.     dxabs = abs(dx);
  473.     dyabs = abs(dy);
  474.     x = 0;
  475.     y = 0;
  476.     px = x1;
  477.     py = y1;
  478.     endy = y2;
  479.  
  480.     ddy = sdy;
  481.     if (dy==0) ddy = 0;    /* ddy = -1, 0, 1 */
  482.     if (ddy==0) {    /* this is a horizontal line */
  483.         bmp_painth(b,x1,x2,y1);     /* paint the whole line */
  484.         goto endpline;
  485.     }
  486.     if (lddy == -ddy)  bmp_paintx(b,x1,y1); /* put in last endxy */
  487.     if (dxabs >= dyabs) {
  488.        horizx = px+sdx; /* start of first row */
  489.        for (i=0; i<dxabs; i++) {
  490.           y += dyabs;
  491.           if (y>=dxabs) {
  492.          y -= dxabs;
  493.          bmp_painth(b,horizx,px,py);     /* end of that row */
  494.          py += sdy;
  495.          horizx = px+sdx;     /* start of next row */
  496.          /* if (py==endy) break; */
  497.          bmp_paintx(b,px+sdx,py);
  498.           }
  499.           px += sdx;
  500.        }
  501.     } else {
  502.        for (i=0; i<dyabs; i++) {
  503.           x += dxabs;
  504.           if (x>=dyabs) {
  505.          x -= dyabs;
  506.          px += sdx;
  507.           }
  508.           py += sdy;
  509.           bmp_paintx(b,px,py);
  510.        }
  511.     }
  512.  
  513. endpline:
  514.     if (ddy!=0) {    /* remember last line if not horiz */
  515.         b->lddy = ddy;
  516.          if (lddy== -2) { /* first line */
  517.             b->sddy = ddy;
  518.             b->ssx = x1;
  519.             b->ssy = y1;
  520.             return;
  521.         }
  522.     }
  523.  
  524.     if (x2==b->sx && y2==b->sy) { /* path is closed */
  525.         if (b->sddy == -b->lddy) { /* direction changed */
  526.             bmp_paintx(b,b->ssx,b->ssy);
  527.         }
  528.     }
  529. }
  530.  
  531. bmp_minmax(Bitmap *b,int y)     /* remember range of y paint values */
  532. {
  533.     if (y<b->painty1) b->painty1 = y;
  534.     if (y>b->painty2) b->painty2 = y;
  535. }
  536.  
  537. /*
  538.     Adds x value onto paint[] range table
  539. */
  540. bmpcheck(Bitmap *b)
  541. {
  542.     int i,*p;
  543.  
  544.     for (i=0;i<16;i++) {
  545. /*        p = &(*b->paint)[i][0];
  546.         printf("P[%d] = %d %d %d %d \n",i,*p,*(p+1),*(p+2),*(p+3));
  547. */
  548.     }
  549. }
  550. bmp_paintx(Bitmap *b, int x, int y)
  551. {
  552.     int *c,nc,i,nrow;
  553.  
  554.  
  555.     i = 0;
  556.     row_grow(&b->paint,y,1);
  557.     c = row_data(b->paint,y);
  558.     c += row_used(b->paint,y) - 1;
  559.     *c = x;
  560.  
  561.     c = row_data(b->paint,y);
  562.     nc = row_used(b->paint,y);
  563. /*
  564.     printf("Paint [%d] x=%d , ",y,x);
  565.     for (i=0;i<nc;i++,c++) {
  566.         printf("%d ",*c);
  567.     }
  568.     printf("\n");
  569. */
  570. }
  571. row_show(char *s,Run *r,int y)
  572. {
  573.     int i,*c,nc;
  574.  
  575.     c = (*r->row)[y];
  576.     nc = r->used[y];
  577.     printf("show {%s} [%d] ",s,y);
  578.     for (i=0;i<nc;i++,c++) {
  579.         printf("%d ",*c);
  580.     }
  581.     printf("\n");
  582. }
  583. /*
  584.     This routine remembers the horizontal lines that
  585.     need to be drawn.
  586.  
  587.     They don't need sorting, and they can be amalgamated e.g.
  588.     They do need putting into ascending order when used.
  589.  
  590.         1 7, 5 9,  can become 1 9
  591. */
  592. showhy(Bitmap *b, int y)
  593. {
  594.     int *c,i;
  595.  
  596.     i = 0;
  597. /*    c = &(*b->horiz)[y][0];
  598.     c = (*b->horiz.row)[y];
  599.     printf("showy ");
  600.     for (;i < (*b->horiz.used)[y];c+=2 ,i+=2) {
  601.         printf("%d %d ",*c,*(c+1));
  602.     }
  603.     printf("\n");
  604. */
  605. }
  606. bmp_painth(Bitmap *b, int x1,int x2, int y)
  607. {
  608.     int *c,i,nc;
  609.  
  610.     /* printf("Addh, (%d) %d %d \n",y,x1,x2); */
  611.  
  612.     if (x1>x2) {i=x2; x2=x1; x1=i;}
  613.     i = 0;
  614.     c = row_data(b->horiz,y);
  615.     nc = row_used(b->horiz,y);
  616.     for (;i < nc-1 ;c+=2 ,i+=2) {
  617.         if (*c<=x1 && *(c+1)>=x1) {
  618.             c++;
  619.             if (*c < x2) *c = x2;
  620.             return;
  621.         }
  622.         if (*c<=x2 && *(c+1)>=x2) {
  623.             if (*c > x1) *c = x1;
  624.             return;
  625.         }
  626.         if (*c-1 == x2) { *c = x1; return;}
  627.         if (*(c+1)+1 == x1) { *(c+1) = x2; return;}
  628.     }
  629.     /* found an empty slot */
  630.  
  631.     row_grow(&b->horiz,y,2); /* make it two bigger */
  632.     c = row_data(b->horiz,y);
  633.     nc = row_used(b->horiz,y);
  634.     c += nc - 2;
  635.     *c = x1;
  636.     *(c+1) = x2;
  637. }
  638.  
  639. /* Clear the current path. */
  640. bmp_newpath(Bitmap *b)
  641. {
  642.     int i,j;
  643.     int *c;
  644.  
  645.     for (i=b->painty1; i<=b->painty2; i++) {
  646.         row_setused(b->paint,i,0);
  647.         row_setused(b->horiz,i,0);
  648.     }
  649.     b->painty1 = b->ny+2;
  650.     b->painty2 = 0;
  651.  
  652.     if (farcoreleft()<50000L) row_shrink(b);
  653. }
  654.  
  655. /*
  656.   from painty1 to painty2
  657.     sort x's and call bmp_paint(b,y,x1,x2);
  658. */
  659. bmp_paintsort(int *p, int np)
  660. {
  661.     int *pp = p;
  662.     int a,b,fixed,i;
  663.  
  664.     fixed = true;
  665.     for (;fixed;) {
  666.        fixed = false;
  667.        for (p = pp, i = 0; i<(np-1); i++, p++) {
  668.           if (*p > *(p+1)) {
  669.         a = *p;
  670.         *p = *(p+1);
  671.         *(p+1) = a;
  672.         fixed=true;
  673.           }
  674.        }
  675.     }
  676.     p = pp;
  677. /*
  678.     printf("(sort) ");
  679.     for (;*p!=-2;p++) printf("%d ",*p);
  680.     printf("\n");
  681. */}
  682.  
  683.  
  684. bmp_fill(Bitmap *b)
  685. {
  686.     int i,k,nrow,ncrow,j,x1,x2;
  687.     int *c,*p,np,nc;
  688.  
  689.     /* printf ("Fill, color is %d \n",b->ink[0][0]); */
  690.     if (b->sx != b->x1 || b->sy != b->y1) {
  691.         printf("Closing path\n");
  692.         bmp_pline(b,b->sx,b->sy);
  693.     }
  694.     for (i=b->painty1; i<=b->painty2; i++) {
  695.        p = row_data(b->paint,i);
  696.        np = row_used(b->paint,i);
  697.        bmp_paintsort(p,np);
  698.        for (j=0;j<np-1; j+=2, p+=2) {
  699.           c = row_data(b->clip,i);
  700.           nc = row_used(b->clip,i);
  701.           if (!b->clipping) bmp_paintrange(b,i,*p,*(p+1)); /* no clipping */
  702.           else {
  703.          for (k=0;k<nc-1; k+=2, c+=2) {
  704.            x1 = *p; x2 = *(p+1);
  705.            if (x1< *c) x1 = *c;
  706.            if (x2> *(c+1)) x2 = *(c+1);
  707.            if (x1<=x2) bmp_paintrange(b,i,x1,x2); /* clipped range */
  708.          }
  709.           }
  710.        }
  711.  
  712.        /* now paint the thin horizontal bits */
  713.        p = row_data(b->horiz,i);
  714.        np = row_used(b->horiz,i);
  715.        for (j=0;j<np-1; j+=2, p+=2) {
  716.           if (!b->clipping) bmp_paintrange(b,i,*p,*(p+1)); /* no clipping */
  717.           else {
  718.              c = row_data(b->clip,i);
  719.              nc = row_used(b->clip,i);
  720.              for (k=0;k<nc-1; k+=2, c+=2) {
  721.            x1 = *p; x2 = *(p+1);
  722.            if (x1< *c) x1 = *c;
  723.            if (x2> *(c+1)) x2 = *(c+1);
  724.            if (x1<=x2) bmp_paintrange(b,i,x1,x2); /* clipped range */
  725.          }
  726.           }
  727.        }
  728.        /* end horizontal bits */
  729.     }
  730. }
  731.  
  732.  
  733.  
  734. /* Coppies bitmap on while applying clip (not using ink[])
  735. */
  736. /*
  737. bmp_copy(Bitmap *b,char *bitmap,int nx,int ny)
  738. {
  739. }
  740. */
  741. /* Move paint array onto clip array.  */
  742. bmp_clip(Bitmap *b)
  743. {
  744.     int i;
  745.     int *c,*p,nc;
  746.  
  747.     if (dev_noclip) return;
  748.  
  749.     /* Sort the paint array before copying it */
  750.     for (i=0;i<b->ny; i++) {
  751.         c = row_data(b->paint,i);
  752.         bmp_paintsort(c,row_used(b->paint,i));
  753.     }
  754.  
  755.     /* Now simply copy it over */
  756.     for (i=0;i<b->ny; i++) {
  757.         p = row_data(b->paint,i);
  758.         nc = row_used(b->paint,i);
  759.  
  760.         if (nc>0) {
  761.             row_grow(&b->clip,i,nc);
  762.             c = row_data(b->clip,i);
  763.             memcpy(c,p,nc*sizeof(int));
  764.         }
  765.  
  766.     }
  767.  
  768.     b->clipping = true; /* remeber that clipping is on now */
  769. }
  770.  
  771. /* Clears the clipping array    */
  772. bmp_newclip(Bitmap *b)
  773. {
  774.     int i,j;
  775.     int *c;
  776.  
  777.     if (dev_noclip) return;
  778.     b->clipping = false;
  779.     for (i=0; i<=b->ny+1; i++) {
  780.         row_setused(b->clip,i,0);
  781.     }
  782. }
  783.  
  784. /*
  785.     Coppies clipping array and lastclip pointer into malloced area
  786.     and sets lastclip to point to this new malloced area.
  787. */
  788. bmp_saveclip(Bitmap *b)
  789. {
  790.     int *c;
  791.  
  792.     if (dev_noclip) return;
  793.     /* should save clipping region */
  794. }
  795.  
  796. bmp_restoreclip(Bitmap *b)
  797. {
  798.     int *c;
  799.     if (dev_noclip) return;
  800.     /* should restore from saved memory but I'm in a hurry */
  801.     b->clipping = false;
  802.  
  803. #ifdef __TURBOC__
  804.     row_shrinkx(&b->clip,b->ny);
  805. #endif
  806. }
  807.  
  808. /*    Sets ink based on a lookup table
  809.     255 = white, 0 = black
  810. */
  811. bmp_color(Bitmap *b,int colindex)
  812. {
  813.     int i,j;
  814.     for (i=0;i<16;i++)
  815.         for (j=0;j<16;j++)
  816.         b->ink[i][j] = colindex;
  817. }
  818.  
  819.  
  820. unsigned int grey_bits[] = {0x0000, 0x0200, 0x0802, 0x0a02,
  821.         0x5050, 0x5250, 0x5852, 0x5a52,
  822.         0xa5a5, 0xa7a5, 0xada7, 0xafa7,
  823.         0xf5f5, 0xf7f5, 0xfdf7, 0xfff7, 0xffff};
  824.  
  825.  
  826. static unsigned int pat_shade1[] = {
  827.     0xc000, 0x6000, 0x3000, 0x1800, 0xc00, 0x600, 0x300,
  828.     0x180, 0xc0, 0x60, 0x30, 0x18, 0xc, 0x6, 0x3, 0x8001 };
  829. static unsigned int pat_shade2[] = {
  830.     0xc018, 0x600c, 0x3006, 0x1803, 0x8c01, 0xc600, 0x6300, 0x3180,
  831.     0x18c0, 0xc60, 0x630, 0x318, 0x18c, 0xc6, 0x63, 0x8031 };
  832. static unsigned int pat_shade3[] = {
  833.     0xf078, 0x783c, 0x3c1e, 0x1e0f, 0x8f07, 0xc783, 0xe3c1, 0xf1e0,
  834.     0x78f0, 0x3c78, 0x1e3c, 0xf1e, 0x78f, 0x83c7, 0xc1e3, 0xe0f1 };
  835. static unsigned int pat_shade4[] = {
  836.     0x7e00, 0x3f00, 0x1f80, 0xfc0, 0x7e0, 0x3f0, 0x1f8, 0xfc,
  837.     0x7e, 0x3f, 0x801f, 0xc00f, 0xe007, 0xf003, 0xf801, 0xfc00 };
  838. static unsigned int pat_shade5[] = {
  839.     0x6006,   0x7ffe,0x6006,0x300c,0x1818,0xc30, 0x660, 0x3c0,
  840.     0x660, 0xc30, 0x1998,0x33cc,0x67e6,0x7ffe,0x6006,   0x6006   };
  841. static unsigned int pat_grid1[] = {
  842.     0xc003, 0x6006, 0x300c, 0x1818, 0xc30, 0x660, 0x3c0, 0x180,
  843.     0x3c0, 0x660, 0xc30, 0x1818, 0x300c, 0x6006, 0xc003, 0x8001 };
  844. static unsigned int pat_grid2[] = {
  845.     0xf00f, 0x781e, 0x3c3c, 0x1e78, 0xff0, 0xfe0, 0xfc0, 0xf80,
  846.     0xfc0, 0xfe0, 0xff0, 0x1e78, 0x3c3c, 0x781e, 0xf00f, 0xf00f };
  847. static unsigned int pat_grid3[] = {
  848.     0xffff, 0xffff, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0xffff,
  849.     0xffff, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0xffff, 0xffff};
  850. static unsigned int pat_grid4[] = {
  851.     0x303, 0x303, 0xcfc0, 0xcfc0, 0x3ff0, 0x3ff0, 0xfcc, 0xfcc,
  852.     0x303, 0x303, 0xcc0f, 0xcc0f, 0xf03f, 0xf03f, 0xc0cf, 0xc0cf };
  853. static unsigned int pat_grid5[] = {
  854.     0x300, 0x300, 0x300, 0x300, 0xcc0, 0xcc0, 0xf03f, 0xf03f,
  855.     0x3, 0x3, 0x3, 0x3, 0xc00c, 0xc00c, 0x3ff0, 0x3ff0 };
  856.  
  857.  
  858. #define NGREY 17
  859. bmp_setcolor(Bitmap *bb,int r, int g, int b, int ftyp)
  860. {
  861.     /* values between 0-255 */
  862.     unsigned int i,j,m,nib,k,n,xx,savenib,ix,iy,savem;
  863.     unsigned int *patt;
  864.     int cindex;
  865.     float f;
  866.  
  867.     f = (r*3+g*2+b)/(255*6.0);
  868.  
  869.     i = (1-f)*(NGREY-.8);
  870.     if (f<1 && i==0) i = 1;
  871.  
  872.     savem = grey_bits[i];
  873.  
  874.     /* Fill types,
  875.         2=pat_black, 3=pat_red, 4=pat_green,
  876.         5=pat_blue, 6=pat_yellow
  877.     */
  878.  
  879.     if (ftyp>1 && ftyp<7) {
  880.         cindex = 0;
  881.         if (ftyp==3) cindex = 1;
  882.         if (ftyp==4) cindex = 2;
  883.         if (ftyp==5) cindex = 4;
  884.         if (ftyp==6) cindex = 3;
  885.         if (!iscolor) cindex = 0;
  886.         if (g==0x0 && b==0x20) patt = pat_shade1;
  887.         if (g==0x0 && b==0x0c) patt = pat_shade1;
  888.         if (g==0x0 && b==0x10) patt = pat_shade2;
  889.         if (r==0x5 && b==0x20) patt = pat_shade3;
  890.         if (g==0x0 && b==0x40) patt = pat_shade4;
  891.         if (g==0x0 && b==0x60) patt = pat_shade5;
  892.         if (g==0x20 && b==0x20) patt = pat_grid1;
  893.         if (g==0xf && b==0xf)   patt = pat_grid1;
  894.         if (g==0x10 && b==0x10) patt = pat_grid2;
  895.         if (g==0x20 && b==0x20) patt = pat_grid3;
  896.         if (g==0x40 && b==0x40) patt = pat_grid4;
  897.         if (g==0x60 && b==0x60) patt = pat_grid5;
  898.         bmp_ink16(bb,patt,cindex);
  899.         return;
  900.     }
  901.     /* 0 = black, 1=red, green, blue, yellow, magenta, brown, ... white */
  902.  
  903.     if (r==g && g==b) {
  904.         bmp_ink4(bb,savem,0);
  905.         return;
  906.     }
  907.     if (iscolor) {
  908.         cindex = -1;
  909.         if (r>20 && g==0 && b==0) {cindex = 1; f=r;}
  910.         if (g>20 && r==0 && b==0) {cindex = 2; f=g;}
  911.         if (b>20 && g==0 && r==0) {cindex = 4; f=b;}
  912.         if (r>20 && g>20 && b==0) {cindex = 3; f=r;}
  913.         if (cindex>=0) {
  914.             f = f/255.0;
  915.             i = (f)*(NGREY-.8);
  916.             if (f<1 && i==(NGREY-1)) i = NGREY-2;
  917.             bmp_ink4(bb,grey_bits[i],cindex);
  918.             return;
  919.         }
  920.         if (r>150 && g<50 && b<50)  cindex = 1;
  921.         if (r<50 && g>150 && b<50)  cindex = 2;
  922.         if (r<50 && g<50 && b>150)  cindex = 4;
  923.         if (r>150 && g>150 && b<50)  cindex = 3;
  924.         if (b>50 && g>50 && r<18)    cindex = 6; /* CYAN */
  925.         if (r>50 && b>50 && g<20)  cindex = 5; /* Magenta */
  926.         if (cindex >= 0) {
  927.             bmp_color(bb,cindex);
  928.             return;
  929.         }
  930.     }
  931.     bmp_ink4(bb,savem,0);
  932. }
  933. bmp_ink4(Bitmap *bb,unsigned int savem,int cindex)
  934. {
  935.     /* values between 0-255 */
  936.     unsigned int i,j,m,nib,k,n,xx,savenib,ix,iy;
  937.     unsigned int *patt;
  938.     float f;
  939.  
  940.     for (ix=0; ix<16; ix+=4) {
  941.       for (iy=0; iy<16; iy+=4) {
  942.         m = savem;
  943.         for (j=0; j<4; j++) {
  944.           nib = m & 0xf;
  945.           for (k=0; k<4; k++) {
  946.             if (nib&1) bb->ink[ix+j][iy+k] = cindex;
  947.             else bb->ink[ix+j][iy+k]  = 15;
  948.             nib = nib >> 1;
  949.           }
  950.           m = m >> 4;
  951.         }
  952.       }
  953.     }
  954.  
  955. }
  956. bmp_ink16(Bitmap *bb,unsigned int newink[],int cindex)
  957. {
  958.     unsigned int m;
  959.     int i,ix,iy;
  960.  
  961.     for (iy=0; iy<16; iy++) {
  962.         m = newink[iy];
  963.         for (ix=15; ix>=0; ix--) {
  964.             if (m&1 == 1)  bb->ink[iy][ix] = cindex;
  965.             else bb->ink[iy][ix]  = 15;
  966. /*            printf("ix iy %d %d  %d\n",ix,iy,bb->ink[ix][iy]);
  967. */            m = m >> 1;
  968.         }
  969.     }
  970. }
  971. bmp_lwidth(Bitmap *b,int x)
  972. {
  973.     b->lwidth = x;
  974. }
  975.  
  976. bmp_lstyle(Bitmap *b,long n,int l)
  977.    /* n is a pattern, 01110001110;  l is len of one pattern dot in pixels */
  978. {
  979.     b->lstyle = n;
  980.     b->lstyle_mask = 0x80000000;
  981.     b->lstyle_dotlen = l;
  982.     b->lstyle_dotpix = 0;
  983. }
  984.  
  985. /* (depth must be 1, expands this into the pat[][] array,
  986.     each 1 becomes a 255)
  987. */
  988. /*
  989. bmp_pattern(Bitmap *b,char *pat,int nxbytes,int nybytes,int depth)
  990. {
  991. }
  992. */
  993. /* Returns pointer to a row of the bitmap */
  994.  
  995. unsigned char *bmp_expanded(Bitmap *b,int y);
  996. char *bmp_row(Bitmap *b,int y)
  997. {
  998.     pr_ly = -1;
  999.     if (b->compress) {
  1000.         return (char *) bmp_expanded(b,y);
  1001.     } else {
  1002.         return (*b->data)[y];
  1003.     }
  1004. }
  1005. /* this compression routine won't work with more than one 'Bitmap' as
  1006. it doesn't store it's data in Bitmap *b, like it should. */
  1007.  
  1008. unsigned char *bmp_expanded(Bitmap *b,int y)
  1009. {
  1010.     static unsigned char *bitrow,*bitc;
  1011.     static unsigned char *o,*bc,c,*lastv;
  1012.     static int lasty = -2;
  1013.     char *v;
  1014.     int nc,x,i,j,nxbyte;
  1015.     int totwid = 0;
  1016.  
  1017.  
  1018.     if (lasty==y) return bitrow;
  1019.     nxbyte = b->nx/8+1;
  1020.     if (iscolor) nxbyte = b->nx/2+2;
  1021.     if (bitrow==NULL) bitrow = (ucharp) calloc(1,nxbyte+3);
  1022.     if (bitc == NULL) bitc = (ucharp) calloc(1,nxbyte*2+3);
  1023.     if (bitrow==NULL || bitc==NULL) bmp_die("bitc allocation error\n");
  1024.     v = (*b->data)[y];
  1025.  
  1026.     if (lasty != -2) {
  1027.       o = bitc;
  1028. /*      if (lasty==296) {
  1029.          printf("Store [%d]",lasty);
  1030.           for (i=0;i<nxbyte;i++) printf("%x ",bitrow[i]);
  1031.           printf("\n");
  1032.       }
  1033. */
  1034.       for (x=0; x<nxbyte ; x++) {
  1035.         c = bitrow[x];
  1036.         nc = 1;
  1037.         for (;x<(nxbyte-1) && bitrow[x+1]==c && nc<250; x++) nc++;
  1038.         *o++ = nc;
  1039.         *o++ = c;
  1040.         totwid = totwid + 2;
  1041.       }
  1042.       if (totwid>nxbyte*2) printf("Total width %d nx=%d\n",totwid,nxbyte);
  1043.      *o++ = 0;
  1044.      *o++ = 0; /* nulls at end */
  1045.      nc = o-bitc+1;
  1046.  
  1047.  
  1048.      if (lastv!=NULL) lastv = (unsigned char *) realloc(lastv,nc);
  1049.       else lastv = (ucharp) malloc(nc);
  1050.       if (lastv==NULL) {
  1051.         printf("Failed to allocate enough memory for bitmap \n");
  1052.         abort();
  1053.       }
  1054.       memcpy(lastv,bitc,nc);
  1055.       (*b->data)[lasty] = (char *) lastv;
  1056.     }
  1057.     lasty = y;
  1058.     lastv = (ucharp) v;
  1059.  
  1060.     nc = 0;
  1061.     if (v==NULL) {
  1062.         memset(bitrow,255,nxbyte);
  1063.         return bitrow;
  1064.     }
  1065.  
  1066.     nc = 0;
  1067.     bc = (ucharp) v;
  1068.  
  1069.     for (i=0, o = bitrow; bc[i]!=0 ; i+=2) {
  1070.         for (j=0; j<bc[i]; j++) {
  1071.             *o++ = bc[i+1]; nc++;
  1072.             if (nc>nxbyte) {
  1073.  
  1074.             printf("ERR[%d] ",y);
  1075.             for (i=0;bc[i]!=0;i+=2) printf("%d,%x ",bc[i],bc[i+1]);
  1076.             printf("\n");
  1077.  
  1078.  
  1079.                 printf("gone past end [%d] %d %d \n",y,nxbyte,nc);
  1080.                 return bitrow;
  1081.             }
  1082.         }
  1083.     }
  1084. /*
  1085.     if (y==296) {
  1086.         printf("EXP[%d] ",y);   for (i=0;i<10;i++) printf("%d ",bitrow[i]);
  1087.         printf("\n");
  1088.     }
  1089. */
  1090.     return bitrow;
  1091. }
  1092. bmp_die(char *s)
  1093. {
  1094.     printf("%s",s);
  1095.     exit(EXIT_FAILURE);
  1096. }
  1097.  
  1098. bmp_pbezier(Bitmap *bb,int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
  1099. {
  1100.     float ax,bx,cx,ay,by,cy,xxx,yyy,t,nstep;
  1101.     int dist,i;
  1102.  
  1103.  
  1104.  
  1105.     dbg printf("pbezier, %d %d   %d %d   %d %d   %d %d \n",x0,y0,x1,y1,x2,y2,x3,y3);
  1106.     dist = abs(x3-x0) + abs(y3-y0);
  1107.     nstep = 20;
  1108.     if (dist<30) nstep = 10;
  1109.     if (dist<10) nstep = 5;
  1110.     if (dist<5) nstep = 3;
  1111.     if (dist<=2) {
  1112.         bmp_pline(bb,x3,y3);
  1113.         return;
  1114.     }
  1115.     cx = (x1-x0)*3;
  1116.     bx = (x2-x1)*3-cx;
  1117.     ax = x3-x0-cx-bx;
  1118.     cy = (y1-y0)*3;
  1119.     by = (y2-y1)*3-cy;
  1120.     ay = y3-y0-cy-by;
  1121.     for (i=0;i<=nstep;i++) {
  1122.         t = (float) i/nstep;
  1123.         xxx = ax*pow(t,3.0) + bx*t*t + cx*t + x0;
  1124.         yyy = ay*pow(t,3.0) + by*t*t + cy*t + y0;
  1125.         bmp_pline(bb,(int) xxx,(int) yyy);
  1126.     }
  1127. }
  1128. bmp_bezier(Bitmap *bb,int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
  1129. {
  1130.     float ax,bx,cx,ay,by,cy,xxx,yyy,t,nstep,xx,yy;
  1131.     int dist,i;
  1132.  
  1133.     dist = abs(x3-x0) + abs(y3-y0);
  1134.     nstep = 20;
  1135.     if (dist<30) nstep = 10;
  1136.     if (dist<10) nstep = 5;
  1137.     if (dist<5) nstep = 3;
  1138.     if (dist<=2) {
  1139.         bmp_line(bb,x0,y0,x3,y3);
  1140.         return;
  1141.     }
  1142.     cx = (x1-x0)*3;
  1143.     bx = (x2-x1)*3-cx;
  1144.     ax = x3-x0-cx-bx;
  1145.     cy = (y1-y0)*3;
  1146.     by = (y2-y1)*3-cy;
  1147.     ay = y3-y0-cy-by;
  1148.     xx = x0; yy = y0;
  1149.     for (i=0;i<=nstep;i++) {
  1150.         t = (float) i/nstep;
  1151.         xxx = ax*pow(t,3.0) + bx*t*t + cx*t + x0;
  1152.         yyy = ay*pow(t,3.0) + by*t*t + cy*t + y0;
  1153.         bmp_line(bb,(int) xx,(int) yy, (int) xxx, (int) yyy);
  1154.         xx = xxx; yy = yyy;
  1155.     }
  1156. }
  1157.  
  1158. #define OUTCODES_CSD( X, Y, OUTCODE )           \
  1159.     ( OUTCODE ) = 0;                            \
  1160.     if ((Y) >= b->ny )          OUTCODE |= 1; \
  1161.     else  if ((Y) < 0 )    OUTCODE |= 2; \
  1162.     if ((X) >= b->nx  )          OUTCODE |= 4; \
  1163.     else  if ((X) < 0 )    OUTCODE |= 8;
  1164.  
  1165. int bmp_clipline(Bitmap *b,int *x1, int *y1, int *x2, int *y2)
  1166. {
  1167.     int outcode1,outcode2;
  1168.  
  1169.     OUTCODES_CSD( *x2, *y2, outcode2 );
  1170.     OUTCODES_CSD( *x1, *y1, outcode1 );
  1171.  
  1172.         if (outcode1 & outcode2)         /* trivial reject */
  1173.          return true; /* throw line away */
  1174.     if (!(outcode2 | outcode1))    /* trivial accept */
  1175.          return false;
  1176.  
  1177.     doclip(0,b->nx-1,x1);
  1178.     doclip(0,b->nx-1,x2);
  1179.     doclip(0,b->ny-1,y1);
  1180.     doclip(0,b->ny-1,y2);
  1181.     return false;
  1182. }
  1183. doclip(int min, int max, int *v)
  1184. {
  1185.     if (*v < min) *v = min;
  1186.     if (*v > max) *v = max;
  1187. }
  1188.  
  1189. showfree()
  1190. {
  1191. #ifdef __TURBOC__
  1192.    struct farheapinfo hi;
  1193.    long total=0;
  1194.  
  1195.    hi.ptr = NULL;
  1196.    while( farheapwalk( &hi ) == _HEAPOK ) {
  1197.     if (!hi.in_use) total += hi.size;
  1198.    }
  1199.    printf("Total mem free %ld \n",total);
  1200. #endif
  1201. }
  1202.  
  1203.