165 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			165 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | #include "color.h"
 | ||
|  | #include "geometry.h"
 | ||
|  | #include "util.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // MACROS
 | ||
|  | #define DrawPixel(buffer, width, color, x, y)\
 | ||
|  | {\ | ||
|  |     buffer[width * y + x] = color;\ | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // PRIVATE PROTOTYPES
 | ||
|  | static void FillTriangleFlatBottom( | ||
|  |         uint32_t *buffer, int width, uint32_t color, | ||
|  |         float x0, float y0, | ||
|  |         float x1, float y1, | ||
|  |         float x2, float y2); | ||
|  | 
 | ||
|  | static void FillTriangleFlatTop( | ||
|  |         uint32_t *buffer, int width, uint32_t color, | ||
|  |         float x0, float y0, | ||
|  |         float x1, float y1, | ||
|  |         float x2, float y2); | ||
|  | 
 | ||
|  | 
 | ||
|  | // PUBLIC FUNCTIONS
 | ||
|  | void FillTriangle( | ||
|  |         uint32_t *buffer, int width, uint32_t color, | ||
|  |         float x0, float y0, | ||
|  |         float x1, float y1, | ||
|  |         float x2, float y2) | ||
|  | { | ||
|  |     // Horizontal or vertical
 | ||
|  |     if ((FLOAT_EQUAL(x0,x1) && FLOAT_EQUAL(x1, x2)) | ||
|  |         || (FLOAT_EQUAL(y0, y1) && FLOAT_EQUAL(y1, y2))) | ||
|  |     { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     // Sort in ascending Y order
 | ||
|  |     float temp; | ||
|  |     if (y0 > y1) | ||
|  |     { | ||
|  |         SWAP(x0, x1, temp); | ||
|  |         SWAP(y0, y1, temp); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (y0 > y2) | ||
|  |     { | ||
|  |         SWAP(x0, x2, temp); | ||
|  |         SWAP(y0, y2, temp); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (y1 > y2) | ||
|  |     { | ||
|  |         SWAP(x1, x2, temp); | ||
|  |         SWAP(y1, y2, temp); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     // Flat top triangle
 | ||
|  |     if (FLOAT_EQUAL(y0, y1)) | ||
|  |     { | ||
|  |         FillTriangleFlatTop(buffer, width, color, x0, y0, x1, y1, x2, y2); | ||
|  |     } | ||
|  | 
 | ||
|  |     // Flat bottom triangle
 | ||
|  |     else if (FLOAT_EQUAL(y1, y2)) | ||
|  |     { | ||
|  |         FillTriangleFlatBottom(buffer, width, color, x0, y0, x1, y1, x2, y2); | ||
|  |     } | ||
|  | 
 | ||
|  |     // Other - decompose into two triangles
 | ||
|  |     else | ||
|  |     { | ||
|  |         // Calculate x coordinate at point of decomposition using intercept theorem
 | ||
|  |         // New y is the same as y1
 | ||
|  |         float x3 = x0 + (((y1 - y0) / (y2 - y0)) * (x2 - x0)); | ||
|  |         float y3 = y1; | ||
|  | 
 | ||
|  |         FillTriangleFlatBottom(buffer, width, color, x0, y0, x1, y1, x3, y3); | ||
|  |         FillTriangleFlatTop(buffer, width, color, x1, y1, x3, y3, x2, y2); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // PRIVATE FUNCTIONS
 | ||
|  | static void FillTriangleFlatBottom( | ||
|  |         uint32_t *buffer, int width, uint32_t color, | ||
|  |         float x0, float y0, | ||
|  |         float x1, float y1, | ||
|  |         float x2, float y2) | ||
|  | { | ||
|  |     if (x2 < x1) | ||
|  |     { | ||
|  |         float temp; | ||
|  |         SWAP(x1, x2, temp); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     // Top-left fill convention
 | ||
|  |     float dxdy_left = (x1 - x0) / (y1 - y0); | ||
|  |     float dxdy_right = (x2 - x0) / (y2 - y0); | ||
|  |     int yStart = (int)ceilf(y0); | ||
|  |     int yEnd = (int)ceilf(y2) - 1; | ||
|  |     float xStart = x0 + dxdy_left * (yStart - y0); | ||
|  |     float xEnd = x0 + dxdy_right * (yStart - y0); | ||
|  | 
 | ||
|  | 
 | ||
|  |     // Fill
 | ||
|  |     for (int y = yStart; y <= yEnd; ++y) | ||
|  |     { | ||
|  |         int xStartInt = (int)xStart; | ||
|  |         int xEndInt = (int)xEnd; | ||
|  | 
 | ||
|  |         for (int x = xStartInt; x <= xEndInt; ++x) | ||
|  |         { | ||
|  |             DrawPixel(buffer, width, color, x, y); | ||
|  |         } | ||
|  | 
 | ||
|  |         xStart += dxdy_left; | ||
|  |         xEnd += dxdy_right; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | static void FillTriangleFlatTop( | ||
|  |         uint32_t *buffer, int width, uint32_t color, | ||
|  |         float x0, float y0, | ||
|  |         float x1, float y1, | ||
|  |         float x2, float y2) | ||
|  | { | ||
|  |     if (x1 < x0) | ||
|  |     { | ||
|  |         float temp; | ||
|  |         SWAP(x1, x0, temp); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     // Top-left fill convention
 | ||
|  |     float dxdy_left = (x2 - x0) / (y2 - y0); | ||
|  |     float dxdy_right = (x2 - x1) / (y2 - y1); | ||
|  |     int yStart = (int)ceilf(y0); | ||
|  |     int yEnd = (int)ceilf(y2) - 1; | ||
|  |     float xStart = x0 + dxdy_left * (yStart - y0); | ||
|  |     float xEnd = x1 + dxdy_right * (yStart - y0); | ||
|  | 
 | ||
|  | 
 | ||
|  |     // Fill
 | ||
|  |     for (int y = yStart; y <= yEnd; ++y) | ||
|  |     { | ||
|  |         int xStartInt = (int)xStart; | ||
|  |         int xEndInt = (int)xEnd; | ||
|  | 
 | ||
|  |         for (int x = xStartInt; x <= xEndInt; ++x) | ||
|  |         { | ||
|  |             DrawPixel(buffer, width, color, x, y); | ||
|  |         } | ||
|  | 
 | ||
|  |         xStart += dxdy_left; | ||
|  |         xEnd += dxdy_right; | ||
|  |     } | ||
|  | } | ||
|  | 
 |