PageRenderTime 50ms CodeModel.GetById 18ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/rel-1.3.35/Examples/GIFPlot/Lib/frame.c

#
C | 924 lines | 590 code | 152 blank | 182 comment | 141 complexity | 4e4111073b69a40b55b9b82b914347ab MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
  1/* ----------------------------------------------------------------------------- 
  2 * frame.c
  3 *
  4 *     Frame buffer management
  5 * 
  6 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
  7 * Copyright (C) 1995-1996
  8 *
  9 * See the file LICENSE for information on usage and redistribution.	
 10 * ----------------------------------------------------------------------------- */
 11
 12#define FRAME
 13#include "gifplot.h"
 14#include <float.h>
 15
 16/* ------------------------------------------------------------------------
 17   FrameBuffer *new_FrameBuffer(int width, int height)
 18
 19   Creates a new framebuffer for storing data.
 20   ------------------------------------------------------------------------ */
 21
 22FrameBuffer *new_FrameBuffer(unsigned int width, unsigned int height) {
 23
 24  FrameBuffer *f;
 25  int  FrameBuffer_resize(FrameBuffer *f, int width, int height);
 26
 27  /* Create a new frame buffer */
 28  
 29  f = (FrameBuffer *) malloc(sizeof(FrameBuffer));
 30  f->pixels = (Pixel **) 0;
 31  f->zbuffer = (Zvalue **) 0;
 32  /* Set its size */
 33  
 34  if (FrameBuffer_resize(f, width, height) == -1) {
 35    free((char *) f);
 36    return (FrameBuffer *) 0;
 37  }
 38
 39  f->xmin = 0;
 40  f->ymin = 0;
 41  f->xmax = width;
 42  f->ymax = height;
 43  return f;
 44}
 45
 46/* ------------------------------------------------------------------------
 47   void delete_FrameBuffer(FrameBuffer *f)
 48
 49   Destroys the given framebuffer
 50   ------------------------------------------------------------------------ */
 51
 52void delete_FrameBuffer(FrameBuffer *f) {
 53
 54  if (f) {
 55    if (f->pixels) {
 56      free((char *) f->pixels[0]);
 57      free((char *) f->pixels);
 58    }
 59    if (f->zbuffer) {
 60      free((char *) f->zbuffer[0]);
 61      free((char *) f->zbuffer);
 62    }
 63    free((char *)f);
 64  }
 65}
 66
 67/* ------------------------------------------------------------------------
 68   int *FrameBuffer_resize(FrameBuffer *f, int width, int height)
 69
 70   Resize the given framebuffer. Returns 0 on success, -1 on failure.
 71   ------------------------------------------------------------------------ */
 72
 73int FrameBuffer_resize(FrameBuffer *f, int width, int height) {
 74  int i;
 75  if ((f) && (width > 0) && (height > 0)) {
 76    if (f->pixels) {
 77      free((char *)f->pixels[0]);
 78      free((char *)f->pixels);
 79    }
 80    f->pixels = (Pixel **) malloc (height*sizeof(Pixel *));
 81    if (!f->pixels) return -1;
 82    f->pixels[0] = (Pixel *) malloc(height*width*sizeof(Pixel));
 83    if (!f->pixels[0]) {
 84      free((char *)f->pixels);
 85      return -1;
 86    }
 87    for (i = 0; i < height; i++) 
 88      f->pixels[i] = f->pixels[0] + i*width;
 89    f->width = width;
 90    f->height = height;
 91    if (f->zbuffer) {
 92      FrameBuffer_zresize(f,width,height);
 93    }
 94    return 0;
 95  } else {
 96    return -1;
 97  }
 98}
 99
