C donut
This commit is contained in:
parent
9809dfccd0
commit
a3a74765c9
17
makefile
17
makefile
|
@ -5,17 +5,15 @@ BUILD_DIR := ./build
|
||||||
SRC_DIRS := ./src ./includes
|
SRC_DIRS := ./src ./includes
|
||||||
RESOURCE_DIRS := ./resources
|
RESOURCE_DIRS := ./resources
|
||||||
|
|
||||||
CXX := g++
|
|
||||||
CC := gcc
|
CC := gcc
|
||||||
ld := g++
|
ld := g++
|
||||||
|
|
||||||
|
|
||||||
BASEFLAGS = -g -Wall -Wextra -Wconversion -Wduplicated-branches -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wuseless-cast -Wdouble-promotion -Wshadow -Wformat=2
|
BASEFLAGS = -g -Wall -Wextra -Wconversion -Wduplicated-branches -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wdouble-promotion -Wshadow -Wformat=2
|
||||||
CXXFLAGS = -std=c++20 $(BASEFLAGS) -Wuseless-cast
|
|
||||||
CFLAGS = $(BASEFLAGS) -Wjump-misses-init
|
CFLAGS = $(BASEFLAGS) -Wjump-misses-init
|
||||||
# Find all the C and C++ files we want to compile
|
# Find all the C and C++ files we want to compile
|
||||||
# Note the single quotes around the * expressions. The shell will incorrectly expand these otherwise, but we want to send the * directly to the find command.
|
# Note the single quotes around the * expressions. The shell will incorrectly expand these otherwise, but we want to send the * directly to the find command.
|
||||||
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
|
SRCS := $(shell find $(SRC_DIRS) -name '*.c')
|
||||||
|
|
||||||
# Prepends BUILD_DIR and appends .o to every src file
|
# Prepends BUILD_DIR and appends .o to every src file
|
||||||
# As an example, ./your_dir/hello.cpp turns into ./build/./your_dir/hello.cpp.o
|
# As an example, ./your_dir/hello.cpp turns into ./build/./your_dir/hello.cpp.o
|
||||||
|
@ -30,9 +28,6 @@ INC_DIRS := $(shell find $(SRC_DIRS) -type d)
|
||||||
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
|
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
|
||||||
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
|
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
|
||||||
|
|
||||||
# The -MMD and -MP flags together generate Makefiles for us!
|
|
||||||
# These files will have .d instead of .o as the output.
|
|
||||||
CPPFLAGS := $(INC_FLAGS) -MMD -MP
|
|
||||||
|
|
||||||
# The final build step.
|
# The final build step.
|
||||||
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
|
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
|
||||||
|
@ -44,10 +39,6 @@ $(BUILD_DIR)/%.c.o: %.c
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
# Build step for C++ source
|
|
||||||
$(BUILD_DIR)/%.cpp.o: %.cpp
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +46,3 @@ $(BUILD_DIR)/%.cpp.o: %.cpp
|
||||||
clean:
|
clean:
|
||||||
rm -r $(BUILD_DIR)
|
rm -r $(BUILD_DIR)
|
||||||
|
|
||||||
# Include the .d makefiles. The - at the front suppresses the errors of missing
|
|
||||||
# Makefiles. Initially, all the .d files will be missing, and we don't want those
|
|
||||||
# errors to show up.
|
|
||||||
-include $(DEPS)
|
|
93
src/donut.c
Normal file
93
src/donut.c
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
|
||||||
|
#include "donut.h"
|
||||||
|
#include "point.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include "point_list.h"
|
||||||
|
#include "texture.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
|
vec3_t sample_rgb(texture_t tex, size_t index) {
|
||||||
|
u8 red = tex.bytes[index];
|
||||||
|
u8 green = tex.bytes[index + 1];
|
||||||
|
u8 blue = tex.bytes[index + 2];
|
||||||
|
vec3_t color = vec3((f64)red, (f64)green, (f64)blue);
|
||||||
|
color = mul_vec(color, vec3(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0));
|
||||||
|
return color;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3_t mix_transparency(vec3_t transparent, vec3_t solid) {
|
||||||
|
if (transparent.i == 0.0 && transparent.j == 0.0 && transparent.k == 0.0) {
|
||||||
|
return solid;
|
||||||
|
} else {
|
||||||
|
return transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void generate_cube(point_list_t *points, texture_t bottom_tex, texture_t top_tex, texture_t side_tex, i32 face_x, i32 face_y) {
|
||||||
|
const vec3_t grass_color_scale = vec3(0.4, 1.0, 0.4);
|
||||||
|
const size_t image_size = 16;
|
||||||
|
const size_t point_count = 32;
|
||||||
|
const size_t world_width = 16;
|
||||||
|
for (size_t l_x = 0; l_x < point_count; l_x++) {
|
||||||
|
for (size_t l_y = 0; l_y < point_count; l_y++) {
|
||||||
|
|
||||||
|
f64 sx = (f64)l_x / (f64)point_count;
|
||||||
|
f64 sy = (f64)l_y / (f64)point_count;
|
||||||
|
size_t index = 3 * ((size_t)(sx * (f64)(image_size)) + (size_t)(sy * (f64)(image_size)) * image_size);
|
||||||
|
vec3_t dirt = sample_rgb(bottom_tex, index);
|
||||||
|
vec3_t grass = sample_rgb(top_tex, index);
|
||||||
|
vec3_t side = sample_rgb(side_tex, index);
|
||||||
|
grass = mul_vec(grass, grass_color_scale);
|
||||||
|
side = mul_vec(side, grass_color_scale);
|
||||||
|
|
||||||
|
side = mix_transparency(side, dirt);
|
||||||
|
|
||||||
|
f64 x_w = sx * (f64)world_width;
|
||||||
|
f64 y_w = sy * (f64)world_width;
|
||||||
|
f64 w_w = (f64)world_width;
|
||||||
|
|
||||||
|
if (face_y == -1 || (face_y == 1 && face_x == 0)) {
|
||||||
|
push_point(points, point(vec3(x_w, 0, y_w), side));
|
||||||
|
}
|
||||||
|
if (face_x == -1 || (face_x == 1 && face_y == 0)) {
|
||||||
|
push_point(points, point(vec3(0, x_w, y_w), side));
|
||||||
|
}
|
||||||
|
if (face_x == 1 || (face_x == -1 && face_y == 0)) {
|
||||||
|
push_point(points, point(vec3(w_w, x_w, y_w), side));
|
||||||
|
}
|
||||||
|
if (face_y == 1 || (face_y == -1 && face_x == 0)) {
|
||||||
|
push_point(points, point(vec3(x_w, w_w, y_w), side));
|
||||||
|
}
|
||||||
|
|
||||||
|
push_point(points, point(vec3(x_w, y_w, w_w), dirt));
|
||||||
|
push_point(points, point(vec3(x_w, y_w, 0.0), grass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < points->length; i++) {
|
||||||
|
point_t *p = &points->list[i];
|
||||||
|
p->pos.i += ((f64)(face_x) * (f64)(world_width) - (f64)(world_width) / 2.0);
|
||||||
|
p->pos.j += ((f64)(face_y) * (f64)(world_width) - (f64)(world_width) / 2.0);
|
||||||
|
p->pos.k += (-(f64)world_width / 2.0);
|
||||||
|
rotate_j(&p->pos, 180 * 3.14159265 / 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
point_list_t generate_donut(texture_t bottom, texture_t top, texture_t side) {
|
||||||
|
point_list_t donut_points = point_list(15000);
|
||||||
|
for (i32 x = -1; x <= 1; x++) {
|
||||||
|
for (i32 y = -1; y <= 1; y++) {
|
||||||
|
if (x == y && x == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
point_list_t cube_points = point_list(2000);
|
||||||
|
generate_cube(&cube_points, bottom, top, side, x, y);
|
||||||
|
extend_point_list(&donut_points, &cube_points);
|
||||||
|
free_point_list(&cube_points);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return donut_points;
|
||||||
|
}
|
|
@ -1,94 +0,0 @@
|
||||||
// Alexander Bass
|
|
||||||
// Created 4/16/24
|
|
||||||
|
|
||||||
#include "donut.h"
|
|
||||||
#include "point.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "rgb.h"
|
|
||||||
|
|
||||||
rgb sample_rgb(u8 *texture, usize index) {
|
|
||||||
u8 d_red = texture[index * 3];
|
|
||||||
u8 d_green = texture[index * 3 + 1];
|
|
||||||
u8 d_blue = texture[index * 3 + 2];
|
|
||||||
f64 d_r = (f64)d_red / 255.0;
|
|
||||||
f64 d_g = (f64)d_green / 255.0;
|
|
||||||
f64 d_b = (f64)d_blue / 255.0;
|
|
||||||
return rgb(d_r, d_g, d_b);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline rgb mix_transparency(rgb transparent, rgb solid) {
|
|
||||||
if (transparent.r == 0.0 && transparent.g == 0.0 && transparent.b == 0.0) {
|
|
||||||
return solid;
|
|
||||||
}
|
|
||||||
return transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Point> generate_cube(u8 *bottom_texture, u8 *top_texture, u8 *side_texture, i32 face_x, i32 face_y) {
|
|
||||||
std::vector<Point> out = {};
|
|
||||||
const usize image_size = 16;
|
|
||||||
const usize point_count = 22;
|
|
||||||
const usize world_width = 16;
|
|
||||||
for (usize l_x = 0; l_x < point_count; l_x++) {
|
|
||||||
for (usize l_y = 0; l_y < point_count; l_y++) {
|
|
||||||
|
|
||||||
f64 sx = (f64)l_x / (f64)point_count;
|
|
||||||
f64 sy = (f64)l_y / (f64)point_count;
|
|
||||||
usize index = (usize)(sx * (f64)(image_size)) + usize(sy * (f64)(image_size)) * image_size;
|
|
||||||
rgb dirt = sample_rgb(bottom_texture, index);
|
|
||||||
rgb grass = sample_rgb(top_texture, index);
|
|
||||||
rgb sides = sample_rgb(side_texture, index);
|
|
||||||
grass.mix(rgb(0.4, 1.0, 0.4));
|
|
||||||
sides.mix(rgb(0.4, 1.0, 0.4));
|
|
||||||
|
|
||||||
sides = mix_transparency(sides, dirt);
|
|
||||||
|
|
||||||
f64 x_w = sx * (f64)world_width;
|
|
||||||
f64 y_w = sy * (f64)world_width;
|
|
||||||
f64 w_w = (f64)world_width;
|
|
||||||
|
|
||||||
if (face_y == -1 || (face_y == 1 && face_x == 0)) {
|
|
||||||
out.push_back(*Point(x_w, 0, y_w).set_rgb(sides));
|
|
||||||
}
|
|
||||||
if (face_x == -1 || (face_x == 1 && face_y == 0)) {
|
|
||||||
out.push_back(*Point(0, x_w, y_w).set_rgb(sides));
|
|
||||||
}
|
|
||||||
if (face_x == 1 || (face_x == -1 && face_y == 0)) {
|
|
||||||
out.push_back(*Point(w_w, x_w, y_w).set_rgb(sides));
|
|
||||||
}
|
|
||||||
if (face_y == 1 || (face_y == -1 && face_x == 0)) {
|
|
||||||
out.push_back(*Point(x_w, w_w, y_w).set_rgb(sides));
|
|
||||||
}
|
|
||||||
|
|
||||||
out.push_back(*Point(x_w, y_w, w_w).set_rgb(dirt));
|
|
||||||
out.push_back(*Point(x_w, y_w, 0.0).set_rgb(grass));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (usize i = 0; i < out.size(); i++) {
|
|
||||||
Point *p = &out[i];
|
|
||||||
p->translate_x((f64)face_x * (f64)world_width - (f64)world_width / 2.0);
|
|
||||||
p->translate_y((f64)face_y * (f64)world_width - (f64)world_width / 2.0);
|
|
||||||
p->translate_z(-(f64)world_width / 2.0);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Point> generate_donut(u8 *bottom_texture, u8 *top_texture, u8 *side_texture, f64 offset) {
|
|
||||||
std::vector<Point> points = {};
|
|
||||||
for (i32 x = -1; x <= 1; x++) {
|
|
||||||
for (i32 y = -1; y <= 1; y++) {
|
|
||||||
if (x == y && x == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::vector<Point> pt = generate_cube(bottom_texture, top_texture, side_texture, x, y);
|
|
||||||
points.insert(points.end(), pt.begin(), pt.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (usize i = 0; i < points.size(); i++) {
|
|
||||||
Point *point = &points[i];
|
|
||||||
point->translate_z(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return points;
|
|
||||||
}
|
|
|
@ -1,8 +1,9 @@
|
||||||
// Alexander Bass
|
// Alexander Bass
|
||||||
// Created 4/16/24
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "point.h"
|
#include "point_list.h"
|
||||||
#include <vector>
|
#include "texture.h"
|
||||||
|
|
||||||
std::vector<Point> generate_donut(u8 *bottom_texture, u8 *top_texture, u8 *side_texture, f64);
|
point_list_t generate_donut(texture_t bottom, texture_t top, texture_t side);
|
||||||
|
|
141
src/main.c
Normal file
141
src/main.c
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
|
||||||
|
#include "donut.h"
|
||||||
|
#include "point.h"
|
||||||
|
#include "point_list.h"
|
||||||
|
#include "ppm/ppm.h"
|
||||||
|
#include "texture.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
#include "vec4.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
const i32 WIDTH = 120;
|
||||||
|
const i32 HEIGHT = 90;
|
||||||
|
const i32 DEPTH = WIDTH;
|
||||||
|
|
||||||
|
void draw(vec4_t *, const point_list_t *);
|
||||||
|
void update(point_list_t *);
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
texture_t dirt = load_ppm_file("dirt.ppm");
|
||||||
|
texture_t grass = load_ppm_file("grass_top.ppm");
|
||||||
|
texture_t grass_side = load_ppm_file("grass_side.ppm");
|
||||||
|
|
||||||
|
// point_list_t points = point_list(300);
|
||||||
|
|
||||||
|
point_list_t points = generate_donut(dirt, grass, grass_side);
|
||||||
|
// extend_point_list(&points, &donut_points);
|
||||||
|
// free_point_list(&donut_points);
|
||||||
|
|
||||||
|
free_texture(&dirt);
|
||||||
|
free_texture(&grass);
|
||||||
|
free_texture(&grass_side);
|
||||||
|
|
||||||
|
vec4_t *pixel_buffer = malloc((size_t)(WIDTH * HEIGHT) * sizeof(vec4_t));
|
||||||
|
for (u32 i = 0; i < (u32)(WIDTH * HEIGHT); i++) {
|
||||||
|
// pixel_buffer[i] = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timespec tim;
|
||||||
|
tim.tv_sec = 0;
|
||||||
|
tim.tv_nsec = 1000000L * 1000L / 60L;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Move cursor to top left
|
||||||
|
printf("\033[0;0H");
|
||||||
|
// Draw points
|
||||||
|
draw(pixel_buffer, &points);
|
||||||
|
// Rotate points
|
||||||
|
update(&points);
|
||||||
|
// Wait
|
||||||
|
nanosleep(&tim, NULL);
|
||||||
|
// Repeat
|
||||||
|
}
|
||||||
|
|
||||||
|
free_point_list(&points);
|
||||||
|
free(pixel_buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 w_x_to_screen(f64 w_x) {
|
||||||
|
return (i32)(round(w_x)) + WIDTH / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 w_y_to_screen(f64 w_y) {
|
||||||
|
return (i32)(round(w_y)) + HEIGHT / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
f64 w_z_to_screen(f64 w_z) {
|
||||||
|
return (w_z + (f64)(DEPTH) / 2.0) / (f64)(DEPTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(vec4_t *pixel_buffer, const point_list_t *points) {
|
||||||
|
for (u32 i = 0; i < (u32)(WIDTH * HEIGHT); i++) {
|
||||||
|
pixel_buffer[i].l = 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pseudo-rasterization
|
||||||
|
for (size_t i = 0; i < points->length; i++) {
|
||||||
|
point_t point = points->list[i];
|
||||||
|
|
||||||
|
vec3_t pos = point.pos;
|
||||||
|
vec3_t color = point.color;
|
||||||
|
|
||||||
|
f64 p_x = pos.i;
|
||||||
|
f64 p_y = pos.j;
|
||||||
|
f64 p_z = pos.k;
|
||||||
|
|
||||||
|
i32 s_x = w_x_to_screen(p_x);
|
||||||
|
i32 s_y = w_y_to_screen(p_y);
|
||||||
|
f64 s_z = w_z_to_screen(p_z);
|
||||||
|
|
||||||
|
if (0 <= s_x && s_x < WIDTH && 0 <= s_y && s_y < HEIGHT) {
|
||||||
|
size_t index = (size_t)(s_x + s_y * WIDTH);
|
||||||
|
vec4_t existing = pixel_buffer[index];
|
||||||
|
if (existing.l < s_z) {
|
||||||
|
pixel_buffer[index].i = color.i;
|
||||||
|
pixel_buffer[index].j = color.j;
|
||||||
|
pixel_buffer[index].k = color.k;
|
||||||
|
pixel_buffer[index].l = s_z;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t y = 0; y < (size_t)(HEIGHT); y++) {
|
||||||
|
for (size_t x = 0; x < (size_t)(WIDTH); x++) {
|
||||||
|
size_t index = x + y * (size_t)(WIDTH);
|
||||||
|
vec4_t pixel = pixel_buffer[index];
|
||||||
|
f64 depth = pixel.l;
|
||||||
|
if (depth <= 0.0) {
|
||||||
|
printf(" ");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(depth >= 0.0);
|
||||||
|
assert(depth <= 1.0);
|
||||||
|
|
||||||
|
u8 red = (u8)(round(pixel.i * depth * 255.0));
|
||||||
|
u8 green = (u8)(round(pixel.j * depth * 255.0));
|
||||||
|
u8 blue = (u8)(round(pixel.k * depth * 255.0));
|
||||||
|
printf("\033[38;2;%u;%u;%um██", red, green, blue);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(point_list_t *points) {
|
||||||
|
for (size_t i = 0; i < points->length; i++) {
|
||||||
|
vec3_t *pos = &points->list[i].pos;
|
||||||
|
rotate_i(pos, 0.02);
|
||||||
|
rotate_j(pos, -0.04);
|
||||||
|
rotate_k(pos, 0.03);
|
||||||
|
}
|
||||||
|
}
|
132
src/main.cpp
132
src/main.cpp
|
@ -1,132 +0,0 @@
|
||||||
// Alexander Bass
|
|
||||||
// Created 4/16/24
|
|
||||||
#include "donut.h"
|
|
||||||
#include "point.h"
|
|
||||||
#include "ppm/ppm.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include <cassert>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cmath>
|
|
||||||
#include <format>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
|
||||||
#include <vector>
|
|
||||||
const i32 WIDTH = 120;
|
|
||||||
const i32 HEIGHT = 100;
|
|
||||||
const i32 DEPTH = WIDTH;
|
|
||||||
|
|
||||||
using std::format;
|
|
||||||
using std::vector, std::ifstream;
|
|
||||||
|
|
||||||
void draw(size_t *grid, vector<Point> &points);
|
|
||||||
void update(vector<Point> &points);
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
ifstream dirt_file("dirt.ppm");
|
|
||||||
u8 *dirt = ppm::load_ppm(dirt_file);
|
|
||||||
dirt_file.close();
|
|
||||||
ifstream grass_file("grass_top.ppm");
|
|
||||||
u8 *grass = ppm::load_ppm(grass_file);
|
|
||||||
grass_file.close();
|
|
||||||
ifstream grass_side_file("grass_side.ppm");
|
|
||||||
u8 *grass_side = ppm::load_ppm(grass_side_file);
|
|
||||||
grass_side_file.close();
|
|
||||||
|
|
||||||
std::vector<Point> points = {};
|
|
||||||
points.push_back(*Point(0, 0, 0).set_rgb(1.0, 0, 0));
|
|
||||||
|
|
||||||
std::vector<Point> donut = generate_donut(dirt, grass, grass_side, 0.0);
|
|
||||||
points.insert(points.end(), donut.begin(), donut.end());
|
|
||||||
donut = generate_donut(dirt, grass, grass_side, 32.0);
|
|
||||||
points.insert(points.end(), donut.begin(), donut.end());
|
|
||||||
donut = generate_donut(dirt, grass, grass_side, -32.0);
|
|
||||||
points.insert(points.end(), donut.begin(), donut.end());
|
|
||||||
delete[] dirt;
|
|
||||||
delete[] grass;
|
|
||||||
delete[] grass_side;
|
|
||||||
|
|
||||||
auto grid = new size_t[WIDTH * HEIGHT];
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
std::cout << "\033c";
|
|
||||||
draw(grid, points);
|
|
||||||
update(points);
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 60));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 w_x_to_screen(f64 w_x) {
|
|
||||||
return static_cast<i32>(std::round(w_x + static_cast<f64>(WIDTH) / 2.0));
|
|
||||||
}
|
|
||||||
i32 w_y_to_screen(f64 w_y) {
|
|
||||||
return static_cast<i32>(std::round(w_y + static_cast<f64>(HEIGHT) / 2.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
f64 w_z_to_screen(f64 w_z) {
|
|
||||||
return (w_z + static_cast<f64>(DEPTH) / 2.0) / static_cast<f64>(DEPTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(size_t *grid, vector<Point> &points) {
|
|
||||||
for (u32 i = 0; i < static_cast<u32>(WIDTH * HEIGHT); i++) {
|
|
||||||
grid[i] = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (size_t i = 0; i < points.size(); i++) {
|
|
||||||
Point p = points[i];
|
|
||||||
f64 p_x = p.get_x();
|
|
||||||
f64 p_y = p.get_y();
|
|
||||||
f64 p_z = p.get_z();
|
|
||||||
|
|
||||||
i32 s_x = w_x_to_screen(p_x);
|
|
||||||
i32 s_y = w_y_to_screen(p_y);
|
|
||||||
f64 s_z = w_z_to_screen(p_z);
|
|
||||||
if (0 <= s_x && s_x < HEIGHT && 0 <= s_y && s_y < HEIGHT) {
|
|
||||||
size_t index = static_cast<size_t>(s_x + s_y * HEIGHT);
|
|
||||||
size_t existing_pixel_handle = grid[index];
|
|
||||||
if (existing_pixel_handle == 0) {
|
|
||||||
grid[index] = i + 1;
|
|
||||||
} else if (points[existing_pixel_handle - 1].get_z() < p_z) {
|
|
||||||
grid[index] = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string line = "";
|
|
||||||
for (size_t y = 0; y < static_cast<size_t>(WIDTH); y++) {
|
|
||||||
for (size_t x = 0; x < static_cast<size_t>(HEIGHT); x++) {
|
|
||||||
size_t index = x + y * HEIGHT;
|
|
||||||
size_t handle = grid[index];
|
|
||||||
if (handle == 0) {
|
|
||||||
line += " ";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Point p = points[handle - 1];
|
|
||||||
f64 depth = w_z_to_screen(p.get_z());
|
|
||||||
assert(depth >= 0.0);
|
|
||||||
assert(depth <= 1.0);
|
|
||||||
f64 red = p.get_r() * depth;
|
|
||||||
f64 green = p.get_g() * depth;
|
|
||||||
f64 blue = p.get_b() * depth;
|
|
||||||
u8 r8 = static_cast<u8>(round(red * 255.0));
|
|
||||||
u8 g8 = static_cast<u8>(round(green * 255.0));
|
|
||||||
u8 b8 = static_cast<u8>(round(blue * 255.0));
|
|
||||||
line += format("\033[38;2;{};{};{}m██", r8, g8, b8);
|
|
||||||
}
|
|
||||||
line += '\n';
|
|
||||||
}
|
|
||||||
std::cout << line;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update(vector<Point> &points) {
|
|
||||||
for (size_t i = 0; i < points.size(); i++) {
|
|
||||||
Point *p = &points[i];
|
|
||||||
p->rotate_x(0.02);
|
|
||||||
p->rotate_y(-0.04);
|
|
||||||
p->rotate_z(0.03);
|
|
||||||
}
|
|
||||||
}
|
|
10
src/point.c
Normal file
10
src/point.c
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#include "point.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
point_t point(vec3_t pos, vec3_t color) {
|
||||||
|
point_t p = {pos, color};
|
||||||
|
return p;
|
||||||
|
}
|
|
@ -1,35 +0,0 @@
|
||||||
// Alexander Bass
|
|
||||||
// Created 4/16/24
|
|
||||||
#include "point.h"
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
void Point::rotate_x(f64 angle) {
|
|
||||||
f64 cos_a = cos(angle);
|
|
||||||
f64 sin_a = sin(angle);
|
|
||||||
f64 y_1 = this->y * cos_a - this->z * sin_a;
|
|
||||||
f64 z_1 = this->y * sin_a + this->z * cos_a;
|
|
||||||
this->y = y_1;
|
|
||||||
this->z = z_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Point::rotate_y(f64 angle) {
|
|
||||||
f64 cos_a = cos(angle);
|
|
||||||
f64 sin_a = sin(angle);
|
|
||||||
|
|
||||||
f64 x_1 = this->x * cos_a + this->z * sin_a;
|
|
||||||
f64 z_1 = this->z * cos_a - this->x * sin_a;
|
|
||||||
this->x = x_1;
|
|
||||||
this->z = z_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Point::rotate_z(f64 angle) {
|
|
||||||
f64 cos_a = cos(angle);
|
|
||||||
f64 sin_a = sin(angle);
|
|
||||||
|
|
||||||
f64 x_1 = this->x * cos_a - this->y * sin_a;
|
|
||||||
f64 y_1 = this->x * sin_a + this->y * cos_a;
|
|
||||||
this->x = x_1;
|
|
||||||
this->y = y_1;
|
|
||||||
}
|
|
83
src/point.h
83
src/point.h
|
@ -1,81 +1,12 @@
|
||||||
// Alexander Bass
|
// Alexander Bass
|
||||||
// Created 4/16/24
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "rgb.h"
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
class Point {
|
#include "vec3.h"
|
||||||
private:
|
typedef struct point_t {
|
||||||
f64 x;
|
vec3_t pos;
|
||||||
f64 y;
|
vec3_t color;
|
||||||
f64 z;
|
} point_t;
|
||||||
f64 r;
|
|
||||||
f64 g;
|
|
||||||
f64 b;
|
|
||||||
|
|
||||||
public:
|
point_t point(vec3_t, vec3_t);
|
||||||
Point(f64 _x, f64 _y, f64 _z) {
|
|
||||||
x = _x;
|
|
||||||
y = _y;
|
|
||||||
z = _z;
|
|
||||||
r = 1.0;
|
|
||||||
g = 1.0;
|
|
||||||
b = 1.0;
|
|
||||||
}
|
|
||||||
void set_xyz(f64 _x, f64 _y, f64 _z) {
|
|
||||||
x = _x;
|
|
||||||
y = _y;
|
|
||||||
z = _z;
|
|
||||||
};
|
|
||||||
void rotate_x(f64 angle);
|
|
||||||
void rotate_y(f64 angle);
|
|
||||||
void rotate_z(f64 angle);
|
|
||||||
Point *translate(f64 dx, f64 dy, f64 dz) {
|
|
||||||
x += dx;
|
|
||||||
y += dy;
|
|
||||||
z += dz;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
f64 get_x() const {
|
|
||||||
return x;
|
|
||||||
};
|
|
||||||
f64 get_y() const {
|
|
||||||
return y;
|
|
||||||
};
|
|
||||||
f64 get_z() const {
|
|
||||||
return z;
|
|
||||||
};
|
|
||||||
|
|
||||||
f64 get_r() const {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
f64 get_g() const {
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
f64 get_b() const {
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void translate_x(f64 dx) {
|
|
||||||
x += dx;
|
|
||||||
}
|
|
||||||
void translate_y(f64 dy) {
|
|
||||||
y += dy;
|
|
||||||
}
|
|
||||||
void translate_z(f64 dz) {
|
|
||||||
z += dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
Point *set_rgb(f64 _r, f64 _g, f64 _b) {
|
|
||||||
r = _r;
|
|
||||||
g = _g;
|
|
||||||
b = _b;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
Point *set_rgb(rgb col) {
|
|
||||||
r = col.r;
|
|
||||||
g = col.g;
|
|
||||||
b = col.b;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
};
|
|
46
src/point_list.c
Normal file
46
src/point_list.c
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/21/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#include "point_list.h"
|
||||||
|
#include "point.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
point_list_t point_list(size_t capacity) {
|
||||||
|
point_t *points = (point_t *)(malloc(sizeof(point_t) * capacity));
|
||||||
|
point_list_t point_list = {points, 0, capacity};
|
||||||
|
return point_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_point(point_list_t *points, point_t point) {
|
||||||
|
// Dynamic length list
|
||||||
|
size_t length = points->length;
|
||||||
|
size_t capacity = points->capacity;
|
||||||
|
if (length == capacity) {
|
||||||
|
size_t new_capacity = capacity + 100;
|
||||||
|
points->list = realloc(points->list, new_capacity * sizeof(point_t));
|
||||||
|
points->capacity = new_capacity;
|
||||||
|
}
|
||||||
|
points->list[length] = point;
|
||||||
|
(points->length)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_point_list(point_list_t *points) {
|
||||||
|
free(points->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void extend_point_list(point_list_t *points, point_list_t *extension) {
|
||||||
|
// Dynamic length list
|
||||||
|
size_t length = points->length;
|
||||||
|
size_t capacity = points->capacity;
|
||||||
|
size_t new_length = length + extension->length;
|
||||||
|
if (new_length >= capacity) {
|
||||||
|
size_t new_capacity = new_length + 100;
|
||||||
|
points->list = realloc(points->list, new_capacity * sizeof(point_t));
|
||||||
|
points->capacity = new_capacity;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < extension->length; i++) {
|
||||||
|
points->list[i + length] = extension->list[i];
|
||||||
|
(points->length)++;
|
||||||
|
}
|
||||||
|
}
|
18
src/point_list.h
Normal file
18
src/point_list.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/21/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#include "point.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct point_list_t {
|
||||||
|
point_t *list;
|
||||||
|
size_t length;
|
||||||
|
size_t capacity;
|
||||||
|
} point_list_t;
|
||||||
|
|
||||||
|
point_list_t point_list(size_t capacity);
|
||||||
|
|
||||||
|
void push_point(point_list_t *points, point_t point);
|
||||||
|
void free_point_list(point_list_t *points);
|
||||||
|
void extend_point_list(point_list_t *list, point_list_t *extension);
|
40
src/ppm/ppm.c
Normal file
40
src/ppm/ppm.c
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#include "ppm.h"
|
||||||
|
|
||||||
|
#include "../texture.h"
|
||||||
|
#include "../types.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
texture_t load_ppm(FILE *file) {
|
||||||
|
assert(fgetc(file) == 'P');
|
||||||
|
assert(fgetc(file) == '3');
|
||||||
|
|
||||||
|
u32 width, height;
|
||||||
|
u32 color;
|
||||||
|
|
||||||
|
fscanf(file, "%d %d", &width, &height);
|
||||||
|
fscanf(file, "%d", &color);
|
||||||
|
|
||||||
|
assert(width == 16 && height == 16);
|
||||||
|
assert(color == 255);
|
||||||
|
|
||||||
|
texture_t tex = texture(width, height);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < width * height * 3; i++) {
|
||||||
|
u8 byte;
|
||||||
|
fscanf(file, "%hhd", &byte);
|
||||||
|
tex.bytes[i] = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_t load_ppm_file(const char *file_name) {
|
||||||
|
FILE *file = fopen(file_name, "r");
|
||||||
|
texture_t tex = load_ppm(file);
|
||||||
|
fclose(file);
|
||||||
|
return tex;
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
// Alexander Bass
|
|
||||||
// Created 4/16/24
|
|
||||||
#include "ppm.h"
|
|
||||||
using std::string;
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
u8 *ppm::load_ppm(std::istream &input) {
|
|
||||||
string header;
|
|
||||||
input >> header;
|
|
||||||
assert(header == "P3");
|
|
||||||
u32 width, height;
|
|
||||||
u32 color;
|
|
||||||
input >> width;
|
|
||||||
input >> height;
|
|
||||||
assert(width == 16 && height == 16);
|
|
||||||
input >> color;
|
|
||||||
assert(color == 255);
|
|
||||||
|
|
||||||
u8 *buffer = new u8[width * height * 3];
|
|
||||||
for (size_t i = 0; i < width * height * 3; i++) {
|
|
||||||
u16 val = 0;
|
|
||||||
|
|
||||||
input >> val;
|
|
||||||
buffer[i] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Alexander Bass
|
// Alexander Bass
|
||||||
// Created 4/16/24
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../texture.h"
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <istream>
|
texture_t load_ppm(FILE *file_stream);
|
||||||
|
texture_t load_ppm_file(const char *file_name);
|
||||||
namespace ppm {
|
|
||||||
|
|
||||||
u8 *load_ppm(std::istream &input);
|
|
||||||
} // namespace ppm
|
|
19
src/rgb.h
19
src/rgb.h
|
@ -1,19 +0,0 @@
|
||||||
// Alexander Bass
|
|
||||||
// Created 4/16/24
|
|
||||||
#pragma once
|
|
||||||
#include "types.h"
|
|
||||||
struct rgb {
|
|
||||||
f64 r;
|
|
||||||
f64 g;
|
|
||||||
f64 b;
|
|
||||||
rgb(f64 _r, f64 _g, f64 _b) {
|
|
||||||
r = _r;
|
|
||||||
g = _g;
|
|
||||||
b = _b;
|
|
||||||
}
|
|
||||||
void mix(rgb rhs) {
|
|
||||||
r *= rhs.r;
|
|
||||||
g *= rhs.g;
|
|
||||||
b *= rhs.b;
|
|
||||||
}
|
|
||||||
};
|
|
15
src/texture.c
Normal file
15
src/texture.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "texture.h"
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/21/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
texture_t texture(u32 width, u32 height) {
|
||||||
|
u8 *bytes = (u8 *)(malloc(sizeof(u8) * width * height * 3));
|
||||||
|
texture_t tex = {bytes, width, height};
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_texture(texture_t *texture) {
|
||||||
|
free(texture->bytes);
|
||||||
|
}
|
14
src/texture.h
Normal file
14
src/texture.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/21/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
typedef struct texture_t {
|
||||||
|
u8 *const bytes;
|
||||||
|
const u32 width;
|
||||||
|
const u32 height;
|
||||||
|
} texture_t;
|
||||||
|
|
||||||
|
texture_t texture(u32 width, u32 height);
|
||||||
|
void free_texture(texture_t *);
|
|
@ -1,8 +1,8 @@
|
||||||
// Alexander Bass
|
// Alexander Bass
|
||||||
// Created 4/15/24
|
// Created 4/15/24
|
||||||
// Modified 4/14/24
|
// Modified 4/21/24
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
|
@ -10,11 +10,9 @@ typedef uint32_t u32;
|
||||||
typedef uint64_t u64;
|
typedef uint64_t u64;
|
||||||
|
|
||||||
typedef int8_t i8;
|
typedef int8_t i8;
|
||||||
typedef std::int16_t i16;
|
typedef int16_t i16;
|
||||||
typedef int32_t i32;
|
typedef int32_t i32;
|
||||||
typedef int64_t i64;
|
typedef int64_t i64;
|
||||||
|
|
||||||
typedef float f32;
|
typedef float f32;
|
||||||
typedef double f64;
|
typedef double f64;
|
||||||
|
|
||||||
typedef std::size_t usize;
|
|
55
src/vec3.c
Normal file
55
src/vec3.c
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#include "vec3.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
void rotate_i(vec3_t *point, f64 angle) {
|
||||||
|
f64 cos_a = cos(angle);
|
||||||
|
f64 sin_a = sin(angle);
|
||||||
|
f64 y_1 = point->j * cos_a - point->k * sin_a;
|
||||||
|
f64 z_1 = point->j * sin_a + point->k * cos_a;
|
||||||
|
point->j = y_1;
|
||||||
|
point->k = z_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rotate_j(vec3_t *point, f64 angle) {
|
||||||
|
f64 cos_a = cos(angle);
|
||||||
|
f64 sin_a = sin(angle);
|
||||||
|
|
||||||
|
f64 x_1 = point->i * cos_a + point->k * sin_a;
|
||||||
|
f64 z_1 = point->k * cos_a - point->i * sin_a;
|
||||||
|
point->i = x_1;
|
||||||
|
point->k = z_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rotate_k(vec3_t *point, f64 angle) {
|
||||||
|
f64 cos_a = cos(angle);
|
||||||
|
f64 sin_a = sin(angle);
|
||||||
|
|
||||||
|
f64 x_1 = point->i * cos_a - point->j * sin_a;
|
||||||
|
f64 y_1 = point->i * sin_a + point->j * cos_a;
|
||||||
|
point->i = x_1;
|
||||||
|
point->j = y_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3_t vec3(f64 i, f64 j, f64 k) {
|
||||||
|
vec3_t vector = {i, j, k};
|
||||||
|
return vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3_t mul_vec(vec3_t lhs, vec3_t rhs) {
|
||||||
|
lhs.i *= rhs.i;
|
||||||
|
lhs.j *= rhs.j;
|
||||||
|
lhs.k *= rhs.k;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3_t mul_scalar(vec3_t lhs, f64 rhs) {
|
||||||
|
lhs.i *= rhs;
|
||||||
|
lhs.j *= rhs;
|
||||||
|
lhs.k *= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
18
src/vec3.h
Normal file
18
src/vec3.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/16/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
typedef struct vec3_t {
|
||||||
|
f64 i;
|
||||||
|
f64 j;
|
||||||
|
f64 k;
|
||||||
|
} vec3_t;
|
||||||
|
|
||||||
|
vec3_t vec3(f64 i, f64 j, f64 k);
|
||||||
|
vec3_t mul_vec(vec3_t lhs, vec3_t rhs);
|
||||||
|
vec3_t mul_scalar(vec3_t lhs, f64 rhs);
|
||||||
|
|
||||||
|
void rotate_i(vec3_t *point, f64 angle);
|
||||||
|
void rotate_j(vec3_t *point, f64 angle);
|
||||||
|
void rotate_k(vec3_t *point, f64 angle);
|
8
src/vec4.c
Normal file
8
src/vec4.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/21/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#include "vec4.h"
|
||||||
|
vec4_t vec4(f64 i, f64 j, f64 k, f64 l) {
|
||||||
|
vec4_t vector = {i, j, k, l};
|
||||||
|
return vector;
|
||||||
|
}
|
13
src/vec4.h
Normal file
13
src/vec4.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Alexander Bass
|
||||||
|
// Created 4/21/24
|
||||||
|
// Modified 4/21/24
|
||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
typedef struct vec4_t {
|
||||||
|
f64 i;
|
||||||
|
f64 j;
|
||||||
|
f64 k;
|
||||||
|
f64 l;
|
||||||
|
} vec4_t;
|
||||||
|
|
||||||
|
vec4_t vec4(f64 i, f64 j, f64 k, f64 l);
|
Loading…
Reference in a new issue