228 lines
6.6 KiB
C
228 lines
6.6 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <SDL.h>
|
|
#include "display.h"
|
|
#include "mesh.h"
|
|
#include "vector.h"
|
|
#include "array.h"
|
|
|
|
#define STEP 0.075
|
|
|
|
triangle_t* triangles_to_render = NULL; //[N_MESH_FACES];
|
|
|
|
vec3_t camera_position = { 0, 0, 0 };
|
|
|
|
float fov_factor = 640;
|
|
|
|
bool is_running = false;
|
|
uint32_t previous_frame_time = 0;
|
|
|
|
void setup(void) {
|
|
// Allocate the required memory in bytes to hold the color buffer
|
|
color_buffer = (uint32_t*) malloc(sizeof(uint32_t) * window_width * window_height);
|
|
|
|
// Creating a SDL texture that is used to display the color buffer
|
|
color_buffer_texture = SDL_CreateTexture(
|
|
renderer,
|
|
SDL_PIXELFORMAT_ARGB8888,
|
|
SDL_TEXTUREACCESS_STREAMING,
|
|
window_width,
|
|
window_height
|
|
);
|
|
|
|
// load cube mesh data
|
|
load_file();
|
|
|
|
}
|
|
|
|
void process_input(void) {
|
|
SDL_Event event;
|
|
SDL_PollEvent(&event);
|
|
|
|
switch (event.type) {
|
|
case SDL_QUIT:
|
|
is_running = false;
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
if (event.key.keysym.sym == SDLK_ESCAPE)
|
|
is_running = false;
|
|
//break;
|
|
if (event.key.keysym.sym == SDLK_UP)
|
|
mesh.rotation.z += STEP;
|
|
if (event.key.keysym.sym == SDLK_LEFT)
|
|
mesh.rotation.x += STEP;
|
|
if (event.key.keysym.sym == SDLK_RIGHT)
|
|
mesh.rotation.y += STEP;
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Function that receives a 3D vector and returns a projected 2D point
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
vec2_t project(vec3_t point) {
|
|
vec2_t projected_point = {
|
|
.x = (fov_factor * point.x) / point.z,
|
|
.y = (fov_factor * point.y) / point.z,
|
|
};
|
|
return projected_point;
|
|
}
|
|
|
|
void update(void) {
|
|
//while (!SDL_TICKS_PASSED(SDL_GetTicks(), previous_frame_time + FRAME_TARGET_TIME));
|
|
|
|
int time_to_wait = FRAME_TARGET_TIME - (SDL_GetTicks() - previous_frame_time);
|
|
|
|
// only delay execution if we are running too fast
|
|
if (time_to_wait > 0 && time_to_wait <= FRAME_TARGET_TIME) {
|
|
SDL_Delay(time_to_wait);
|
|
}
|
|
|
|
previous_frame_time = SDL_GetTicks();
|
|
|
|
mesh.rotation.y += 0.01;
|
|
mesh.rotation.x -= 0.01;
|
|
mesh.rotation.z += 0.01;
|
|
|
|
triangles_to_render = NULL;
|
|
|
|
int num_faces = array_length(mesh.faces);
|
|
for (int i = 0; i < num_faces; i++) {
|
|
face_t mesh_face = mesh.faces[i];
|
|
|
|
vec3_t face_vertices[3];
|
|
face_vertices[0] = mesh.vertices[mesh_face.a - 1];
|
|
face_vertices[1] = mesh.vertices[mesh_face.b - 1];
|
|
face_vertices[2] = mesh.vertices[mesh_face.c - 1];
|
|
|
|
vec3_t transformed_vertices[3];
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
vec3_t transformed_vertex = face_vertices[j];
|
|
|
|
transformed_vertex = vec3_rotate_x(transformed_vertex, mesh.rotation.x);
|
|
transformed_vertex = vec3_rotate_y(transformed_vertex, mesh.rotation.y);
|
|
transformed_vertex = vec3_rotate_z(transformed_vertex, mesh.rotation.z);
|
|
|
|
// translate away from camera in z
|
|
transformed_vertex.z += 5;
|
|
|
|
// save translated vertex in the array of transformed vertices
|
|
transformed_vertices[j] = transformed_vertex;
|
|
}
|
|
|
|
// check backface culling
|
|
vec3_t vector_a = transformed_vertices[0]; /* A */
|
|
vec3_t vector_b = transformed_vertices[1]; /* / \ */
|
|
vec3_t vector_c = transformed_vertices[2]; /* C---B */
|
|
|
|
// get the vector subtraction of B-A and C-A
|
|
vec3_t vector_ab = vec3_subtract(vector_b, vector_a);
|
|
vec3_t vector_ac = vec3_subtract(vector_c, vector_a);
|
|
vec3_normalize(&vector_ab);
|
|
vec3_normalize(&vector_ac);
|
|
|
|
// compute the face normal using the cross product to find perpindicular
|
|
vec3_t normal = vec3_cross(vector_ab, vector_ac);
|
|
vec3_normalize(&normal);
|
|
|
|
// find the vector between a point in the triangle and the camera origin
|
|
vec3_t camera_ray = vec3_subtract(camera_position, vector_a);
|
|
|
|
// calculate how aligned the camera ray is with the face normal
|
|
float dot_normal_camera = vec3_dot(normal, camera_ray);
|
|
|
|
if (dot_normal_camera < 0) {
|
|
continue;
|
|
}
|
|
|
|
triangle_t projected_triangle;
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
// project the current vertex
|
|
vec2_t projected_point = project(transformed_vertices[j]);
|
|
|
|
// scale and translate the projected points to the center of the screen
|
|
projected_point.x += (window_width / 2);
|
|
projected_point.y += (window_height / 2);
|
|
|
|
projected_triangle.points[j] = projected_point;
|
|
}
|
|
|
|
//vec2_t midpoint = triangle_midpoint(projected_triangle);
|
|
//draw_rect(midpoint.x, midpoint.y, 10, 10, 0xFFFF0000);
|
|
|
|
// save the projected triangle in the array of triangles
|
|
array_push(triangles_to_render, projected_triangle);
|
|
|
|
triangle_t normal_triangle;
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
// project the current vertex
|
|
vec2_t projected_point = project(transformed_vertices[j]);
|
|
|
|
// scale and translate the projected points to the center of the screen
|
|
projected_point.x += (window_width / 2);
|
|
projected_point.y += (window_height / 2);
|
|
|
|
normal_triangle.points[j] = projected_point;
|
|
}
|
|
|
|
array_push(triangles_to_render, normal_triangle);
|
|
|
|
}
|
|
}
|
|
|
|
void render(void) {
|
|
draw_grid();
|
|
|
|
// Loop all projected points and render them
|
|
for (int i = 0; i < array_length(triangles_to_render); i++) {
|
|
triangle_t triangle = triangles_to_render[i];
|
|
draw_filled_triangle(triangle, 0xFFFFFFFF);
|
|
draw_triangle(triangle, 0xFF000000);
|
|
draw_rect(triangle.points[0].x, triangle.points[0].y, 3, 3, 0xFFFFFF00);
|
|
draw_rect(triangle.points[1].x, triangle.points[1].y, 3, 3, 0xFFFFFF00);
|
|
draw_rect(triangle.points[2].x, triangle.points[2].y, 3, 3, 0xFFFFFF00);
|
|
}
|
|
|
|
//vec2_t m = triangle_midpoint(t);
|
|
//draw_rect(m.x, m.y, 10, 10, 0xFFFF0000);
|
|
|
|
//draw_line(10, 10, 500, 500, 0x00FF00);
|
|
array_free(triangles_to_render);
|
|
|
|
render_color_buffer();
|
|
|
|
clear_color_buffer(0xFF000000);
|
|
|
|
SDL_RenderPresent(renderer);
|
|
}
|
|
|
|
void free_resources(void) {
|
|
free(color_buffer);
|
|
array_free(mesh.faces);
|
|
array_free(mesh.vertices);
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
is_running = initialize_window();
|
|
|
|
setup();
|
|
|
|
while (is_running) {
|
|
process_input();
|
|
update();
|
|
render();
|
|
}
|
|
|
|
destroy_window();
|
|
free_resources();
|
|
|
|
return 0;
|
|
}
|