The first thing I implemented was a triangle fill function. I pretty much just started with the "brute-force" approach, which was basically my own best guess at an implementation. I basically started by sorting the points of the triangle by their Y screenspace coordinates. I divided my triangle in half (horizontally at the mid-point) so that I could scan convert each half separately. I won't go into the details of the algorithm (you can find many articles on basic triangle filling online) but essetially, i'd iterate through each scanline of the triangle half and fill in pixels within the bounds of the triangle edges. On my very first try, triangles were generally looking right, except that on occasion, the triangles would warp out of shape. I realized that my inverse slope calculations were off because I was using floating point coordinates instead of converting to discreet integer values beforehand.
Things were looking quite great at this point, but there seemed to be some noticeable overdraw in some places. After reading up on a few rasterization articles online, I discovered that I wasn't properly using a "Fill convention". For those who don't know, its just a standard way of filling pixels such that adjacent primitives will not overlap or leave a gap between each other. The used whats known as a "top-left" fill convention. This basically means that all pixels that intersect the top-left edges of the primitive will be filled, but pixels intersecting other edges will not be.
The next big thing to add is some depth testing.
Here are some progress pics: