summaryrefslogtreecommitdiff
path: root/src/triangle.h
diff options
context:
space:
mode:
authorSimponic <loganthebean222@gmail.com>2020-08-04 23:36:21 -0600
committerSimponic <loganthebean222@gmail.com>2020-08-04 23:36:21 -0600
commitebd81999b71ada201a316060fa47a7a66a277935 (patch)
tree930be8337e1144ba227bedb3e72e4473309c28e8 /src/triangle.h
parentb323ae0ca067deb0a48e3d9088160383d698a28f (diff)
downloadsimple3dengine-ebd81999b71ada201a316060fa47a7a66a277935.tar.gz
simple3dengine-ebd81999b71ada201a316060fa47a7a66a277935.zip
Added files
Diffstat (limited to 'src/triangle.h')
-rw-r--r--src/triangle.h139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/triangle.h b/src/triangle.h
new file mode 100644
index 0000000..9ef4de4
--- /dev/null
+++ b/src/triangle.h
@@ -0,0 +1,139 @@
+#include "fixed.h"
+#include "defs.h"
+#include "vertex.h"
+#include "plane.h"
+#include "color.h"
+#include <math.h>
+
+#ifndef TRIANGLE_H
+#define TRIANGLE_H
+
+typedef struct TRIANGLE {
+ int v0;
+ int v1;
+ int v2;
+ COLOR color;
+} TRIANGLE;
+
+static inline TRIANGLE createTriangle(int v0, int v1, int v2, COLOR color) {
+ // Create a triangle from data
+ TRIANGLE temp;
+ temp.v0 = v0;
+ temp.v1 = v1;
+ temp.v2 = v2;
+ temp.color = color;
+ return temp;
+}
+
+static inline VERTEX computeNormal(VERTEX *vertices, TRIANGLE *triangle) {
+ // Use cross product to compute a normal vector to a triangle
+ VERTEX normal, v1, v2;
+
+ // Compute vectors for cross product
+ v1.x = (vertices + triangle->v1)->x - (vertices + triangle->v0)->x;
+ v1.y = (vertices + triangle->v1)->y - (vertices + triangle->v0)->y;
+ v1.z = (vertices + triangle->v1)->z - (vertices + triangle->v0)->z;
+ v2.x = (vertices + triangle->v2)->x - (vertices + triangle->v0)->x;
+ v2.y = (vertices + triangle->v2)->y - (vertices + triangle->v0)->y;
+ v2.z = (vertices + triangle->v2)->z - (vertices + triangle->v0)->z;
+
+ // Compute cross product
+ normal.x = fixed_multiply(v1.y, v2.z) - fixed_multiply(v1.z, v2.y);
+ normal.y = fixed_multiply(v1.z, v2.x) - fixed_multiply(v1.x, v2.z);
+ normal.z = fixed_multiply(v1.x, v2.y) - fixed_multiply(v1.y, v2.x);
+
+ return normal;
+}
+
+static inline void drawTriangle(POINT *v1, POINT *v2, POINT *v3, COLOR *clr, SDL_Renderer *renderer) {
+ // Draw a triangle to screen from data
+ int x1, x2, x3, y1, y2, y3;
+ SDL_SetRenderDrawColor(renderer, clr->red, clr->green, clr->blue, 255);
+ x1 = (v1->x >> FIX_SHIFT) + WINDOW_WIDTH / 2;
+ x2 = (v2->x >> FIX_SHIFT) + WINDOW_WIDTH / 2;
+ x3 = (v3->x >> FIX_SHIFT) + WINDOW_WIDTH / 2;
+ y1 = WINDOW_HEIGHT / 2 - (v1->y >> FIX_SHIFT) - 1;
+ y2 = WINDOW_HEIGHT / 2 - (v2->y >> FIX_SHIFT) - 1;
+ y3 = WINDOW_HEIGHT / 2 - (v3->y >> FIX_SHIFT) - 1;
+
+ SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
+ SDL_RenderDrawLine(renderer, x1, y1, x3, y3);
+ SDL_RenderDrawLine(renderer, x2, y2, x3, y3);
+}
+
+static inline void fillBottomFlatTriangle(POINT *v1, POINT *v2, POINT *v3, COLOR *clr, SDL_Renderer *renderer) {
+ // Ported from sunshine2k.de
+ SDL_SetRenderDrawColor(renderer, clr->red, clr->green, clr->blue, 255);
+ FIXED iSlope1 = fixed_divide(v2->x - v1->x, v2->y - v1->y);
+ FIXED iSlope2 = fixed_divide(v3->x - v1->x, v3->y - v1->y);
+
+ FIXED curx1 = v1->x;
+ FIXED curx2 = curx1;
+ int scanline;
+ for (int scanlineY = ((v1->y + (1 << FIX_SHIFT)) >> FIX_SHIFT); scanlineY <= (v2->y >> FIX_SHIFT); scanlineY++) {
+ scanline = WINDOW_HEIGHT / 2 - scanlineY - 1;
+ SDL_RenderDrawLine(renderer, ((curx1 >> FIX_SHIFT) + WINDOW_WIDTH / 2),
+ scanline, ((curx2 >> FIX_SHIFT) + WINDOW_WIDTH / 2), scanline
+ );
+ curx1 += iSlope1;
+ curx2 += iSlope2;
+ }
+}
+
+static inline void fillTopFlatTriangle(POINT *v1, POINT *v2, POINT *v3, COLOR *clr, SDL_Renderer *renderer) {
+ // Ported from sunshine2k.de
+ SDL_SetRenderDrawColor(renderer, clr->red, clr->green, clr->blue, 255);
+ FIXED iSlope1 = fixed_divide(v3->x - v1->x, v3->y - v1->y);
+ FIXED iSlope2 = fixed_divide(v3->x - v2->x, v3->y - v2->y);
+
+ FIXED curx1 = v3->x;
+ FIXED curx2 = curx1;
+ int scanline;
+ for (int scanlineY = ((v3->y - (1 << FIX_SHIFT)) >> FIX_SHIFT); scanlineY > (v1->y >> FIX_SHIFT); scanlineY--) {
+ scanline = WINDOW_HEIGHT / 2 - scanlineY - 1;
+ SDL_RenderDrawLine(renderer, ((curx1 >> FIX_SHIFT) + WINDOW_WIDTH / 2),
+ scanline, ((curx2 >> FIX_SHIFT) + WINDOW_WIDTH / 2), scanline
+ );
+ curx1 -= iSlope1;
+ curx2 -= iSlope2;
+ }
+}
+
+static inline void drawFilledTriangle(POINT *v1, POINT *v2, POINT *v3, COLOR *clr, SDL_Renderer *renderer) {
+ // Draw a filled triangle at points
+ // Sort the vertex points
+
+ POINT p1, p2, p3;
+ p1 = *v1;
+ p2 = *v2;
+ p3 = *v3;
+ if (p1.y > p2.y) {
+ swapPoint(&p1, &p2);
+ }
+ if (p1.y > p3.y) {
+ swapPoint(&p1, &p3);
+ }
+ if (p2.y > p3.y) {
+ swapPoint(&p2, &p3);
+ }
+
+ // Check if bottom of triangle is flat
+ if (p2.y == p3.y) {
+ fillBottomFlatTriangle(&p1, &p2, &p3, clr, renderer);
+ }
+ // Check if top of triangle is flat
+ else if (p1.y == p2.y) {
+ fillTopFlatTriangle(&p1, &p2, &p3, clr, renderer);
+ }
+ else {
+ // General case where neither top or bottom is flat
+ POINT p4 = createPoint(
+ p1.x + fixed_multiply(fixed_divide(p2.y - p1.y, p3.y - p1.y), (p3.x - p1.x))
+ ,p2.y
+ );
+ fillBottomFlatTriangle(&p1, &p2, &p4, clr, renderer);
+ fillTopFlatTriangle(&p2, &p4, &p3, clr, renderer);
+ }
+}
+
+#endif // TRIANGLE_H