/**********************************************************************
* GIFPlot 0.0
*
* Dave Beazley
*
* Department of Computer Science Theoretical Division (T-11)
* University of Utah Los Alamos National Laboratory
* Salt Lake City, Utah 84112 Los Alamos, New Mexico 87545
* beazley@cs.utah.edu beazley@lanl.gov
*
* Copyright (c) 1996
* The Regents of the University of California and the University of Utah
* All Rights Reserved
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that
* (1) The above copyright notice and the following two paragraphs
* appear in all copies of the source code and (2) redistributions
* including binaries reproduces these notices in the supporting
* documentation. Substantial modifications to this software may be
* copyrighted by their authors and need not follow the licensing terms
* described here, provided that the new terms are clearly indicated in
* all files where they apply.
*
* IN NO EVENT SHALL THE AUTHOR, THE UNIVERSITY OF CALIFORNIA, THE
* UNIVERSITY OF UTAH OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
* DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
* EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* THE AUTHOR, THE UNIVERSITY OF CALIFORNIA, AND THE UNIVERSITY OF UTAH
* SPECIFICALLY DISCLAIM ANY WARRANTIES,INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
* THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
**************************************************************************/
/*************************************************************************
* frame.c
*
* This file defines a whole bunch of primitive operations on framebuffers.
**************************************************************************/
#define FRAME
#include "gifplot.h"
#include <float.h>
/* ------------------------------------------------------------------------
FrameBuffer *new_FrameBuffer(int width, int height)
Creates a new framebuffer for storing data.
------------------------------------------------------------------------ */
FrameBuffer *new_FrameBuffer(unsigned int width, unsigned int height) {
FrameBuffer *f;
int FrameBuffer_resize(FrameBuffer *f, int width, int height);
/* Create a new frame buffer */
f = (FrameBuffer *) malloc(sizeof(FrameBuffer));
f->pixels = (Pixel **) 0;
f->zbuffer = (Zvalue **) 0;
/* Set its size */
if (FrameBuffer_resize(f, width, height) == -1) {
free((char *) f);
return (FrameBuffer *) 0;
}
f->xmin = 0;
f->ymin = 0;
f->xmax = width;
f->ymax = height;
return f;
}
/* ------------------------------------------------------------------------
void delete_FrameBuffer(FrameBuffer *f)
Destroys the given framebuffer
------------------------------------------------------------------------ */
void delete_FrameBuffer(FrameBuffer *f) {
if (f) {
if (f->pixels) {
free((char *) f->pixels[0]);
free((char *) f->pixels);
}
if (f->zbuffer) {
free((char *) f->zbuffer[0]);
free((char *) f->zbuffer);
}
free((char *)f);
}
}
/* ------------------------------------------------------------------------
int *FrameBuffer_resize(FrameBuffer *f, int width, int height)
Resize the given framebuffer. Returns 0 on success, -1 on failure.
------------------------------------------------------------------------ */
int FrameBuffer_resize(FrameBuffer *f, int width, int height) {
int i;
if ((f) && (width > 0) && (height > 0)) {
if (f->pixels) {
free((char *)f->pixels[0]);
free((char *)f->pixels);
}
f->pixels = (Pixel **) malloc (height*sizeof(Pixel *));
if (!f->pixels) return -1;
f->pixels[0] = (Pixel *) malloc(height*width*sizeof(Pixel));
if (!f->pixels[0]) {
free((char *)f->pixels);
return -1;
}
for (i = 0; i < height; i++)
f->pixels[i] = f->pixels[0] + i*width;
f->width = width;
f->height = height;
if (f->zbuffer) {
FrameBuffer_zresize(f,width,height);
}
return 0;
} else {
return -1;
}
}
/* ------------------------------------------------------------------------
void FrameBuffer_clear(FrameBuffer *f, Pixel color)
Clears the current FrameBuffer
------------------------------------------------------------------------ */
void FrameBuffer_clear(FrameBuffer *f, Pixel color) {
Pixel *p;
unsigned int i;
p = &f->pixels[0][0];
for (i = 0; i < f->width*f->height; i++, p++)
*p = color;
}
/* ------------------------------------------------------------------------
void FrameBuffer_plot(FrameBuffer *f, int x1, int y1, Pixel color)
Plots a point and does a bounds check.
------------------------------------------------------------------------ */
void FrameBuffer_plot(FrameBuffer *f, int x1, int y1, Pixel color) {
if ((x1 < f->xmin) || (x1 >= f->xmax) || (y1 < f->ymin) || (y1 >= f->ymax))
return;
f->pixels[y1][x1] = color;
}
/* ------------------------------------------------------------------------
FrameBuffer_horizontal(Framebuffer *f, int xmin, int xmax, int y, Pixel color)
Draw a horizontal line (clipped)
------------------------------------------------------------------------ */
void FrameBuffer_horizontal(FrameBuffer *f, int xmin, int xmax, int y, Pixel color) {
Pixel *p;
int i;
if ((y < f->ymin) || (y >= f->ymax)) return;
if (xmin < f->xmin) xmin = f->xmin;
if (xmax >= f->xmax) xmax = f->xmax - 1;
p = &f->pixels[y][xmin];
for (i = xmin; i <= xmax; i++, p++)
*p = color;
}
/* ------------------------------------------------------------------------
FrameBuffer_horizontalinterp(Framebuffer *f, int xmin, int xmax, int y,
Pixel c1, Pixel c2)
Draw a horizontal line (clipped) with color interpolation.
------------------------------------------------------------------------ */
void FrameBuffer_horizontalinterp(FrameBuffer *f, int xmin, int xmax, int y,
Pixel c1, Pixel c2) {
Pixel *p;
int i;
double mc;
int x1;
if ((y < f->ymin) || (y >= f->ymax)) return;
x1 = xmin;
if (xmin < f->xmin) xmin = f->xmin;
if (xmax >= f->xmax) xmax = f->xmax - 1;
if (xmax < f->xmin) return;
if (xmin >= f->xmax) return;
if (xmin != xmax)
mc = (double)(c2 - c1)/(double) (xmax - xmin);
else
mc = 0.0;
p = &f->pixels[y][xmin];
for (i = xmin; i <= xmax; i++, p++)
*p = (Pixel) (mc*(i-x1) + c1);
}
/* ------------------------------------------------------------------------
FrameBuffer_vertical(Framebuffer *f, int xmin, int xmax, int y, Pixel color)
Draw a Vertical line (clipped)
------------------------------------------------------------------------ */
void FrameBuffer_vertical(FrameBuffer *f, int ymin, int ymax, int x, Pixel color) {
Pixel *p;
int i;
if ((x < f->xmin) || (x >= f->xmax)) return;
if (ymax < f->ymin) return;
if (ymin > f->ymax) return;
if (ymin < f->ymin) ymin = f->ymin;
if (ymax >= f->ymax) ymax = f->ymax - 1;
p = &f->pixels[ymin][x];
for (i = 0; i <= (ymax - ymin); i++, p+=f->width)
*p = color;
}
/* ------------------------------------------------------------------------
void FrameBuffer_box(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel color)
Makes an outline box.
------------------------------------------------------------------------ */
void FrameBuffer_box(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel color) {
int xt, yt;
/* Make sure points are in correct order */
if (x2 < x1) {
xt = x2;
x2 = x1;
x1 = xt;
}
if (y2 < y1) {
yt = y2;
y2 = y1;
y1 = yt;
}
/* Draw lower edge */
FrameBuffer_horizontal(f,x1,x2,y1,color);
/* Draw upper edge */
FrameBuffer_horizontal(f,x1,x2,y2,color);
/* Draw left side */
FrameBuffer_vertical(f,y1,y2,x1,color);
/* Draw right side */
FrameBuffer_vertical(f,y1,y2,x2,color);
}
/* ------------------------------------------------------------------------
void FrameBuffer_solidbox(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel color)
Makes an solid box.
------------------------------------------------------------------------ */
void FrameBuffer_solidbox(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel color) {
int xt, yt;
/* Make sure points are in correct order */
if (x2 < x1) {
xt = x2;
x2 = x1;
x1 = xt;
}
if (y2 < y1) {
yt = y2;
y2 = y1;
y1 = yt;
}
/* Now perform some clipping */
if (y1 < f->ymin) y1 = f->ymin;
if (y2 >= f->ymax) y2 = f->ymax - 1;
/* Fill it in using horizontal lines */
for (yt = y1; yt <= y2; yt++)
FrameBuffer_horizontal(f,x1,x2,yt,color);
}
/* ------------------------------------------------------------------------
void FrameBuffer_interpbox(FrameBuffer *f, int x1, int y1, int x2, int y2
Pixel c1, Pixel c2, Pixel c3, Pixel c4)
Makes a box with interpolated color. Colors are assigned as follows :
(x1,y1) = c1
(x1,y2) = c2
(x2,y1) = c3
(x2,y2) = c4
------------------------------------------------------------------------ */
void FrameBuffer_interpbox(FrameBuffer *f, int x1, int y1, int x2, int y2,
Pixel c1, Pixel c2, Pixel c3, Pixel c4) {
int xt, yt;
Pixel ct;
double mc1,mc2;
int ystart;
/* Make sure points are in correct order */
if (x2 < x1) {
xt = x2;
x2 = x1;
x1 = xt;
ct = c1;
c1 = c3;
c3 = ct;
ct = c2;
c2 = c4;
c4 = ct;
}
if (y2 < y1) {
yt = y2;
y2 = y1;
y1 = yt;
ct = c1;
c1 = c2;
c2 = ct;
ct = c3;
c3 = c4;
c4 = ct;
}
/* Now perform some clipping */
ystart = y1;
mc1 = (double) (c2 - c1)/(double) (y2 - y1);
mc2 = (double) (c4 - c3)/(double) (y2 - y1);
if (y1 < f->ymin) y1 = f->ymin;
if (y2 >= f->ymax) y2 = f->ymax - 1;
/* Fill it in using horizontal lines */
for (yt = y1; yt <= y2; yt++)
FrameBuffer_horizontalinterp(f,x1,x2,yt,(Pixel) ((mc1*(yt - ystart)) + c1),
(Pixel) ((mc2*(yt-ystart))+c3));
}
/* ---------------------------------------------------------------------------
FrameBuffer_line(FrameBuffer *f, int x1, int y1, int x2, int y2, color)
Draws a line on the framebuffer using the Bresenham line algorithm. The
line is clipped to fit within the current view window.
---------------------------------------------------------------------------- */
void FrameBuffer_line(FrameBuffer *f, int x1, int y1, int x2, int y2, Pixel c) {
int dx,dy,dxneg,dyneg, inc1,inc2,di;
int x, y, xpixels, ypixels, xt, yt;
Pixel *p;
double m;
int end1 = 0, end2 = 0;
/* Need to figure out where in the heck this line is */
dx = x2 - x1;
dy = y2 - y1;
if (dx == 0) {
/* Draw a Vertical Line */
if (y1 < y2)
FrameBuffer_vertical(f,y1,y2,x1,c);
else
FrameBuffer_vertical(f,y2,y1,x1,c);
return;
}
if (dy == 0) {
/* Draw a Horizontal Line */
if (x1 < x2)
FrameBuffer_horizontal(f,x1,x2,y1,c);
else
FrameBuffer_horizontal(f,x2,x1,y1,c);
return;
}
/* Figure out where in the heck these lines are using the
Cohen-Sutherland Line Clipping Scheme. */
end1 = ((x1 - f->xmin) < 0) |
(((f->xmax- 1 - x1) < 0) << 1) |
(((y1 - f->ymin) < 0) << 2) |
(((f->ymax-1 - y1) < 0) << 3);
end2 = ((x2 - f->xmin) < 0) |
(((f->xmax-1 - x2) < 0) << 1) |
(((y2 - f->ymin) < 0) << 2) |
(((f->ymax-1 - y2) < 0) << 3);
if (end1 & end2) return; /* Nope : Not visible */
/* Make sure points have a favorable orientation */
if (x1 > x2) {
xt = x1;
x1 = x2;
x2 = xt;
yt = y1;
y1 = y2;
y2 = yt;
}
/* Clip against the boundaries */
m = (y2 - y1)/(double) (x2-x1);
if (x1 < f->xmin) {
y1 = (int) ((f->xmin - x1)*m + y1);
x1 = (int) f->xmin;
}
if (x2 >= f->xmax) {
y2 = (int) ((f->xmax -1 -x1)*m + y1);
x2 = (int) (f->xmax - 1);
}
if (y1 > y2) {
xt = x1;
x1 = x2;
x2 = xt;
yt = y1;
y1 = y2;
y2 = yt;
}
m = 1/m;
if (y1 < f->ymin) {
x1 = (int) ((f->ymin - y1)*m + x1);
y1 = (int) f->ymin;
}
if (y2 >= f->ymax) {
x2 = (int) ((f->ymax-1-y1)*m + x1);
y2 = (int) (f->ymax-1);
}
if ((x1 < f->xmin) || (x1 >= f->xmax) || (y1 < f->ymin) || (y1 >= f->ymax) ||
(x2 < f->xmin) || (x2 >= f->xmax) || (y2 < f->ymin) || (y2 >= f->ymax)) return;
dx = x2 - x1;
dy = y2 - y1;
xpixels = f->width;
ypixels = f->height;
dxneg = (dx < 0) ? 1 : 0;
dyneg = (dy < 0) ? 1 : 0;
dx = abs(dx);
dy = abs(dy);
if (dx >= dy) {
/* Slope between -1 and 1. */
if (dxneg) {
x = x1;
y = y1;
x1 = x2;
y1 = y2;
x2 = x;
y2 = y;
dyneg = !dyneg;
}
inc1 = 2*dy;
inc2 = 2*(dy-dx);
di = 2*dy-dx;
/* Draw a line using x as independent variable */
p = &f->pixels[y1][x1];
x = x1;
while (x <= x2) {
*(p++) = c;
if (di < 0) {
di = di + inc1;
} else {
if (dyneg) {
p = p - xpixels;
di = di + inc2;
} else {
p = p + xpixels;
di = di + inc2;
}
}
x++;
}
} else {
/* Slope < -1 or > 1 */
if (dyneg) {
x = x1;
y = y1;
x1 = x2;
y1 = y2;
x2 = x;
y2 = y;
dxneg = !dxneg;
}
inc1 = 2*dx;
inc2 = 2*(dx-dy);
di = 2*dx-dy;
/* Draw a line using y as independent variable */
p = &f->pixels[y1][x1];
y = y1;
while (y <= y2) {
*p = c;
p = p + xpixels;
if (di < 0) {
di = di + inc1;
} else {
if (dxneg) {
p = p - 1;
di = di + inc2;
} else {
p = p + 1;
di = di + inc2;
}
}
y++;
}
}
}
/* -------------------------------------------------------------------------
FrameBuffer_circle(FrameBuffer f, int xc, int yc, int radius, Pixel c)
Create an outline circle
------------------------------------------------------------------------- */
#define plot_circle(x,y,c) \
if ((x >= xmin) && (x < xmax) && \
(y >= ymin) && (y < ymax)) \
pixels[y][x] = c;
void FrameBuffer_circle(FrameBuffer *f, int xc, int yc, int radius, Pixel c) {
int xpixels, ypixels, x, y, p;
int xmin, ymin, xmax, ymax;
Pixel **pixels;
if (radius <= 0) return;
xpixels = f->width;
ypixels = f->height;
pixels = f->pixels;
xmin = f->xmin;
ymin = f->ymin;
xmax = f->xmax;
ymax = f->ymax;
x = 0;
y = radius;
p = 3-2*radius;
while (x <= y) {
plot_circle(xc+x,yc+y,c);
plot_circle(xc-x,yc+y,c);
plot_circle(xc+x,yc-y,c);
plot_circle(xc-x,yc-y,c);
plot_circle(xc+y,yc+x,c);
plot_circle(xc-y,yc+x,c);
plot_circle(xc+y,yc-x,c);
plot_circle(xc-y,yc-x,c);
if (p < 0) p = p + 4*x + 6;
else {
p = p + 4*(x-y) + 10;
y = y -1;
}
x++;
}
}
/* -------------------------------------------------------------------------
FrameBuffer_solidcircle(FrameBuffer f, int xc, int yc, int radius, Pixel c)
Create an filled circle
------------------------------------------------------------------------- */
#define fill_circle(x,y,c) \
x1 = xc - x; \
x2 = xc + x; \
FrameBuffer_horizontal(f,x1,x2,y,c);
void FrameBuffer_solidcircle(FrameBuffer *f, int xc, int yc, int radius, Pixel c) {
int xpixels, ypixels, x, y, p;
int x1,x2;
int xmin, ymin, xmax, ymax;
Pixel **pixels;
if (radius <= 0) return;
xpixels = f->width;
ypixels = f->height;
pixels = f->pixels;
xmin = f->xmin;
ymin = f->ymin;
xmax = f->xmax;
ymax = f->ymax;
x = 0;
y = radius;
p = 3-2*radius;
while (x <= y) {
fill_circle(x,yc+y,c);
fill_circle(x,yc-y,c);
fill_circle(y,yc+x,c);
fill_circle(y,yc-x,c);
if (p < 0) p = p + 4*x + 6;
else {
p = p + 4*(x-y) + 10;
y = y -1;
}
x++;
}
}
/* ------------------------------------------------------------------------
void FrameBuffer_setclip(f,xmin,ymin,xmax,ymax)
Set clipping region for plotting
------------------------------------------------------------------------ */
void FrameBuffer_setclip(FrameBuffer *f, int xmin, int ymin, int xmax, int ymax) {
if (xmin >= xmax) return;
if (ymin >= ymax) return;
if (xmin < 0) xmin = 0;
if (ymin < 0) ymin = 0;
if (xmax > (int) f->width) xmax = f->width;
if (ymax > (int) f->height) ymax = f->height;
f->xmin = xmin;
f->ymin = ymin;
f->xmax = xmax;
f->ymax = ymax;
}
/* ------------------------------------------------------------------------
void FrameBuffer_noclip(f)
Disable clipping region
------------------------------------------------------------------------ */
void FrameBuffer_noclip(FrameBuffer *f) {
f->xmin = 0;
f->ymin = 0;
f->xmax = f->width;
f->ymax = f->height;
}
/* ------------------------------------------------------------------------
FrameBuffer_zresize(FrameBuffer *f, int width, int height)
This function resizes the framebuffer's zbuffer. If none exist, it
creates a new one.
------------------------------------------------------------------------ */
void FrameBuffer_zresize(FrameBuffer *f, int width, int height) {
int i;
if (f->zbuffer) {
free((char *)f->zbuffer[0]);
free((char *)f->zbuffer);
}
f->zbuffer = (Zvalue **) malloc(height*sizeof(Zvalue *));
f->zbuffer[0] = (Zvalue *) malloc(height*width*sizeof(Zvalue));
for (i = 0; i < height; i++)
f->zbuffer[i] = f->zbuffer[0]+i*width;
}
/* ------------------------------------------------------------------------
FrameBuffer_zclear(FrameBuffer *f)
Clears the z-buffer for a particular frame. Sets all of the z-values to
ZMIN.
------------------------------------------------------------------------- */
void FrameBuffer_zclear(FrameBuffer *f) {
unsigned int i,j;
if (f) {
if (f->zbuffer) {
for (i = 0; i < f->width; i++)
for (j = 0; j < f->height; j++)
f->zbuffer[j][i] = ZMIN;
}
}
}
/* -------------------------------------------------------------------------
FrameBuffer_solidtriangle(FrameBuffer *f, int tx1, int ty2,
int tx2, int ty2,
int tx3, int ty3, Pixel color)
This function draws a 2D filled triangle.
General idea :
1. Transform the three points into screen coordinates
2. Order three points vertically on screen.
3. Check for degenerate cases (where 3 points are colinear).
4. Fill in the resulting triangle using horizontal lines.
-------------------------------------------------------------------------- */
void FrameBuffer_solidtriangle(FrameBuffer *f, int tx1, int ty1,
int tx2, int ty2,
int tx3, int ty3, Pixel color) {
int tempx, tempy;
double m1,m2,m3;
int y;
int ix1, ix2;
/* Figure out which point has the greatest "y" value */
if (ty2 > ty1) { /* Swap points 1 and 2 if 2 is higher */
tempx = tx1;
tempy = ty1;
tx1 = tx2;
ty1 = ty2;
tx2 = tempx;
ty2 = tempy;
}
if (ty3 > ty1) { /* Swap points 1 and 3 if 3 is higher */
tempx = tx1;
tempy = ty1;
tx1 = tx3;
ty1 = ty3;
tx3 = tempx;
ty3 = tempy;
}
if (ty3 > ty2) { /* Swap points 2 and 3 if 3 is higher */
tempx = tx2;
tempy = ty2;
tx2 = tx3;
ty2 = ty3;
tx3 = tempx;
ty3 = tempy;
}
/* Points are now order so that t_1 is the highest point, t_2 is the
middle point, and t_3 is the lowest point */
/* Check for degenerate cases here */
if ((ty1 == ty2) && (ty2 == ty3)) {
/* Points are aligned horizontally. Handle as a special case */
/* Just draw three lines using the outline color */
FrameBuffer_line(f,tx1,ty1,tx2,ty2,color);
FrameBuffer_line(f,tx1,ty1,tx3,ty3,color);
FrameBuffer_line(f,tx2,ty2,tx3,ty3,color);
} else {
if (ty2 < ty1) {
/* First process line segments between (x1,y1)-(x2,y2)
And between (x1,y1),(x3,y3) */
m1 = (double) (tx2 - tx1)/(double) (ty2 - ty1);
m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
y = ty1;
while (y >= ty2) {
/* Calculate x values from slope */
ix1 = (int) (m1*(y-ty1)+0.5) + tx1;
ix2 = (int) (m2*(y-ty1)+0.5) + tx1;
if (ix1 > ix2)
FrameBuffer_horizontal(f,ix2,ix1,y,color);
else
FrameBuffer_horizontal(f,ix1,ix2,y,color);
y--;
}
}
if (ty3 < ty2) {
/* Draw lower half of the triangle */
m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
m3 = (double) (tx3 - tx2)/(double)(ty3 - ty2);
y = ty2;
while (y >= ty3) {
ix1 = (int) (m3*(y-ty2)+0.5)+tx2;
ix2 = (int) (m2*(y-ty1)+0.5)+tx1;
if (ix1 > ix2)
FrameBuffer_horizontal(f,ix2,ix1,y,color);
else
FrameBuffer_horizontal(f,ix1,ix2,y,color);
y--;
}
}
}
}
/* -------------------------------------------------------------------------
FrameBuffer_interptriangle(FrameBuffer *f,
int tx1, int ty2, Pixel c1,
int tx2, int ty2, Pixel c2,
int tx3, int ty3, Pixel c3)
This function draws a filled triangle with color
interpolation.
General idea :
1. Transform the three points into screen coordinates
2. Order three points vertically on screen.
3. Check for degenerate cases (where 3 points are colinear).
4. Fill in the resulting triangle using horizontal lines.
5. Colors are interpolated between end points
-------------------------------------------------------------------------- */
void FrameBuffer_interptriangle(FrameBuffer *f,
int tx1, int ty1, Pixel c1,
int tx2, int ty2, Pixel c2,
int tx3, int ty3, Pixel c3) {
int tempx, tempy;
double m1,m2,m3;
double mc1,mc2,mc3;
Pixel ic1,ic2,tempc;
int y;
int ix1, ix2;
/* Figure out which point has the greatest "y" value */
if (ty2 > ty1) { /* Swap points 1 and 2 if 2 is higher */
tempx = tx1;
tempy = ty1;
tempc = c1;
tx1 = tx2;
ty1 = ty2;
c1 = c2;
tx2 = tempx;
ty2 = tempy;
c2 = tempc;
}
if (ty3 > ty1) { /* Swap points 1 and 3 if 3 is higher */
tempx = tx1;
tempy = ty1;
tempc = c1;
tx1 = tx3;
ty1 = ty3;
c1 = c3;
tx3 = tempx;
ty3 = tempy;
c3 = tempc;
}
if (ty3 > ty2) { /* Swap points 2 and 3 if 3 is higher */
tempx = tx2;
tempy = ty2;
tempc = c2;
tx2 = tx3;
ty2 = ty3;
c2 = c3;
tx3 = tempx;
ty3 = tempy;
c3 = tempc;
}
/* Points are now order so that t_1 is the highest point, t_2 is the
middle point, and t_3 is the lowest point */
/* Check for degenerate cases here */
if ((ty1 == ty2) && (ty2 == ty3)) {
/* Points are aligned horizontally. Handle as a special case */
/* Just draw three lines using the outline color */
if (tx2 > tx1)
FrameBuffer_horizontalinterp(f,tx1,tx2,ty1,c1,c2);
else
FrameBuffer_horizontalinterp(f,tx2,tx1,ty1,c2,c1);
if (tx3 > tx1)
FrameBuffer_horizontalinterp(f,tx1,tx3,ty1,c1,c3);
else
FrameBuffer_horizontalinterp(f,tx3,tx1,ty1,c3,c1);
if (tx3 > tx2)
FrameBuffer_horizontalinterp(f,tx2,tx3,ty2,c2,c3);
else
FrameBuffer_horizontalinterp(f,tx3,tx2,ty2,c3,c2);
} else {
/* First process line segments between (x1,y1)-(x2,y2)
And between (x1,y1),(x3,y3) */
if (ty2 < ty1) {
m1 = (double) (tx2 - tx1)/(double) (ty2 - ty1);
m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
mc1 = (c2 - c1)/(double) (ty2 - ty1);
mc2 = (c3 - c1)/(double) (ty3 - ty1);
y = ty1;
while (y >= ty2) {
/* Calculate x values from slope */
ix1 = (int) (m1*(y-ty1)+0.5) + tx1;
ix2 = (int) (m2*(y-ty1)+0.5) + tx1;
ic1 = (int) (mc1*(y-ty1) + c1);
ic2 = (int) (mc2*(y-ty1) + c1);
if (ix1 > ix2)
FrameBuffer_horizontalinterp(f,ix2,ix1,y,ic2,ic1);
else
FrameBuffer_horizontalinterp(f,ix1,ix2,y,ic1,ic2);
y--;
}
}
if (ty3 < ty2) {
/* Draw lower half of the triangle */
m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
mc2 = (c3 - c1)/(double) (ty3 - ty1);
m3 = (double) (tx3 - tx2)/(double)(ty3 - ty2);
mc3 = (c3 - c2)/(double) (ty3 - ty2);
y = ty2;
while (y >= ty3) {
ix1 = (int) (m3*(y-ty2)+0.5)+tx2;
ix2 = (int) (m2*(y-ty1)+0.5)+tx1;
ic1 = (int) (mc3*(y-ty2)+c2);
ic2 = (int) (mc2*(y-ty1)+c1);
if (ix1 > ix2)
FrameBuffer_horizontalinterp(f,ix2,ix1,y,ic2,ic1);
else
FrameBuffer_horizontalinterp(f,ix1,ix2,y,ic1,ic2);
y--;
}
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1