From ebd81999b71ada201a316060fa47a7a66a277935 Mon Sep 17 00:00:00 2001 From: Simponic Date: Tue, 4 Aug 2020 23:36:21 -0600 Subject: [PATCH] Added files --- src/Makefile | 41 +++++++++++++++ src/color.h | 19 +++++++ src/defs.h | 39 ++++++++++++++ src/fixed.h | 74 ++++++++++++++++++++++++++ src/instance.c | 63 ++++++++++++++++++++++ src/instance.h | 24 +++++++++ src/main.c | 111 +++++++++++++++++++++++++++++++++++++++ src/model.c | 57 ++++++++++++++++++++ src/model.h | 21 ++++++++ src/plane.h | 21 ++++++++ src/pt.h | 36 +++++++++++++ src/triangle.h | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ src/vertex.h | 112 +++++++++++++++++++++++++++++++++++++++ 13 files changed, 757 insertions(+) create mode 100644 src/Makefile create mode 100644 src/color.h create mode 100644 src/defs.h create mode 100644 src/fixed.h create mode 100644 src/instance.c create mode 100644 src/instance.h create mode 100644 src/main.c create mode 100644 src/model.c create mode 100644 src/model.h create mode 100644 src/plane.h create mode 100644 src/pt.h create mode 100644 src/triangle.h create mode 100644 src/vertex.h 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 + +#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(©V); + + // Grayscale color of the triangle from light intensity + clr = createColor(intensity >> FIX_SHIFT, intensity >> FIX_SHIFT, intensity >> FIX_SHIFT); + + if (dotProduct(&n, ©V) < 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 +#include + +#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 +#include +#include + +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 + +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 + +#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 + +#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