```/// LSU EE 7700-1 (Sp 2009), Graphics Processors
//
/// CPU-Only Demo 1: One Triangle

// \$Id:\$

/// Purpose
//
//   Routine render_one_triangle demonstrates the most basic 3D
//   techniques: how to project a triangle specified in object space
//   onto a frame buffer.

/// To compile and run:
//
//     make
//     demo-1-one-triangle

//
//   File coord.h on coordinate and matrix objects and operations.

#include <stdio.h>
#include <strings.h>
#include <stdlib.h>

#include "frame_buffer.h"
#include "coord.h"

inline float
slope(pCoor& a, pCoor& b)
{
return ( b.x - a.x ) / fabs( b.y - a.y );
}

void
render_one_triangle(pFrame_Buffer &frame_buffer)
{
// This routine will be called automatically each time the frame
// buffer needs to be painted.

///
/// Determined by Hardware
///

const int win_width = frame_buffer.get_width();
// const int win_height = frame_buffer.get_height(); // Uncomment if needed.

// Address of start of frame buffer.
//
int32_t* const f_buffer = frame_buffer.get_buffer();

///
/// Determined by Application
///

// Coordinates of triangle to render, in object space.
//
// ( Just one triangle. )
//
pCoor c0(10,9,-3);
pCoor c1(5,10,-3);
pCoor c2(6,17,-6);

///
/// Determined by Application
///

// Location of viewer, transformation to eye coordinates.
//
// Transform object coordinates to eye space: viewer is at (0,0,0)
// looking in -z direction with +y straight up and +x pointing to
// right.

pMatrix_Translate center_eye(-6,-10,0);

// Perspective projection, transformation to clip coordinates.
//
// Transform eye coordinates to clip coordinates: each visible
// coordinate in [-1,1].

pMatrix_Frustum frustum(12,20,1,20);

// Transform to window coordinates.
//
// Transform device coordinates (homogenized clip coordinates) to
// window coordinates: x in [0,win_width) and y in [0,win_height).

pMatrix_Translate center_window(1,1,0);
pMatrix_Scale scale(win_width/2);

pMatrix transform = scale * center_window * frustum * center_eye;

//
// Apply transformation to transform triangle coordinates from
// object space to clip space.
//
pCoor c0w = transform * c0;  c0w.homogenize();
pCoor c1w = transform * c1;  c1w.homogenize();
pCoor c2w = transform * c2;  c2w.homogenize();

// For convenience and performance, convert y coordinates to integers.
//
const int c0y = (int)c0w.y;
const int c1y = (int)c1w.y;
const int c2y = (int)c2w.y;

// Enforce y ordering: c0w.y < c1w.y < c2w.y
//
if ( c0y >= c1y || c1y >= c2y )
{fprintf(stderr,"Ordering violation."); exit(1);}

///
/// Rasterization
///

float x_02 = c0w.x;   // Call this the left (side of triangle) position.
float x_012 = c0w.x;  // Call this the right position.
float dx_02 = slope(c0w,c2w);
float dx_012 = slope(c0w,c1w);
// Note: if direction -1 then what is called "left" is really right, etc.
const int direction = dx_02 < dx_012 ? 1 : -1;

// Position of first row in frame buffer to write.
//
int fb_line_idx = c0y * win_width;

// Outer loop proceeds from bottom to top.
//
for ( int y = c0y;  y < c2y;  y++ )
{
// Inner loop proceeds from "left" to "right"
//
for ( int x = (int)x_02; x != (int)x_012; x += direction )
{
// Write a green pixel.
f_buffer[fb_line_idx + x] = 0xff00;
}

// Change slope if point c1 reached.
//
if ( y == c1y ) dx_012 = slope(c1w,c2w);

// Move down by one pixel.
//
fb_line_idx += win_width;  // Advance frame buffer pointer to next row.
x_02 += dx_02;             // Advance "left" x position.
x_012 += dx_012;           // Advance "right" x position.
}
}

int
main(int argc, char **argv)
{
// Instantiate frame buffer simulation object.
//
pFrame_Buffer frame_buffer(argc,argv);

// Tell frame buffer simulator to call render_one_triangle.
//
frame_buffer.show(render_one_triangle);

return 0;
}
```