100/* ------------------------------------------------------------------------
101   void FrameBuffer_clear(FrameBuffer *f, Pixel color)
102
103   Clears the current FrameBuffer
104   ------------------------------------------------------------------------ */
105
106void FrameBuffer_clear(FrameBuffer *f, Pixel color) {
107  Pixel *p;
108  unsigned int i;
109  p = &f->pixels[0][0];
110
111  for (i = 0; i < f->width*f->height; i++, p++)
112    *p = color;
113}
114
115/* ------------------------------------------------------------------------
116   void FrameBuffer_plot(FrameBuffer *f, int x1, int y1, Pixel color)
117
118   Plots a point and does a bounds check.
119   ------------------------------------------------------------------------ */
120
121void FrameBuffer_plot(FrameBuffer *f, int x1, int y1, Pixel color) {
122
123  if ((x1 < f->xmin) || (x1 >= f->xmax) || (y1 < f->ymin) || (y1 >= f->ymax))
124    return;
125  f->pixels[y1][x1] = color;
126
127}
128
129/* ------------------------------------------------------------------------
130   FrameBuffer_horizontal(Framebuffer *f, int xmin, int xmax, int y, Pixel color)
131
132   Draw a horizontal line (clipped)
133   ------------------------------------------------------------------------ */
134
135void FrameBuffer_horizontal(FrameBuffer *f, int xmin, int xmax, int y, Pixel color) {
136  
137  Pixel *p;
138  int    i;
139  
140  if ((y < f->ymin) || (y >= f->ymax)) return;
141  if (xmin < f->xmin) xmin = f->xmin;
142  if (xmax >= f->xmax) xmax = f->xmax - 1;
143
144  p = &f->pixels[y][xmin];
145  for (i = xmin; i <= xmax; i++, p++)
146    *p = color;
147
148}
149
150/* ------------------------------------------------------------------------
151   FrameBuffer_horizontalinterp(Framebuffer *f, int xmin, int xmax, int y,
152                                Pixel c1, Pixel c2)
153
154   Draw a horizontal line (clipped) with color interpolation.
155   ------------------------------------------------------------------------ */
156
157void FrameBuffer_horizontalinterp(FrameBuffer *f, int xmin, int xmax, int y,
158				  Pixel c1, Pixel c2) {
159  
160  Pixel *p;
161  int    i;
162  double mc;
163  int    x1;
164  if ((y < f->ymin) || (y >= f->ymax)) return;
165
166  x1 = xmin;
167  if (xmin < f->xmin) xmin = f->xmin;
168  if (xmax >= f->xmax) xmax = f->xmax - 1;
169  if (xmax < f->xmin) return;
170  if (xmin >= f->xmax) return;
171
172  if (xmin != xmax)
173    mc = (double)(c2 - c1)/(double) (xmax - xmin);
174  else
175    mc = 0.0;
176
177  p = &f->pixels[y][xmin];
178  for (i = xmin; i <= xmax; i++, p++) 
179    *p = (Pixel) (mc*(i-x1) + c1);
180  
181}
182
183
184/* ------------------------------------------------------------------------
185   FrameBuffer_vertical(Framebuffer *f, int xmin, int xmax, int y, Pixel color)
186
187   Draw a Vertical line (clipped)
188   ------------------------------------------------------------------------ */
189
190void FrameBuffer_vertical(FrameBuffer *f, int ymin, int ymax, int x, Pixel color) {
191  
192  Pixel *p;
193  int    i;
194  
195  if ((x < f->xmin) || (x >= f->xmax)) return;
196  if (ymax < f->ymin) return;
197  if (ymin > f->ymax) return;
198  if (ymin < f->ymin) ymin = f->ymin;
199  if (ymax >= f->ymax) ymax = f->ymax - 1;
200
201  p = &f->pixels[ymin][x];
202  for (i = 0; i <= (ymax - ymin); i++, p+=f->width)
203    *p = color;
204
205}
206  
207/* ------------------------------------------------------------------------
208   void FrameBuffer_box(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel color)
209
210   Makes an outline box.
211   ------------------------------------------------------------------------ */
212
213void FrameBuffer_box(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel color) {
214
215  int  xt, yt;
216
217  /* Make sure points are in correct order */
218
219  if (x2 < x1) {
220    xt = x2;
221    x2 = x1;
222    x1 = xt;
223  }
224  if (y2 < y1) {
225    yt = y2;
226    y2 = y1;
227    y1 = yt;
228  }
229
230  /* Draw lower edge */
231
232  FrameBuffer_horizontal(f,x1,x2,y1,color);
233
234  /* Draw upper edge */
235
236  FrameBuffer_horizontal(f,x1,x2,y2,color);
237
238  /* Draw left side */
239
240  FrameBuffer_vertical(f,y1,y2,x1,color);
241
242  /* Draw right side */
243
244  FrameBuffer_vertical(f,y1,y2,x2,color);
245  
246}
247
248/* ------------------------------------------------------------------------
249   void FrameBuffer_solidbox(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel color)
250
251   Makes an solid box.
252   ------------------------------------------------------------------------ */
253
254void FrameBuffer_solidbox(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel color) {
255
256  int  xt, yt;
257
258  /* Make sure points are in correct order */
259
260  if (x2 < x1) {
261    xt = x2;
262    x2 = x1;
263    x1 = xt;
264  }
265  if (y2 < y1) {
266    yt = y2;
267    y2 = y1;
268    y1 = yt;
269  }
270
271  /* Now perform some clipping */
272
273  if (y1 < f->ymin) y1 = f->ymin;
274  if (y2 >= f->ymax) y2 = f->ymax - 1;
275
276  /* Fill it in using horizontal lines */
277  
278  for (yt = y1; yt <= y2; yt++)
279    FrameBuffer_horizontal(f,x1,x2,yt,color);
280
281}
282
283/* ------------------------------------------------------------------------
284   void FrameBuffer_interpbox(FrameBuffer *f, int x1, int y1, int x2, int y2
285                              Pixel c1, Pixel c2, Pixel c3, Pixel c4)
286
287   Makes a box with interpolated color.   Colors are assigned as follows :
288   (x1,y1) = c1
289   (x1,y2) = c2
290   (x2,y1) = c3
291   (x2,y2) = c4
292   ------------------------------------------------------------------------ */
293
294void FrameBuffer_interpbox(FrameBuffer *f, int x1, int y1, int x2, int y2,
295			   Pixel c1, Pixel c2, Pixel c3, Pixel c4) {
296
297  int  xt, yt;
298  Pixel ct;
299  double  mc1,mc2;
300  int  ystart;
301  /* Make sure points are in correct order */
302
303  if (x2 < x1) {
304    xt = x2;
305    x2 = x1;
306    x1 = xt;
307    ct = c1;
308    c1 = c3;
309    c3 = ct;
310    ct = c2;
311    c2 = c4;
312    c4 = ct;
313  }
314  if (y2 < y1) {
315    yt = y2;
316    y2 = y1;
317    y1 = yt;
318    ct = c1;
319    c1 = c2;
320    c2 = ct;
321    ct = c3;
322    c3 = c4;
323    c4 = ct;
324  }
325
326  /* Now perform some clipping */
327
328  ystart = y1;
329  mc1 = (double) (c2 - c1)/(double) (y2 - y1);
330  mc2 = (double) (c4 - c3)/(double) (y2 - y1);
331  if (y1 < f->ymin) y1 = f->ymin;
332  if (y2 >= f->ymax) y2 = f->ymax - 1;
333
334  /* Fill it in using horizontal lines */
335  
336  for (yt = y1; yt <= y2; yt++)
337    FrameBuffer_horizontalinterp(f,x1,x2,yt,(Pixel) ((mc1*(yt - ystart)) + c1),
338				  (Pixel) ((mc2*(yt-ystart))+c3));
339
340}
341
342/* ---------------------------------------------------------------------------
343   FrameBuffer_line(FrameBuffer *f, int x1, int y1, int x2, int y2, color)
344
345   Draws a line on the framebuffer using the Bresenham line algorithm.  The
346   line is clipped to fit within the current view window.
347   ---------------------------------------------------------------------------- */
348
349void FrameBuffer_line(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel c) {
350
351  int  dx,dy,dxneg,dyneg, inc1,inc2,di;
352  int  x, y, xpixels, ypixels, xt, yt;
353  Pixel *p;
354  double m;
355  int  end1 = 0, end2 = 0;
356  
357  /* Need to figure out where in the heck this line is */
358
359  dx = x2 - x1;
360  dy = y2 - y1;
361
362  if (dx == 0) {
363    /* Draw a Vertical Line */
364    if (y1 < y2)
365      FrameBuffer_vertical(f,y1,y2,x1,c);
366    else
367      FrameBuffer_vertical(f,y2,y1,x1,c);
368    return;
369  }
370  if (dy == 0) {
371    /* Draw a Horizontal Line */
372    if (x1 < x2)
373      FrameBuffer_horizontal(f,x1,x2,y1,c);
374    else
375      FrameBuffer_horizontal(f,x2,x1,y1,c);
376    return;
377  }
378
379  /* Figure out where in the heck these lines are using the
380     Cohen-Sutherland Line Clipping Scheme. */
381
382  end1 = ((x1 - f->xmin) < 0) |
383    (((f->xmax- 1 - x1) < 0) << 1) |
384    (((y1 - f->ymin) < 0) << 2) |
385    (((f->ymax-1 - y1) < 0) << 3);
386
387  end2 = ((x2 - f->xmin) < 0) |
388    (((f->xmax-1 - x2) < 0) << 1) |
389    (((y2 - f->ymin) < 0) << 2) |
390    (((f->ymax-1 - y2) < 0) << 3);
391
392  if (end1 & end2) return;      /* Nope : Not visible */
393
394  /* Make sure points have a favorable orientation */
395  
396  if (x1 > x2) {
397    xt = x1;
398    x1 = x2;
399    x2 = xt;
400    yt = y1;
401    y1 = y2;
402    y2 = yt;
403  }
404  
405  /* Clip against the boundaries */
406  m = (y2 - y1)/(double) (x2-x1);
407  if (x1 < f->xmin) {
408    y1 = (int) ((f->xmin - x1)*m + y1);
409    x1 = (int) f->xmin;
410  }
411  if (x2 >= f->xmax) {
412    y2 = (int) ((f->xmax -1 -x1)*m + y1);
413    x2 = (int) (f->xmax - 1);
414  }
415
416  if (y1 > y2) {
417    xt = x1;
418    x1 = x2;
419    x2 = xt;
420    yt = y1;
421    y1 = y2;
422    y2 = yt;
423  }
424
425  m = 1/m;
426  if (y1 < f->ymin) {
427    x1 = (int) ((f->ymin - y1)*m + x1);
428    y1 = (int) f->ymin;
429  }
430  if (y2 >= f->ymax) {
431    x2 = (int) ((f->ymax-1-y1)*m + x1);
432    y2 = (int) (f->ymax-1);
433  }
434
435  if ((x1 < f->xmin) || (x1 >= f->xmax) || (y1 < f->ymin) || (y1 >= f->ymax) ||
436      (x2 < f->xmin) || (x2 >= f->xmax) || (y2 < f->ymin) || (y2 >= f->ymax)) return;
437
438  dx = x2 - x1;
439  dy = y2 - y1;
440  xpixels = f->width;
441  ypixels = f->height;
442  
443  dxneg = (dx < 0) ? 1 : 0;
444  dyneg = (dy < 0) ? 1 : 0;
445  
446  dx = abs(dx);
447  dy = abs(dy);
448  if (dx >= dy) {
449    /* Slope between -1 and 1. */
450    if (dxneg) {
451      x = x1;
452      y = y1;
453      x1 = x2;
454      y1 = y2;
455      x2 = x;
456      y2 = y;
457      dyneg = !dyneg;
458    }
459    inc1 = 2*dy;
460    inc2 = 2*(dy-dx);
461    di = 2*dy-dx;
462
463    /* Draw a line using x as independent variable */
464    
465    p = &f->pixels[y1][x1];
466    x = x1;
467    while (x <= x2) {
468      *(p++) = c;
469      if (di < 0) {
470	di = di + inc1;
471      } else {
472	if (dyneg) {
473	  p = p - xpixels;
474	  di = di + inc2;
475	} else {
476	  p = p + xpixels;
477	  di = di + inc2;
478	}
479      }
480      x++;
481    }
482  } else {
483    /* Slope < -1 or > 1 */
484    if (dyneg) {
485      x = x1;
486      y = y1;
487      x1 = x2;
488      y1 = y2;
489      x2 = x;
490      y2 = y;
491      dxneg = !dxneg;
492    }
493    inc1 = 2*dx;
494    inc2 = 2*(dx-dy);
495    di = 2*dx-dy;
496
497    /* Draw a line using y as independent variable */
498    
499    p = &f->pixels[y1][x1];
500    y = y1;
501    while (y <= y2) {
502      *p = c;
503      p = p + xpixels;
504      if (di < 0) {
505	di = di + inc1;
506      } else {
507	if (dxneg) {
508	  p = p - 1;
509	  di = di + inc2;
510	} else {
511	  p = p + 1;
512	  di = di + inc2;
513	}
514      }
515      y++;
516    }
517  }    
518}
519
520
521/* -------------------------------------------------------------------------
522   FrameBuffer_circle(FrameBuffer f, int xc, int yc, int radius, Pixel c)
523
524   Create an outline circle
525   ------------------------------------------------------------------------- */
526
527#define plot_circle(x,y,c) \
528   if ((x >= xmin) && (x < xmax) && \
529       (y >= ymin) && (y < ymax)) \
530        pixels[y][x] = c;
531	
532void FrameBuffer_circle(FrameBuffer *f, int xc, int yc, int radius, Pixel c) {
533
534  int xpixels, ypixels, x, y, p;
535  int xmin, ymin, xmax, ymax;
536  Pixel **pixels;
537
538  if (radius <= 0) return;
539  xpixels = f->width;
540  ypixels = f->height;
541  pixels = f->pixels;
542  xmin = f->xmin;
543  ymin = f->ymin;
544  xmax = f->xmax;
545  ymax = f->ymax;
546  x = 0;
547  y = radius;
548  p = 3-2*radius;
549  while (x <= y) {
550    plot_circle(xc+x,yc+y,c);
551    plot_circle(xc-x,yc+y,c);
552    plot_circle(xc+x,yc-y,c);
553    plot_circle(xc-x,yc-y,c);
554    plot_circle(xc+y,yc+x,c);
555    plot_circle(xc-y,yc+x,c);
556    plot_circle(xc+y,yc-x,c);
557    plot_circle(xc-y,yc-x,c);
558    if (p < 0) p = p + 4*x + 6;
559    else {
560      p = p + 4*(x-y) + 10;
561      y = y -1;
562    }
563    x++;
564  }
565}
566
567
568/* -------------------------------------------------------------------------
569   FrameBuffer_solidcircle(FrameBuffer f, int xc, int yc, int radius, Pixel c)
570
571   Create an filled circle
572   ------------------------------------------------------------------------- */
573
574       
575#define fill_circle(x,y,c) \
576       x1 = xc - x; \
577       x2 = xc + x; \
578       FrameBuffer_horizontal(f,x1,x2,y,c);
579	
580void FrameBuffer_solidcircle(FrameBuffer *f, int xc, int yc, int radius, Pixel c) {
581
582  int xpixels, ypixels, x, y, p;
583  int x1,x2;
584  int xmin, ymin, xmax, ymax;
585  Pixel **pixels;
586
587  if (radius <= 0) return;
588  xpixels = f->width;
589  ypixels = f->height;
590  pixels = f->pixels;
591  xmin = f->xmin;
592  ymin = f->ymin;
593  xmax = f->xmax;
594  ymax = f->ymax;
595  x = 0;
596  y = radius;
597  p = 3-2*radius;
598  while (x <= y) {
599    fill_circle(x,yc+y,c);
600    fill_circle(x,yc-y,c);
601    fill_circle(y,yc+x,c);
602    fill_circle(y,yc-x,c);
603    if (p < 0) p = p + 4*x + 6;
604    else {
605      p = p + 4*(x-y) + 10;
606      y = y -1;
607    }
608    x++;
609  }
610}
611
612/* ------------------------------------------------------------------------
613   void FrameBuffer_setclip(f,xmin,ymin,xmax,ymax)
614
615   Set clipping region for plotting
616   ------------------------------------------------------------------------ */
617
618void FrameBuffer_setclip(FrameBuffer *f, int xmin, int ymin, int xmax, int ymax) {
619
620  if (xmin >= xmax) return;
621  if (ymin >= ymax) return;
622
623  if (xmin < 0) xmin = 0;
624  if (ymin < 0) ymin = 0;
625  if (xmax > (int) f->width) xmax = f->width;
626  if (ymax > (int) f->height) ymax = f->height;
627
628  f->xmin = xmin;
629  f->ymin = ymin;
630  f->xmax = xmax;
631  f->ymax = ymax;
632}
633
634/* ------------------------------------------------------------------------
635   void FrameBuffer_noclip(f)
636
637   Disable clipping region
638   ------------------------------------------------------------------------ */
639
640void FrameBuffer_noclip(FrameBuffer *f) {
641  f->xmin = 0;
642  f->ymin = 0;
643  f->xmax = f->width;
644  f->ymax = f->height;
645}
646
647
648/* ------------------------------------------------------------------------
649   FrameBuffer_zresize(FrameBuffer *f, int width, int height)
650
651   This function resizes the framebuffer's zbuffer.  If none exist, it
652   creates a new one.
653   ------------------------------------------------------------------------ */
654
655void FrameBuffer_zresize(FrameBuffer *f, int width, int height) {
656  int i;
657
658  if (f->zbuffer) {
659    free((char *)f->zbuffer[0]);
660    free((char *)f->zbuffer);
661  }
662  f->zbuffer = (Zvalue **) malloc(height*sizeof(Zvalue *));
663  f->zbuffer[0] = (Zvalue *) malloc(height*width*sizeof(Zvalue));
664  for (i = 0; i < height; i++)
665    f->zbuffer[i] = f->zbuffer[0]+i*width;
666}
667
668/* ------------------------------------------------------------------------
669   FrameBuffer_zclear(FrameBuffer *f)
670
671   Clears the z-buffer for a particular frame.   Sets all of the z-values to
672   ZMIN.
673   ------------------------------------------------------------------------- */
674
675void FrameBuffer_zclear(FrameBuffer *f) {
676  unsigned int i,j;
677  if (f) {
678    if (f->zbuffer) {
679      for (i = 0; i < f->width; i++)
680	for (j = 0; j < f->height; j++)
681	  f->zbuffer[j][i] = ZMIN;
682    }
683  }
684}
685   
686
687
688/* -------------------------------------------------------------------------
689   FrameBuffer_solidtriangle(FrameBuffer *f, int tx1, int ty2, 
690                                 int tx2, int ty2, 
691				 int tx3, int ty3, Pixel color) 
692
693   This function draws a 2D filled triangle.   
694
695   General idea :
696         1.   Transform the three points into screen coordinates
697	 2.   Order three points vertically on screen.
698	 3.   Check for degenerate cases (where 3 points are colinear).
699	 4.   Fill in the resulting triangle using horizontal lines.
700   -------------------------------------------------------------------------- */
701
702void FrameBuffer_solidtriangle(FrameBuffer *f, int tx1, int ty1, 
703			       int tx2, int ty2,
704			       int tx3, int ty3, Pixel color) {
705  int        tempx, tempy;
706  double     m1,m2,m3;
707  int        y;
708  int        ix1, ix2;
709
710  /* Figure out which point has the greatest "y" value */
711
712  if (ty2 > ty1) {   /* Swap points 1 and 2 if 2 is higher */
713    tempx = tx1;
714    tempy = ty1;
715    tx1 = tx2;
716    ty1 = ty2;
717    tx2 = tempx;
718    ty2 = tempy;
719  }
720  if (ty3 > ty1) {  /* Swap points 1 and 3 if 3 is higher */
721    tempx = tx1;
722    tempy = ty1;
723    tx1 = tx3;
724    ty1 = ty3;
725    tx3 = tempx;
726    ty3 = tempy;
727  }
728  if (ty3 > ty2) { /* Swap points 2 and 3 if 3 is higher */ 
729    tempx = tx2;
730    tempy = ty2;
731    tx2 = tx3;
732    ty2 = ty3;
733    tx3 = tempx;
734    ty3 = tempy;
735  }
736
737  /* Points are now order so that t_1 is the highest point, t_2 is the
738     middle point, and t_3 is the lowest point */
739
740  /* Check for degenerate cases here */
741
742  if ((ty1 == ty2) && (ty2 == ty3)) {
743
744    /* Points are aligned horizontally.   Handle as a special case */
745    /* Just draw three lines using the outline color */
746
747    FrameBuffer_line(f,tx1,ty1,tx2,ty2,color);
748    FrameBuffer_line(f,tx1,ty1,tx3,ty3,color);
749    FrameBuffer_line(f,tx2,ty2,tx3,ty3,color);
750
751  } else {
752
753    if (ty2 < ty1) {
754      /* First process line segments between (x1,y1)-(x2,y2)
755	 And between (x1,y1),(x3,y3) */
756
757      m1 = (double) (tx2 - tx1)/(double) (ty2 - ty1);
758      m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
759
760      y = ty1;
761      while (y >= ty2) {
762	/* Calculate x values from slope */
763	ix1 = (int) (m1*(y-ty1)+0.5) + tx1;
764	ix2 = (int) (m2*(y-ty1)+0.5) + tx1;
765	if (ix1 > ix2) 
766	  FrameBuffer_horizontal(f,ix2,ix1,y,color);
767	else
768	  FrameBuffer_horizontal(f,ix1,ix2,y,color);
769	y--;
770      }
771    }
772    if (ty3 < ty2) {
773      /* Draw lower half of the triangle */
774      m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
775      m3 = (double) (tx3 - tx2)/(double)(ty3 - ty2);
776      y = ty2;
777      while (y >= ty3) {
778	ix1 = (int) (m3*(y-ty2)+0.5)+tx2;
779	ix2 = (int) (m2*(y-ty1)+0.5)+tx1;
780	if (ix1 > ix2)
781	  FrameBuffer_horizontal(f,ix2,ix1,y,color);
782	else
783	  FrameBuffer_horizontal(f,ix1,ix2,y,color);
784	y--;
785      }
786    }
787  }
788}
789
790/* -------------------------------------------------------------------------
791   FrameBuffer_interptriangle(FrameBuffer *f,
792   int tx1, int ty2, Pixel c1,
793   int tx2, int ty2, Pixel c2,
794   int tx3, int ty3, Pixel c3)
795
796   This function draws a filled triangle with color
797   interpolation.  
798
799   General idea :
800         1.   Transform the three points into screen coordinates
801	 2.   Order three points vertically on screen.
802	 3.   Check for degenerate cases (where 3 points are colinear).
803	 4.   Fill in the resulting triangle using horizontal lines.
804	 5.   Colors are interpolated between end points
805   -------------------------------------------------------------------------- */
806
807void FrameBuffer_interptriangle(FrameBuffer *f,
808				int tx1, int ty1, Pixel c1,
809				int tx2, int ty2, Pixel c2,
810				int tx3, int ty3, Pixel c3) {
811  int        tempx, tempy;
812  double     m1,m2,m3;
813  double     mc1,mc2,mc3;
814  Pixel      ic1,ic2,tempc;
815  int        y;
816  int        ix1, ix2;
817
818  /* Figure out which point has the greatest "y" value */
819
820  if (ty2 > ty1) {   /* Swap points 1 and 2 if 2 is higher */
821    tempx = tx1;
822    tempy = ty1;
823    tempc = c1;
824    tx1 = tx2;
825    ty1 = ty2;
826    c1 = c2;
827    tx2 = tempx;
828    ty2 = tempy;
829    c2 = tempc;
830  }
831  if (ty3 > ty1) {  /* Swap points 1 and 3 if 3 is higher */
832    tempx = tx1;
833    tempy = ty1;
834    tempc = c1;
835    tx1 = tx3;
836    ty1 = ty3;
837    c1 = c3;
838    tx3 = tempx;
839    ty3 = tempy;
840    c3 = tempc;
841  }
842  if (ty3 > ty2) { /* Swap points 2 and 3 if 3 is higher */ 
843    tempx = tx2;
844    tempy = ty2;
845    tempc = c2;
846    tx2 = tx3;
847    ty2 = ty3;
848    c2 = c3;
849    tx3 = tempx;
850    ty3 = tempy;
851    c3 = tempc;
852  }
853
854  /* Points are now order so that t_1 is the highest point, t_2 is the
855     middle point, and t_3 is the lowest point */
856
857  /* Check for degenerate cases here */
858
859  if ((ty1 == ty2) && (ty2 == ty3)) {
860
861    /* Points are aligned horizontally.   Handle as a special case */
862    /* Just draw three lines using the outline color */
863
864    if (tx2 > tx1)
865      FrameBuffer_horizontalinterp(f,tx1,tx2,ty1,c1,c2);
866    else
867      FrameBuffer_horizontalinterp(f,tx2,tx1,ty1,c2,c1);
868    if (tx3 > tx1)
869      FrameBuffer_horizontalinterp(f,tx1,tx3,ty1,c1,c3);
870    else
871      FrameBuffer_horizontalinterp(f,tx3,tx1,ty1,c3,c1);
872    if (tx3 > tx2)
873      FrameBuffer_horizontalinterp(f,tx2,tx3,ty2,c2,c3);
874    else
875      FrameBuffer_horizontalinterp(f,tx3,tx2,ty2,c3,c2);
876    
877  } else {
878
879    /* First process line segments between (x1,y1)-(x2,y2)
880       And between (x1,y1),(x3,y3) */
881
882    if (ty2 < ty1) {
883      m1 = (double) (tx2 - tx1)/(double) (ty2 - ty1);
884      m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
885      mc1 = (c2 - c1)/(double) (ty2 - ty1);
886      mc2 = (c3 - c1)/(double) (ty3 - ty1);
887
888      y = ty1;
889      while (y >= ty2) {
890	/* Calculate x values from slope */
891	ix1 = (int) (m1*(y-ty1)+0.5) + tx1;
892	ix2 = (int) (m2*(y-ty1)+0.5) + tx1;
893	ic1 = (int) (mc1*(y-ty1) + c1);
894	ic2 = (int) (mc2*(y-ty1) + c1);
895	if (ix1 > ix2) 
896	  FrameBuffer_horizontalinterp(f,ix2,ix1,y,ic2,ic1);
897	else
898	  FrameBuffer_horizontalinterp(f,ix1,ix2,y,ic1,ic2);
899	y--;
900      }
901    }
902    if (ty3 < ty2) {
903      /* Draw lower half of the triangle */
904      m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
905      mc2 = (c3 - c1)/(double) (ty3 - ty1);
906      m3 = (double) (tx3 - tx2)/(double)(ty3 - ty2);
907      mc3 = (c3 - c2)/(double) (ty3 - ty2);
908      y = ty2;
909      while (y >= ty3) {
910	ix1 = (int) (m3*(y-ty2)+0.5)+tx2;
911	ix2 = (int) (m2*(y-ty1)+0.5)+tx1;
912	ic1 = (int) (mc3*(y-ty2)+c2);
913	ic2 = (int) (mc2*(y-ty1)+c1);
914	if (ix1 > ix2)
915	  FrameBuffer_horizontalinterp(f,ix2,ix1,y,ic2,ic1);
916	else
917	  FrameBuffer_horizontalinterp(f,ix1,ix2,y,ic1,ic2);
918	y--;
919      }
920    }
921  }
922}
923
924