/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