From 933819a219cfdf77ec8d1df709646b5e75080b54 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 22 Apr 2023 22:11:16 +0200 Subject: [PATCH] a bit slow, but that's a start --- .gitignore | 3 + CMakeLists.txt | 58 ++++++++ README.md | 1 + assets/icon-sel.png | Bin 0 -> 3536 bytes assets/icon-uns.png | Bin 0 -> 1700 bytes assets/icon.xcf | Bin 0 -> 55168 bytes src/backend/gint/shader.cc | 56 +++++++ src/backend/linux/programs.cc | 53 +++++++ src/backend/linux/programs.h | 188 ++++++++++++++++++++++++ src/backend/linux/render.cc | 0 src/chaos-drop.h | 85 +++++++++++ src/main.cc | 269 ++++++++++++++++++++++++++++++++++ src/raytracing.cc | 243 ++++++++++++++++++++++++++++++ 13 files changed, 956 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 assets/icon-sel.png create mode 100644 assets/icon-uns.png create mode 100644 assets/icon.xcf create mode 100644 src/backend/gint/shader.cc create mode 100644 src/backend/linux/programs.cc create mode 100644 src/backend/linux/programs.h create mode 100644 src/backend/linux/render.cc create mode 100644 src/chaos-drop.h create mode 100644 src/main.cc create mode 100644 src/raytracing.cc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ba078b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build-*/ +*.g3a +*.mp4 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..14d8805 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.15) +project(ChaosDrop VERSION 1.0 LANGUAGES CXX C ASM) + +list(APPEND CMAKE_MODULE_PATH "$ENV{AZUR_PATH_${AZUR_PLATFORM}}/lib/cmake") +find_package(Azur 0.1 REQUIRED) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +set(SOURCES + src/main.cc + src/raytracing.cc) +set(ASSETS) + +if(AZUR_PLATFORM STREQUAL gint) + list(APPEND SOURCES + src/backend/gint/shader.cc) +# list(APPEND ASSETS +# ...) +endif() + +if(AZUR_PLATFORM STREQUAL linux) + list(APPEND SOURCES + src/backend/linux/render.cc + src/backend/linux/programs.cc) +endif() + +# No emscripten backend for now +if(AZUR_PLATFORM STREQUAL emscripten) +# configure_file(backend/emscripten/index.html index.html) +# list(APPEND SOURCES +# src/backend/emscripten/render.cc) + message(FATAL_ERROR "No emscripten build yet") +endif() + +add_executable(chaos-drop ${SOURCES} ${ASSETS}) +target_compile_options(chaos-drop PRIVATE -Wall -Wextra -O2) + +if(AZUR_PLATFORM STREQUAL gint) + find_package(Gint 2.10 REQUIRED) + find_package(LibProf 2.4 REQUIRED) + include(Fxconv) + fxconv_declare_assets(${ASSETS} WITH_METADATA) + + target_link_libraries(chaos-drop Azur::Azur LibProf::LibProf Gint::Gint -lm) + target_link_options(chaos-drop PRIVATE + -Wl,-Map=map -Wl,--print-memory-usage) + + include(GenerateG3A) + generate_g3a(TARGET chaos-drop + NAME "Chaos Drop" + OUTPUT "ChaosDrop.g3a" + ICONS assets/icon-uns.png assets/icon-sel.png) +endif() + +if(AZUR_PLATFORM STREQUAL linux) + target_link_libraries(chaos-drop Azur::Azur Azur::ImGui) +endif() diff --git a/README.md b/README.md new file mode 100644 index 0000000..2603dbc --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +A reckless attempt at making a game with real-time raytracing, because my brain is filled with ludicrous ideas that keep turning out to be barely possible. diff --git a/assets/icon-sel.png b/assets/icon-sel.png new file mode 100644 index 0000000000000000000000000000000000000000..0ce3029cc00aea4c3cfad161c6f2bd7b60f68f1f GIT binary patch literal 3536 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 KMNUMnLSTaFG`Vj8 literal 0 HcmV?d00001 diff --git a/assets/icon-uns.png b/assets/icon-uns.png new file mode 100644 index 0000000000000000000000000000000000000000..039c096cc2ab31206abf45b5867ee55594d732ae GIT binary patch literal 1700 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 Ol}iESO+rylvHuUZ)lew_ literal 0 HcmV?d00001 diff --git a/src/backend/gint/shader.cc b/src/backend/gint/shader.cc new file mode 100644 index 0000000..a362b58 --- /dev/null +++ b/src/backend/gint/shader.cc @@ -0,0 +1,56 @@ +#include "../../chaos-drop.h" +#include + +uint8_t CD_RAYTRACE_SHADER_ID = -1; + +struct cd_raytrace_cmd +{ + /* Shader ID for Azur */ + uint8_t shader_id; + uint8_t _[3]; + + /* Camera used for rendering */ + struct camera const *camera; + /* Current y value */ + int y; +}; + +#include +/* TODO: Write raytrace shader in assembler (MUCH NEEDED) */ +void cd_raytrace_shader(void *uniforms0, void *cmd0, void *fragment) +{ + memset(fragment, 0x55, azrp_width * azrp_frag_height * 2); + + uint32_t uniforms = (uint32_t)uniforms0; + struct cd_raytrace_cmd *cmd = (struct cd_raytrace_cmd *)cmd0; + + int frag_height = uniforms; + int h = (frag_height > 112 - cmd->y) ? 112 - cmd->y : frag_height; + render_fragment(cmd->camera, (uint16_t *)fragment, cmd->y, h); + cmd->y += h; +} + +GCONSTRUCTOR +static void register_shader(void) +{ + CD_RAYTRACE_SHADER_ID = azrp_register_shader(cd_raytrace_shader); +} + +void cd_raytrace(struct camera const *camera) +{ + prof_enter(azrp_perf_cmdgen); + + struct cd_raytrace_cmd cmd; + cmd.shader_id = CD_RAYTRACE_SHADER_ID; + cmd.camera = camera; + cmd.y = 0; + + azrp_queue_command(&cmd, sizeof cmd, 0, azrp_frag_count); + prof_leave(azrp_perf_cmdgen); +} + +void cd_raytrace_configure(void) +{ + uint32_t value = azrp_frag_height; + azrp_set_uniforms(CD_RAYTRACE_SHADER_ID, (void *)value); +} diff --git a/src/backend/linux/programs.cc b/src/backend/linux/programs.cc new file mode 100644 index 0000000..c9adcd2 --- /dev/null +++ b/src/backend/linux/programs.cc @@ -0,0 +1,53 @@ +#include "programs.h" +#include + +//--- +// 2D Texture shader +//--- + +ProgramTexture::ProgramTexture(): Program() +{ + glBindVertexArray(this->vao); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + // TODO: Better way to access Azur's internal shaders + extern char const *azur_glsl__vs_tex2d; + extern char const *azur_glsl__fs_tex2d; + + this->prog = azur::gl::loadProgramSources( + GL_VERTEX_SHADER, azur_glsl__vs_tex2d, + GL_FRAGMENT_SHADER, azur_glsl__fs_tex2d, + 0); +} + +void ProgramTexture::set_vertex_attributes() const +{ + glVertexAttribPointer(glGetAttribLocation(this->prog, "a_vertex"), + 2, GL_FLOAT, GL_FALSE, + sizeof(ProgramTexture_Attributes), + (void *)offsetof(ProgramTexture_Attributes, vertex) + ); + glVertexAttribPointer(glGetAttribLocation(this->prog, "a_texture_pos"), + 2, GL_FLOAT, GL_FALSE, + sizeof(ProgramTexture_Attributes), + (void *)offsetof(ProgramTexture_Attributes, uv) + ); +} + +void ProgramTexture::add_texture(int x, int y, int width, int height) +{ + ProgramTexture_Attributes attr[4] = { + { glm::vec2(x, y), glm::vec2(0.0, 0.0) }, + { glm::vec2(x+width, y), glm::vec2(1.0, 0.0) }, + { glm::vec2(x, y+height), glm::vec2(0.0, 1.0) }, + { glm::vec2(x+width, y+height), glm::vec2(1.0, 1.0) }, + }; + + this->vertices.push_back(attr[0]); + this->vertices.push_back(attr[1]); + this->vertices.push_back(attr[2]); + this->vertices.push_back(attr[1]); + this->vertices.push_back(attr[2]); + this->vertices.push_back(attr[3]); +} diff --git a/src/backend/linux/programs.h b/src/backend/linux/programs.h new file mode 100644 index 0000000..241e80c --- /dev/null +++ b/src/backend/linux/programs.h @@ -0,0 +1,188 @@ +//-Program: wrapper for shader + VAO + VBO (from Magic Lab) + +#pragma once + +#include +#include +#include + +template +struct Program +{ + Program(); + virtual ~Program(); + + /* Since this holds non-trivial OpenGL objects, disable copy/move */ + Program(Program const &other) = delete; + Program(Program &&other) = delete; + + /* Adds a vertex to the vertex data buffer */ + void add_vertex(VertexAttributes const &attributes); + + /* Set vertex attributes when the buffer is loaded */ + virtual void set_vertex_attributes() const = 0; + + /* Update the VBO and draw */ + void prepare_draw(); + void draw(); + + /* Utilities to set uniforms */ + void set_uniform(char const *name, float f); + void set_uniform(char const *name, float f1, float f2); + void set_uniform(char const *name, float f1, float f2, float f3); + void set_uniform(char const *name, glm::vec2 const &v2); + void set_uniform(char const *name, glm::vec3 const &v3); + void set_uniform(char const *name, glm::vec4 const &v4); + void set_uniform(char const *name, glm::mat2 const &m2); + void set_uniform(char const *name, glm::mat3 const &m3); + void set_uniform(char const *name, glm::mat4 const &m4); + + /* Program ID */ + GLuint prog; + /* Vertex Array Object and Vertex Buffer Object with parameters */ + GLuint vao, vbo; + + /* Vertex attributes to be loaded in the VBO */ + std::vector vertices; + /* Size of the VBO, in number of vertices */ + /* Number of spots currently used in [vertex_data] */ + size_t vbo_size; +}; + +template +Program::Program(): vertices {} +{ + prog = 0; + glGenVertexArrays(1, &vao); + glGenBuffers(1, &vbo); + + vbo_size = 0; +} + +template +void Program::add_vertex(T const &attributes) +{ + vertices.push_back(attributes); +} + +template +void Program::prepare_draw() +{ + if(!vertices.size()) return; + + glBindVertexArray(vao); + glUseProgram(prog); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + + /* If the size of the VBO is too small or much larger than needed, resize + it; otherwise, simply swap the data without reallocating */ + if(vbo_size < vertices.size() || vbo_size > vertices.size() * 4) { + glBufferData(GL_ARRAY_BUFFER, sizeof(T) * vertices.size(), + vertices.data(), GL_DYNAMIC_DRAW); + } + else { + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(T) * vertices.size(), + vertices.data()); + } + + this->set_vertex_attributes(); +} + +template +void Program::draw() +{ + prepare_draw(); + + // TODO: Do not hardcode the specific operation GL_TRIANGLES + glDrawArrays(GL_TRIANGLES, 0, vertices.size()); +} + +template +void Program::set_uniform(char const *name, float f) +{ + glUniform1f(glGetUniformLocation(this->prog, name), f); +} + +template +void Program::set_uniform(char const *name, float f1, float f2) +{ + glUniform2f(glGetUniformLocation(this->prog, name), f1, f2); +} + +template +void Program::set_uniform(char const *name, float f1, float f2, float f3) +{ + glUniform3f(glGetUniformLocation(this->prog, name), f1, f2, f3); +} + +template +void Program::set_uniform(char const *name, glm::vec2 const &v2) +{ + glUniform2fv(glGetUniformLocation(this->prog, name), 1, &v2[0]); +} + +template +void Program::set_uniform(char const *name, glm::vec3 const &v3) +{ + glUniform3fv(glGetUniformLocation(this->prog, name), 1, &v3[0]); +} + +template +void Program::set_uniform(char const *name, glm::vec4 const &v4) +{ + glUniform4fv(glGetUniformLocation(this->prog, name), 1, &v4[0]); +} + +template +void Program::set_uniform(char const *name, glm::mat2 const &m2) +{ + glUniformMatrix2fv(glGetUniformLocation(this->prog, name), 1, GL_FALSE, + &m2[0][0]); +} + +template +void Program::set_uniform(char const *name, glm::mat3 const &m3) +{ + glUniformMatrix3fv(glGetUniformLocation(this->prog, name), 1, GL_FALSE, + &m3[0][0]); +} + +template +void Program::set_uniform(char const *name, glm::mat4 const &m4) +{ + glUniformMatrix4fv(glGetUniformLocation(this->prog, name), 1, GL_FALSE, + &m4[0][0]); +} + +template +Program::~Program() +{ + glDeleteBuffers(1, &vbo); + glDeleteVertexArrays(1, &vao); + glDeleteProgram(prog); +} + +//--- +// 2D texture shader +//--- + +/* 6 vertices (a quad) for each texture */ +struct ProgramTexture_Attributes +{ + /* Location of the vertex */ + glm::vec2 vertex; + /* Location within the texture */ + glm::vec2 uv; +}; + +struct ProgramTexture: public Program +{ + ProgramTexture(); + void set_vertex_attributes() const override; + + /* Add a full texture of the specified size + TODO: This always uses texture #0 + TODO: Specify sub-regions */ + void add_texture(int x, int y, int width, int height); +}; diff --git a/src/backend/linux/render.cc b/src/backend/linux/render.cc new file mode 100644 index 0000000..e69de29 diff --git a/src/chaos-drop.h b/src/chaos-drop.h new file mode 100644 index 0000000..5b98e49 --- /dev/null +++ b/src/chaos-drop.h @@ -0,0 +1,85 @@ +/* The world is a drop chute, arranged horizontally. The coordinate system is + right-handed, with the following orientation from the top view of the chute: + + z + ^ + | + | + y (x)-----> x + + The player primarily moves in the +y direction (... although in practice + objects move towards the player to better use the limited range of fixed- + point values). + + We compute directions of rays based on points on the virtual screen placed + in the world, in front of the camera. We make rays start at the camera + position so the distance between the camera and screen does not matter; we + arbitrarily place the screen at a distance which makes the screen height + correspond to 2*HALF_SCREEN_HEIGHT world units. This is to help avoid + precision loss with fixed-point numbers. */ + +#include +#include +using namespace libnum; +struct mat3; + +/* Number of world units that we fix the screen's half height to. The screen is + placed at the correct distance to make that happen. */ +#define HALF_SCREEN_HEIGHT 2 +/* World boundaries */ +#define WORLD_SIZE 8 /* (± 4) */ +/* Viewport size, in pixels */ +#define VWIDTH 198 +#define VHEIGHT 112 + +struct camera { + num fov; + num screen_distance; + + /* Camera position (usually stays at z=0, objects move towards it) */ + vec3 pos; + /* Angles of rotation */ + float yaw, pitch, roll; + num cos_r, sin_r; + num cos_p, sin_p; + num cos_y, sin_y; + /* Corresponding directions, in world coordinates */ + vec3 forward, right, up; + + /* Game stuff... */ + + num neon_position; +}; + +void camera_set_fov(struct camera *camera, float fov_degrees); +mat3 matrix_camera2world(struct camera const *camera); +void camera_update_angles(struct camera *camera); +void render_fragment(struct camera const *camera, uint16_t *fragment, + int y_start, int y_height); + +//=== Azur shader wrapping the raytracing ===// + +void cd_raytrace(struct camera const *camera); +void cd_raytrace_configure(void); + +//=== Input management ===// + +struct input { + bool left; + bool right; + bool up; + bool down; + bool OPTN; +}; + +//=== Additions to libnum ===// + +struct mat3 +{ + num x11, x12, x13; + num x21, x22, x23; + num x31, x32, x33; +}; + +mat3 operator *(mat3 const &A, mat3 const &B); +vec3 operator *(mat3 const &M, vec3 const &u); diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..3e1b0ad --- /dev/null +++ b/src/main.cc @@ -0,0 +1,269 @@ +#define __BSD_VISIBLE 1 +#include +#include +#include +#include "chaos-drop.h" + +#if defined(AZUR_TOOLKIT_SDL) +#include +#include +#include +#include "backend/linux/programs.h" + +static uint16_t vram[VWIDTH * VHEIGHT]; +std::unique_ptr shader_texture = nullptr; +static GLuint tex_vram; + +static void view_update(void) +{ + SDL_Window *window = azur_sdl_window(); + int width, height; + SDL_GetWindowSize(window, &width, &height); + + /* Transform from pixel coordinates within the winfow to GL coordinates */ + glm::mat3 tr_pixel2gl( + 2.0f / width, 0.0f, 0.0f, + 0.0f, -2.0f / height, 0.0f, + -1.0f, 1.0f, 1.0f); + + glUseProgram(shader_texture->prog); + shader_texture->set_uniform("u_transform", tr_pixel2gl); +} + +static void init(void) +{ + shader_texture = std::make_unique(); + view_update(); + memset(vram, 0x55, sizeof vram); + + glGenTextures(1, &tex_vram); + glBindTexture(GL_TEXTURE_2D, tex_vram); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VWIDTH, VHEIGHT, 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, vram); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + +static void quit(void) +{ +} + +static int platform_update(struct input *input) +{ + SDL_Event e; + *input = (struct input){}; + + while(SDL_PollEvent(&e)) { +// ImGui_ImplSDL2_ProcessEvent(&e); +// render_needed = std::max(render_needed, 1); + + if(e.type == SDL_QUIT) + return 1; + if(e.type == SDL_WINDOWEVENT && + e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + view_update(); + } + } + + Uint8 const *state = SDL_GetKeyboardState(NULL); + input->up = state[SDL_SCANCODE_UP]; + input->down = state[SDL_SCANCODE_DOWN]; + input->left = state[SDL_SCANCODE_LEFT]; + input->right = state[SDL_SCANCODE_RIGHT]; + return 0; +} + +static void platform_render(void) +{ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VWIDTH, VHEIGHT, 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, vram); + + SDL_Window *window = azur_sdl_window(); + + shader_texture->vertices.clear(); + shader_texture->add_texture(0, 0, 3*VWIDTH, 3*VHEIGHT); + shader_texture->draw(); + + SDL_GL_SwapWindow(window); +} + +#elif defined(AZUR_TOOLKIT_GINT) + +#include +#include +#include +#include +#include +#include +#define vram gint_vram + +static int platform_update(struct input *input) +{ + key_event_t e; + + while((e = pollevent()).type != KEYEV_NONE) { + if(e.type == KEYEV_UP) + continue; + + if(e.key == KEY_EXIT) + return 1; + if(e.key == KEY_MENU) + gint_osmenu(); + if(e.key == KEY_OPTN) + input->OPTN = true; + } + + input->left = keydown(KEY_LEFT); + input->right = keydown(KEY_RIGHT); + input->up = keydown(KEY_UP); + input->down = keydown(KEY_DOWN); + return 0; +} + +static void platform_render(void) +{ + azrp_update(); +} + +static void init(void) +{ + prof_init(); + azrp_config_scale(2); + cd_raytrace_configure(); +} + +static void quit(void) +{ + prof_quit(); +} + +#endif + +mat3 operator *(mat3 const &A, mat3 const &B) +{ + mat3 C; + + C.x11 = A.x11 * B.x11 + A.x12 * B.x21 + A.x13 * B.x31; + C.x12 = A.x11 * B.x12 + A.x12 * B.x22 + A.x13 * B.x32; + C.x13 = A.x11 * B.x13 + A.x12 * B.x23 + A.x13 * B.x33; + + C.x21 = A.x21 * B.x11 + A.x22 * B.x21 + A.x23 * B.x31; + C.x22 = A.x21 * B.x12 + A.x22 * B.x22 + A.x23 * B.x32; + C.x23 = A.x21 * B.x13 + A.x22 * B.x23 + A.x23 * B.x33; + + C.x31 = A.x31 * B.x11 + A.x32 * B.x21 + A.x33 * B.x31; + C.x32 = A.x31 * B.x12 + A.x32 * B.x22 + A.x33 * B.x32; + C.x33 = A.x31 * B.x13 + A.x32 * B.x23 + A.x33 * B.x33; + + return C; +} + +vec3 operator * (mat3 const &M, vec3 const &u) +{ + vec3 v; + + v.x = M.x11 * u.x + M.x12 * u.y + M.x13 * u.z; + v.y = M.x21 * u.x + M.x22 * u.y + M.x23 * u.z; + v.z = M.x31 * u.x + M.x32 * u.y + M.x33 * u.z; + + return v; +} + +static struct camera *camera = NULL; +static bool debug = false; + +void render(void) +{ +#ifdef AZUR_TOOLKIT_GINT + azrp_perf_clear(); + cd_raytrace(camera); + platform_render(); + + if(debug) { + drect(0, DHEIGHT-20, DWIDTH-1, DHEIGHT-1, C_WHITE); + dprint(4, 209, C_BLACK, "render:%4d+%4dus", + prof_time(azrp_perf_render) - prof_time(azrp_perf_r61524), + prof_time(azrp_perf_r61524)); + r61524_display(gint_vram, DHEIGHT-20, 20, R61524_DMA_WAIT); + } +#else + render_fragment(camera, vram, 0, VHEIGHT); + platform_render(); +#endif +} + +int update(void) +{ + struct input input = {}; + if(platform_update(&input)) + return 1; + + /* Yes I'm aware I'm always changing the angles */ + bool changed = false; + + static num const mv_speed = 0.35; + static num const wall = WORLD_SIZE * 0.45; /* margin */ + static float const rot_speed = 0.01; + static float const rot_snap = 0.6; + static float const rot_max = 0.2; + static num const neon_speed = 2; + + if(input.left) { + camera->pos.x = max(camera->pos.x - mv_speed, -wall); + camera->yaw = fmaxf(camera->yaw - rot_speed, -rot_max); + changed = true; + } + else if(input.right) { + camera->pos.x = min(camera->pos.x + mv_speed, wall); + camera->yaw = fminf(camera->yaw + rot_speed, rot_max); + changed = true; + } + else { + camera->yaw *= rot_snap; + changed = true; + } + + if(input.up) { + camera->pos.z = min(camera->pos.z + mv_speed, wall); + camera->pitch = fmaxf(camera->pitch - rot_speed, -rot_max); + changed = true; + } + else if(input.down) { + camera->pos.z = max(camera->pos.z - mv_speed, -wall); + camera->pitch = fminf(camera->pitch + rot_speed, rot_max); + changed = true; + } + else { + camera->pitch *= rot_snap; + changed = true; + } + + if(changed) + camera_update_angles(camera); + + camera->neon_position = + (camera->neon_position + num(32) - neon_speed) % num(32); + + if(input.OPTN) + debug = !debug; + return 0; +} + +int main(void) +{ + if(azur_init("Chaos Drop!", 3*VWIDTH, 3*VHEIGHT)) + return 1; + + struct camera c = {}; + camera = &c; + /* TODO: Why do I need such a low FOV?! */ + camera_set_fov(camera, 80.0); + camera_update_angles(camera); + + init(); + int rc = azur_main_loop(render, 30, update, -1, AZUR_MAIN_LOOP_TIED); + quit(); + return rc; +} diff --git a/src/raytracing.cc b/src/raytracing.cc new file mode 100644 index 0000000..754ea51 --- /dev/null +++ b/src/raytracing.cc @@ -0,0 +1,243 @@ +#define __BSD_VISIBLE 1 +#include "chaos-drop.h" +#include +#include + +void camera_set_fov(struct camera *camera, float fov_degrees) +{ + camera->fov = num(fov_degrees); + float fov_radians = fov_degrees * 3.14159 / 180; + /* Use FOV as the horizontal viewing angle */ + float sd = (VWIDTH * HALF_SCREEN_HEIGHT / VHEIGHT) / tanf(fov_radians / 2); + /* The screen is at such a distance that 16 units is half the height. We + don't care where it is placed as we'll always send rays from the camera + itself. This is to ensure good ranges for fixed point values */ + camera->screen_distance = num(sd); +} + +mat3 matrix_camera2world(struct camera const *camera) +{ + num cos_r = camera->cos_r; + num sin_r = camera->sin_r; + num cos_p = camera->cos_p; + num sin_p = camera->sin_p; + num cos_y = camera->cos_y; + num sin_y = camera->sin_y; + +#if 0 + mat3 m_roll = { + cos_r, 0, sin_r, + 0, 1, 0, + -sin_r, 0, cos_r, + }; + mat3 m_pitch = { + 1, 0, 0, + 0, cos_p, +sin_p, + 0, -sin_p, cos_p, + }; + mat3 m_yaw = { + cos_y, +sin_y, 0, + -sin_y, cos_y, 0, + 0, 0, 1, + }; + mat3 M = m_roll * (m_pitch * m_yaw); +#endif + + mat3 m_anti_roll = { + cos_r, 0, -sin_r, + 0, 1, 0, + +sin_r, 0, cos_r, + }; + mat3 m_anti_pitch = { + 1, 0, 0, + 0, cos_p, -sin_p, + 0, +sin_p, cos_p, + }; + mat3 m_anti_yaw = { + cos_y, -sin_y, 0, + +sin_y, cos_y, 0, + 0, 0, 1, + }; + return m_anti_yaw * (m_anti_pitch * m_anti_roll); +} + +void camera_update_angles(struct camera *camera) +{ + float c, s; + + sincosf(camera->roll, &s, &c); + camera->sin_r = s; + camera->cos_r = c; + + sincosf(camera->pitch, &s, &c); + camera->sin_p = s; + camera->cos_p = c; + + sincosf(camera->yaw, &s, &c); + camera->sin_y = s; + camera->cos_y = c; + + mat3 c2w = matrix_camera2world(camera); + camera->forward = c2w * vec3(0, 1, 0); + camera->right = c2w * vec3(1, 0, 0); + camera->up = c2w * vec3(0, 0, 1); +} + +using snum = num16; +using svec3 = vec; +svec3 svec3_of_vec3(vec3 v) +{ + return svec3(snum(v.x), snum(v.y), snum(v.z)); +} + +enum object { + /* Wall sides */ + LEFT = 1, TOP, RIGHT, BOTTOM, +}; + +static int cast_ray(svec3 const &origin, svec3 const &rayDir, snum *t) +{ + snum tx_rx_rz, tz_rx_rz; + int hitx = 0, hitz = 0; + + if(rayDir.x > 0) { + tx_rx_rz = (snum(WORLD_SIZE / 2) - origin.x) * rayDir.z; + hitx = RIGHT; + } + else if(rayDir.x < 0) { + tx_rx_rz = (snum(-WORLD_SIZE / 2) - origin.x) * rayDir.z; + hitx = LEFT; + } + + if(rayDir.z > 0) { + tz_rx_rz = (snum(WORLD_SIZE / 2) - origin.z) * rayDir.x; + hitz = TOP; + } + else if(rayDir.z < 0) { + tz_rx_rz = (snum(-WORLD_SIZE / 2) - origin.z) * rayDir.x; + hitz = BOTTOM; + } + + // static int done = 0; + // if(++done <= 4) + // printf("tx=%f tz=%f rx=%f rz=%f tx_rx_rz=%f tz_rx_rz=%f\n", + // (float)tx, (float)tz, (float)rayDir.x, (float)rayDir.z, + // (float)tx_rx_rz, (float)tz_rx_rz); + + int rx_rz_sign = (rayDir.x < 0) ^ (rayDir.z < 0); + + if(hitz && (!hitx || (tz_rx_rz < tx_rx_rz) ^ rx_rz_sign)) { + if(t) { + if(hitz == TOP) + *t = num16::div_positive(snum(WORLD_SIZE / 2) - origin.z, + rayDir.z); + else + *t = num16::div_positive(origin.z + snum(WORLD_SIZE / 2), + -rayDir.z); + } + return hitz; + } + else if(hitx) { + if(t) { + if(hitx == RIGHT) + *t = num16::div_positive(snum(WORLD_SIZE / 2) - origin.x, + rayDir.x); + else + *t = num16::div_positive(origin.x + snum(WORLD_SIZE / 2), + -rayDir.x); + } + return hitx; + } + + return 0; +} + +void render_fragment(struct camera const *camera, uint16_t *fragment, + int y_start, int y_height) +{ + svec3 origin = svec3_of_vec3(camera->pos); + svec3 forward = svec3_of_vec3(camera->forward); + svec3 right = svec3_of_vec3(camera->right); + svec3 up = svec3_of_vec3(camera->up); + + /* Screen center in front of the camera */ + svec3 screen_center = origin + snum(camera->screen_distance) * forward; + /* Unitary movements, in world coordinates, on screen placed in world, + corresponding to individual pixel sizes */ + svec3 pixel_dy = snum(HALF_SCREEN_HEIGHT) * up / snum(VHEIGHT / 2); + svec3 pixel_dx = snum(HALF_SCREEN_HEIGHT) * right / snum(VHEIGHT / 2); + + svec3 rayDir_row = screen_center - origin + + snum(VHEIGHT/2 - y_start) * pixel_dy + + snum(0 - VWIDTH/2) * pixel_dx; +/* printf("%f %f %f\n", + (float)rayDir_row.x, + (float)rayDir_row.y, + (float)rayDir_row.z); */ + + for(int y = y_start; y < y_start + y_height; y++) { + svec3 rayDir = rayDir_row; + + for(int x = 0; x < VWIDTH; x++) { + snum t; + int obj = cast_ray(origin, rayDir, &t); + int recolor = 0; + snum collision_y; + + if(obj == LEFT || obj == RIGHT) { + svec3 collision; + collision.z = origin.z + t * rayDir.z; + + if(collision.z >= snum(-WORLD_SIZE / 4) + && collision.z < snum(WORLD_SIZE / 4)) { + collision.x = origin.x + t * rayDir.x; + collision.y = origin.y + t * rayDir.y; + rayDir.x = -rayDir.x; + obj = cast_ray(collision, rayDir, &t); + recolor = 1 + (obj == RIGHT); + collision_y = collision.y + t * rayDir.y; + rayDir.x = -rayDir.x; + } + else { + collision_y = origin.y + t * rayDir.y; + } + } + else { + collision_y = origin.y + t * rayDir.y; + } + + static uint16_t const colors[5] = { + 0x0000, 0xf800, 0x07e0, 0x001f, 0xffe0, + }; + uint16_t color = colors[obj]; + + /* Don't show neons that are too far to avoid flickering */ + if(collision_y < 64) { + snum neon_pos = snum(camera->neon_position); + if(obj == TOP || obj == BOTTOM) + neon_pos += snum(16); + snum neon = collision_y - neon_pos; + neon.v = neon.v & (snum(32).v - 1); + /* Also make neons larger when they're far to further avoid + flickering */ + snum neon_size = 1; + if(collision_y > 20) + neon_size += ((collision_y-snum(20)) * snum(1.0/4)); + if(neon <= neon_size) + color = 0xffff; + } + + if(recolor == 1) + color = ((color & 0xf7de) >> 1) + (0xf000 >> 1); + if(recolor == 2) + color = ((color & 0xf7de) >> 1) + (0x001f >> 1); + + *fragment++ = color; + rayDir += pixel_dx; + } + + rayDir_row -= pixel_dy; + } + +// printf("%f %f %f\n", (float)rayDir.x, (float)rayDir.y, (float)rayDir.z); +}