From f642b0ec02a6bdd1ddf1eea5bdce66c3dd4d6c10 Mon Sep 17 00:00:00 2001 From: Austin Morlan Date: Wed, 5 Sep 2018 18:53:11 -0700 Subject: [PATCH] Add triangle filling with a solid color --- Makefile | 4 +- include/color.h | 25 +++++++ include/geometry.h | 10 +++ src/engine.cpp | 10 +++ src/geometry.cpp | 164 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 include/color.h create mode 100644 src/geometry.cpp diff --git a/Makefile b/Makefile index 9c1f2ea..657cada 100644 --- a/Makefile +++ b/Makefile @@ -36,10 +36,10 @@ WARNINGS_OFF=-Wno-missing-braces -Wno-gnu-anonymous-struct -Wno-old-style-cast\ CFLAGS=$(D) $(O) -std=c++11 $(WARNINGS_ON) $(WARNINGS_OFF) -I$(INCLUDE_DIR) LIBS=-lSDL2 -_HEADERS = engine.h geometry.h loader.h platform.h point.h transform.h util.h +_HEADERS = color.h engine.h geometry.h loader.h platform.h point.h transform.h util.h HEADERS = $(patsubst %,$(INCLUDE_DIR)/%,$(_HEADERS)) -_OBJS = engine.o loader.o main.o platform.o transform.o +_OBJS = engine.o geometry.o loader.o main.o platform.o transform.o OBJS = $(patsubst %,$(BUILD_DIR)/%,$(_OBJS)) $(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp $(HEADERS) diff --git a/include/color.h b/include/color.h new file mode 100644 index 0000000..1fc67fb --- /dev/null +++ b/include/color.h @@ -0,0 +1,25 @@ +#ifndef COLOR_H + +#include + + +struct ColorU32 +{ + union + { + struct + { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; + }; + + uint32_t u32; + }; +}; + + +#define COLOR_H +#endif + diff --git a/include/geometry.h b/include/geometry.h index a3959d4..5083dde 100644 --- a/include/geometry.h +++ b/include/geometry.h @@ -1,9 +1,11 @@ #ifndef GEOMETRY_H #include "point.h" +#include #include +// STRUCTURES struct Face { unsigned int vertIndex[3]; @@ -33,6 +35,14 @@ struct Mesh }; +// PUBLIC FUNCTIONS +void FillTriangle( + uint32_t *buffer, int width, uint32_t color, + float x0, float y0, + float x1, float y1, + float x2, float y2); + + #define GEOMETRY_H #endif diff --git a/src/engine.cpp b/src/engine.cpp index d82ceb4..cc82c35 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -1,5 +1,7 @@ #include "camera.h" +#include "color.h" #include "engine.h" +#include "geometry.h" #include "loader.h" #include "matrix.h" #include "transform.h" @@ -73,6 +75,14 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input) unsigned int v0 = mesh.faces[f].vertIndex[0]; unsigned int v1 = mesh.faces[f].vertIndex[1]; unsigned int v2 = mesh.faces[f].vertIndex[2]; + + ColorU32 white = {0xff,0xff,0xff,0xff}; + + FillTriangle( + buffer.pixels, buffer.width, white.u32, + mesh.vertsTransformed[v0].x, mesh.vertsTransformed[v0].y, + mesh.vertsTransformed[v1].x, mesh.vertsTransformed[v1].y, + mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y); } } diff --git a/src/geometry.cpp b/src/geometry.cpp new file mode 100644 index 0000000..82ce269 --- /dev/null +++ b/src/geometry.cpp @@ -0,0 +1,164 @@ +#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; + } +} +