Added files
This commit is contained in:
parent
b323ae0ca0
commit
ebd81999b7
41
src/Makefile
Normal file
41
src/Makefile
Normal file
@ -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
|
19
src/color.h
Normal file
19
src/color.h
Normal file
@ -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
|
39
src/defs.h
Normal file
39
src/defs.h
Normal file
@ -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
|
74
src/fixed.h
Normal file
74
src/fixed.h
Normal file
@ -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
|
63
src/instance.c
Normal file
63
src/instance.c
Normal file
@ -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;
|
||||||
|
}
|
24
src/instance.h
Normal file
24
src/instance.h
Normal file
@ -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
|
111
src/main.c
Normal file
111
src/main.c
Normal file
@ -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;
|
||||||
|
}
|
57
src/model.c
Normal file
57
src/model.c
Normal file
@ -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);
|
||||||
|
}
|
21
src/model.h
Normal file
21
src/model.h
Normal file
@ -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
|
21
src/plane.h
Normal file
21
src/plane.h
Normal file
@ -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
|
36
src/pt.h
Normal file
36
src/pt.h
Normal file
@ -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
|
139
src/triangle.h
Normal file
139
src/triangle.h
Normal file
@ -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
|
112
src/vertex.h
Normal file
112
src/vertex.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user