summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile41
-rw-r--r--src/color.h19
-rw-r--r--src/defs.h39
-rw-r--r--src/fixed.h74
-rw-r--r--src/instance.c63
-rw-r--r--src/instance.h24
-rw-r--r--src/main.c111
-rw-r--r--src/model.c57
-rw-r--r--src/model.h21
-rw-r--r--src/plane.h21
-rw-r--r--src/pt.h36
-rw-r--r--src/triangle.h139
-rw-r--r--src/vertex.h112
13 files changed, 757 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..4a3fac7
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,41 @@
+# A simple Makefile for compiling small SDL projects
+
+# set the compiler
+CC := gcc
+
+# set the compiler flags
+CFLAGS := `sdl2-config --libs --cflags` -ggdb3 -O0 --std=c99 -Wall -lSDL2_image -lm -g
+# add header files here
+HDRS := color.h defs.h fixed.h model.h triangle.h vertex.h model.h instance.h
+
+# add source files here
+SRCS := main.c model.c instance.c
+
+# generate names of object files
+OBJS := $(SRCS:.c=.o)
+
+# name of executable
+EXEC := a.out
+
+# default recipe
+all: $(EXEC)
+
+showfont: showfont.c Makefile
+ $(CC) -o $@ $@.c $(CFLAGS) $(LIBS)
+
+glfont: glfont.c Makefile
+ $(CC) -o $@ $@.c $(CFLAGS) $(LIBS)
+
+# recipe for building the final executable
+$(EXEC): $(OBJS) $(HDRS) Makefile
+ $(CC) -o $@ $(OBJS) $(CFLAGS)
+
+# recipe for building object files
+#$(OBJS): $(@:.o=.c) $(HDRS) Makefile
+# $(CC) -o $@ $(@:.o=.c) -c $(CFLAGS)
+
+# recipe to clean the workspace
+clean:
+ rm -f $(EXEC) $(OBJS)
+
+.PHONY: all clean
diff --git a/src/color.h b/src/color.h
new file mode 100644
index 0000000..11516f0
--- /dev/null
+++ b/src/color.h
@@ -0,0 +1,19 @@
+#ifndef COLOR_H
+#define COLOR_H
+
+typedef struct COLOR {
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+} COLOR;
+
+static inline COLOR createColor(unsigned char red, unsigned char green, unsigned char blue) {
+ // Create a color given values
+ COLOR temp;
+ temp.red = red;
+ temp.green = green;
+ temp.blue = blue;
+ return temp;
+}
+
+#endif // COLOR_H
diff --git a/src/defs.h b/src/defs.h
new file mode 100644
index 0000000..fb1687c
--- /dev/null
+++ b/src/defs.h
@@ -0,0 +1,39 @@
+#include "color.h"
+#include <SDL2/SDL.h>
+
+#ifndef DEFS_H
+#define DEFS_H
+
+#define WINDOW_WIDTH 960
+#define WINDOW_HEIGHT 640
+
+#define ZPlane 1
+#define viewport_width 3
+#define viewport_height 2
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+typedef signed char s8;
+typedef signed short s16;
+typedef signed int s32;
+
+static inline void drawPixel(int x, int y, COLOR clr, SDL_Renderer *renderer) {
+ // Draw pixel to screen
+ SDL_SetRenderDrawColor(renderer, clr.red, clr.green, clr.blue, 255);
+ SDL_RenderDrawPoint(renderer, WINDOW_WIDTH / 2 + x, WINDOW_HEIGHT / 2 - y - 1);
+}
+
+static inline void updateDisplay(SDL_Renderer *renderer) {
+ // Update a SDL renderer
+ SDL_RenderPresent(renderer);
+}
+
+static inline void fillDisplay(SDL_Renderer *renderer, COLOR clr) {
+ // Fill a renderer with color
+ SDL_SetRenderDrawColor(renderer, clr.red, clr.blue, clr.green, 255);
+ SDL_RenderClear(renderer);
+}
+
+#endif // DEFS_H
diff --git a/src/fixed.h b/src/fixed.h
new file mode 100644
index 0000000..297110e
--- /dev/null
+++ b/src/fixed.h
@@ -0,0 +1,74 @@
+#include "defs.h"
+
+#ifndef FIXED_H
+#define FIXED_H
+
+#define FIX_SHIFT 8
+#define HALF_FIX_SHIFT 4
+#define FIX_SCALE ( 1 << FIX_SHIFT )
+#define FIX_SCALE_FLOAT ((float)(FIX_SCALE))
+
+typedef s32 FIXED;
+
+static inline FIXED fixed_OverMultiply(FIXED a, FIXED b) {
+ // This should multiply two fixed-point numbers sacrificing a little
+ // accuracy in exchange for less chance of an overflow
+
+ return ((a >> HALF_FIX_SHIFT) * (b >> HALF_FIX_SHIFT));
+}
+
+static inline FIXED fixed_multiply (FIXED a, FIXED b) {
+ // Multiply two fixed numbers. Possibility of overflow.
+ return (a * b) >> FIX_SHIFT;
+}
+
+static inline FIXED fixed_divide(FIXED a, FIXED b) {
+ if (b != 0){
+ return (a * FIX_SCALE) / b;
+ }
+ else {
+ return 100000 << FIX_SHIFT;
+ }
+}
+
+static inline FIXED float_to_fixed(float a) {
+ // Convert a float to fixed point
+ return ((FIXED)(a * FIX_SCALE_FLOAT));
+}
+
+static inline float fixed_to_float(FIXED a) {
+ // Convert fixed point to float
+ return (a / FIX_SCALE_FLOAT);
+}
+
+static inline void swapFixed(FIXED *a, FIXED *b) {
+ // Swap two fixed point integer pointers
+ FIXED temp;
+ temp = *a;
+ *a = *b;
+ *b = temp;
+}
+
+static inline FIXED fixed_sqrt(FIXED a, int iterations) {
+ // Calculate square root of a fixed-point number using Binary-Search
+ FIXED low = 0;
+ FIXED high = a;
+ FIXED mid;
+ FIXED midSquared;
+ for (int i = 0; i < iterations; i++) {
+ mid = fixed_divide((low + high), 2 << FIX_SHIFT);
+ midSquared = fixed_OverMultiply(mid, mid);
+ if (midSquared == a) {
+ return mid;
+ }
+ else if (midSquared > a) {
+ high = mid;
+ }
+ else {
+ low = mid;
+ }
+ }
+ return mid;
+}
+
+#endif // FIXED_H
diff --git a/src/instance.c b/src/instance.c
new file mode 100644
index 0000000..e1462b4
--- /dev/null
+++ b/src/instance.c
@@ -0,0 +1,63 @@
+#include "instance.h"
+
+void renderInstance(INSTANCE *instance, SDL_Renderer *renderer) {
+ // Render an instance
+ // Array for projected points
+ POINT projected[instance->model->vertices_length];
+ // Pointers for transformed vertices
+ VERTEX *transformed = malloc(sizeof(VERTEX) * instance->model->vertices_length);
+
+ for (int i = 0; i < instance->model->vertices_length; i++) {
+ // Apply translation and rotation
+ *(transformed + i) = *(instance->model->vertices + i);
+ applyXRotation((transformed + i), *instance->xRotation);
+ applyYRotation((transformed + i), *instance->yRotation);
+ applyZRotation((transformed + i), *instance->zRotation);
+ *(transformed + i) = addVertices((transformed + i), instance->position);
+ // Project vertices
+ projected[i] = projectVertex(transformed + i);
+ }
+ VERTEX n, copyV;
+ // A directional light source
+ VERTEX playerLight = createVertex(0, 0, -1 << FIX_SHIFT);
+ normalizeVertex(&playerLight);
+ TRIANGLE *addr;
+ FIXED intensity;
+ COLOR clr;
+ for (int i = 0; i < instance->model->triangles_length; i++) {
+ // Render the triangle
+ addr = (instance->model->triangles + i);
+ n = computeNormal(transformed, addr);
+ normalizeVertex(&n);
+ // Intensity of light on the triangle
+ intensity = fixed_multiply(dotProduct(&n, &playerLight) + (1 << FIX_SHIFT), 127 << FIX_SHIFT);
+ copyV = *(transformed + addr->v2);
+ normalizeVertex(&copyV);
+
+ // Grayscale color of the triangle from light intensity
+ clr = createColor(intensity >> FIX_SHIFT, intensity >> FIX_SHIFT, intensity >> FIX_SHIFT);
+
+ if (dotProduct(&n, &copyV) < 0) {
+ // The triangle is viewable by the camera
+ drawFilledTriangle(
+ &(projected[addr->v0]),
+ &(projected[addr->v1]),
+ &(projected[addr->v2]),
+ &clr,
+ renderer
+ );
+
+ }
+ }
+ transformed = NULL;
+ free(transformed);
+}
+
+void destroyInstance(INSTANCE *instance) {
+ // Free memory from instance
+ instance->model = NULL;
+ instance->position = NULL;
+ instance->zRotation = NULL;
+ instance->xRotation = NULL;
+ instance->yRotation = NULL;
+}
diff --git a/src/instance.h b/src/instance.h
new file mode 100644
index 0000000..c9be41d
--- /dev/null
+++ b/src/instance.h
@@ -0,0 +1,24 @@
+#include "defs.h"
+#include "pt.h"
+#include "vertex.h"
+#include "triangle.h"
+#include "model.h"
+#include <math.h>
+#include <stdlib.h>
+
+#ifndef INSTANCE_H
+#define INSTANCE_H
+
+typedef struct INSTANCE {
+ MODEL *model;
+ VERTEX *position;
+ FIXED scale;
+ FIXED *xRotation;
+ FIXED *yRotation;
+ FIXED *zRotation;
+} INSTANCE;
+
+void renderInstance();
+void destroyInstance();
+
+#endif // INSTANCE_H
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..152088e
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,111 @@
+#include "defs.h"
+#include "color.h"
+#include "model.h"
+#include "instance.h"
+#include "fixed.h"
+#include <stdlib.h>
+#include <SDL2/SDL.h>
+#include <unistd.h>
+
+int runningGame = 1;
+
+int main() {
+ // Create sdl window
+ SDL_Event event;
+ SDL_Renderer *renderer;
+ SDL_Window *window;
+
+ // Array of keys being pressed
+ const unsigned char *keys = SDL_GetKeyboardState(NULL);
+
+ // Initialize sdl window
+ SDL_Init(SDL_INIT_VIDEO);
+ SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer);
+ fillDisplay(renderer, createColor(0, 0, 0));
+
+ // Positions and rotations of each cube
+ VERTEX positions[2] = {createVertex(2 << FIX_SHIFT, 0 << FIX_SHIFT, 7 << FIX_SHIFT),
+ createVertex(-2 << FIX_SHIFT, 0, 7 << FIX_SHIFT)
+ };
+ FIXED xRots[2] = {0 << FIX_SHIFT, 0 << FIX_SHIFT};
+ FIXED yRots[2] = {30 << FIX_SHIFT, 30 << FIX_SHIFT};
+ FIXED zRots[2] = {0 << FIX_SHIFT, 0 << FIX_SHIFT};
+
+ // Create cube and instances of cube
+ MODEL cube;
+ INSTANCE instances[2];
+ for (int i = 0; i < 2; i++) {
+ // Set properties of each cube
+ instances[i].scale = 1;
+ instances[i].xRotation = &xRots[i];
+ instances[i].yRotation = &yRots[i];
+ instances[i].zRotation = &zRots[i];
+ instances[i].model = &cube;
+ instances[i].position = &positions[i];
+ }
+ // Initialize the base cube model
+ initializeCube(&cube);
+
+ while(runningGame) {
+ // Draw the cubes and interact with them
+ fillDisplay(renderer, createColor(0,0,0));
+ for (int i = 0; i < 2; i++) {
+ renderInstance(&instances[i], renderer);
+ }
+ updateDisplay(renderer);
+ while (SDL_PollEvent(&event)) {
+ for (int i = 0; i < 2; i++) {
+ // Check events and update each cube accordingly
+ if (event.type == SDL_QUIT) {
+ runningGame = 0;
+ }
+ if (keys[SDL_SCANCODE_RIGHT]) {
+ positions[i].x += float_to_fixed(0.2);
+ }
+ if (keys[SDL_SCANCODE_LEFT]) {
+ positions[i].x -= float_to_fixed(0.2);
+ }
+ if (keys[SDL_SCANCODE_DOWN]) {
+ positions[i].y -= float_to_fixed(0.1);
+ }
+ if (keys[SDL_SCANCODE_UP]) {
+ positions[i].y += float_to_fixed(0.1);
+ }
+ if (keys[SDL_SCANCODE_W]) {
+ positions[i].z += float_to_fixed(0.1);
+ }
+ if (keys[SDL_SCANCODE_S]) {
+ positions[i].z -= float_to_fixed(0.1);
+ }
+ if (keys[SDL_SCANCODE_Q]) {
+ xRots[i] += float_to_fixed(1);
+ }
+ if (keys[SDL_SCANCODE_E]) {
+ xRots[i] += float_to_fixed(-1);
+ }
+ if (keys[SDL_SCANCODE_Z]) {
+ zRots[i] += float_to_fixed(1);
+ }
+ if (keys[SDL_SCANCODE_C]) {
+ zRots[i] += float_to_fixed(-1);
+ }
+ if (keys[SDL_SCANCODE_A]) {
+ yRots[i] += float_to_fixed(1);
+ }
+ if (keys[SDL_SCANCODE_D]) {
+ yRots[i] += float_to_fixed(-1);
+ }
+ }
+ }
+ sleep(.1);
+ }
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+
+ destroyModel(&cube);
+ for (int i = 0; i < 2; i++) {
+ destroyInstance(&instances[i]);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/src/model.c b/src/model.c
new file mode 100644
index 0000000..fe24143
--- /dev/null
+++ b/src/model.c
@@ -0,0 +1,57 @@
+#include "model.h"
+#include <stdlib.h>
+
+void initializeCube(MODEL *cube) {
+ // Initialize a cube model
+ cube->bounds_center = createVertex(0, 0, 0);
+ COLOR red = createColor(255,0,0);
+ COLOR green = createColor(0,255,0);
+ COLOR blue = createColor(0,0,255);
+ COLOR yellow = createColor(255,255,0);
+ COLOR pink = createColor(255, 0, 100);
+ COLOR weird = createColor(100, 255, 70);
+ cube->vertices = malloc(sizeof(VERTEX) * 8);
+ cube->triangles = malloc(sizeof(TRIANGLE) * 12);
+ cube->vertices_length = 8;
+ cube->triangles_length = 12;
+ VERTEX vertices[8] = {
+ createVertex( -1 << FIX_SHIFT, -1 << FIX_SHIFT, -1 << FIX_SHIFT), // (0,0,0) 0
+ createVertex( -1 << FIX_SHIFT, 1 << FIX_SHIFT, -1 << FIX_SHIFT), // (0,1,0) 1
+ createVertex( 1 << FIX_SHIFT, 1 << FIX_SHIFT, -1 << FIX_SHIFT), // (1,1,0) 2
+ createVertex( 1 << FIX_SHIFT, -1 << FIX_SHIFT, -1 << FIX_SHIFT), // (1,0,0) 3
+ createVertex( 1 << FIX_SHIFT, 1 << FIX_SHIFT, 1 << FIX_SHIFT), // (1,1,1) 4
+ createVertex( 1 << FIX_SHIFT, -1 << FIX_SHIFT, 1 << FIX_SHIFT), // (1,0,1) 5
+ createVertex( -1 << FIX_SHIFT, 1 << FIX_SHIFT, 1 << FIX_SHIFT), // (0,1,1) 6
+ createVertex( -1 << FIX_SHIFT, -1 << FIX_SHIFT, 1 << FIX_SHIFT), // (0,0,1) 7
+ };
+ TRIANGLE triangles[12] = {
+ createTriangle( 0, 1, 2, red),
+ createTriangle( 0, 2, 3, red),
+ createTriangle( 3, 2, 4, green),
+ createTriangle( 3, 4, 5, green),
+ createTriangle( 5, 4, 6, blue),
+ createTriangle( 5, 6, 7, blue),
+ createTriangle( 7, 6, 1, yellow),
+ createTriangle( 7, 1, 0, yellow),
+ createTriangle( 1, 6, 4, pink),
+ createTriangle( 1, 4, 2, pink),
+ createTriangle( 5, 7, 0, weird),
+ createTriangle( 5, 0, 3, weird),
+ };
+ for (int i = 0; i < 8; i++) {
+ // Copy vertices data to cube
+ *(cube->vertices + i) = vertices[i];
+ }
+ for (int i = 0; i < 12; i++) {
+ // Copy triangles to cube
+ *(cube->triangles + i) = triangles[i];
+ }
+}
+
+void destroyModel(MODEL *model) {
+ // Free memory of a model
+ model->vertices = NULL;
+ model->triangles = NULL;
+ free(model->vertices);
+ free(model->triangles);
+}
diff --git a/src/model.h b/src/model.h
new file mode 100644
index 0000000..aed360d
--- /dev/null
+++ b/src/model.h
@@ -0,0 +1,21 @@
+#include "defs.h"
+#include "fixed.h"
+#include "vertex.h"
+#include "triangle.h"
+#include "pt.h"
+
+#ifndef MODEL_H
+#define MODEL_H
+
+typedef struct MODEL {
+ VERTEX *vertices;
+ int vertices_length;
+ TRIANGLE *triangles;
+ int triangles_length;
+ VERTEX bounds_center;
+} MODEL;
+
+void initializeCube();
+void destroyModel();
+
+#endif // MODEL_H
diff --git a/src/plane.h b/src/plane.h
new file mode 100644
index 0000000..f83350f
--- /dev/null
+++ b/src/plane.h
@@ -0,0 +1,21 @@
+#include "defs.h"
+#include "vertex.h"
+#include "fixed.h"
+
+#ifndef PLANE_H
+#define PLANE_H
+
+typedef struct PLANE {
+ VERTEX normal;
+ FIXED distance;
+} PLANE;
+
+static inline PLANE createPlane(VERTEX *normal, FIXED distance) {
+ // Create a plane from data
+ PLANE temp;
+ temp.normal = *normal;
+ temp.distance = distance;
+ return temp;
+}
+
+#endif // PLANE_H
diff --git a/src/pt.h b/src/pt.h
new file mode 100644
index 0000000..b9f8841
--- /dev/null
+++ b/src/pt.h
@@ -0,0 +1,36 @@
+#include "defs.h"
+#include "fixed.h"
+
+#ifndef PT_H
+#define PT_H
+
+typedef struct POINT {
+ FIXED x;
+ FIXED y;
+} POINT;
+
+static inline void convertPointToScreen(POINT *point) {
+ // Convert point where (SCREEN_WIDTH / 2 * x,
+ // SCREEN_HEIGHT / 2 - y - 1)
+ // is the origin (0,0)
+ point->x += (WINDOW_WIDTH / 2) << FIX_SHIFT;
+ point->y = (WINDOW_HEIGHT / 2 - (point->y >> FIX_SHIFT) - 1) << FIX_SHIFT;
+}
+
+static inline POINT createPoint(FIXED x, FIXED y) {
+ // Create a point from data
+ POINT temp;
+ temp.x = x;
+ temp.y = y;
+ return temp;
+}
+
+
+static inline void swapPoint(POINT *p1, POINT *p2) {
+ POINT temp;
+ temp = *p1;
+ *p1 = *p2;
+ *p2 = temp;
+}
+
+#endif // PT_H
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
diff --git a/src/vertex.h b/src/vertex.h
new file mode 100644
index 0000000..7880495
--- /dev/null
+++ b/src/vertex.h
@@ -0,0 +1,112 @@
+#include "defs.h"
+#include "fixed.h"
+#include "pt.h"
+#include <math.h>
+
+#ifndef VERTEX_H
+#define VERTEX_H
+
+typedef struct VERTEX {
+ FIXED x;
+ FIXED y;
+ FIXED z;
+} VERTEX;
+
+static inline POINT viewportToScreen (POINT *point) {
+ // Convert a viewport coordinate to screen x, y
+ return createPoint(fixed_multiply(point->x, fixed_divide(WINDOW_WIDTH << FIX_SHIFT, viewport_width << FIX_SHIFT)),
+ fixed_multiply(point->y, fixed_divide(WINDOW_HEIGHT << FIX_SHIFT, viewport_height << FIX_SHIFT))
+ );
+}
+
+static inline POINT projectVertex(VERTEX *vertex) {
+ // Project a vertex to a point
+ POINT temp;
+ if (vertex->z != 0) {
+ // Make sure we don't divide by zero
+ temp = createPoint(fixed_multiply(vertex->x, fixed_divide(ZPlane << FIX_SHIFT, vertex->z)),
+ fixed_multiply(vertex->y, fixed_divide(ZPlane << FIX_SHIFT, vertex->z))
+ );
+ }
+ else {
+ temp = createPoint(0, 0);
+ }
+ temp = viewportToScreen(&temp);
+ return temp;
+}
+
+static inline VERTEX createVertex(FIXED x, FIXED y, FIXED z) {
+ // Create a vertex from data
+ VERTEX temp;
+ temp.x = x;
+ temp.y = y;
+ temp.z = z;
+ return temp;
+}
+
+static inline VERTEX addVertices(VERTEX *a, VERTEX *b) {
+ // Add two vertices together
+ VERTEX temp = createVertex(a->x + b->x, a->y + b->y, a->z + b->z);
+ return temp;
+}
+
+static inline void applyXRotation(VERTEX *vertex, FIXED xRotation) {
+ // Apply rotation to vertex on x-axis
+ FIXED sinTheta = float_to_fixed(sin(fixed_to_float(xRotation) * (3.14159 / 180)));
+ FIXED cosTheta = float_to_fixed(cos(fixed_to_float(xRotation) * (3.14159 / 180)));
+ FIXED y = vertex->y;
+ FIXED z = vertex->z;
+ vertex->y = fixed_multiply(y, cosTheta) - fixed_multiply(z, sinTheta);
+ vertex->z = fixed_multiply(z, cosTheta) + fixed_multiply(y, sinTheta);
+}
+
+static inline void applyYRotation(VERTEX *vertex, FIXED yRotation) {
+ // Apply rotation to vertex on y-axis
+ FIXED sinTheta = float_to_fixed(sin(fixed_to_float(yRotation) * (3.14159 / 180)));
+ FIXED cosTheta = float_to_fixed(cos(fixed_to_float(yRotation) * (3.14159 / 180)));
+ FIXED x = vertex->x;
+ FIXED z = vertex->z;
+ vertex->x = fixed_multiply(x, cosTheta) + fixed_multiply(z, sinTheta);
+ vertex->z = fixed_multiply(z, cosTheta) - fixed_multiply(x, sinTheta);
+}
+
+static inline void applyZRotation(VERTEX *vertex, FIXED zRotation) {
+ // Apply rotation to vertex on z-axis
+ FIXED sinTheta = float_to_fixed(sin(fixed_to_float(zRotation) * (3.14159 / 180)));
+ FIXED cosTheta = float_to_fixed(cos(fixed_to_float(zRotation) * (3.14159 / 180)));
+ FIXED x = vertex->x;
+ FIXED y = vertex->y;
+ vertex->x = fixed_multiply(x, cosTheta) - fixed_multiply(y, sinTheta);
+ vertex->y = fixed_multiply(y, cosTheta) + fixed_multiply(x, sinTheta);
+}
+
+static inline VERTEX crossProduct(VERTEX *a, VERTEX *b) {
+ // Calculate the cross product of two vertices
+ return createVertex(
+ fixed_multiply(a->y, b->z) - fixed_multiply(a->z, b->y),
+ fixed_multiply(a->z, b->x) - fixed_multiply(a->x, b->z),
+ fixed_multiply(a->x, b->y) - fixed_multiply(a->y, b->x)
+ );
+}
+
+static inline FIXED dotProduct(VERTEX *a, VERTEX *b) {
+ // Dot two vertices
+ FIXED product = fixed_multiply(a->x, b->x) +
+ fixed_multiply(a->y, b->y) +
+ fixed_multiply(a->z, b->z);
+ return product;
+}
+
+static inline void normalizeVertex(VERTEX *vertex) {
+ // Normalize (magnitude = 1) a vertex
+ float x = fixed_to_float(vertex->x);
+ float y = fixed_to_float(vertex->y);
+ float z = fixed_to_float(vertex->z);
+ float d = sqrtf(x*x + y*y + z*z);
+
+ vertex->x = float_to_fixed(fixed_to_float(vertex->x) / d);
+ vertex->y = float_to_fixed(fixed_to_float(vertex->y) / d);
+ vertex->z = float_to_fixed(fixed_to_float(vertex->z) / d);
+}
+
+#endif // VERTEX_H