home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / gimpressionist / ppmtool.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-22  |  16.4 KB  |  690 lines

  1. #ifdef HAVE_CONFIG_H
  2. #include "config.h"
  3. #else
  4. #define HAVE_DIRENT_H
  5. #define HAVE_UNISTD_H
  6. #endif
  7. #include <stdio.h>
  8. #ifdef HAVE_UNISTD_H
  9. #include <unistd.h>
  10. #endif
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <math.h>
  14. #include "ppmtool.h"
  15. #include "gimpressionist.h"
  16.  
  17. int readline(FILE *f, char *buffer, int len)
  18. {
  19. again:
  20.   if(!fgets(buffer, len, f))
  21.     return -1;
  22.   if(*buffer == '#') {
  23.     goto again;
  24.   }
  25.   while(strlen(buffer) && buffer[strlen(buffer)-1] <= ' ')
  26.     buffer[strlen(buffer)-1] = '\0';
  27.   return 0;
  28. }
  29.  
  30. void fatal(char *s)
  31. {
  32.   fprintf(stderr, "%s\n", s);
  33.   exit(1);
  34. }
  35.  
  36. void killppm(struct ppm *p)
  37. {
  38.   free(p->col);
  39.   p->col = NULL;
  40.   p->height = p->width = 0;
  41. }
  42.  
  43.  
  44. void newppm(struct ppm *p, int xs, int ys)
  45. {
  46.   int x;
  47.   guchar bgcol[3] = {0,0,0};
  48.  
  49.   if(xs < 1)
  50.     xs = 1;
  51.   if(ys < 1)
  52.     ys = 1;
  53.  
  54.   p->width = xs;
  55.   p->height = ys;
  56.   p->col = g_malloc(xs * 3 * ys);
  57.   for(x = 0; x < xs * 3 * ys; x += 3) {
  58.     p->col[x+0] = bgcol[0];
  59.     p->col[x+1] = bgcol[1];
  60.     p->col[x+2] = bgcol[2];
  61.   }
  62. }
  63.  
  64. void getrgb(struct ppm *s, float xo, float yo, guchar *d)
  65. {
  66.   float ix, iy;
  67.   int x1, x2, y1, y2;
  68.   float x1y1, x2y1, x1y2, x2y2;
  69.   float r, g, b;
  70.   int bail = 0;
  71.   int rowstride = s->width * 3;
  72.  
  73.   if(xo < 0.0) bail=1;
  74.   else if(xo >= s->width-1) { xo = s->width-1; } /* bail=1; */
  75.   if(yo < 0.0) bail=1;
  76.   else if(yo >= s->height-1) { yo= s->height-1; } /* bail=1; */
  77.  
  78.   if(bail) {
  79.     d[0] = d[1] = d[2] = 0;
  80.     return;
  81.   }
  82.  
  83.   ix = (int)xo;
  84.   iy = (int)yo;
  85.  
  86.   /*
  87.   x1 = wrap(ix, s->width);
  88.   x2 = wrap(ix+1, s->width);
  89.   y1 = wrap(iy, s->height);
  90.   y2 = wrap(iy+1, s->height);
  91.   */
  92.   x1 = ix; x2 = ix + 1;
  93.   y1 = iy; y2 = iy + 1;
  94.  
  95.   /* printf("x1=%d y1=%d x2=%d y2=%d\n",x1,y1,x2,y2); */
  96.  
  97.   x1y1 = (1.0-xo+ix)*(1.0-yo+iy);
  98.   x2y1 = (xo-ix)*(1.0-yo+iy);
  99.   x1y2 = (1.0-xo+ix)*(yo-iy);
  100.   x2y2 = (xo-ix)*(yo-iy);
  101.  
  102.   r = s->col[y1*rowstride + x1*3 + 0] * x1y1;
  103.   g = s->col[y1*rowstride + x1*3 + 1] * x1y1;
  104.   b = s->col[y1*rowstride + x1*3 + 2] * x1y1;
  105.  
  106.   if(x2y1 > 0.0) r += s->col[y1*rowstride + x2*3 + 0] * x2y1;
  107.   if(x2y1 > 0.0) g += s->col[y1*rowstride + x2*3 + 1] * x2y1;
  108.   if(x2y1 > 0.0) b += s->col[y1*rowstride + x2*3 + 2] * x2y1;
  109.  
  110.   if(x1y2 > 0.0) r += s->col[y2*rowstride + x1*3 + 0] * x1y2;
  111.   if(x1y2 > 0.0) g += s->col[y2*rowstride + x1*3 + 1] * x1y2;
  112.   if(x1y2 > 0.0) b += s->col[y2*rowstride + x1*3 + 2] * x1y2;
  113.  
  114.   if(x2y2 > 0.0) r += s->col[y2*rowstride + x2*3 + 0] * x2y2;
  115.   if(x2y2 > 0.0) g += s->col[y2*rowstride + x2*3 + 1] * x2y2;
  116.   if(x2y2 > 0.0) b += s->col[y2*rowstride + x2*3 + 2] * x2y2;
  117.  
  118.   d[0] = r;
  119.   d[1] = g;
  120.   d[2] = b;
  121. }
  122.  
  123.  
  124. void resize(struct ppm *p, int nx, int ny)
  125. {
  126.   int x, y;
  127.   float xs = p->width/(float)nx;
  128.   float ys = p->height/(float)ny;
  129.   struct ppm tmp = {0,0,NULL};
  130.  
  131.   newppm(&tmp, nx, ny);
  132.   for(y = 0; y < ny; y++) {
  133.     guchar *row = tmp.col + y * tmp.width * 3;
  134.     for(x = 0; x < nx; x++) {
  135.       getrgb(p, x*xs, y*ys, &row[x*3]);
  136.     }
  137.   }
  138.   killppm(p);
  139.   p->width = tmp.width;
  140.   p->height = tmp.height;
  141.   p->col = tmp.col;
  142. }
  143.  
  144. void rescale(struct ppm *p, double sc)
  145. {
  146.   resize(p, p->width * sc, p->height * sc);
  147. }
  148.  
  149. void resize_fast(struct ppm *p, int nx, int ny)
  150. {
  151.   int x, y;
  152.   float xs = p->width/(float)nx;
  153.   float ys = p->height/(float)ny;
  154.   struct ppm tmp = {0,0,NULL};
  155.  
  156.   newppm(&tmp, nx, ny);
  157.   for(y = 0; y < ny; y++) {
  158.     for(x = 0; x < nx; x++) {
  159.       int rx = x*xs, ry = y*ys;
  160.       memcpy(&tmp.col[y*tmp.width*3+x*3], &p->col[ry*p->width*3+rx*3], 3);
  161.     }
  162.   }
  163.   killppm(p);
  164.   p->width = tmp.width;
  165.   p->height = tmp.height;
  166.   p->col = tmp.col;
  167. }
  168.  
  169.  
  170. struct _BrushHeader
  171. {
  172.   unsigned int   header_size; /*  header_size = sz_BrushHeader + brush name  */
  173.   unsigned int   version;     /*  brush file version #  */
  174.   unsigned int   width;       /*  width of brush  */
  175.   unsigned int   height;      /*  height of brush  */
  176.   unsigned int   bytes;       /*  depth of brush in bytes--always 1 */
  177.   unsigned int   magic_number;/*  GIMP brush magic number  */
  178.   unsigned int   spacing;     /*  brush spacing  */
  179. };
  180.  
  181. void msb2lsb(unsigned int *i)
  182. {
  183.   guchar *p = (guchar *)i, c;
  184.   c = p[1]; p[1] = p[2]; p[2] = c;
  185.   c = p[0]; p[0] = p[3]; p[3] = c;
  186. }
  187.  
  188. void loadgbr(char *fn, struct ppm *p)
  189. {
  190.   FILE *f;
  191.   struct _BrushHeader hdr;
  192.   guchar *ptr;
  193.   int x, y;
  194.  
  195.   f = fopen(fn, "rb");
  196.   if(!f) {
  197.     ptr = findfile(fn);
  198.     f = fopen(ptr, "rb");
  199.   }
  200.  
  201.   if(p->col) killppm(p);
  202.  
  203.   if(!f) {
  204.     fprintf(stderr, "loadgbr: Unable to open file \"%s\"!\n", fn);
  205.     newppm(p, 10,10);
  206.     return;
  207.   }
  208.  
  209.   fread(&hdr, 1, sizeof(struct _BrushHeader), f);
  210.  
  211.   for(x = 0; x < 7; x++)
  212.     msb2lsb(&((unsigned int *)&hdr)[x]);
  213.  
  214.   newppm(p, hdr.width, hdr.height);
  215.  
  216.   ptr = g_malloc(hdr.width);
  217.   fseek(f, hdr.header_size, SEEK_SET);
  218.   for(y = 0; y < p->height; y++) {
  219.     fread(ptr, p->width, 1, f);
  220.     for(x = 0; x < p->width; x++) {
  221.       int k = y*p->width*3 + x*3;
  222.       p->col[k+0] = p->col[k+1] = p->col[k+2] = ptr[x];
  223.     }
  224.   }
  225.   fclose(f);
  226.   free(ptr);
  227. }
  228.  
  229. void loadppm(char *fn, struct ppm *p)
  230. {
  231.   char line[200];
  232.   int y, pgm = 0;
  233.   FILE *f;
  234.  
  235.   if(!strcmp(&fn[strlen(fn)-4], ".gbr")) {
  236.     loadgbr(fn, p);
  237.     return;
  238.   }
  239.  
  240.   f = fopen(fn, "rb");
  241.   if(!f) f = fopen(findfile(fn), "rb");
  242.  
  243.   if(p->col) killppm(p);
  244.  
  245.   if(!f) {
  246.     fprintf(stderr, "loadppm: Unable to open file \"%s\"!\n", fn);
  247.     newppm(p, 10,10);
  248.     return;
  249.     /* fatal("Aborting!"); */
  250.   }
  251.  
  252.   readline(f, line, 200);
  253.   if(strcmp(line, "P6")) {
  254.     if(strcmp(line, "P5")) {
  255.       fclose(f);
  256.       printf( "loadppm: File \"%s\" not PPM/PGM? (line=\"%s\")%c\n", fn, line, 7);
  257.       newppm(p, 10,10);
  258.       return;
  259.       /* fatal("Aborting!"); */
  260.     }
  261.     pgm = 1;
  262.   }
  263.   readline(f, line, 200);
  264.   p->width = atoi(line);
  265.   p->height = atoi(strchr(line, ' ')+1);
  266.   readline(f, line, 200);
  267.   if(strcmp(line, "255")) {
  268.     printf ("loadppm: File \"%s\" not valid PPM/PGM? (line=\"%s\")%c\n", fn, line, 7);
  269.     newppm(p, 10,10);
  270.     return;
  271.     /* fatal("Aborting!"); */
  272.   }
  273.   p->col = g_malloc(p->height * p->width * 3);
  274.  
  275.   if(!pgm) {
  276.     fread(p->col, p->height * 3 * p->width, 1, f);
  277.   } else {
  278.     guchar *tmpcol = g_malloc(p->width * p->height);
  279.     fread(tmpcol, p->height * p->width, 1, f);
  280.     for(y = 0; y < p->width * p->height * 3; y++) {
  281.       p->col[y] = tmpcol[y/3];
  282.     }
  283.   }
  284.   fclose(f);
  285. }
  286.  
  287. void fill(struct ppm *p, guchar *c)
  288. {
  289.   int x, y;
  290.  
  291.   if((c[0] == c[1]) && (c[0] == c[2])) {
  292.     guchar col = c[0];
  293.     for(y = 0; y < p->height; y++) {
  294.       memset(p->col + y*p->width*3, col, p->width*3);
  295.     }
  296.   } else {
  297.     for(y = 0; y < p->height; y++) {
  298.       guchar *row = p->col + y * p->width * 3;
  299.       for(x = 0; x < p->width; x++) {
  300.     int k = x * 3;
  301.     row[k+0] = c[0];
  302.     row[k+1] = c[1];
  303.     row[k+2] = c[2];
  304.       }
  305.     }
  306.   }
  307. }
  308.  
  309. void copyppm(struct ppm *s, struct ppm *p)
  310. {
  311.   if(p->col)
  312.     killppm(p);
  313.   p->width = s->width;
  314.   p->height = s->height;
  315.   p->col = g_malloc(p->width * 3 * p->height);
  316.   memcpy(p->col, s->col, p->width * 3 * p->height);
  317. }
  318.  
  319. void freerotate(struct ppm *p, double amount)
  320. {
  321.   int x, y;
  322.   double nx, ny;
  323.   double R, a;
  324.   struct ppm tmp = {0,0,NULL};
  325.   double f = amount*G_PI*2/360.0;
  326.   int rowstride = p->width * 3;
  327.  
  328.   a = p->width/(float)p->height;
  329.   R = p->width<p->height?p->width/2:p->height/2;
  330.  
  331.   newppm(&tmp, p->width, p->height);
  332.   for(y = 0; y < p->height; y++) {
  333.     for(x = 0; x < p->width; x++) {
  334.       double r, d;
  335.       nx = fabs(x-p->width/2.0);
  336.       ny = fabs(y-p->height/2.0);
  337.       r = sqrt(nx*nx + ny*ny);
  338.  
  339.       d = atan2((y-p->height/2.0),(x-p->width/2.0));
  340.  
  341.       nx = (p->width/2.0 + cos(d-f) * r);
  342.       ny = (p->height/2.0 + sin(d-f) * r);
  343.       getrgb(p, nx, ny, tmp.col + y*rowstride+x*3);
  344.     }
  345.   }
  346.   killppm(p);
  347.   p->width = tmp.width;
  348.   p->height = tmp.height;
  349.   p->col = tmp.col;
  350. }
  351.  
  352. void crop(struct ppm *p, int lx, int ly, int hx, int hy)
  353. {
  354.   struct ppm tmp = {0,0,NULL};
  355.   int x, y;
  356.   int srowstride = p->width * 3;
  357.   int drowstride;
  358.  
  359.   newppm(&tmp, hx-lx, hy-ly);
  360.   drowstride = tmp.width * 3;
  361.   for(y = ly; y < hy; y++)
  362.     for(x = lx; x < hx; x++)
  363.       memcpy(&tmp.col[(y-ly)*drowstride+(x-lx)*3],
  364.          &p->col[y*srowstride+x*3], 3);
  365.   killppm(p);
  366.   p->col = tmp.col;
  367.   p->width = tmp.width;
  368.   p->height = tmp.height;
  369. }
  370.  
  371. void autocrop(struct ppm *p, int room)
  372. {
  373.   int lx = 0, hx = p->width, ly = 0, hy = p->height;
  374.   int x, y, n = 0;
  375.   guchar tc[3];
  376.   struct ppm tmp = {0,0,NULL};
  377.   int rowstride = p->width * 3;
  378.   int drowstride;
  379.  
  380.   /* upper */
  381.   memcpy(&tc, p->col, 3);
  382.   for(y = 0; y < p->height; y++) {
  383.     n = 0;
  384.     for(x = 0; x < p->width; x++) {
  385.       if(memcmp(&tc, &p->col[y*rowstride+x*3], 3)) { n++; break; }
  386.     }
  387.     if(n) break;
  388.   }
  389.   if(n) ly = y;
  390.   /* printf("ly = %d\n", ly); */
  391.  
  392.   /* lower */
  393.   memcpy(&tc, &p->col[(p->height-1)*rowstride], 3);
  394.   for(y = p->height-1; y >= 0; y--) {
  395.     n = 0;
  396.     for(x = 0; x < p->width; x++) {
  397.       if(memcmp(&tc, &p->col[y*rowstride+x*3], 3)) { n++; break; }
  398.     }
  399.     if(n) break;
  400.   }
  401.   if(n) hy = y+1;
  402.   if(hy >= p->height) hy = p->height - 1;
  403.   /* printf("hy = %d\n", hy); */
  404.  
  405.   /* left */
  406.   memcpy(&tc, &p->col[ly*rowstride], 3);
  407.   for(x = 0; x < p->width; x++) {
  408.     n = 0;
  409.     for(y = ly; y <= hy && y < p->height; y++) {
  410.       if(memcmp(&tc, &p->col[y*rowstride+x*3], 3)) { n++; break; }
  411.     }
  412.     if(n) break;
  413.   }
  414.   if(n) lx = x;
  415.   /* printf("lx = %d\n", lx); */
  416.  
  417.   /* right */
  418.   memcpy(&tc, &p->col[ly*rowstride + (p->width-1)*3], 3);
  419.   for(x = p->width-1; x >= 0; x--) {
  420.     n = 0;
  421.     for(y = ly; y <= hy; y++) {
  422.       if(memcmp(&tc, &p->col[y*rowstride+x*3], 3)) { n++; break; }
  423.     }
  424.     if(n) break;
  425.   }
  426.   if(n) hx = x+1;
  427.   /* printf("hx = %d\n", hx); */
  428.  
  429.   lx -= room; if(lx<0) lx = 0;
  430.   ly -= room; if(ly<0) ly = 0;
  431.   hx += room; if(hx>=p->width) hx = p->width-1;
  432.   hy += room; if(hy>=p->height) hy = p->height-1;
  433.  
  434.   newppm(&tmp, hx-lx, hy-ly);
  435.   drowstride = tmp.width * 3;
  436.   for(y = ly; y < hy; y++)
  437.     for(x = lx; x < hx; x++)
  438.       memcpy(&tmp.col[(y-ly)*drowstride+(x-lx)*3],
  439.          &p->col[y*rowstride+x*3], 3);
  440.   killppm(p);
  441.   p->col = tmp.col;
  442.   p->width = tmp.width;
  443.   p->height = tmp.height;
  444. }
  445.  
  446. void pad(struct ppm *p, int left,int right, int top, int bottom, guchar *bg)
  447. {
  448.   int x, y;
  449.   struct ppm tmp = {0,0,NULL};
  450.  
  451.   newppm(&tmp, p->width+left+right, p->height+top+bottom);
  452.   for(y = 0; y < tmp.height; y++) {
  453.     guchar *row, *srcrow;
  454.     row = tmp.col + y * tmp.width * 3;
  455.     if((y < top) || (y >= tmp.height-bottom)) {
  456.       for(x = 0; x < tmp.width; x++) {
  457.     int k = x * 3;
  458.         row[k+0] = bg[0];
  459.         row[k+1] = bg[1];
  460.         row[k+2] = bg[2];
  461.       }
  462.       continue;
  463.     }
  464.     srcrow = p->col + (y-top) * p->width * 3;
  465.     for(x = 0; x < left; x++) {
  466.       int k = x * 3;
  467.       row[k+0] = bg[0];
  468.       row[k+1] = bg[1];
  469.       row[k+2] = bg[2];
  470.     }
  471.     for(; x < tmp.width-right; x++) {
  472.       int k = y * tmp.width * 3 + x * 3;
  473.       tmp.col[k+0] = srcrow[(x-left)*3+0];
  474.       tmp.col[k+1] = srcrow[(x-left)*3+1];
  475.       tmp.col[k+2] = srcrow[(x-left)*3+2];
  476.     }
  477.     for(; x < tmp.width; x++) {
  478.       int k = x * 3;
  479.       row[k+0] = bg[0];
  480.       row[k+1] = bg[1];
  481.       row[k+2] = bg[2];
  482.     }
  483.   }
  484.   killppm(p);
  485.   p->width = tmp.width;
  486.   p->height = tmp.height;
  487.   p->col = tmp.col;
  488. }
  489.  
  490. void saveppm(struct ppm *p, char *fn)
  491. {
  492.   FILE *f = fopen(fn, "wb");
  493.   fprintf(f, "P6\n%d %d\n255\n", p->width, p->height);
  494.   fwrite(p->col, p->width * 3 * p->height, 1, f);
  495.   fclose(f);
  496. }
  497.  
  498. void edgepad(struct ppm *p, int left,int right, int top, int bottom)
  499. {
  500.   int x,y;
  501.   struct ppm tmp = {0,0,NULL};
  502.   guchar testcol[3] = {0,255,0};
  503.   int srowstride, drowstride;
  504.  
  505.   newppm(&tmp, p->width+left+right, p->height+top+bottom);
  506.   fill(&tmp, testcol);
  507.  
  508.   srowstride = p->width * 3;
  509.   drowstride = tmp.width * 3;
  510.   
  511.   for(y = 0; y < top; y++) {
  512.     memcpy(&tmp.col[y*drowstride+left*3], p->col, srowstride);
  513.   }
  514.   for(; y-top < p->height; y++) {
  515.     memcpy(&tmp.col[y*drowstride+left*3], p->col + (y-top)*srowstride, srowstride);
  516.   }
  517.   for(; y < tmp.height; y++) {
  518.     memcpy(&tmp.col[y*drowstride+left*3], p->col + (p->height-1)*srowstride, srowstride);
  519.   }
  520.   for(y = 0; y < tmp.height; y++) {
  521.     guchar *col, *tmprow;
  522.  
  523.     tmprow = tmp.col + y*drowstride;
  524.     col = tmp.col + y*drowstride + left*3;
  525.  
  526.     for(x = 0; x < left; x++) {
  527.       memcpy(&tmprow[x*3], col, 3);
  528.     }
  529.     col = tmp.col + y*drowstride + (tmp.width-right-1)*3;
  530.     for(x = 0; x < right; x++) {
  531.       memcpy(&tmprow[(x+tmp.width-right-1)*3], col, 3);
  532.     }
  533.   }
  534.   killppm(p);
  535.   p->width = tmp.width;
  536.   p->height = tmp.height;
  537.   p->col = tmp.col;
  538. }
  539.  
  540. void ppmgamma(struct ppm *p, float e, int r, int g, int b)
  541. {
  542.   int x, l = p->width * 3 * p->height;
  543.   guchar xlat[256], *pix;
  544.   if(e > 0.0) for(x = 0; x < 256; x++) {
  545.     xlat[x] = pow((x/255.0),(1.0/e))*255.0;
  546.   } else if(e < 0.0) for(x = 0; x < 256; x++) {
  547.     xlat[255-x] = pow((x/255.0),(-1.0/e))*255.0;
  548.   } else for(x = 0; x < 256; x++) { xlat[x] = 0; }
  549.  
  550.   pix = p->col;
  551.   if(r) for(x = 0; x < l; x += 3) pix[x] = xlat[pix[x]];
  552.   if(g) for(x = 1; x < l; x += 3) pix[x] = xlat[pix[x]];
  553.   if(b) for(x = 2; x < l; x += 3) pix[x] = xlat[pix[x]];
  554. }
  555.  
  556. void ppmbrightness(struct ppm *p, float e, int r, int g, int b)
  557. {
  558.   int x, l = p->width * 3 * p->height;
  559.   guchar xlat[256], *pix;
  560.   for(x = 0; x < 256; x++) {
  561.     xlat[x] = x*e;
  562.   } 
  563.  
  564.   pix = p->col;
  565.   if(r) for(x = 0; x < l; x += 3) pix[x] = xlat[pix[x]];
  566.   if(g) for(x = 1; x < l; x += 3) pix[x] = xlat[pix[x]];
  567.   if(b) for(x = 2; x < l; x += 3) pix[x] = xlat[pix[x]];
  568. }
  569.  
  570.  
  571. void blur(struct ppm *p, int xrad, int yrad)
  572. {
  573.   int x, y, k;
  574.   int tx, ty;
  575.   struct ppm tmp = {0,0,NULL};
  576.   int r, g, b, n;
  577.   int rowstride = p->width * 3;
  578.  
  579.   newppm(&tmp, p->width, p->height);
  580.   for(y = 0; y < p->height; y++) {
  581.     for(x = 0; x < p->width; x++) {
  582.       r = g = b = n = 0;
  583.       for(ty = y-yrad; ty <= y+yrad; ty++) {
  584.         for(tx = x-xrad; tx <= x+xrad; tx++) {
  585.           if(ty<0) continue;
  586.           if(ty>=p->height) continue;
  587.           if(tx<0) continue;
  588.           if(tx>=p->width) continue;
  589.       k = ty*rowstride + tx*3;
  590.           r += p->col[k+0];
  591.           g += p->col[k+1];
  592.           b += p->col[k+2];
  593.           n++;
  594.         }
  595.       }
  596.       k = y*rowstride + x*3;
  597.       tmp.col[k+0] = r / n;
  598.       tmp.col[k+1] = g / n;
  599.       tmp.col[k+2] = b / n;
  600.     }
  601.   }
  602.   killppm(p);
  603.   p->width = tmp.width;
  604.   p->height = tmp.height;
  605.   p->col = tmp.col;
  606. }
  607.  
  608. void putrgb_fast(struct ppm *s, float xo, float yo, guchar *d)
  609. {
  610.   guchar *tp;
  611.   tp = s->col + s->width * 3 * (int)(yo+0.5) + 3 * (int)(xo+0.5);
  612.   tp[0] = d[0];
  613.   tp[1] = d[1];
  614.   tp[2] = d[2];
  615. }
  616.  
  617. void putrgb(struct ppm *s, float xo, float yo, guchar *d)
  618. {
  619.   int x, y;
  620.   float aa, ab, ba, bb;
  621.   int k, rowstride = s->width * 3;
  622.  
  623.   x = xo;
  624.   y = yo;
  625.  
  626.   if((x < 0) || (y < 0) || (x >= s->width-1) || (y >= s->height-1))
  627.     return;
  628.  
  629.   xo -= x;
  630.   yo -= y;
  631.  
  632.   aa = (1.0-xo)*(1.0-yo);
  633.   ab = xo*(1.0-yo);
  634.   ba = (1.0-xo)*yo;
  635.   bb = xo*yo;
  636.  
  637.   k = y*rowstride + x*3;
  638.   s->col[k+0] *= (1.0-aa);
  639.   s->col[k+1] *= (1.0-aa);
  640.   s->col[k+2] *= (1.0-aa);
  641.   
  642.   s->col[k+3] *= (1.0-ab);
  643.   s->col[k+4] *= (1.0-ab);
  644.   s->col[k+5] *= (1.0-ab);
  645.  
  646.   s->col[k+rowstride+0] *= (1.0-ba);
  647.   s->col[k+rowstride+1] *= (1.0-ba);
  648.   s->col[k+rowstride+2] *= (1.0-ba);
  649.  
  650.   s->col[k+rowstride+3] *= (1.0-bb);
  651.   s->col[k+rowstride+4] *= (1.0-bb);
  652.   s->col[k+rowstride+5] *= (1.0-bb);
  653.  
  654.   s->col[k+0] += aa * d[0];
  655.   s->col[k+1] += aa * d[1];
  656.   s->col[k+2] += aa * d[2];
  657.   s->col[k+3] += ab * d[0];
  658.   s->col[k+4] += ab * d[1];
  659.   s->col[k+5] += ab * d[2];
  660.   s->col[k+rowstride+0] += ba * d[0];
  661.   s->col[k+rowstride+1] += ba * d[1];
  662.   s->col[k+rowstride+2] += ba * d[2];
  663.   s->col[k+rowstride+3] += bb * d[0];
  664.   s->col[k+rowstride+4] += bb * d[1];
  665.   s->col[k+rowstride+5] += bb * d[2];
  666. }
  667.  
  668. void drawline(struct ppm *p, float fx, float fy, float tx, float ty, guchar *col)
  669. {
  670.   float i;
  671.   float d, x, y;
  672.   if(fabs(fx-tx) > fabs(fy-ty)) {
  673.     if(fx > tx) { i=tx; tx=fx; fx=i; i=ty; ty=fy; fy=i; }
  674.     d = (ty-fy)/(tx-fx);
  675.     y = fy;
  676.     for(x = fx; x <= tx; x+=1.0) {
  677.       putrgb(p, x, y, col);
  678.       y += d;
  679.     }
  680.   } else {
  681.     if(fy > ty) { i=tx; tx=fx; fx=i; i=ty; ty=fy; fy=i; }
  682.     d = (tx-fx)/(ty-fy);
  683.     x = fx;
  684.     for(y = fy; y <= ty; y+=1.0) {
  685.       putrgb(p, x, y, col);
  686.       x += d;
  687.     }
  688.   }
  689. }
  690.