aboutsummaryrefslogtreecommitdiff
path: root/src/engine.cpp
diff options
context:
space:
mode:
authorvimene <vincent.menegaux@gmail.com>2026-01-13 02:04:52 +0100
committervimene <vincent.menegaux@gmail.com>2026-01-13 02:04:52 +0100
commitdb41d43345ea73cf7c1bbb29448e52ffb822e3e0 (patch)
tree4635d654e301b3f31f8d2626f3bc2c6f2a6e50a8 /src/engine.cpp
parent7f08187a46e30925e4563585fab2c6f92400330a (diff)
downloadengine-db41d43345ea73cf7c1bbb29448e52ffb822e3e0.tar.gz
added textures for the hardware renderer
- removed "using" directive in .hpp - reverse order of arguments for quaternion rotation, i.e. q.rot(v) instead of v.rot(q), where q is a quaterinon and v a vector - pass the inverse of the view matrix to render_and_present_frame, to allow light calculation in shaders (we used to just pass the matrix of the quaternion of the transformation, i.e. discard scaling and translations) - added another mesh and texture (viking_room) for testing purposes - added transparent background option - added Quaternion::look_towards(), which is the equivalent of Matrix4::look_at() but only for rotations - various improvement to .obj parsing - load texture coordinates from .obj file - merged duplicate vertices in Mesh::linearize_indices()
Diffstat (limited to 'src/engine.cpp')
-rw-r--r--src/engine.cpp249
1 files changed, 147 insertions, 102 deletions
diff --git a/src/engine.cpp b/src/engine.cpp
index bde3058..aed0970 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -55,6 +55,7 @@ using
engine::fb::CharacterFrameBuffer,
engine::fb::PixelFrameBuffer,
engine::o3d::Scene,
+ engine::o3d::Object3D,
engine::o3d::Mesh,
engine::o3d::Triangle,
engine::o3d::Camera,
@@ -82,9 +83,10 @@ enum class GameType {
plane,
suzanne,
plane_and_suzanne,
+ test,
};
-constexpr GameType game_type { GameType::plane_and_suzanne };
+constexpr GameType game_type { GameType::test };
static void print_usage(std::ostream& output_stream) {
output_stream << "Usage: ./engine [-htg] [--help] [--term] [--graphical]\n"
@@ -139,7 +141,7 @@ static void scene_main(const Matrix4& final_transform_mat, Scene& scene,
if (kb.is_down(KeyboardKey::fw) || kb.is_down(KeyboardKey::key_left)
|| kb.is_down(KeyboardKey::bw) || kb.is_down(KeyboardKey::key_right))
movement.normalize();
- scene.camera.transform.loc += movement.rot(Quaternion::rot_y(ry)) * movement_speed * ellapsed_time;
+ scene.camera.transform.loc += Quaternion::rot_y(ry).rot(movement) * movement_speed * ellapsed_time;
scene.camera.transform.rot = Quaternion::euler_zxy(rx, ry, 0.f);
scene.camera.fov = (kb.is_down(KeyboardKey::zoom) ? 40.f : 80.f) * PI / 180.f;
@@ -152,7 +154,7 @@ static void scene_main(const Matrix4& final_transform_mat, Scene& scene,
auto proj_mat = final_transform_mat
* Matrix4::perspective(scene.camera.fov, static_cast<float>(surface_width) / static_cast<float>(surface_height), .5f, 12.f);
- render_and_present_frame(scene.camera.transform.to_inverse_mat4(), proj_mat, time, ellapsed_time);
+ render_and_present_frame(scene.camera.transform.to_inverse_mat4(), proj_mat, scene.camera.transform.to_mat4(), time, ellapsed_time);
}
}
@@ -162,7 +164,7 @@ static void render_software(Renderer<FrameBuffer>& renderer, const Matrix4& fina
PollEventsFn poll_events, UpdateRendererSizeFn update_renderer_size, PresentFrameFn present_frame) {
scene_main(final_transform_mat, scene,
// update_surface_size
- [&]() {
+ [&] {
update_renderer_size();
return std::tuple { renderer.width(), renderer.height() };
},
@@ -170,25 +172,33 @@ static void render_software(Renderer<FrameBuffer>& renderer, const Matrix4& fina
poll_events,
// render_and_present_frame
- [&](const Matrix4& view_mat, const Matrix4& proj_mat, float /* time */, float /* ellapsed_time */) {
- auto proj_view_mat = proj_mat * view_mat;
+ [&](const Matrix4& /* view_mat */, const Matrix4& /* proj_mat */, const Matrix4& /* inv_view_mat */, float /* time */, float /* ellapsed_time */) {
+ // TODO: remove
renderer.clear();
- for (const auto& obj : scene.objs) {
- auto model_mat = obj.transform.to_mat4();
- auto final_mat = proj_view_mat * model_mat;
- const auto& mesh = obj.mesh;
- std::vector<Vector4> vertices;
- std::vector<VertexData> vertices_data;
- for (const auto& vertex : mesh.vertices) {
- vertices.push_back(final_mat * Vector4 { vertex, 1.f });
- vertices_data.push_back(VertexData((model_mat * vertex).xyz()));
- }
- for (const auto& triangle_indices : mesh.indices) {
- [&]<std::size_t... j>(std::integer_sequence<std::size_t, j...>) {
- renderer.draw_triangle({{vertices[triangle_indices[j][0]], mesh.normals[triangle_indices[j][1]], vertices_data[triangle_indices[j][0]]}...});
- }(std::make_integer_sequence<std::size_t, 3>());
- }
- }
+ // auto proj_view_mat = proj_mat * view_mat;
+ // renderer.clear();
+ // for (const auto& obj : scene.objs) {
+ // auto model_mat = obj.transform.to_mat4();
+ // auto final_mat = proj_view_mat * model_mat;
+ // const auto& mesh = obj.mesh;
+ // std::vector<Vector4> vertices;
+ // std::vector<Vector3> normals;
+ // std::vector<VertexData> vertices_data;
+ // for (const auto& vertex : mesh.vertices) {
+ // Vector4 vertex4 { vertex, 1.f };
+ // vertices.push_back(final_mat * vertex4);
+ // vertices_data.push_back(VertexData((model_mat * vertex4).xyz()));
+ // }
+ // for (const auto& normal : mesh.normals)
+ // normals.push_back((model_mat * Vector4 { normal, 0.f }).xyz());
+ // for (const auto& triangle_indices : mesh.indices) {
+ // [&]<std::size_t... j>(std::index_sequence<j...>) {
+ // renderer.draw_triangle(
+ // {{vertices[triangle_indices[j][0]], normals[triangle_indices[j][1]], vertices_data[triangle_indices[j][0]]}...}
+ // );
+ // }(std::make_index_sequence<3>());
+ // }
+ // }
present_frame();
}
);
@@ -208,10 +218,10 @@ static int main_term(Scene& scene) {
set_escdelay(0);
curs_set(0);
- auto renderer = [&]() {
+ auto renderer = [&] {
int w, h;
getmaxyx(stdscr, h, w);
- return Renderer<CharacterFrameBuffer> { CharacterFrameBuffer { static_cast<unsigned int>(w), static_cast<unsigned int>(h) } };
+ return Renderer { CharacterFrameBuffer { static_cast<unsigned int>(w), static_cast<unsigned int>(h) } };
}();
render_software(renderer, Matrix4::scale(Vector3(2.f, 1.f, 1.f)), scene,
@@ -289,14 +299,14 @@ static int main_term(Scene& scene) {
},
// update_renderer_size
- [&]() {
+ [&] {
int w, h;
getmaxyx(stdscr, h, w);
renderer.resize(static_cast<unsigned int>(w), static_cast<unsigned int>(h));
},
// present_frame
- [&]() {
+ [&] {
mvaddnstr(0, 0, renderer.fb.chars(), renderer.width() * renderer.height());
}
);
@@ -331,6 +341,7 @@ constexpr bool enable_validation_layers = true;
constexpr size_t max_frames_in_flight = 2;
constexpr bool show_fps = false;
+constexpr bool transparent_window = false;
struct PhysicalDeviceEntry {
uint32_t idx;
@@ -347,7 +358,7 @@ enum class GraphicalRendererMode {
};
static bool check_validation_layer_support() {
- auto avail_layers = [&]() {
+ auto avail_layers = [&] {
uint32_t avail_layers_count;
if (VkResult res = vkEnumerateInstanceLayerProperties(&avail_layers_count, nullptr); res != VK_SUCCESS) {
std::cerr << "failed to enumerate instance layer properties, error code: " << string_VkResult(res) << std::endl;
@@ -477,7 +488,7 @@ static uint32_t find_mem_type(VkPhysicalDevice physical_device, uint32_t type_fi
static std::tuple<VkBuffer, VkDeviceMemory>
create_buf(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags mem_flags) {
- auto buf = [&]() {
+ auto buf = [&] {
VkBufferCreateInfo buf_ci {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -499,7 +510,7 @@ create_buf(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size,
VkMemoryRequirements buf_mem_requirements;
vkGetBufferMemoryRequirements(device, buf, &buf_mem_requirements);
- auto buf_device_mem = [&]() {
+ auto buf_device_mem = [&] {
VkMemoryAllocateInfo buf_mem_ai {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = nullptr,
@@ -522,7 +533,7 @@ create_buf(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size,
}
static VkCommandBuffer begin_single_time_cmds(VkDevice device, VkCommandPool cmd_pool) {
- auto cmd_buf = [&]() {
+ auto cmd_buf = [&] {
VkCommandBufferAllocateInfo cmd_buf_ai {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = nullptr,
@@ -612,7 +623,7 @@ static void copy_buf_to_img(VkCommandBuffer cmd_buf, VkBuffer src, VkImage dst,
static std::tuple<VkImage, VkDeviceMemory>
create_img(VkPhysicalDevice physical_device, VkDevice device, uint32_t width, uint32_t height, VkFormat format,
VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags mem_flags) {
- auto texture_img = [&]() {
+ auto texture_img = [&] {
VkImageCreateInfo img_ci {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
@@ -639,7 +650,7 @@ create_img(VkPhysicalDevice physical_device, VkDevice device, uint32_t width, ui
return texture_img;
}();
- auto texture_img_device_mem = [&]() {
+ auto texture_img_device_mem = [&] {
VkMemoryRequirements mem_requirements;
vkGetImageMemoryRequirements(device, texture_img, &mem_requirements);
VkMemoryAllocateInfo mem_ai {
@@ -668,7 +679,7 @@ static std::tuple<VkImage, VkDeviceMemory, VkImageView>
create_depth_resources(VkPhysicalDevice physical_device, VkDevice device, VkExtent2D swapchain_extent, VkFormat depth_format) {
auto [depth_img, depth_img_device_mem] = create_img(physical_device, device, swapchain_extent.width, swapchain_extent.height, depth_format,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- auto depth_img_view = [&]() {
+ auto depth_img_view = [&] {
VkImageViewCreateInfo img_view_ci {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = {},
@@ -743,6 +754,10 @@ static int main_graphical(Scene& scene) {
// init window
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ if (transparent_window) {
+ glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
+ glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
+ }
bool fb_resized = false;
@@ -777,7 +792,7 @@ static int main_graphical(Scene& scene) {
exit(EXIT_FAILURE);
}
- auto instance = [&]() {
+ auto instance = [&] {
VkApplicationInfo app_info {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = nullptr,
@@ -788,7 +803,7 @@ static int main_graphical(Scene& scene) {
.apiVersion = VK_API_VERSION_1_4,
};
- auto instance_exts = [&]() {
+ auto instance_exts = [&] {
std::vector<const char*> instance_exts;
{
uint32_t glfw_extension_count;
@@ -800,7 +815,7 @@ static int main_graphical(Scene& scene) {
return instance_exts;
}();
- auto avail_instance_exts = [&]() {
+ auto avail_instance_exts = [&] {
uint32_t avail_instance_exts_count;
if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &avail_instance_exts_count, nullptr); res != VK_SUCCESS) {
std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl;
@@ -863,7 +878,7 @@ static int main_graphical(Scene& scene) {
}
// create window surface
- auto surface = [&]() {
+ auto surface = [&] {
VkSurfaceKHR surface;
if (VkResult res = glfwCreateWindowSurface(instance, window, nullptr, &surface); res != VK_SUCCESS) {
std::cerr << "failed to create window surface, error code: " << string_VkResult(res) << std::endl;
@@ -873,10 +888,10 @@ static int main_graphical(Scene& scene) {
}();
// select physical device and queues
- auto [physical_device, graphics_queue_family_index, present_queue_family_index, physical_device_props, physical_device_features, depth_format] = [&]() {
+ auto [physical_device, graphics_queue_family_index, present_queue_family_index, physical_device_props, physical_device_features, depth_format] = [&] {
std::multimap<unsigned, PhysicalDeviceEntry> physical_devices;
- auto avail_physical_devices = [&]() {
+ auto avail_physical_devices = [&] {
uint32_t avail_physical_devices_count;
if (VkResult res = vkEnumeratePhysicalDevices(instance, &avail_physical_devices_count, nullptr); res != VK_SUCCESS) {
std::cerr << "failed to enumerate physical devices, error code: " << string_VkResult(res) << std::endl;
@@ -900,7 +915,7 @@ static int main_graphical(Scene& scene) {
for (uint32_t i = 0; i < avail_physical_devices.size(); i++) {
const auto& avail_physical_device = avail_physical_devices[i];
- auto physical_device_props = [&]() {
+ auto physical_device_props = [&] {
VkPhysicalDeviceProperties2 physical_device_props{};
physical_device_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
vkGetPhysicalDeviceProperties2(avail_physical_device, &physical_device_props);
@@ -910,14 +925,14 @@ static int main_graphical(Scene& scene) {
std::cout << " " << (i + 1) << ". " << physical_device_props.properties.deviceName << ":" << std::endl;
std::cout << " apiVersion: " << engine::vk::api { physical_device_props.properties.apiVersion } << std::endl;
- auto physical_device_features = [&]() {
+ auto physical_device_features = [&] {
VkPhysicalDeviceFeatures2 physical_device_features{};
physical_device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
vkGetPhysicalDeviceFeatures2(avail_physical_device, &physical_device_features);
return physical_device_features;
}();
- auto physical_device_ext_props = [&]() {
+ auto physical_device_ext_props = [&] {
uint32_t physical_device_ext_props_count;
if (VkResult res = vkEnumerateDeviceExtensionProperties(avail_physical_device, nullptr,
&physical_device_ext_props_count, nullptr); res != VK_SUCCESS) {
@@ -941,7 +956,7 @@ static int main_graphical(Scene& scene) {
std::cout << " " << ext << std::endl;
}
- auto queue_family_properties = [&]() {
+ auto queue_family_properties = [&] {
uint32_t queue_family_properties_count;
vkGetPhysicalDeviceQueueFamilyProperties2(avail_physical_device, &queue_family_properties_count, nullptr);
std::vector<VkQueueFamilyProperties2> queue_family_properties(queue_family_properties_count);
@@ -975,7 +990,7 @@ static int main_graphical(Scene& scene) {
std::cout << "none";
std::cout << std::endl;
- auto score = [&]() {
+ auto score = [&] {
if (VK_API_VERSION_VARIANT(physical_device_props.properties.apiVersion) != 0
|| physical_device_props.properties.apiVersion < VK_API_VERSION_1_4)
return std::optional<unsigned> {};
@@ -1051,7 +1066,7 @@ static int main_graphical(Scene& scene) {
best->second.present_queue_family_index, best->second.props, best->second.features, best->second.depth_format };
}();
- auto device = [&]() {
+ auto device = [&] {
// TODO: really weird way of making a single structure if
// graphics_queue_family_index == present_queue_family_index
// here, in this cas, we create both *CreateInfo, and then tell VkDeviceCreateInfo that
@@ -1135,7 +1150,7 @@ static int main_graphical(Scene& scene) {
return device;
}();
- auto [graphics_queue, present_queue] = [&]() {
+ auto [graphics_queue, present_queue] = [&] {
const auto map_family_to_queue = [&](uint32_t queue_family_index) {
VkQueue queue;
vkGetDeviceQueue(device, queue_family_index, 0, &queue);
@@ -1166,13 +1181,13 @@ static int main_graphical(Scene& scene) {
VkDeviceMemory depth_img_device_mem;
VkImageView depth_img_view;
- const auto destroy_swapchain = [&]() {
+ const auto destroy_swapchain = [&] {
for (auto it_img_view = swapchain_img_views.rbegin(); it_img_view != swapchain_img_views.rend(); ++it_img_view)
vkDestroyImageView(device, *it_img_view, nullptr);
vkDestroySwapchainKHR(device, swapchain, nullptr);
};
- const auto recreate_swapchain = [&]() {
+ const auto recreate_swapchain = [&] {
bool is_first_swapchain = (swapchain == nullptr);
if (!is_first_swapchain) {
if (VkResult res = vkDeviceWaitIdle(device); res != VK_SUCCESS) {
@@ -1185,7 +1200,7 @@ static int main_graphical(Scene& scene) {
// TODO: should probably use version 2 of theses functions, but glfwCreateWindowSurface
// return version 1, so for now we will use version 1
- auto surface_capabilities = [&]() {
+ auto surface_capabilities = [&] {
VkSurfaceCapabilitiesKHR surface_capabilities;
if (VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_capabilities); res != VK_SUCCESS) {
std::cerr << "failed to get physical device surface capabilities, error code: " << string_VkResult(res) << std::endl;
@@ -1202,8 +1217,16 @@ static int main_graphical(Scene& scene) {
exit(EXIT_FAILURE);
}
}
+ {
+ VkCompositeAlphaFlagsKHR required_composite_alpha =
+ (transparent_window ? VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR);
+ if ((surface_capabilities.supportedCompositeAlpha & required_composite_alpha) != required_composite_alpha) {
+ std::cerr << "required composite alpha flags not present" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
- swapchain_extent = [&]() {
+ swapchain_extent = [&] {
if (surface_capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
return surface_capabilities.currentExtent;
int width, height;
@@ -1220,8 +1243,8 @@ static int main_graphical(Scene& scene) {
};
}();
- surface_format = [&]() {
- auto surface_formats = [&]() {
+ surface_format = [&] {
+ auto surface_formats = [&] {
uint32_t surface_formats_count;
if (VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &surface_formats_count, nullptr); res != VK_SUCCESS) {
std::cerr << "failed to get physical device surface formats, error code: " << string_VkResult(res) << std::endl;
@@ -1246,9 +1269,9 @@ static int main_graphical(Scene& scene) {
exit(EXIT_FAILURE);
}();
- [&]() {
- auto present_mode = [&]() {
- auto present_modes = [&]() {
+ [&] {
+ auto present_mode = [&] {
+ auto present_modes = [&] {
uint32_t present_modes_count;
if (VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_modes_count, nullptr); res != VK_SUCCESS) {
std::cerr << "failed to get physical device present modes, error code: " << string_VkResult(res) << std::endl;
@@ -1293,7 +1316,7 @@ static int main_graphical(Scene& scene) {
.queueFamilyIndexCount = {},
.pQueueFamilyIndices = {},
.preTransform = surface_capabilities.currentTransform,
- .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ .compositeAlpha = (transparent_window ? VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR),
.presentMode = present_mode,
.clipped = VK_TRUE,
.oldSwapchain = {},
@@ -1316,7 +1339,7 @@ static int main_graphical(Scene& scene) {
}
}();
- [&]() {
+ [&] {
uint32_t swapchain_imgs_count;
if (VkResult res = vkGetSwapchainImagesKHR(device, swapchain, &swapchain_imgs_count, nullptr); res != VK_SUCCESS) {
std::cerr << "failed to get swapchain images, error code: " << string_VkResult(res) << std::endl;
@@ -1329,7 +1352,7 @@ static int main_graphical(Scene& scene) {
}
}();
- [&]() {
+ [&] {
swapchain_img_views.resize(swapchain_imgs.size());
for (uint32_t i = 0; i < swapchain_imgs.size(); i++) {
VkImageViewCreateInfo img_view_ci {
@@ -1361,10 +1384,10 @@ static int main_graphical(Scene& scene) {
recreate_swapchain();
- auto renderer_mode = GraphicalRendererMode::software;
+ auto renderer_mode = GraphicalRendererMode::hardware;
// create descriptor set layout
- auto descriptor_set_layout = [&]() {
+ auto descriptor_set_layout = [&] {
std::array descriptor_set_layout_bindings {
VkDescriptorSetLayoutBinding {
.binding = 0,
@@ -1397,10 +1420,10 @@ static int main_graphical(Scene& scene) {
}();
// create pipeline
- auto [pl_layout, graphics_pl] = [&]() {
+ auto [pl_layout, graphics_pl] = [&] {
// reading shader file
- auto shader_module = [&]() {
- auto shader_code = [&]() {
+ auto shader_module = [&] {
+ auto shader_code = [&] {
const char* shader_file_name = SHADERSDIR "/shader.spv";
std::ifstream shader_file(shader_file_name, std::ios::ate | std::ios::binary);
if (!shader_file.is_open()) {
@@ -1429,7 +1452,7 @@ static int main_graphical(Scene& scene) {
return shader_module;
}();
- auto [pl_layout, graphics_pl] = [&]() {
+ auto [pl_layout, graphics_pl] = [&] {
std::array pl_shader_stage_cis {
VkPipelineShaderStageCreateInfo {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
@@ -1563,7 +1586,7 @@ static int main_graphical(Scene& scene) {
.blendConstants = { 0.f, 0.f, 0.f, 0.f },
};
- auto pl_layout = [&]() {
+ auto pl_layout = [&] {
VkPipelineLayoutCreateInfo pl_layout_ci {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
@@ -1628,7 +1651,7 @@ static int main_graphical(Scene& scene) {
}();
// create command pool
- auto cmd_pool = [&]() {
+ auto cmd_pool = [&] {
VkCommandPoolCreateInfo cmd_pool_ci {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.pNext = nullptr,
@@ -1649,9 +1672,9 @@ static int main_graphical(Scene& scene) {
std::tie(depth_img, depth_img_device_mem, depth_img_view) = create_depth_resources(physical_device, device, swapchain_extent, depth_format);
// create texture image
- auto [texture_img, texture_img_device_mem] = [&]() {
+ auto [texture_img, texture_img_device_mem] = [&] {
int w, h, channels;
- stbi_uc* pixels = stbi_load(DATADIR "/assets/textures/texture.jpg", &w, &h, &channels, STBI_rgb_alpha);
+ stbi_uc* pixels = stbi_load(DATADIR "/assets/textures/viking_room.png", &w, &h, &channels, STBI_rgb_alpha);
// TODO: we're also using this size as the host pixels buffer size, I don't know if mixing
// the two will cause problems later. Right now they are the same, so it doesn't
@@ -1708,7 +1731,7 @@ static int main_graphical(Scene& scene) {
// TODO: this is the same code, with minor differences, than the one that create swapchain image
// views, so maybe we should create a function. The thing is, this code only call a single
// function with a single create-info, so I'm not sure if it would make sense
- auto texture_img_view = [&]() {
+ auto texture_img_view = [&] {
VkImageViewCreateInfo img_view_ci {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = {},
@@ -1734,7 +1757,7 @@ static int main_graphical(Scene& scene) {
}();
// create texture sampler
- auto sampler = [&]() {
+ auto sampler = [&] {
VkSamplerCreateInfo sampler_ci {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = nullptr,
@@ -1765,7 +1788,7 @@ static int main_graphical(Scene& scene) {
}();
// create vertex buffers
- auto [vertex_bufs, vertex_buf_device_mems] = [&]() {
+ auto [vertex_bufs, vertex_buf_device_mems] = [&] {
std::vector<VkBuffer> vertex_bufs;
std::vector<VkDeviceMemory> vertex_buf_device_mems;
for (const auto& vertices : meshes_vertices) {
@@ -1817,7 +1840,7 @@ static int main_graphical(Scene& scene) {
// TODO: this code is pretty much a duplicate with minor differences of the vertex_bufs one. We
// should probably factor it out in a function. Also, every TODOs were remove for this one, but
// they still hold
- auto [index_bufs, index_buf_device_mems] = [&]() {
+ auto [index_bufs, index_buf_device_mems] = [&] {
std::vector<VkBuffer> index_bufs;
std::vector<VkDeviceMemory> index_buf_device_mems;
for (const auto& indices : meshes_indices) {
@@ -1861,7 +1884,7 @@ static int main_graphical(Scene& scene) {
}();
// create uniform buffers
- auto [uniform_bufs, uniform_buf_device_mems, uniform_buf_mems] = [&]() {
+ auto [uniform_bufs, uniform_buf_device_mems, uniform_buf_mems] = [&] {
constexpr VkDeviceSize uniform_buf_size = sizeof(engine::vk::UniformBufferObject);
std::vector<VkBuffer> uniform_bufs(max_frames_in_flight * scene.objs.size(), nullptr);
std::vector<VkDeviceMemory> uniform_buf_device_mems(max_frames_in_flight * scene.objs.size(), nullptr);
@@ -1879,7 +1902,7 @@ static int main_graphical(Scene& scene) {
}();
// create descriptor pool
- auto descriptor_pool = [&]() {
+ auto descriptor_pool = [&] {
std::array descriptor_pool_sizes {
VkDescriptorPoolSize {
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
@@ -1912,7 +1935,7 @@ static int main_graphical(Scene& scene) {
// TODO: right now, we just send every descriptors every frame and for every object, without
// taking into account update frequencies. For example we should have only one set for the
// camera, shared between every objects, etc
- auto descriptor_sets = [&]() {
+ auto descriptor_sets = [&] {
std::vector<VkDescriptorSetLayout> layouts(max_frames_in_flight * scene.objs.size(), descriptor_set_layout);
VkDescriptorSetAllocateInfo descriptor_set_ai {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
@@ -1974,7 +1997,7 @@ static int main_graphical(Scene& scene) {
}();
// create command buffers
- auto cmd_bufs = [&]() {
+ auto cmd_bufs = [&] {
VkCommandBufferAllocateInfo cmd_buf_ai {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = nullptr,
@@ -1991,10 +2014,10 @@ static int main_graphical(Scene& scene) {
}();
// create sync objects
- auto [sems_present_complete, sems_render_finished] = [&]() {
+ auto [sems_present_complete, sems_render_finished] = [&] {
// TODO: remove duplicate code
- auto sems_present_complete = [&]() {
+ auto sems_present_complete = [&] {
std::array<VkSemaphore, max_frames_in_flight> sems_present_complete;
size_t num = 0;
for (auto& sem : sems_present_complete) {
@@ -2011,7 +2034,7 @@ static int main_graphical(Scene& scene) {
return sems_present_complete;
}();
- auto sems_render_finished = [&]() {
+ auto sems_render_finished = [&] {
std::vector<VkSemaphore> sems_render_finished(swapchain_imgs.size());
size_t num = 0;
for (auto& sem : sems_render_finished) {
@@ -2050,7 +2073,7 @@ static int main_graphical(Scene& scene) {
}
std::cout << " ]" << std::endl;
- auto fences_in_flight = [&]() {
+ auto fences_in_flight = [&] {
std::array<VkFence, max_frames_in_flight> fences_in_flight;
size_t num = 0;
for (auto& fence_in_flight : fences_in_flight) {
@@ -2087,7 +2110,7 @@ static int main_graphical(Scene& scene) {
std::array<VkDeviceMemory, max_frames_in_flight> software_renderer_buf_device_mems;
std::array<void*, max_frames_in_flight> software_renderer_buf_mems;
- auto destroy_software_renderer_bufs = [&]() {
+ auto destroy_software_renderer_bufs = [&] {
for (size_t i = max_frames_in_flight; i > 0; i--) {
vkUnmapMemory(device, software_renderer_buf_device_mems[i - 1]);
vkFreeMemory(device, software_renderer_buf_device_mems[i - 1], nullptr);
@@ -2095,7 +2118,7 @@ static int main_graphical(Scene& scene) {
}
};
- auto recreate_software_renderer_bufs = [&]() {
+ auto recreate_software_renderer_bufs = [&] {
if (!first_software_renderer_buf_creation) {
destroy_software_renderer_bufs();
if (software_renderer.width() != swapchain_extent.width || software_renderer.height() != swapchain_extent.height)
@@ -2125,7 +2148,7 @@ static int main_graphical(Scene& scene) {
scene_main(Matrix4::idty(), scene,
// update_surface_size
- [&]() {
+ [&] {
return std::tuple { swapchain_extent.width, swapchain_extent.height };
},
@@ -2219,7 +2242,7 @@ static int main_graphical(Scene& scene) {
},
// render_and_present_frame
- [&](const Matrix4& view_mat, const Matrix4& proj_mat, float /* time */, float ellapsed_time) {
+ [&](const Matrix4& view_mat, const Matrix4& proj_mat, const Matrix4& inv_view_mat, float /* time */, float ellapsed_time) {
if (show_fps)
std::cout << "\rfps: " << (1.f / ellapsed_time) << " ";
@@ -2246,9 +2269,6 @@ static int main_graphical(Scene& scene) {
}
}
- // TODO: this is where we set uniform buffers for the hardware renderer, and where we
- // render for the software renderer. We should do approximately the same thing in the
- // same place for both renderers
switch (renderer_mode) {
case GraphicalRendererMode::hardware:
{
@@ -2256,20 +2276,24 @@ static int main_graphical(Scene& scene) {
for (size_t i = 0; i < scene.objs.size(); i++) {
// TODO: should use push constants
engine::vk::UniformBufferObject ubo {
- .model = scene.objs[i].transform.to_mat4(),
- .view = view_mat,
- .proj = proj_mat,
- .camera_rot = Matrix4::from_quaternion(scene.camera.transform.rot),
- .camera_loc = scene.camera.transform.loc,
+ .model = scene.objs[i].transform.to_mat4(),
+ .view = view_mat,
+ .proj = proj_mat,
+ .inv_view = inv_view_mat,
};
memcpy(uniform_buf_mems[frame_idx * scene.objs.size() + i], &ubo, sizeof(engine::vk::UniformBufferObject));
}
}
break;
case GraphicalRendererMode::software:
+ break;
+ }
+
+ switch (renderer_mode) {
+ case GraphicalRendererMode::hardware:
+ break;
+ case GraphicalRendererMode::software:
{
- // TODO: this is a copy-paste of the code in render_software, which is obviously
- // bad
auto proj_view_mat = proj_mat * view_mat;
software_renderer.clear();
for (const auto& obj : scene.objs) {
@@ -2277,17 +2301,27 @@ static int main_graphical(Scene& scene) {
auto final_mat = proj_view_mat * model_mat;
const auto& mesh = obj.mesh;
std::vector<Vector4> vertices;
+ std::vector<Vector3> normals;
std::vector<VertexData> vertices_data;
for (const auto& vertex : mesh.vertices) {
- vertices.push_back(final_mat * Vector4 { vertex, 1.f });
- vertices_data.push_back(VertexData((model_mat * vertex).xyz()));
+ Vector4 vertex4 { vertex, 1.f };
+ vertices.push_back(final_mat * vertex4);
+ vertices_data.push_back(VertexData((model_mat * vertex4).xyz()));
}
+ for (const auto& normal : mesh.normals)
+ normals.push_back((model_mat * Vector4 { normal, 0.f }).xyz());
for (const auto& triangle_indices : mesh.indices) {
- [&]<std::size_t... j>(std::integer_sequence<std::size_t, j...>) {
- software_renderer.draw_triangle(
- {{vertices[triangle_indices[j][0]], mesh.normals[triangle_indices[j][1]], vertices_data[triangle_indices[j][0]]}...}
- );
- }(std::make_integer_sequence<std::size_t, 3>());
+ software_renderer.draw_triangle([&]<size_t... j>(std::index_sequence<j...>) constexpr -> engine::o3d::Triangle {
+ return {
+ {
+ vertices[triangle_indices[j][0]],
+ normals [triangle_indices[j][1]],
+ mesh.uvs[triangle_indices[j][2]],
+ vertices_data[triangle_indices[j][0]]
+ }
+ ...
+ };
+ }(std::make_index_sequence<3>()));
}
}
memcpy(software_renderer_buf_mems[frame_idx], software_renderer.fb.pixels(), swapchain_extent.width * swapchain_extent.height * 4);
@@ -2380,7 +2414,7 @@ static int main_graphical(Scene& scene) {
}
{
- VkClearValue clear_color_val { .color { .float32 = { 0.f, 0.f, 0.f, 1.f } } };
+ VkClearValue clear_color_val { .color { .float32 = { 0.f, 0.f, 0.f, (transparent_window ? 0.f : 1.f) } } };
VkClearValue clear_depth_val { .depthStencil { .depth = 1.f, .stencil = 0 } };
VkRenderingAttachmentInfo rendering_color_info {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
@@ -2760,6 +2794,17 @@ int main(int argc, char *argv[]) {
}
},
};
+ case GameType::test:
+ return {
+ {
+ engine::parse_object(DATADIR "/assets/viking_room.obj"),
+ {
+ Vector3(0.f, .5f, 0.f),
+ Quaternion::look_towards({ -1.f, 0.f, 0.f }, { 0.f, 0.f, 1.f }).conjugate(),
+ Vector3(1.f, 1.f, 1.f),
+ }
+ },
+ };
}
std::unreachable();
}()