|
|
@ -10,6 +10,7 @@
|
|
|
|
#include <cglm/types.h>
|
|
|
|
#include <cglm/types.h>
|
|
|
|
#include <cglm/mat4.h>
|
|
|
|
#include <cglm/mat4.h>
|
|
|
|
#include <cglm/affine.h>
|
|
|
|
#include <cglm/affine.h>
|
|
|
|
|
|
|
|
#include <cglm/cam.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
@ -111,7 +112,7 @@ typedef struct VulkanContextStruct {
|
|
|
|
} VulkanContext;
|
|
|
|
} VulkanContext;
|
|
|
|
|
|
|
|
|
|
|
|
struct Vertex{
|
|
|
|
struct Vertex{
|
|
|
|
vec2 pos;
|
|
|
|
vec3 pos;
|
|
|
|
vec3 color;
|
|
|
|
vec3 color;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -121,14 +122,18 @@ struct SceneUBO {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const struct Vertex vertices[] = {
|
|
|
|
const struct Vertex vertices[] = {
|
|
|
|
{.pos = {-0.5f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}},
|
|
|
|
{.pos = {-0.5f, -0.5f, 0.5f}, .color = {1.0f, 0.0f, 0.0f}},
|
|
|
|
{.pos = { 0.5f, -0.5f}, .color = {0.0f, 1.0f, 0.0f}},
|
|
|
|
{.pos = { 0.5f, -0.5f, 0.5f}, .color = {0.0f, 1.0f, 0.0f}},
|
|
|
|
{.pos = { 0.5f, 0.5f}, .color = {0.0f, 0.0f, 1.0f}},
|
|
|
|
{.pos = { 0.5f, 0.5f, 0.5f}, .color = {0.0f, 0.0f, 1.0f}},
|
|
|
|
{.pos = {-0.5f, 0.5f}, .color = {1.0f, 1.0f, 1.0f}},
|
|
|
|
{.pos = {-0.5f, 0.5f, 0.5f}, .color = {1.0f, 1.0f, 1.0f}},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//const uint16_t indices[] = {
|
|
|
|
|
|
|
|
// 0, 1, 2, 2, 3, 0,
|
|
|
|
|
|
|
|
//};
|
|
|
|
|
|
|
|
//
|
|
|
|
const uint16_t indices[] = {
|
|
|
|
const uint16_t indices[] = {
|
|
|
|
0, 1, 2, 2, 3, 0,
|
|
|
|
2, 1, 0, 0, 3, 2,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const char * validation_layers[] = {
|
|
|
|
const char * validation_layers[] = {
|
|
|
@ -170,7 +175,7 @@ VkVertexInputAttributeDescription vertex_attributes[2];
|
|
|
|
VkVertexInputAttributeDescription* vertex_attribute_descriptions() {
|
|
|
|
VkVertexInputAttributeDescription* vertex_attribute_descriptions() {
|
|
|
|
vertex_attributes[0].binding = 0;
|
|
|
|
vertex_attributes[0].binding = 0;
|
|
|
|
vertex_attributes[0].location = 0;
|
|
|
|
vertex_attributes[0].location = 0;
|
|
|
|
vertex_attributes[0].format = VK_FORMAT_R32G32_SFLOAT;
|
|
|
|
vertex_attributes[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
|
|
vertex_attributes[0].offset = offsetof(struct Vertex, pos);
|
|
|
|
vertex_attributes[0].offset = offsetof(struct Vertex, pos);
|
|
|
|
|
|
|
|
|
|
|
|
vertex_attributes[1].binding = 0;
|
|
|
|
vertex_attributes[1].binding = 0;
|
|
|
@ -570,50 +575,47 @@ VkDevice create_logical_device(VkPhysicalDevice physical_device, QueueIndices qu
|
|
|
|
return device;
|
|
|
|
return device;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct MaybeSwapchainDetails {
|
|
|
|
SwapchainDetails get_swapchain_details(VkPhysicalDevice physical_device, VkSurfaceKHR surface) {
|
|
|
|
bool valid;
|
|
|
|
SwapchainDetails details = {};
|
|
|
|
SwapchainDetails details;
|
|
|
|
details.formats = 0;
|
|
|
|
};
|
|
|
|
details.present_modes = 0;
|
|
|
|
|
|
|
|
|
|
|
|
struct MaybeSwapchainDetails get_swapchain_details(VkPhysicalDevice physical_device, VkSurfaceKHR surface) {
|
|
|
|
|
|
|
|
struct MaybeSwapchainDetails ret = {};
|
|
|
|
|
|
|
|
ret.valid = false;
|
|
|
|
|
|
|
|
ret.details.formats = 0;
|
|
|
|
|
|
|
|
ret.details.present_modes = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkResult result;
|
|
|
|
VkResult result;
|
|
|
|
|
|
|
|
|
|
|
|
result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &ret.details.capabilities);
|
|
|
|
result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &details.capabilities);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &ret.details.formats_count, 0);
|
|
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &details.formats_count, 0);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret.details.formats = malloc(sizeof(VkSurfaceFormatKHR)*ret.details.formats_count);
|
|
|
|
details.formats = malloc(sizeof(VkSurfaceFormatKHR)*details.formats_count);
|
|
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &ret.details.formats_count, ret.details.formats);
|
|
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &details.formats_count, details.formats);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(ret.details.formats);
|
|
|
|
free(details.formats);
|
|
|
|
return ret;
|
|
|
|
details.formats = 0;
|
|
|
|
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &ret.details.present_modes_count, 0);
|
|
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &details.present_modes_count, 0);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(ret.details.formats);
|
|
|
|
free(details.formats);
|
|
|
|
return ret;
|
|
|
|
details.formats = 0;
|
|
|
|
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret.details.present_modes = malloc(sizeof(VkPresentModeKHR)*ret.details.present_modes_count);
|
|
|
|
details.present_modes = malloc(sizeof(VkPresentModeKHR)*details.present_modes_count);
|
|
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &ret.details.present_modes_count, ret.details.present_modes);
|
|
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &details.present_modes_count, details.present_modes);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(ret.details.formats);
|
|
|
|
free(details.formats);
|
|
|
|
free(ret.details.present_modes);
|
|
|
|
free(details.present_modes);
|
|
|
|
return ret;
|
|
|
|
details.formats = 0;
|
|
|
|
|
|
|
|
details.present_modes = 0;
|
|
|
|
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ret.valid = true;
|
|
|
|
return details;
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkSurfaceFormatKHR choose_swapchain_format(SwapchainDetails swapchain_details) {
|
|
|
|
VkSurfaceFormatKHR choose_swapchain_format(SwapchainDetails swapchain_details) {
|
|
|
@ -1441,12 +1443,12 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.present_family, context->queue_indices.present_index, &context->queues.present);
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.present_family, context->queue_indices.present_index, &context->queues.present);
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.transfer_family, context->queue_indices.transfer_index, &context->queues.transfer);
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.transfer_family, context->queue_indices.transfer_index, &context->queues.transfer);
|
|
|
|
|
|
|
|
|
|
|
|
struct MaybeSwapchainDetails maybe_details = get_swapchain_details(context->physical_device, context->surface);
|
|
|
|
SwapchainDetails swapchain_details = get_swapchain_details(context->physical_device, context->surface);
|
|
|
|
if(maybe_details.valid == false) {
|
|
|
|
if(swapchain_details.formats == 0) {
|
|
|
|
fprintf(stderr, "failed to create vulkan logical device\n");
|
|
|
|
fprintf(stderr, "failed to create vulkan logical device\n");
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
context->swapchain_details = maybe_details.details;
|
|
|
|
context->swapchain_details = swapchain_details;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
context->swapchain_format = choose_swapchain_format(context->swapchain_details);
|
|
|
|
context->swapchain_format = choose_swapchain_format(context->swapchain_details);
|
|
|
@ -1654,10 +1656,114 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
|
|
|
|
return context;
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vec3 world_position = {0.0f, 0.0f, 0.0f};
|
|
|
|
|
|
|
|
float rotation = 0.0f;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
|
|
|
bool forward: 1;
|
|
|
|
|
|
|
|
bool backward: 1;
|
|
|
|
|
|
|
|
bool left: 1;
|
|
|
|
|
|
|
|
bool right: 1;
|
|
|
|
|
|
|
|
bool turn_left: 1;
|
|
|
|
|
|
|
|
bool turn_right: 1;
|
|
|
|
|
|
|
|
} key_flags = {
|
|
|
|
|
|
|
|
.forward = false,
|
|
|
|
|
|
|
|
.backward = false,
|
|
|
|
|
|
|
|
.left = false,
|
|
|
|
|
|
|
|
.right = false,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
|
|
|
|
|
|
|
(void)scancode;
|
|
|
|
|
|
|
|
(void)window;
|
|
|
|
|
|
|
|
(void)mods;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch(key) {
|
|
|
|
|
|
|
|
case GLFW_KEY_W:
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
|
|
|
key_flags.forward = true;
|
|
|
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
|
|
|
key_flags.forward = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case GLFW_KEY_A:
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
|
|
|
key_flags.left = true;
|
|
|
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
|
|
|
key_flags.left = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case GLFW_KEY_S:
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
|
|
|
key_flags.backward = true;
|
|
|
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
|
|
|
key_flags.backward = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case GLFW_KEY_D:
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
|
|
|
key_flags.right = true;
|
|
|
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
|
|
|
key_flags.right = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case GLFW_KEY_RIGHT:
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
|
|
|
key_flags.turn_right = true;
|
|
|
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
|
|
|
key_flags.turn_right = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case GLFW_KEY_LEFT:
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
|
|
|
key_flags.turn_left = true;
|
|
|
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
|
|
|
key_flags.turn_left = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult update_ubo(void** buffers, uint32_t frame_index) {
|
|
|
|
VkResult update_ubo(void** buffers, uint32_t frame_index) {
|
|
|
|
|
|
|
|
if(key_flags.forward) {
|
|
|
|
|
|
|
|
world_position[2] += 0.01;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(key_flags.backward) {
|
|
|
|
|
|
|
|
world_position[2] -= 0.01;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(key_flags.left) {
|
|
|
|
|
|
|
|
world_position[0] -= 0.01;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(key_flags.right) {
|
|
|
|
|
|
|
|
world_position[0] += 0.01;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(key_flags.turn_right) {
|
|
|
|
|
|
|
|
rotation += 0.01;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(key_flags.turn_left) {
|
|
|
|
|
|
|
|
rotation -= 0.01;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct SceneUBO ubo = {};
|
|
|
|
struct SceneUBO ubo = {};
|
|
|
|
glm_mat4_identity(ubo.proj);
|
|
|
|
glm_perspective(30.0f, 800.0/600.0, 0.1, 1, ubo.proj);
|
|
|
|
glm_mat4_identity(ubo.view);
|
|
|
|
vec3 forward = {0.0f, 0.0f, 1.0f};
|
|
|
|
|
|
|
|
vec3 up = {0.0f, 1.0f, 0.0f};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vec3 dir;
|
|
|
|
|
|
|
|
mat4 rot;
|
|
|
|
|
|
|
|
glm_rotate_make(rot, rotation, up);
|
|
|
|
|
|
|
|
glm_mat4_mulv3(rot, forward, 1.0f, dir);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glm_look(world_position, dir, up, ubo.view);
|
|
|
|
|
|
|
|
|
|
|
|
memcpy(buffers[frame_index], (void*)&ubo, sizeof(ubo));
|
|
|
|
memcpy(buffers[frame_index], (void*)&ubo, sizeof(ubo));
|
|
|
|
|
|
|
|
|
|
|
@ -1728,6 +1834,7 @@ void main_loop(GLFWwindow* window, VulkanContext* context) {
|
|
|
|
context->current_frame = 0;
|
|
|
|
context->current_frame = 0;
|
|
|
|
while(!glfwWindowShouldClose(window)) {
|
|
|
|
while(!glfwWindowShouldClose(window)) {
|
|
|
|
glfwPollEvents();
|
|
|
|
glfwPollEvents();
|
|
|
|
|
|
|
|
|
|
|
|
draw_frame(context);
|
|
|
|
draw_frame(context);
|
|
|
|
context->current_frame += 1;
|
|
|
|
context->current_frame += 1;
|
|
|
|
if(context->current_frame >= context->max_frames_in_flight) {
|
|
|
|
if(context->current_frame >= context->max_frames_in_flight) {
|
|
|
@ -1782,6 +1889,7 @@ int main() {
|
|
|
|
return 2;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glfwSetKeyCallback(window, key_callback);
|
|
|
|
main_loop(window, context);
|
|
|
|
main_loop(window, context);
|
|
|
|
|
|
|
|
|
|
|
|
cleanup(window, context);
|
|
|
|
cleanup(window, context);
|
|
|
|