#include #include #include #include #include #include "lowlevel.h" /* Variables local to this file */ int W; /* width of frame buffer */ int H; /* height of frame buffer */ color current; /* current color */ vertex* v[3]; /* the array of vertices we store away */ int ind = 0; /* index of current vertex in the array */ /*****************************************************************************/ /* Fake frame buffer - Use an array of 3 GLubytes per pixel as an imitiation frame buffer. We'll color the pixels of this array to draw a triangle */ /* pointer to fake frame buffer */ GLubyte* fb; /* Allocate storage for fake frame buffer, and fill it with all white */ void initFakeFrameBuffer(int w, int h) { int i; fb = (GLubyte*) malloc(W*H*3*sizeof(GLubyte)); for (i=0; ix = x; v->y = y; return(v); } /* Save a triangle vertex */ void setVertex(int x, int y) { if (ind < 3) { v[ind] = newVertex(x,y); ind++; } } /* Start a new triangle */ void beginTriangle() { ind = 0; } /*****************************************************************************/ /* Actual triangle drawing code */ /* Makes the data structure for the edge between bottom point b and top point t */ edge* newEdge(vertex* b, vertex* t) { edge* e; int dx,dy; e = (edge*) malloc(sizeof(edge)); e->x = b->x; /* edge passes through bottom vertex */ /* D = ax + by +c - must be zero since edge goes through bottom vertex */ e->D = 0; dx = t->x - b->x; dy = t->y - b->y; if (dy == 0) {} /* doesn't matter, edge will never be used */ else { e->xSmallStep = dx/dy; /* integer divide */ if (dx < 0) { /* positive or negative slope? */ e->xSmallStep --; } e->a = -dy; e->incDSmall = e->a * e->xSmallStep + dx; } return(e); } /* Called in second-to-innermost loop: Moves the x position of the edge at each row */ void yInc(edge* e) { e->x += e->xSmallStep; e->D += e->incDSmall; /* edge moves, increasing error */ if (e->D > 0) { /* lots of error, take a big step */ e->x++; /* pixel moves a bit more */ e->D += e->a; /* decreasing error (a is negative) */ } } /* Innermost loop - draws one row of a triangle */ void drawRow(int left, int right, int y) { int x = left; while (x < right) { /* draw pixel using macro (see lowlevel.h) */ DRAWPIX(x,y,current.red,current.green,current.blue); x++; } } /* Draws a triangle with bottom vertex b, top vertex t, and point m to the left of line from b to t */ void drawLeftTriangle(vertex* b, vertex* t, vertex* m) { edge* lEdge; edge* rEdge; int y; /* draw rows from bottom-middle edge to bottom-top edge */ lEdge = newEdge(b,m); rEdge = newEdge(b,t); //interpolate edge colors for (y=b->y; yy; y++) { drawRow(lEdge->x,rEdge->x,y); yInc(lEdge); yInc(rEdge); } free(lEdge); /* now rows from middle-top edge to bottom-top edge */ lEdge = newEdge(m,t); for (; y<=t->y;y++) { drawRow(lEdge->x,rEdge->x,y); yInc(lEdge); yInc(rEdge); } free(lEdge); free(rEdge); } /* Draws a triangle with bottom vertex b, top vertex t, and point m to the right of line from b to t */ void drawRightTriangle(vertex* b, vertex* t, vertex* m) { edge* lEdge; edge* rEdge; int y; /* Draw rows from bottom-top edge to bottom-middle edge */ lEdge = newEdge(b,t); rEdge = newEdge(b,m); for (y=b->y; yy; y++) { drawRow(lEdge->x,rEdge->x, y); yInc(lEdge); yInc(rEdge); } free(rEdge); /* Draw rows from bottom-top edge to middle-top edge */ rEdge = newEdge(m,t); for (; y<=t->y;y++) { drawRow(lEdge->x,rEdge->x, y); yInc(lEdge); yInc(rEdge); } free(lEdge); free(rEdge); } /* Main triangle drawing function */ void endTriangle() { vertex* b; vertex* t; vertex* m; int flag = 0x0; /* bit flags for tests */ int A,B,C; /* implcit line coefficients */ /* First, figure out which vertex should be b (bottom vertex), t (top vertex) and m (middle vertex) */ if (v[0]->y < v[1]->y) flag = 0x1; flag <<= 1; /* shift over one bit */ if (v[1]->y < v[2]->y) flag |= 0x1; flag <<= 1; if (v[2]->y < v[0]->y) flag |= 0x1; switch (flag) { case 0x1: /* 001 */ t = v[0]; m = v[1]; b = v[2]; break; case 0x2: /* 010 */ m = v[0]; b = v[1]; t = v[2]; break; case 0x3: /* 011 */ t = v[0]; b = v[1]; m = v[2]; break; case 0x4: /* 100 */ b = v[0]; t = v[1]; m = v[2]; break; case 0x5: /* 101 */ m = v[0]; t = v[1]; b = v[2]; break; case 0x6: /* 110 */ b = v[0]; m = v[1]; t = v[2]; break; default: printf("Bad triangle! \n"); /* only gets here if all vertices equal */ return; } /* Now test to see if m is right or left of line bt */ /* Use implicit line equation */ A = b->y - t->y; B = t->x - b->x; C = b->x * t->y - t->x * b->y; if (A*m->x + B*m->y + C > 0) drawLeftTriangle(b,t,m); else drawRightTriangle(b,t,m); free(v[0]); free(v[1]); free(v[2]); }