From 37fdcb8a0f435c42f737252450626f2bd38bbd0f Mon Sep 17 00:00:00 2001 From: ladevieq Date: Tue, 5 May 2026 00:50:13 +0200 Subject: Clean up around included files --- include/aabb.hpp | 3 +- include/bvh.hpp | 5 +- include/camera.hpp | 2 - include/gltf.hpp | 67 +++--- include/material.hpp | 15 -- include/mesh.hpp | 22 +- include/scene.hpp | 60 ++--- include/utils.hpp | 78 ++++--- include/vec3.hpp | 2 +- include/vulkan-loader.hpp | 23 +- include/window.hpp | 89 +++++--- src/bvh.cpp | 9 +- src/camera.cpp | 1 - src/gltf.cpp | 564 +++++++++++++++++++++++++++++----------------- src/mesh.cpp | 4 +- src/scene.cpp | 166 +++++--------- src/utils.cpp | 92 ++++---- src/vec3.cpp | 19 +- src/vulkan-loader.cpp | 4 +- src/window.cpp | 115 ++++++---- 20 files changed, 743 insertions(+), 597 deletions(-) diff --git a/include/aabb.hpp b/include/aabb.hpp index adeb1fb..4e47a8f 100644 --- a/include/aabb.hpp +++ b/include/aabb.hpp @@ -1,8 +1,9 @@ #ifndef __AABB_HPP_ #define __AABB_HPP_ +#include + #include "vec3.hpp" -#include "triangle.hpp" class aabb { public: diff --git a/include/bvh.hpp b/include/bvh.hpp index 2b66dcb..28a8554 100644 --- a/include/bvh.hpp +++ b/include/bvh.hpp @@ -1,10 +1,9 @@ #pragma once -#include +#include -#include "aabb.hpp" -// #include "sphere.hpp" #include "triangle.hpp" +#include "aabb.hpp" struct bvh_node { aabb bounding_box; diff --git a/include/camera.hpp b/include/camera.hpp index 5c1db61..ab81896 100644 --- a/include/camera.hpp +++ b/include/camera.hpp @@ -1,8 +1,6 @@ #ifndef __CAMERA_HPP_ #define __CAMERA_HPP_ -#include "vec3.hpp" - class camera { public: camera( diff --git a/include/gltf.hpp b/include/gltf.hpp index 1ccaf56..72d757c 100644 --- a/include/gltf.hpp +++ b/include/gltf.hpp @@ -3,59 +3,60 @@ #include -#include - -using json = nlohmann::json; - -#include "material.hpp" +#include "utils.hpp" +#include "handle.hpp" #include "mesh.hpp" +#include "material.hpp" struct node { - std::vector children; - Mesh* mesh = nullptr; + std::vector children; + u32 mesh; }; struct raw_image { int32_t width; int32_t height; int32_t channels; - uint8_t *data; + const uint8_t *data; }; -namespace std::filesystem { - class path; -} +struct buffer { + u8* bytes; + size_t size; +}; class gltf { public: - gltf(const std::filesystem::path &filepath); - - node root_node; - -private: - - void load_node(uint32_t index, node &parent); - - void load_meshes(); - - Mesh::submesh load_primitive(const json &primitive); - - Mesh::attribute load_attribute(uint32_t accessor_index); - - void load_textures(const std::filesystem::path &path); + gltf(const char* filepath); + void deinit(); - void load_materials(); + std::vector root_nodes; - json gltf_json; + std::vector nodes; std::vector meshes; std::vector materials; -#ifdef API_TEST std::vector> textures; // handle samplers; -#else - std::vector textures; -#endif // API_TEST - std::vector> buffers; + std::vector buffers; + + + // gbl only + struct glb_chunk { + u32 length; + u32 type; + u8 data[1]; + }; + + struct glb_header { + u32 magic; + u32 version; + u32 length; + }; + std::vector chunks; + glb_header* header; + + // TODO: remove + bool is_glb; }; #endif diff --git a/include/material.hpp b/include/material.hpp index 35710d2..167e58e 100644 --- a/include/material.hpp +++ b/include/material.hpp @@ -1,24 +1,9 @@ #pragma once -#include - -#include "vec3.hpp" - -#ifdef API_TEST -#include "vk-device-types.hpp" -#else -class Texture; -#endif - struct material { color base_color; -#ifdef API_TEST handle base_color_texture; handle metallic_roughness_texture; -#else - Texture* base_color_texture; - Texture* metallic_roughness_texture; -#endif // API_TEST float metalness = 1.f; float roughness = 1.f; }; diff --git a/include/mesh.hpp b/include/mesh.hpp index b88896d..c396814 100644 --- a/include/mesh.hpp +++ b/include/mesh.hpp @@ -1,15 +1,5 @@ #pragma once -#include -#include -#include - -#ifdef API_TEST -#include "vk-device-types.hpp" -#else -#include "vk-renderer.hpp" -#endif // API_TEST - enum ATTRIBUTE_TYPE { POSITION, NORMAL, @@ -34,15 +24,15 @@ public: }; struct attribute { - uint8_t* data = nullptr; + const uint8_t* data = nullptr; size_t length = 0; }; struct submesh { attribute indices; std::array attributes; - uint32_t vertex_count = 0; - uint32_t index_count = 0; + u32 vertex_count = 0; + u32 index_count = 0; // material& material; }; @@ -93,15 +83,9 @@ private: std::vector submeshes; struct gpu_mesh { -#ifdef API_TEST std::array, ATTRIBUTE_TYPE::MAX_ATTRIBUTE> attributes; const device_buffer& indices; const device_buffer& submeshes; -#else - std::array attributes; - Buffer* indices; - Buffer* submeshes; -#endif // API_TEST }; // allocate gpu mesh upon instanciation diff --git a/include/scene.hpp b/include/scene.hpp index 091e4fc..a1c76e2 100644 --- a/include/scene.hpp +++ b/include/scene.hpp @@ -1,44 +1,36 @@ #ifndef __SCENE_HPP_ #define __SCENE_HPP_ -#include - -#ifdef API_TEST -#include "vk-device-types.hpp" -#include "vk-device.hpp" -#endif // API_TEST -#include "camera.hpp" - class Buffer; -class scene { - struct metadata { - camera cam; +struct metadata { + camera cam; - uint32_t max_bounce = 3; - uint32_t min_bounce = 1; + uint32_t max_bounce = 3; + uint32_t min_bounce = 1; - uint32_t width; - uint32_t height; + uint32_t width; + uint32_t height; - uint32_t sample_index = 0; + uint32_t sample_index = 1; - uint32_t enable_dof = (uint32_t)false; - uint32_t debug_bvh = (uint32_t)false; - int32_t downscale_factor = 2; + uint32_t enable_dof = (uint32_t)false; + uint32_t debug_bvh = (uint32_t)false; + int32_t downscale_factor = 1; - metadata(const camera &cam, uint32_t width, uint32_t height); - }; + metadata(const camera &cam, uint32_t width, uint32_t height); +}; +class scene { // void random_scene(); + gltf model; public: scene(const camera& cam, uint32_t width, uint32_t height); + void deinit(); metadata meta; -#ifdef API_TEST - handle scene_buffer_handle; handle indices_buffer_handle; handle positions_buffer_handle; handle normals_buffer_handle; @@ -46,22 +38,12 @@ public: handle bvh_buffer_handle; handle materials_buffer_handle; - uint64_t scene_buffer_address() { return vkdevice::get_render_device().get_buffer(scene_buffer_handle).device_address; }; - uint64_t indices_buffer_address() { return vkdevice::get_render_device().get_buffer(indices_buffer_handle).device_address; }; - uint64_t positions_buffer_address() { return vkdevice::get_render_device().get_buffer(positions_buffer_handle).device_address; }; - uint64_t normals_buffer_address() { return vkdevice::get_render_device().get_buffer(normals_buffer_handle).device_address; }; - uint64_t uvs_buffer_address() { return vkdevice::get_render_device().get_buffer(uvs_buffer_handle).device_address; }; - uint64_t bvh_buffer_address() { return vkdevice::get_render_device().get_buffer(bvh_buffer_handle).device_address; }; - uint64_t materials_buffer_address() { return vkdevice::get_render_device().get_buffer(materials_buffer_handle).device_address; }; -#else - Buffer* scene_buffer; - Buffer* indices_buffer; - Buffer* positions_buffer; - Buffer* normals_buffer; - Buffer* uvs_buffer; - Buffer* bvh_buffer; - Buffer* materials_buffer; -#endif // API_TEST + uint64_t indices_buffer_address() { return vkdevice::get().get_buffer(indices_buffer_handle).device_address; }; + uint64_t positions_buffer_address() { return vkdevice::get().get_buffer(positions_buffer_handle).device_address; }; + uint64_t normals_buffer_address() { return vkdevice::get().get_buffer(normals_buffer_handle).device_address; }; + uint64_t uvs_buffer_address() { return vkdevice::get().get_buffer(uvs_buffer_handle).device_address; }; + uint64_t bvh_buffer_address() { return vkdevice::get().get_buffer(bvh_buffer_handle).device_address; }; + uint64_t materials_buffer_address() { return vkdevice::get().get_buffer(materials_buffer_handle).device_address; }; }; #endif // !__SCENE_HPP_ diff --git a/include/utils.hpp b/include/utils.hpp index e49b218..19a5d9f 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -1,13 +1,56 @@ #pragma once -#include -#include - -std::vector read_file(const char* path); +static constexpr size_t KB = 1024U; +static constexpr size_t MB = 1024U * KB; +static constexpr size_t GB = 1024U * MB; +const char* DUMMY_NAME = "NO_NAME"; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +uint8_t* read_file(const char* path, size_t size); + +const uint32_t max_markers = 1024U; +// hashmap ? +uint32_t marker_count = 0U; +const char* marker_names[max_markers] = { 0 }; +uint64_t marker_counter_start[max_markers] = { 0 }; +uint64_t marker_counter_end[max_markers] = { 0 }; + +#define BEGIN_MARKER(name) \ + static uint32_t marker_##name##_index = UINT32_MAX; \ + do { \ + if (marker_##name##_index == UINT32_MAX) { \ + marker_##name##_index = marker_count++; \ + marker_names[marker_##name##_index] = #name; \ + } \ + { \ + LARGE_INTEGER start_qpc; \ + QueryPerformanceCounter(&start_qpc); \ + marker_counter_start[marker_##name##_index] = start_qpc.QuadPart; \ + } \ + } while(0); + +#define END_MARKER(name) \ + do { \ + LARGE_INTEGER end_qpc; \ + QueryPerformanceCounter(&end_qpc); \ + marker_counter_end[marker_##name##_index] = end_qpc.QuadPart; \ + } while(0); #define PI 3.14159265359 #define EPSILON 0.000001 + +#define ALIGN(value, alignment) \ + (((value) + ((alignment) - 1)) & ~((alignment) - 1)) + inline float deg_to_rad(float deg) { return static_cast(deg * PI / 180.f); } @@ -31,31 +74,14 @@ inline float clamp(float x, float min, float max) { } -#if defined(WINDOWS) - -#include +#if _WIN32 void log_last_error(); -class watcher { -public: - typedef void(*func)(void); - - static bool watch_file(const char* filepath, func callback); - - static bool watch_dir(const char* dir_path); - - static void pull_changes(); - -private: +typedef void(*func)(void); +bool watch_file(const char* filepath, func callback); - struct watch_data { - HANDLE dir_handle; - OVERLAPPED overlapped; - DWORD buffer[512]; - }; +bool watch_dir(const char* dir_path); - inline static std::unordered_map callbacks; - inline static std::unordered_map watched_dirs; -}; +void pull_changes(); #endif diff --git a/include/vec3.hpp b/include/vec3.hpp index 42172e6..5fd143d 100644 --- a/include/vec3.hpp +++ b/include/vec3.hpp @@ -1,7 +1,6 @@ #ifndef __VEC3_HPP_ #define __VEC3_HPP_ -#include #include struct vec3u { @@ -60,6 +59,7 @@ class vec3 { vec3& normalize(); [[nodiscard]] bool near_zero() const; + [[nodiscard]] bool is_zero() const; void print() const; diff --git a/include/vulkan-loader.hpp b/include/vulkan-loader.hpp index ec1464d..7a3a68e 100644 --- a/include/vulkan-loader.hpp +++ b/include/vulkan-loader.hpp @@ -3,8 +3,7 @@ #define VK_NO_PROTOTYPES -#if defined(WINDOWS) -#include +#if _WIN32 #include typedef unsigned long DWORD; typedef const wchar_t* LPCWSTR; @@ -24,7 +23,6 @@ typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES; X(vkGetInstanceProcAddr) \ X(vkGetDeviceProcAddr) - #define VULKAN_APPLICATION_FUNCTIONS \ X(vkCreateInstance) \ X(vkEnumerateInstanceVersion) \ @@ -154,32 +152,15 @@ typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES; X(vkDestroyBuffer) \ X(vkDestroyRenderPass) + #define X(name) extern PFN_##name name; - VULKAN_EXPORTED_FUNCTIONS VULKAN_APPLICATION_FUNCTIONS VULKAN_INSTANCE_FUNCTIONS VULKAN_DEVICE_FUNCTIONS #undef X - -#define X(name) void Load_##name(); - VULKAN_EXPORTED_FUNCTIONS - VULKAN_APPLICATION_FUNCTIONS -#undef X - -#define X(name) void Load_##name(VkInstance _instance); - VULKAN_INSTANCE_FUNCTIONS -#undef X - -#define X(name) void Load_##name(VkDevice _device); - VULKAN_DEVICE_FUNCTIONS -#undef X - - void load_vulkan(); - void load_instance_functions(VkInstance instance); - void load_device_functions(VkDevice device); #endif // !__VULKAN_LOADER_HPP_ diff --git a/include/window.hpp b/include/window.hpp index 2484742..9c79614 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -1,23 +1,10 @@ #ifndef __WINDOW_HPP_ #define __WINDOW_HPP_ -#include - -class vkrenderer; - #if defined(LINUX) #include #include -#elif defined(WINDOWS) -// #include -typedef struct HWND__* HWND; -typedef int64_t LRESULT; -typedef int64_t LPARAM; -typedef uint64_t WPARAM; -typedef unsigned int UINT; -typedef void* LPVOID; -#define CALLBACK __stdcall #endif // enum MODIFIERS: uint32_t { @@ -37,14 +24,22 @@ typedef void* LPVOID; // }; // TODO improve this -#if defined(WINDOWS) -enum KEYS: uint32_t { +#if _WIN32 +enum KEY: uint32_t { LSHIFT = 0x10, RSHIFT = 0x10, LCTRL = 0x11, RCTRL = 0x11, ALT, SPACE = 0x20, + PAGE_UP, + PAGE_DOWN, + END, + HOME, + LEFT_ARROW, + UP_ARROW, + RIGHT_ARROW, + DOWN_ARROW, A = 0x41, B, C, @@ -71,10 +66,22 @@ enum KEYS: uint32_t { X, Y, Z, - MAX_KEYS = 255 + F1 = 0x70, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + MAX_KEY = 0xff }; #else -enum KEYS: uint32_t { +enum KEY: uint32_t { SPACE = 32, A = 0x61, B, @@ -108,25 +115,43 @@ enum KEYS: uint32_t { RCTRL, LALT = 65513, RALT, - MAX_KEYS = 0xffff + MAX_KEY = 0xffff }; #endif -enum BUTTONS: uint32_t { +enum BUTTON: uint32_t { LEFT, RIGHT, MIDDLE, - MAX_BUTTONS = 255 + MAX_BUTTON = 255 }; -enum EVENT_TYPES: int32_t { +enum EVENT_TYPE: int32_t { QUIT, RESIZE, KEY_PRESS, + KEY_DOWN, KEY_RELEASE, + KEY_UP, BUTTON_PRESS, BUTTON_RELEASE, - MOUSE_MOVE + MOUSE_MOVE, + MOUSE_WHEEL, +}; + +enum CURSOR_TYPE: int32_t { + ARROW, + TEXT_INPUT, + SIZE_ALL, + SIZE_NS, + SIZE_WE, + SIZE_NESW, + SIZE_NWSE, + HAND, + WAIT, + PROGRESS, + NOT_ALLOWED, + MAX_CURSOR, }; // struct event { @@ -148,10 +173,14 @@ struct event { int32_t x; int32_t y; } position; - KEYS key; - BUTTONS button; + struct { + int32_t x; + int32_t y; + } delta; + KEY key; + BUTTON button; } data; - EVENT_TYPES type; + EVENT_TYPE type; }; class window { @@ -161,13 +190,15 @@ class window { void poll_events(); -#if defined(WINDOWS) +#if _WIN32 void message_loop(); LRESULT message_handler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam); static LRESULT CALLBACK window_procedure(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam); + static void set_cursor(enum CURSOR_TYPE type); + HWND handle {}; const char* window_class_name; LPVOID main_fiber; @@ -190,8 +221,10 @@ class window { bool isOpen; - bool keyboard[KEYS::MAX_KEYS] { false }; - bool mouse[BUTTONS::MAX_BUTTONS] { false }; + bool keyboard[KEY::MAX_KEY] { false }; + bool mouse[BUTTON::MAX_BUTTON] { false }; + + static HCURSOR cursors[CURSOR_TYPE::MAX_CURSOR]; }; #endif // !__WINDOW_HPP_ diff --git a/src/bvh.cpp b/src/bvh.cpp index 8e62a93..9362504 100644 --- a/src/bvh.cpp +++ b/src/bvh.cpp @@ -1,11 +1,5 @@ #include "bvh.hpp" -#include - -#include -#include -#include - // bvh::bvh(std::vector& spheres, std::vector& packed_nodes) // :spheres(spheres) { // packed_nodes.resize(2 * spheres.size() - 1); @@ -48,6 +42,7 @@ bvh::bvh(std::vector& triangles, std::vector& packed_nodes) :triangles(triangles) { + BEGIN_MARKER(GENERATE_BVH); assert(!triangles.empty()); packed_nodes.resize(2 * triangles.size() - 1); @@ -84,6 +79,8 @@ bvh::bvh(std::vector& triangles, std::vector& packed_ node.next_id = temp_nodes[old_node.next_id].df_id; } } + + END_MARKER(GENERATE_BVH); } //------------------------- diff --git a/src/camera.cpp b/src/camera.cpp index 4c63630..8139c5b 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -1,5 +1,4 @@ #include "camera.hpp" -#include "utils.hpp" camera::camera( point3 position, diff --git a/src/gltf.cpp b/src/gltf.cpp index 4cdfdce..2ddf16a 100644 --- a/src/gltf.cpp +++ b/src/gltf.cpp @@ -1,145 +1,177 @@ #include "gltf.hpp" -#include -#include - -#ifndef API_TEST -#define STB_IMAGE_IMPLEMENTATION -#endif -#include - -#include "utils.hpp" -#ifdef API_TEST -#include "vk-device-types.hpp" -#include "vk-device.hpp" -#include "vk-command-buffer.hpp" -#include -#else -#include "vk-renderer.hpp" -#endif - -gltf::gltf(const std::filesystem::path& filepath) { - auto parent_path = filepath.parent_path(); - std::fstream f{ filepath }; - - if (!f.is_open()) { - OutputDebugStringA("failed to open!"); +using namespace simdjson; + +ondemand::object root; + +struct accessor { + u32 view_index = 0U; + u32 count = 0U; + u32 component_type = 0U; + std::string_view type; +}; + +struct buffer_view { + u32 buffer_index = 0U; + u32 length = 0U; + u32 offset = 0U; +}; + +// component types +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_FLOAT 0x1406 +#define GL_FIXED 0x140C + +#define SCALAR 0x5343414C4152 +#define VEC2 0x56454332 +#define VEC3 0x56454333 +#define VEC4 0x56454334 + +static u32 accessor_type_to_component_count(std::string_view& type) { + if (strncmp("SCALAR", type.data(), type.size()) == 0) { + return 1U; + } else if (strncmp("VEC2", type.data(), type.size()) == 0) { + return 2U; + } else if (strncmp("VEC3", type.data(), type.size()) == 0) { + return 3U; + } else if (strncmp("VEC4", type.data(), type.size()) == 0) { + return 4U; } + assert(false); + return 0U; +} - f >> gltf_json; - - auto& scene = gltf_json["scenes"][0]; - - auto& gltf_buffers = gltf_json["buffers"]; - auto buffer_count = gltf_buffers.size(); - buffers.resize(gltf_buffers.size()); - for (auto buffer_index{ 0U }; buffer_index < buffer_count; buffer_index++) { - auto buffer_path = parent_path / gltf_buffers[buffer_index]["uri"].get(); - buffers[buffer_index] = read_file(buffer_path.string().c_str()); +static u32 component_type_size(u32 type) { + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return 1U; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return 2U; + case GL_FLOAT: + case GL_FIXED: + return 4U; + default: assert(false); } + return 0U; +} - load_textures(parent_path); - load_materials(); +static Mesh::submesh load_primitive(ondemand::object& primitive, std::vector& buffers, std::vector& accessors, std::vector& buffer_views) { + Mesh::submesh submesh; + + // indices + { + u32 indices_id = primitive["indices"].get_uint32(); + struct accessor& accessor = accessors[indices_id]; - load_meshes(); + struct buffer_view& view = buffer_views[accessor.view_index]; + struct buffer& buffer = buffers[view.buffer_index]; - auto& root_children = scene["nodes"]; - size_t root_children_count = scene["nodes"].size(); - root_node.children.resize(root_children_count); + submesh.indices = { + .data = &buffer.bytes[view.offset], + .length = accessor.count * accessor_type_to_component_count(accessor.type) * component_type_size(accessor.component_type), + }; - for (size_t child_index = 0; child_index < root_children_count; child_index++) { - load_node(root_children[child_index].get(), root_node.children[child_index]); + submesh.index_count = accessor.count; } - f.close(); -} + // positions + { + u32 pos_id = primitive["attributes"]["POSITION"].get_uint32(); + struct accessor& accessor = accessors[pos_id]; -void gltf::load_node(uint32_t index, node& parent) { - const auto& gltf_node = gltf_json["nodes"][index]; + struct buffer_view& view = buffer_views[accessor.view_index]; + struct buffer& buffer = buffers[view.buffer_index]; - if (gltf_node.contains("children")) { - const auto& children = gltf_node["children"]; - uint32_t children_count = gltf_node["children"]; - parent.children.resize(children_count); + submesh.attributes[ATTRIBUTE_TYPE::POSITION] = { + .data = &buffer.bytes[view.offset], + .length = accessor.count * accessor_type_to_component_count(accessor.type) * component_type_size(accessor.component_type), + }; - for (size_t child_index = 0; child_index < children_count; child_index++) { - load_node(children[child_index].get(), parent.children[child_index]); - } + submesh.vertex_count = accessor.count; } - if (gltf_node.contains("mesh")) { - parent.mesh = &meshes[gltf_node["mesh"].get()]; - } -} + u32 normal_index = 0U; + if (!primitive["attributes"]["NORMAL"].get(normal_index)) { + struct accessor& accessor = accessors[normal_index]; + u32 view_index = accessor.view_index; -void gltf::load_meshes() { - const auto& gltf_meshes = gltf_json["meshes"]; - auto meshes_count = gltf_meshes.size(); - meshes.resize(meshes_count); + struct buffer_view& view = buffer_views[view_index]; + struct buffer& buffer = buffers[view.buffer_index]; - for (size_t mesh_index = 0; mesh_index < meshes_count; mesh_index++) { - auto& mesh = meshes[mesh_index]; - const auto& primitives = gltf_meshes[mesh_index]["primitives"]; - - for (const auto& primitive : primitives) { - auto& material = materials[primitive["material"].get()]; - mesh.add_submesh(load_primitive(primitive), material); - } - - Mesh::register_mesh(mesh); + submesh.attributes[ATTRIBUTE_TYPE::NORMAL] = { + .data = &buffer.bytes[view.offset], + .length = accessor.count * accessor_type_to_component_count(accessor.type) * component_type_size(accessor.component_type), + }; } -} -Mesh::submesh gltf::load_primitive(const json& primitive) { - Mesh::submesh submesh; + u32 texcoord_index = 0U; + if (!primitive["attributes"]["TEXCOORD_0"].get(texcoord_index)) { + struct accessor& accessor = accessors[texcoord_index]; + u32 view_index = accessor.view_index; - submesh.indices = load_attribute(primitive["indices"]); - submesh.attributes[ATTRIBUTE_TYPE::POSITION] = load_attribute(primitive["attributes"]["POSITION"]); - - if (primitive["attributes"].contains("NORMAL")) { - submesh.attributes[ATTRIBUTE_TYPE::NORMAL] = load_attribute(primitive["attributes"]["NORMAL"]); - } + struct buffer_view& view = buffer_views[view_index]; + struct buffer& buffer = buffers[view.buffer_index]; - if (primitive["attributes"].contains("TEXCOORD_0")) { - submesh.attributes[ATTRIBUTE_TYPE::UV_0] = load_attribute(primitive["attributes"]["TEXCOORD_0"]); + submesh.attributes[ATTRIBUTE_TYPE::UV_0] = { + .data = &buffer.bytes[view.offset], + .length = accessor.count * accessor_type_to_component_count(accessor.type) * component_type_size(accessor.component_type), + }; } - submesh.index_count = gltf_json["accessors"][primitive["indices"].get()]["count"].get(); - submesh.vertex_count = gltf_json["accessors"][primitive["attributes"]["POSITION"].get()]["count"].get(); - return submesh; } -Mesh::attribute gltf::load_attribute(uint32_t accessor_index) { - auto view_index = gltf_json["accessors"][accessor_index]["bufferView"].get(); - const auto& view = gltf_json["bufferViews"][view_index]; - auto offset = view["byteOffset"].get(); - auto& buffer = buffers[view["buffer"].get()]; - - return { - &buffer[offset], - view["byteLength"].get() - }; -} - -void gltf::load_textures(const std::filesystem::path& path) { - const auto& gltf_images = gltf_json["images"]; - auto images_count = gltf_images.size(); - std::vector images{ images_count }; +static void load_textures(char* path, std::vector>& textures, std::vector& buffers, std::vector& buffer_views, bool is_glb) { + ondemand::array gltf_images = root["images"]; + std::vector images(gltf_images.count_elements()); + size_t path_len = strlen(path); + char path_buffer[2048] = { 0U }; + strncpy(path_buffer, path, path_len); + BEGIN_MARKER(LOAD_TEXTURES); + u32 image_index = 0U; + for (ondemand::object gltf_image : gltf_images) { + if (is_glb) { + // TODO: consider mimeType + struct buffer_view& view = buffer_views[gltf_image["bufferView"]]; + struct buffer& buffer = buffers[view.buffer_index]; + + raw_image& image = images[image_index++]; + + image.data = stbi_load_from_memory(&buffer.bytes[view.offset], view.length, &image.width, &image.height, &image.channels, 4); + + } else { + std::string_view uri_view = gltf_image["uri"]; + strncpy(path_buffer + path_len, uri_view.data(), uri_view.length()); + path_buffer[path_len + uri_view.length()] = '\0'; + + raw_image& image = images[image_index++]; + image.data = stbi_load(path_buffer, &image.width, &image.height, &image.channels, 4); + } + } + END_MARKER(LOAD_TEXTURES); - std::vector v(images_count); - std::iota(v.begin(), v.end(), 0); + // ondemand::array gltf_samplers = root["samplers"]; + // std::vector> samplers(gltf_samplers.count_elements()); - const auto& gltf_textures = gltf_json["textures"]; - auto textures_count = gltf_textures.size(); - textures.resize(textures_count); + // auto sampler = device.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); + // for (size_t sampler_index = 0; sampler_index < samplers_count; sampler_index++) { + // samplers[sampler_index] = vkrenderer::create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); + // } -#ifdef API_TEST - auto& device = vkdevice::get_render_device(); + vkdevice& device = vkdevice::get(); constexpr auto buffers_count = 2U; - auto total_size = images_count * 4096U * 4096 * sizeof(uint32_t); - auto buffer_size = total_size / 32U; + auto total_size = images.size() * 4096U * 4096 * sizeof(uint32_t); + // TODO: Fix nasty stuff going on + // Crash on buffer destruction + // Load wrong images + // auto buffer_size = total_size / 32U; + auto buffer_size = total_size / 2U; handle staging_buffers_handle[buffers_count] = { device.create_buffer({ @@ -156,46 +188,28 @@ void gltf::load_textures(const std::filesystem::path& path) { }), }; + // TODO: Create a proper upload heap + BEGIN_MARKER(UPLOAD_TEXTURES); graphics_command_buffer command_buffers[buffers_count]; device.allocate_command_buffers(command_buffers, buffers_count, QueueType::GRAPHICS, "upload_buffer"); auto buffer_index = 0U; auto command_buffer = command_buffers[buffer_index]; auto buffer_handle = staging_buffers_handle[buffer_index]; - auto buffer = device.get_buffer(buffer_handle); + device_buffer& buffer = device.get_buffer(buffer_handle); command_buffer.start(); -#endif // API_TEST - std::for_each(std::execution::par, v.begin(), v.end(), [&](const size_t image_index) { - const auto& gltf_image = gltf_images[image_index]; - auto filepath = (path / gltf_image["uri"].get()).string(); - auto& image = images[image_index]; - image.data = stbi_load(filepath.c_str(), &image.width, &image.height, &image.channels, 4); - }); - - // const auto &gltf_samplers = gltf_json["samplers"]; - // auto samplers_count = gltf_samplers.size(); - // std::vector samplers{samplers_count}; - -#ifdef API_TEST - const auto &gltf_samplers = gltf_json["samplers"]; - auto samplers_count = gltf_samplers.size(); - std::vector> samplers{samplers_count}; - - // auto sampler = device.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); - // for (size_t sampler_index = 0; sampler_index < samplers_count; sampler_index++) { - // samplers[sampler_index] = vkrenderer::create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); - // } - - for (size_t texture_index = 0; texture_index < textures_count; texture_index++) { - auto gltf_texture = gltf_textures[texture_index]; - auto& image = images[gltf_texture["source"].get()]; + ondemand::array gltf_textures = root["textures"]; + textures.resize(gltf_textures.count_elements()); + u32 texture_index = 0U; + for (ondemand::object gltf_texture: gltf_textures) { + raw_image& image = images[gltf_texture["source"]]; // if (gltf_texture.contains("sampler")) { - // auto sampler_index = gltf_texture["sampler"].get(); + // u32 sampler_index = gltf_texture["sampler"].get_uint32(); // sampler = samplers[sampler_index]; // } - auto texture = device.create_texture({ + handle texture = device.create_texture({ .width = static_cast(image.width), .height = static_cast(image.height), .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, @@ -203,105 +217,247 @@ void gltf::load_textures(const std::filesystem::path& path) { .type = VK_IMAGE_TYPE_2D, }); - uint64_t size = image.width * image.height * sizeof(uint32_t); - auto offset = buffer.offset; - if (offset + size > buffer_size) { + u32 size = image.width * image.height * sizeof(uint32_t); + if (buffer.allocated_size + size > buffer.size) { command_buffer.stop(); - device.submit(&command_buffer, 1 ); + device.submit(&command_buffer, 1); - buffer_index = (++buffer_index) % buffers_count; + buffer_index = (buffer_index + 1U) % buffers_count; command_buffer = command_buffers[buffer_index]; buffer_handle = staging_buffers_handle[buffer_index]; buffer = device.get_buffer(buffer_handle); buffer.reset(); - device.wait(); + // TODO: Remove the wait + // device.wait(); command_buffer.start(); - offset = 0U; } - void* ptr = buffer.allocate(size); - memcpy(ptr, image.data, size); + memcpy(buffer.allocate(size), image.data, size); command_buffer.barrier(texture, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - command_buffer.copy(buffer_handle, texture, static_cast(offset)); + command_buffer.copy(buffer_handle, texture, static_cast(buffer.offset)); command_buffer.barrier(texture, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL); - textures[texture_index] = texture; + textures[texture_index++] = texture; } - command_buffer.stop(); - device.submit(&command_buffer, 1); + if (buffer.allocated_size > 0U) { + command_buffer.stop(); + device.submit(&command_buffer, 1); + } device.wait(); device.destroy_buffer(staging_buffers_handle[0]); device.destroy_buffer(staging_buffers_handle[1]); -#else - Sampler* sampler = vkrenderer::create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); - // for (size_t sampler_index = 0; sampler_index < samplers_count; sampler_index++) { - // samplers[sampler_index] = vkrenderer::create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); - // } - - for (size_t texture_index = 0; texture_index < textures_count; texture_index++) { - auto gltf_texture = gltf_textures[texture_index]; + END_MARKER(UPLOAD_TEXTURES); +} - auto& image = images[gltf_texture["source"].get()]; - // if (gltf_texture.contains("sampler")) { - // auto sampler_index = gltf_texture["sampler"].get(); - // sampler = samplers[sampler_index]; - // } +static void load_materials(std::vector& materials, std::vector>& textures) { + ondemand::array gltf_materials = root["materials"]; + materials.resize(gltf_materials.count_elements()); + + u32 material_index = 0U; + for (ondemand::object object: gltf_materials) { + material& material = materials[material_index++]; + material.base_color = vec3(1.f); + material.metalness = 1.f; + material.roughness = 1.f; + + ondemand::object pbr_params; + if (!object["pbrMetallicRoughness"].get(pbr_params)) { + ondemand::array base_color; + if (!pbr_params["baseColorFactor"].get(base_color)) { + u32 id = 0U; + for (double val : base_color) { + material.base_color.arr[id++] = static_cast(val); + } + } - auto* texture = vkrenderer::create_2d_texture(static_cast(image.width), static_cast(image.height), VK_FORMAT_R8G8B8A8_UNORM, sampler); + ondemand::object base_color_texture; + if (!pbr_params["baseColorTexture"].get(base_color_texture)) { + material.base_color_texture = textures[base_color_texture["index"]]; + } - texture->update(image.data); + pbr_params["metallicFactor"].get(material.metalness); + pbr_params["roughnessFactor"].get(material.roughness); - textures[texture_index] = texture; + ondemand::object metallic_roughness_texture; + if (!pbr_params["metallicRoughnessTexture"].get(metallic_roughness_texture)) { + material.metallic_roughness_texture = textures[metallic_roughness_texture["index"]]; + } + } } -#endif } -void gltf::load_materials() { - const auto& gltf_materials = gltf_json["materials"]; - auto materials_count = gltf_materials.size(); - materials.resize(materials_count); - - for (size_t material_index = 0; material_index < materials_count; material_index++) { - const auto& gltf_material = gltf_materials[material_index]; - auto& material = materials[material_index]; - - if (gltf_material.contains("pbrMetallicRoughness")) { - const auto& pbr_params = gltf_material["pbrMetallicRoughness"]; - - if (pbr_params.contains("baseColorFactor")) { - const auto& base_color = pbr_params["baseColorFactor"]; - material.base_color.set<0>(base_color[0].get()); - material.base_color.set<1>(base_color[1].get()); - material.base_color.set<2>(base_color[2].get()); - material.base_color.arr[3] = base_color[3].get(); // Since we use a vec3 for colors we are not allowed toset fourth value with set<3> - } else { - material.base_color = vec3(1.f); - } +gltf::gltf(const char* filepath) { + BEGIN_MARKER(LOAD_GLTF); + + ondemand::parser parser; + padded_string json; + ondemand::document doc; + + const char* ext = PathFindExtensionA(filepath); + + char buffer_path[2048U] = { 0U }; + char* filename = nullptr; + GetFullPathNameA( filepath, 2048U, buffer_path, &filename); + size_t parent_dir_len = filename - buffer_path; + + // TODO: Remove + is_glb = strcmp(ext, ".glb") == 0; + + if (is_glb) { + size_t filesize = 0U; + size_t read = 0U; + u8* glb_buffer = read_file(filepath, &filesize); + header = (struct glb_header*)glb_buffer; + assert(filesize == header->length); + // assert(header->magic == (u32)"glTF"); + + read += sizeof(*header); + chunks.push_back((struct glb_chunk*)(header + 1)); + read += offsetof(struct glb_chunk, data) + chunks.back()->length; + while (read != header->length) { + chunks.push_back((struct glb_chunk*)(glb_buffer + read)); + read += offsetof(struct glb_chunk, data) + chunks.back()->length; + } - if (pbr_params.contains("baseColorTexture")) { - auto base_color_index = pbr_params["baseColorTexture"]["index"].get(); - material.base_color_texture = textures[base_color_index]; + doc = parser.iterate((const char*)&chunks[0]->data[0U], chunks[0]->length, filesize); + root = doc; + + ondemand::array gltf_buffers = root["buffers"]; + assert(gltf_buffers.count_elements() == chunks.size() - 1U); + buffers.resize(gltf_buffers.count_elements()); + u32 buffer_index = 0U; + for (u32 chunk_index = 1U; chunk_index < chunks.size(); chunk_index++) { + buffers[buffer_index++] = buffer { + .bytes = chunks[chunk_index]->data, + .size = chunks[chunk_index]->length, + }; + } + } else { + json = padded_string::load(filepath); + doc = parser.iterate(json); + root = doc; + + { + ondemand::array gltf_buffers = root["buffers"]; + buffers.resize(gltf_buffers.count_elements()); + u32 buffer_index = 0U; + for (ondemand::object value: gltf_buffers) { + std::string_view uri_view = value["uri"]; + strncpy(buffer_path + parent_dir_len, uri_view.data(), uri_view.length()); + buffer_path[parent_dir_len + uri_view.length()] = '\0'; + + size_t file_size = 0U; + uint8_t* bytes = read_file(buffer_path, &file_size); + buffers[buffer_index++] = { + .bytes = bytes, + .size = file_size, + }; } + } + } - if (pbr_params.contains("metallicFactor")) { - material.metalness = pbr_params["metallicFactor"].get(); - } else { - material.metalness = 1.0; - } - if (pbr_params.contains("roughnessFactor")) { - material.roughness = pbr_params["roughnessFactor"].get(); - } else { - material.roughness = 1.0; + std::vector accessors; + { + ondemand::array gltf_accessors = root["accessors"]; + accessors.resize(gltf_accessors.count_elements()); + u32 accessor_index = 0U; + for (ondemand::object value: gltf_accessors) { + struct accessor& accessor = accessors[accessor_index++]; + value["bufferView"].get(accessor.view_index); + value["count"].get(accessor.count); + value["type"].get(accessor.type); + value["componentType"].get(accessor.component_type); + } + } + + std::vector buffer_views; + { + ondemand::array gltf_views = root["bufferViews"]; + buffer_views.resize(gltf_views.count_elements()); + u32 view_index = 0U; + for (ondemand::object value: gltf_views) { + struct buffer_view& view = buffer_views[view_index++]; + value["buffer"].get(view.buffer_index); + value["byteLength"].get(view.length); + value["byteOffset"].get(view.offset); + } + } + + + { + ondemand::array gltf_nodes = root["nodes"]; + nodes.resize(gltf_nodes.count_elements()); + + u32 node_index = 0U; + for (ondemand::object gltf_node: gltf_nodes) { + struct node& node = nodes[node_index++]; + + ondemand::array gltf_children; + if (!gltf_node["children"].get(gltf_children)) { + node.children.resize(gltf_children.count_elements()); + + u32 child_index = 0U; + for (auto child : gltf_children) { + node.children[child_index++] = child.get_uint32(); + } } - if (pbr_params.contains("metallicRoughnessTexture")) { - auto metallic_roughness_index = pbr_params["metallicRoughnessTexture"]["index"].get(); - material.metallic_roughness_texture = textures[metallic_roughness_index]; + node.mesh = UINT32_MAX; + gltf_node["mesh"].get(node.mesh); + } + } + + + // root nodes + { + u32 scene_index = root["scene"].get_uint32(); + ondemand::array gltf_scene_nodes = root["scenes"].at(scene_index)["nodes"]; + root_nodes.resize(gltf_scene_nodes.count_elements()); + + u32 index = 0U; + for (auto node_index: gltf_scene_nodes) { + root_nodes[index++] = node_index.get_uint32(); + } + } + + buffer_path[parent_dir_len] = '\0'; + load_textures(buffer_path, textures, buffers, buffer_views, is_glb); + load_materials(materials, textures); + + // meshes + { + ondemand::array gltf_meshes = root["meshes"]; + meshes.resize(gltf_meshes.count_elements()); + + u32 mesh_index = 0U; + for (ondemand::object gltf_mesh: gltf_meshes) { + Mesh& mesh = meshes[mesh_index++]; + ondemand::array gltf_primitives = gltf_mesh["primitives"]; + + for (ondemand::object primitive : gltf_primitives) { + material& material = materials[primitive["material"]]; + mesh.add_submesh(load_primitive(primitive, buffers, accessors, buffer_views), material); } + + Mesh::register_mesh(mesh); } } + + END_MARKER(LOAD_GLTF); +} + +void gltf::deinit() { + for (handle handle: textures) { + vkdevice::get().destroy_texture(handle); + } + + for (struct buffer& buffer: buffers) { + free(buffer.bytes); + } + + free(header); } diff --git a/src/mesh.cpp b/src/mesh.cpp index 3863ca8..cbfe392 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,6 +1,6 @@ #include "mesh.hpp" -static std::vector meshes {}; +static std::vector registered_meshes {}; void Mesh::add_submesh(const submesh& submesh, material& material) { submeshes.emplace_back( @@ -42,5 +42,5 @@ void Mesh::add_submesh(const submesh& submesh, material& material) { } void Mesh::register_mesh(const Mesh& mesh) { - meshes.push_back(mesh); + registered_meshes.push_back(mesh); } diff --git a/src/scene.cpp b/src/scene.cpp index 9d6b981..9369eae 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -1,17 +1,5 @@ #include "scene.hpp" - -#include -#include - -#ifdef API_TEST -#include -#else -#include "vk-renderer.hpp" -#endif // API_TEST - -#include "gltf.hpp" -#include "bvh.hpp" -// #include "material.hpp" +#include "mesh.hpp" // void scene::random_scene() { // material ground_material = { { 0.5, 0.5, 0.5 } }; @@ -63,15 +51,19 @@ // } -scene::metadata::metadata(const camera &cam, uint32_t width, uint32_t height) +metadata::metadata(const camera &cam, uint32_t width, uint32_t height) : cam(cam), width(width), height(height) {} scene::scene(const camera& cam, uint32_t width, uint32_t height) - :meta(cam, width, height){ + // :model("../models/sponza/Sponza.gltf"), meta(cam, width, height) { + // :model("../models/BistroInterior/BistroInterior.gltf"), meta(cam, width, height) { + // :model("../models/BistroExterior/BistroExterior.gltf"), meta(cam, width, height) { + // :model("../models/sponza-avif-hi.glb"), meta(cam, width, height) { + // :model("../models/main_sponza/NewSponza_Main_glTF_003.gltf"), meta(cam, width, height) { + // :model("../models/pkg_a_curtains/NewSponza_Curtains_glTF.gltf"), meta(cam, width, height) { + :model("../models/sponza.glb"), meta(cam, width, height) { -#ifdef API_TEST - auto& device = vkdevice::get_render_device(); -#endif + auto& device = vkdevice::get(); // Geometry & BVH std::vector indices; @@ -81,51 +73,50 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) std::vector materials; std::vector packed_nodes; - // auto root_node = gltf::load("../models/BistroInterior", "BistroInterior.gltf"); - auto gltf_model = gltf("../models/sponza/Sponza.gltf"); - std::vector triangles; - size_t triangles_offset = 0; - size_t vertices_offset = 0; - std::queue nodes_to_load {}; - nodes_to_load.push(gltf_model.root_node); - - while(!nodes_to_load.empty()) { - auto &node = nodes_to_load.front(); - - if (node.mesh != nullptr) { - const auto* mesh = node.mesh; - const auto& mesh_positions = mesh->get_attribute(ATTRIBUTE_TYPE::POSITION); - const auto& mesh_normals = mesh->get_attribute(ATTRIBUTE_TYPE::NORMAL); - const auto& mesh_uvs_0 = mesh->get_attribute(ATTRIBUTE_TYPE::UV_0); - const auto& mesh_indices = mesh->get_indices(); - - indices.resize(indices.size() + mesh_indices.size()); - positions.resize(vertices_offset + mesh_positions.size()); - normals.resize(vertices_offset + mesh_normals.size()); - uvs.resize(vertices_offset + mesh_uvs_0.size()); + u32 triangles_offset = 0U; + u32 vertices_offset = 0U; + u32 positions_count = 0U; + u32 normals_count = 0U; + u32 uvs_count = 0U; + std::vector nodes_to_load = model.root_nodes; + + for (u32 cur_node_index = 0U; cur_node_index < nodes_to_load.size(); cur_node_index++) { + struct node &node = model.nodes[nodes_to_load[cur_node_index]]; + + if (node.mesh != UINT32_MAX) { + const Mesh& mesh = model.meshes[node.mesh]; + const auto& mesh_positions = mesh.get_attribute(ATTRIBUTE_TYPE::POSITION); + const auto& mesh_normals = mesh.get_attribute(ATTRIBUTE_TYPE::NORMAL); + const auto& mesh_uvs_0 = mesh.get_attribute(ATTRIBUTE_TYPE::UV_0); + const auto& mesh_indices = mesh.get_indices(); + + indices.resize(indices.size() + mesh_indices.size()); + positions.resize(positions_count + mesh_positions.size()); + normals.resize(normals_count + mesh_normals.size()); + uvs.resize(uvs_count + mesh_uvs_0.size()); std::memcpy( - positions.data() + vertices_offset * Mesh::attribute_components(ATTRIBUTE_TYPE::POSITION), + positions.data() + positions_count, mesh_positions.data(), - mesh_positions.size() * sizeof(float) + mesh_positions.size() * sizeof(mesh_positions[0U]) ); std::memcpy( - normals.data() + vertices_offset * Mesh::attribute_components(ATTRIBUTE_TYPE::NORMAL), + normals.data() + normals_count, mesh_normals.data(), - mesh_normals.size() * sizeof(float) + mesh_normals.size() * sizeof(mesh_normals[0U]) ); std::memcpy( - uvs.data() + vertices_offset * Mesh::attribute_components(ATTRIBUTE_TYPE::UV_0), + uvs.data() + uvs_count, mesh_uvs_0.data(), - mesh_uvs_0.size() * sizeof(float) + mesh_uvs_0.size() * sizeof(mesh_uvs_0[0U]) ); auto index_offset { 0U }; // Add offset to indices in order to have absolute indices - for (const auto& submesh: mesh->get_submeshes()) { + for (const auto& submesh: mesh.get_submeshes()) { auto vertex_offset = vertices_offset + submesh.vertex_offset; const auto& material = submesh.material; @@ -151,9 +142,6 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) indices[triangle_offset + 2] = static_cast((submesh_level_index_3 + vertex_offset) | (0xff000000 & (materials.size() << 24))); } -// const auto& albedo_image = vkrenderer::api.get_image(material.base_color_texture->device_image); -// const auto& albedo_sampler = vkrenderer::api.get_sampler(material.base_color_texture->sampler->device_sampler); - auto& mat = materials.emplace_back(gpu_material { .base_color = material.base_color, // .albedo_texture_id = albedo_image.bindless_sampled_index, @@ -162,7 +150,6 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) .roughness = material.roughness }); -#ifdef API_TEST if (material.base_color_texture.id != handle::invalid_id) { mat.albedo_texture_id = device.get_texture(material.base_color_texture).get_sampled_index(); // mat.albedo_texture_sampler_id = device.get_sampler(0); @@ -172,28 +159,18 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) mat.metallic_roughness_texture_id = device.get_texture(material.metallic_roughness_texture).get_sampled_index(); // mat.metallic_roughness_texture_sampler_id = device.get_sampler(0); } -#else - if (material.metallic_roughness_texture != nullptr) { - // auto& gpu_material = materials.back(); -// const auto& metallic_roughness_image = vkrenderer::api.get_image(material.metallic_roughness_texture->device_image); -// const auto& metallic_roughness_sampler = vkrenderer::api.get_sampler(material.metallic_roughness_texture->sampler->device_sampler); - -// gpu_material.metallic_roughness_texture_id = metallic_roughness_image.bindless_sampled_index; -// gpu_material.metallic_roughness_texture_sampler_id = metallic_roughness_sampler.bindless_index; - } -#endif - } - triangles_offset += mesh->triangle_count(); - vertices_offset += mesh->vertices_count(); + triangles_offset += mesh.triangle_count(); + vertices_offset += mesh.vertices_count(); + positions_count = vertices_offset * Mesh::attribute_components(ATTRIBUTE_TYPE::POSITION); + normals_count = vertices_offset * Mesh::attribute_components(ATTRIBUTE_TYPE::NORMAL); + uvs_count = vertices_offset * Mesh::attribute_components(ATTRIBUTE_TYPE::UV_0); } - for (auto &new_node: node.children) { - nodes_to_load.push(new_node); + for (u32 child_index: node.children) { + nodes_to_load.push_back(child_index); } - - nodes_to_load.pop(); } // random_scene(); @@ -201,28 +178,13 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) bvh builder(triangles, packed_nodes); // bvh builder(spheres, packed_nodes); -#ifdef API_TEST - { - scene_buffer_handle = device.create_buffer({ - .size = sizeof(meta) * 3U, - .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, - }); - - const auto& scene_buffer = device.get_buffer(scene_buffer_handle); - uint8_t* ptr = static_cast(scene_buffer.mapped_ptr); - memcpy(static_cast(ptr), &meta, sizeof(meta)); - memcpy(static_cast(ptr + sizeof(meta)), &meta, sizeof(meta)); - memcpy(static_cast(ptr + sizeof(meta) * 2U), &meta, sizeof(meta)); - } - { indices_buffer_handle = device.create_buffer({ .size = indices.size() * sizeof(indices[0]), .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "indices", }); const auto& indices_buffer = device.get_buffer(indices_buffer_handle); void* ptr = indices_buffer.mapped_ptr; @@ -235,6 +197,7 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "positions", }); const auto& positions_buffer = device.get_buffer(positions_buffer_handle); void* ptr = positions_buffer.mapped_ptr; @@ -247,6 +210,7 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "normals", }); const auto& normals_buffer = device.get_buffer(normals_buffer_handle); void* ptr = normals_buffer.mapped_ptr; @@ -259,6 +223,7 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "uvs", }); const auto& uvs_buffer = device.get_buffer(uvs_buffer_handle); void* ptr = uvs_buffer.mapped_ptr; @@ -271,6 +236,7 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "bvh", }); const auto& bvh_buffer = device.get_buffer(bvh_buffer_handle); void* ptr = bvh_buffer.mapped_ptr; @@ -283,33 +249,21 @@ scene::scene(const camera& cam, uint32_t width, uint32_t height) .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "materials", }); const auto& materials_buffer = device.get_buffer(materials_buffer_handle); void* ptr = materials_buffer.mapped_ptr; memcpy(ptr, materials.data(), materials.size() * sizeof(materials[0])); } -#else - scene_buffer = vkrenderer::create_buffer(sizeof(meta) * vkrenderer::virtual_frames_count); - scene_buffer->write(&meta, 0, sizeof(meta)); - scene_buffer->write(&meta, sizeof(meta), sizeof(meta)); - scene_buffer->write(&meta, sizeof(meta) * 2, sizeof(meta)); - - indices_buffer = vkrenderer::create_buffer(indices.size() * sizeof(indices[0])); - indices_buffer->write(indices.data(), 0, indices.size() * sizeof(indices[0])); - - positions_buffer = vkrenderer::create_buffer(positions.size() * sizeof(positions[0])); - positions_buffer->write(positions.data(), 0, positions.size() * sizeof(positions[0])); - - normals_buffer = vkrenderer::create_buffer(normals.size() * sizeof(normals[0])); - normals_buffer->write(normals.data(), 0, normals.size() * sizeof(normals[0])); - - uvs_buffer = vkrenderer::create_buffer(uvs.size() * sizeof(uvs[0])); - uvs_buffer->write(uvs.data(), 0, uvs.size() * sizeof(uvs[0])); +} - bvh_buffer = vkrenderer::create_buffer(packed_nodes.size() * sizeof(packed_nodes[0])); - bvh_buffer->write(packed_nodes.data(), 0, packed_nodes.size() * sizeof(packed_nodes[0])); +void scene::deinit() { + vkdevice::get().destroy_buffer(indices_buffer_handle); + vkdevice::get().destroy_buffer(positions_buffer_handle); + vkdevice::get().destroy_buffer(normals_buffer_handle); + vkdevice::get().destroy_buffer(uvs_buffer_handle); + vkdevice::get().destroy_buffer(bvh_buffer_handle); + vkdevice::get().destroy_buffer(materials_buffer_handle); - materials_buffer = vkrenderer::create_buffer(materials.size() * sizeof(materials[0])); - materials_buffer->write(materials.data(), 0, materials.size() * sizeof(materials[0])); -#endif // API_TEST + model.deinit(); } diff --git a/src/utils.cpp b/src/utils.cpp index ffe50b3..4c383db 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,54 +1,46 @@ #include "utils.hpp" -#if defined(WINDOWS) -#include -#endif - -#include -#include +#include -std::vector read_file(const char* path) { -#if defined(WINDOWS) - FILE* f = nullptr; - errno_t err = fopen_s(&f, path, "rb"); +uint8_t* read_file(const char* path, size_t* size) { +#if _WIN32 + HANDLE f = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (err != 0) { - std::cerr << "Cannot open file !" << std::endl; - return {}; + if (f == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Cannot open file !\n"); + return nullptr; } -#elif defined(LINUX) +#elif LINUX FILE* f = fopen(path, "rb"); if (!f) { - std::cerr << "Cannot open file !" << std::endl; + fprintf(stderr, "Cannot open file !\n"); return {}; } #endif - if (fseek(f, 0, SEEK_END) != 0) { - return {}; + LARGE_INTEGER file_size = { .QuadPart = 0ULL }; + if (!GetFileSizeEx(f, &file_size)) { + return nullptr; } + *size = file_size.LowPart; - std::vector file_content(ftell(f)); + void* content = malloc(*size); - if (fseek(f, 0, SEEK_SET) != 0) { - return {}; - } - - if (fread(file_content.data(), sizeof(uint8_t), file_content.size(), f) != file_content.size()) { - std::cerr << "Reading file content failed" << std::endl; - return {}; + DWORD bread = 0U; + if (!ReadFile(f, content, static_cast(*size), &bread, NULL) || bread != *size) { + fprintf(stderr, "Reading file content failed\n"); + return nullptr; } - fclose(f); + CloseHandle(f); - return file_content; + return (uint8_t*)content; } - -#ifdef WINDOWS +#if _WIN32 void log_last_error() { - auto error_code = GetLastError(); + DWORD error_code = GetLastError(); const char* error_message = nullptr; FormatMessageA( @@ -63,29 +55,49 @@ void log_last_error() { nullptr ); - std::cerr << error_message << std::endl; + fprintf(stderr, "%s\n", error_message); } -bool watcher::watch_file(const char* filepath, watcher::func callback) { +struct watch_data { + HANDLE dir_handle; + OVERLAPPED overlapped; + DWORD buffer[512]; +}; + +static std::unordered_map callbacks; +static std::unordered_map watched_dirs; + +bool watch_file(const char* filepath, func callback) { DWORD attrib = GetFileAttributes(filepath); if (attrib == INVALID_FILE_ATTRIBUTES) return false; - std::filesystem::path path(filepath); - if (!watcher::watch_dir(path.parent_path().string().c_str())) + size_t buffer_size = 2048U; + char* fullpath = static_cast(malloc(buffer_size)); + char* filename = nullptr; + GetFullPathNameA( filepath, 2028, fullpath, &filename); + + size_t dir_len = filename - fullpath; + char* parent_dir = static_cast(malloc(dir_len)); + strncpy(parent_dir, fullpath, dir_len); + + free(fullpath); + + if (!watch_dir(parent_dir)) { return false; + } - auto [_, is_inserted] = watcher::callbacks.emplace(filepath, callback); + auto [_, is_inserted] = callbacks.emplace(filepath, callback); return is_inserted; } -bool watcher::watch_dir(const char* dir_path) { +bool watch_dir(const char* dir_path) { DWORD attrib = GetFileAttributes(dir_path); if (attrib == INVALID_FILE_ATTRIBUTES || (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0U ) return false; - if (watcher::watched_dirs.find(dir_path) != watcher::watched_dirs.end()) + if (watched_dirs.find(dir_path) != watched_dirs.end()) return true; HANDLE dir_handle = CreateFileA( @@ -103,7 +115,7 @@ bool watcher::watch_dir(const char* dir_path) { return false; } - auto [dir, _] = watcher::watched_dirs.emplace(dir_path, watch_data{ .dir_handle = dir_handle, .overlapped{}, .buffer{} }); + auto [dir, _] = watched_dirs.emplace(dir_path, watch_data{ .dir_handle = dir_handle, .overlapped{}, .buffer{} }); if (FAILED(ReadDirectoryChangesW(dir_handle, dir->second.buffer, sizeof(watch_data::buffer), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, nullptr, &dir->second.overlapped, nullptr))) { log_last_error(); @@ -113,8 +125,8 @@ bool watcher::watch_dir(const char* dir_path) { return true; } -void watcher::pull_changes() { - for (auto& dir : watcher::watched_dirs) { +void pull_changes() { + for (auto& dir : watched_dirs) { auto& watch_data = dir.second; if (!HasOverlappedIoCompleted(&watch_data.overlapped)) continue; diff --git a/src/vec3.cpp b/src/vec3.cpp index 3167bc2..414ee73 100644 --- a/src/vec3.cpp +++ b/src/vec3.cpp @@ -1,10 +1,8 @@ -#include -#include -#include - -#include "utils.hpp" #include "vec3.hpp" +// #include +// #include + vec3::vec3() : v(_mm_setzero_ps()) {} vec3::vec3(float x) : v(_mm_set1_ps(x)) {} @@ -122,7 +120,16 @@ bool vec3::near_zero() const { float v0 = fabs(static_cast(_mm_extract_ps(v, 0))); float v1 = fabs(static_cast(_mm_extract_ps(v, 1))); float v2 = fabs(static_cast(_mm_extract_ps(v, 2))); - return (v0 < EPSILON) && (v1 < EPSILON) && (v2 < EPSILON); + return (v0 < FLT_EPSILON) && (v1 < FLT_EPSILON) && (v2 < FLT_EPSILON); +} + +bool vec3::is_zero() const { + // __m128 e = _mm_set1_ps(EPSILON); + // _mm_cmplt_ps(_mm_andnot_ps(_mm_set1_ps(-0.0f), v), e); + float v0 = fabs(static_cast(_mm_extract_ps(v, 0))); + float v1 = fabs(static_cast(_mm_extract_ps(v, 1))); + float v2 = fabs(static_cast(_mm_extract_ps(v, 2))); + return (v0 == 0.f) && (v1 == 0.f) && (v2 == 0.f); } void vec3::print() const { diff --git a/src/vulkan-loader.cpp b/src/vulkan-loader.cpp index c799f17..399b566 100644 --- a/src/vulkan-loader.cpp +++ b/src/vulkan-loader.cpp @@ -1,8 +1,6 @@ #include "vulkan-loader.hpp" -#include - -#if defined(WINDOWS) +#if defined(_WIN32) // extern "C" void* GetProcAddress(HMODULE, const char*); // extern "C" HMODULE LoadLibraryA(const char*); HMODULE vulkanLibrary = LoadLibraryA("vulkan-1.dll"); diff --git a/src/window.cpp b/src/window.cpp index 7ba3bc0..38c9765 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,6 +1,5 @@ #include "window.hpp" - #ifdef LINUX #include @@ -169,10 +168,23 @@ void window::poll_events() { } } -#elif defined(WINDOWS) -#include - -#include "utils.hpp" +#elif _WIN32 +#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) +#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) + +HCURSOR window::cursors[CURSOR_TYPE::MAX_CURSOR] = { + LoadCursorA(NULL, IDC_ARROW), + LoadCursorA(NULL, IDC_IBEAM), + LoadCursorA(NULL, IDC_SIZEALL), + LoadCursorA(NULL, IDC_SIZENS), + LoadCursorA(NULL, IDC_SIZEWE), + LoadCursorA(NULL, IDC_SIZENESW), + LoadCursorA(NULL, IDC_SIZENWSE), + LoadCursorA(NULL, IDC_HAND), + LoadCursorA(NULL, IDC_WAIT), + LoadCursorA(NULL, IDC_APPSTARTING), + LoadCursorA(NULL, IDC_NO), +}; LRESULT CALLBACK window::window_procedure(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) { window* win = nullptr; @@ -250,29 +262,27 @@ void window::message_loop() { MSG msg {}; while(true) { - // Generate keydown events pressed keys - for (size_t virtual_key { KEYS::LSHIFT }; virtual_key < KEYS::MAX_KEYS; virtual_key++) { - if (keyboard[virtual_key]) { - events.push_back({ - .data { - .key = (KEYS)virtual_key, - }, - .type = EVENT_TYPES::KEY_PRESS, - }); - } - } - - while (PeekMessageA(&msg, nullptr, 0, 0, PM_REMOVE) != 0) { TranslateMessage(&msg); DispatchMessageA(&msg); } + for (u32 key_index = 0U; key_index <= KEY::MAX_KEY; key_index++) { + events.push_back(event { + .data { + .key = (KEY)key_index, + }, + .type = keyboard[key_index] ? EVENT_TYPE::KEY_DOWN : EVENT_TYPE::KEY_UP, + }); + } + SwitchToFiber(main_fiber); } } void window::poll_events() { + events.clear(); + SwitchToFiber(message_loop_fiber); } @@ -281,7 +291,10 @@ LRESULT window::message_handler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lpar case WM_CLOSE: case WM_DESTROY: case WM_QUIT: { - events.push_back({ .data {}, .type = EVENT_TYPES::QUIT }); + events.push_back({ + .data {}, + .type = EVENT_TYPE::QUIT + }); isOpen = false; break; } @@ -296,86 +309,90 @@ LRESULT window::message_handler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lpar .height = height, }, }, - .type = EVENT_TYPES::RESIZE + .type = EVENT_TYPE::RESIZE }); break; } case WM_KEYDOWN: { - keyboard[wparam] = true; - events.push_back({ .data { - .key = (KEYS)wparam, + .key = (KEY)wparam, }, - .type = EVENT_TYPES::KEY_PRESS, + .type = EVENT_TYPE::KEY_PRESS, }); + keyboard[wparam] = true; break; } case WM_KEYUP: { - keyboard[wparam] = false; - events.push_back({ .data { - .key = (KEYS)wparam, + .key = (KEY)wparam, }, - .type = EVENT_TYPES::KEY_RELEASE, + .type = EVENT_TYPE::KEY_RELEASE, }); + keyboard[wparam] = false; break; } case WM_LBUTTONDOWN: { + mouse[BUTTON::LEFT] = true; events.push_back({ .data { - .button = BUTTONS::LEFT, + .button = BUTTON::LEFT, }, - .type = EVENT_TYPES::BUTTON_PRESS, + .type = EVENT_TYPE::BUTTON_PRESS, }); break; } case WM_LBUTTONUP: { + mouse[BUTTON::LEFT] = false; events.push_back({ .data { - .button = BUTTONS::LEFT, + .button = BUTTON::LEFT, }, - .type = EVENT_TYPES::BUTTON_RELEASE, + .type = EVENT_TYPE::BUTTON_RELEASE, }); break; } case WM_RBUTTONDOWN: { + mouse[BUTTON::RIGHT] = true; events.push_back({ .data { - .button = BUTTONS::RIGHT, + .button = BUTTON::RIGHT, }, - .type = EVENT_TYPES::BUTTON_PRESS, + .type = EVENT_TYPE::BUTTON_PRESS, }); break; } case WM_RBUTTONUP: { + mouse[BUTTON::RIGHT] = false; events.push_back({ .data { - .button = BUTTONS::RIGHT, + .button = BUTTON::RIGHT, }, - .type = EVENT_TYPES::BUTTON_RELEASE, + .type = EVENT_TYPE::BUTTON_RELEASE, }); break; } case WM_MBUTTONDOWN: { + mouse[BUTTON::MIDDLE] = true; events.push_back({ .data { - .button = BUTTONS::MIDDLE, + .button = BUTTON::MIDDLE, }, - .type = EVENT_TYPES::BUTTON_PRESS, + .type = EVENT_TYPE::BUTTON_PRESS, }); break; } case WM_MBUTTONUP: { + mouse[BUTTON::MIDDLE] = false; events.push_back({ .data { - .button = BUTTONS::MIDDLE, + .button = BUTTON::MIDDLE, }, - .type = EVENT_TYPES::BUTTON_RELEASE, + .type = EVENT_TYPE::BUTTON_RELEASE, }); break; } @@ -387,7 +404,19 @@ LRESULT window::message_handler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lpar .y = GET_Y_LPARAM(lparam), }, }, - .type = EVENT_TYPES::MOUSE_MOVE, + .type = EVENT_TYPE::MOUSE_MOVE, + }); + break; + } + case WM_MOUSEWHEEL: { + events.push_back({ + .data { + .delta { + .x = 0, + .y = GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA, + }, + }, + .type = EVENT_TYPE::MOUSE_WHEEL, }); break; } @@ -400,6 +429,10 @@ LRESULT window::message_handler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lpar return 0; } + +void window::set_cursor(enum CURSOR_TYPE type) { + SetCursor(window::cursors[type]); +} #elif defined(MACOS) window::window(uint32_t width, uint32_t height) { } -- cgit v1.3