/// 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 /// More Information // // 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; }