added a dumb rotating cylinder (with camera controls)

This commit is contained in:
Андреев Григорий 2025-07-22 02:33:24 +03:00
parent 9a870d7101
commit a666755c03
10 changed files with 709 additions and 365 deletions

View File

@ -4,7 +4,8 @@ project(splitter_draft C)
#include_directories(${CMAKE_SOURCE_DIR})
set(CMAKE_C_FLAGS "-Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type --std=c99 -g -ggdb -O0")
add_compile_definitions(_POSIX_C_SOURCE=200112L )
add_compile_definitions(_POSIX_C_SOURCE=200112L)
add_compile_definitions(_GNU_SOURCE)
add_executable(main src/l1/main.c)

View File

@ -52,7 +52,6 @@ NODISCARD VecU8 generate_xvecy_struct_definition(ConstSpanU8 xvec, ConstSpanU8 m
return res;
}
// todo: replace all these number operations with function forms
NODISCARD VecU8 generate_xvecy_method_add_xvecy(ConstSpanU8 xvec, ConstSpanU8 member, int cc) {
VecU8 res = VecU8_new();
string_append_xvecy(&res, xvec, cc);
@ -559,7 +558,9 @@ NODISCARD VecU8 generate_xmat234x234_structs_and_methods(ConstSpanU8 xmat, Const
void generate_geometry_header() {
VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_GEOM"));
VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("cvec"), cstr("U8")));
VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("ivec"), cstr("S32")));
VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("vec"), cstr("float")));
VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("dvec"), cstr("double")));
VecU8_append_vec(&res, generate_xmat234x234_structs_and_methods(cstr("mat"), cstr("vec"), cstr("float"), sizeof(float)));

View File

@ -2,7 +2,77 @@
#define PROTOTYPE1_SRC_L2_MARGARET_GRAPHICS_GEOM_H
#include "../../../gen/geom.h"
#include "math.h"
mat4 margaret_translation_mat4(vec3 vec) {
return mat4_new(
1, 0, 0, vec.x,
0, 1, 0, vec.y,
0, 0, 1, vec.z,
0, 0, 0, 1
);
}
mat3 margaret_3d_rot_mat3(vec3 r, float a) {
float cosa = cosf(a);
float sina = sinf(a);
return mat3_new(
r.x * r.x * (1 - cosa) + cosa, r.x * r.y * (1 - cosa) - sina * r.z, r.x * r.z * (1 - cosa) + sina * r.y,
r.x * r.y * (1 - cosa) + sina * r.z, r.y * r.y * (1 - cosa) + cosa, r.y * r.z * (1 - cosa) - sina * r.x,
r.x * r.z * (1 - cosa) - sina * r.y, r.y * r.z * (1 - cosa) + sina * r.x, r.z * r.z * (1 - cosa) + cosa
);
}
mat4 margaret_mat3_to_mat4(mat3 A) {
return mat4_new(
A.x.x, A.y.x, A.z.x, 0,
A.x.y, A.y.y, A.z.y, 0,
A.x.z, A.y.z, A.z.z, 0,
0, 0, 0, 1);
}
mat4 margaret_mat3_to_mat4_transposed(mat3 A) {
return mat4_new(
A.x.x, A.x.y, A.x.z, 0,
A.y.x, A.y.y, A.y.z, 0,
A.z.x, A.z.y, A.z.z, 0,
0, 0, 0, 1);
}
mat4 margaret_3d_rot_mat4(vec3 r, double a) {
return margaret_mat3_to_mat4(margaret_3d_rot_mat3(r, a));
}
mat4 margaret_perspective_projection_mat4(float right, float top, float near, float far) {
return mat4_new(
near/right, 0, 0, 0,
0, -near/top, 0, 0,
0, 0, (far + near) / (near - far), 2 * far * near / (near - far),
0, 0, -1, 0 );
}
mat4 margaret_perspective_projection_fov_mat4(float win_width, float win_height, float fov,
float spat_frustum_near, float spat_frustum_far) {
float right = tanf(fov / 2) * spat_frustum_near;
float top = win_height * right / win_width;
return margaret_perspective_projection_mat4(right, top, spat_frustum_near, spat_frustum_far);
}
mat3 margaret_simple_camera_rot_m_basis_in_cols(float yaw, float pitch, float roll) {
float cos_ya = cosf(yaw);
float sin_ya = sinf(yaw);
float cos_pi = cosf(pitch);
float sin_pi = sinf(pitch);
float cos_ro = cosf(roll);
float sin_ro = sinf(roll);
return (mat3){
.x = (vec3){cos_ro * cos_ya + sin_ro * sin_pi * sin_ya, sin_ro * cos_pi, -cos_ro * sin_ya + sin_ro * sin_pi * cos_ya},
.y = (vec3){-sin_ro * cos_ya + cos_ro * sin_pi * sin_ya, cos_ro * cos_pi, sin_ro * sin_ya + cos_ro * sin_pi * cos_ya},
.z = (vec3){cos_pi * sin_ya, -sin_pi, cos_pi * cos_ya}
};
}
#endif

View File

@ -871,7 +871,7 @@ MargaretSingleWindowSetup MargaretSingleWindowSetup_new() {
margaret_win_init_set_properties(dpy, win);
/* 3) Select for ConfigureNotify and Expose events */
XSelectInput(dpy, win, StructureNotifyMask | ExposureMask);
XSelectInput(dpy, win, StructureNotifyMask | ExposureMask | PointerMotionMask | KeyPressMask | KeyReleaseMask);
return (MargaretSingleWindowSetup){ .dpy = dpy, .win = win };
}

View File

@ -3,6 +3,8 @@
#include "../../l1/core/VecSpan_int_primitives.h"
// todo: move this out of margaret (may still keep it in l2)
U8 U8_to_lowercase(U8 ch) {
if ('A' <= ch && ch <= 'Z')
return ch - 'A' + 'a';

View File

@ -3,88 +3,22 @@
#include <math.h>
#include "../../l1/system/fileio.h"
#include <time.h>
#include "r0_assets.h"
// Only for linux
#include <sys/wait.h>
// todo: generate this class in l2
typedef struct {
vec3 pos;
vec2 tex;
} OA_Vertex;
VkPipelineLayout pipeline_layout;
VkPipeline pipeline;
VkDescriptorSetLayout descriptor_set_layout;
} PipelineHands;
typedef struct {
vec3 s;
float _0;
} MyUbo;
typedef struct {
VkBuffer vbo;
VkBuffer ebo;
// If topology is triangle list,then this is trice the amount of triangles
size_t indices;
} OA_ObjectOnScene;
#define OA_ObjectOnScene_drop(vp) {}
#define OA_ObjectOnScene_clone(vp) (*(vp))
VecT_trivmove_struct_Definition(OA_ObjectOnScene)
VecT_trivmove_method_Definition(OA_ObjectOnScene)
VecT_primitive_zeroinit_method_Definition(OA_ObjectOnScene)
typedef struct {
VecOA_ObjectOnScene oa_objects;
VkClearColorValue color;
} Scene;
// todo: generate this function in l2
VkRenderPass create_render_pass_1(VkDevice logical_device, VkFormat image_format) {
// Color attachments array for our render pass
VkAttachmentDescription all_attachments[1] = { (VkAttachmentDescription){
.format = image_format,
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
} };
// For our one single render subpass
VkAttachmentReference color_attachment_refs[1] = { (VkAttachmentReference){
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
} };
VkSubpassDescription subpasses_descr[1] = { (VkSubpassDescription){
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.colorAttachmentCount = ARRAY_SIZE(color_attachment_refs),
.pColorAttachments = color_attachment_refs,
} };
VkSubpassDependency subpass_dependencies[1] = {
// subpass_0_external
(VkSubpassDependency) {
.srcSubpass = VK_SUBPASS_EXTERNAL,
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = 0,
.dstSubpass = 0,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
}};
VkRenderPassCreateInfo render_pass_crinfo = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = ARRAY_SIZE(all_attachments),
.pAttachments = all_attachments,
.subpassCount = ARRAY_SIZE(subpasses_descr),
.pSubpasses = subpasses_descr,
.dependencyCount = ARRAY_SIZE(subpass_dependencies),
.pDependencies = subpass_dependencies,
};
VkRenderPass render_pass;
if (vkCreateRenderPass(logical_device, &render_pass_crinfo, NULL, &render_pass) != VK_SUCCESS)
abortf("vkCreateRenderPass");
return render_pass;
void destroy_graphics_pipeline_hands(VkDevice device, PipelineHands hands) {
vkDestroyPipeline(device, hands.pipeline, NULL);
vkDestroyPipelineLayout(device, hands.pipeline_layout, NULL);
vkDestroyDescriptorSetLayout(device, hands.descriptor_set_layout, NULL);
}
// todo: generate this function in l2
@ -139,19 +73,228 @@ VkRenderPass create_render_pass_0(VkDevice logical_device, VkFormat image_format
return render_pass;
}
// todo: generate this class in l2
typedef struct {
VkPipelineLayout pipeline_layout;
VkPipeline pipeline;
VkDescriptorSetLayout descriptor_set_layout;
} PipelineHands;
margaret_prep_buffer_mem_info_of_gpu_vbo_Definition(Vertex)
void destroy_graphics_pipeline_hands(VkDevice device, PipelineHands hands) {
vkDestroyPipeline(device, hands.pipeline, NULL);
vkDestroyPipelineLayout(device, hands.pipeline_layout, NULL);
vkDestroyDescriptorSetLayout(device, hands.descriptor_set_layout, NULL);
PipelineHands create_graphics_pipeline_0(
VkDevice device, VkRenderPass render_pass, uint32_t subpass
) {
VecU8 vert_bin_code = read_whole_file_or_abort("test_shaders/spv/0/vert.spv");
VecU8 frag_bin_code = read_whole_file_or_abort("test_shaders/spv/0/frag.spv");
VkShaderModule vert_module = margaret_VkShaderModule_new(device, vert_bin_code);
VkShaderModule frag_module = margaret_VkShaderModule_new(device, frag_bin_code);
VecU8_drop(vert_bin_code);
VecU8_drop(frag_bin_code);
VkPipelineShaderStageCreateInfo shader_stages_crinfo[2] = {
margaret_shader_stage_vertex_crinfo(vert_module),
margaret_shader_stage_fragment_crinfo(frag_module)
};
VkVertexInputBindingDescription vertex_bindings[1] = { {
.binding = 0,
.stride = sizeof(Vertex),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
} };
VkVertexInputAttributeDescription vertex_attributes[2] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(Vertex, pos),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex, tex),
},
};
VkPipelineVertexInputStateCreateInfo vertex_input_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = ARRAY_SIZE(vertex_bindings),
.pVertexBindingDescriptions = vertex_bindings,
.vertexAttributeDescriptionCount = ARRAY_SIZE(vertex_attributes),
.pVertexAttributeDescriptions = vertex_attributes,
};
VkPipelineInputAssemblyStateCreateInfo input_assembly_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE,
};
VkPipelineViewportStateCreateInfo viewport_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
// We are using dynamic viewport and scissors, that is why we do not attach viewport/scissor values
// when creating a rendering pipeline. We will do that later
.viewportCount = 1,
.scissorCount = 1,
};
VkPipelineRasterizationStateCreateInfo rasterizer_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
// .cullMode = VK_CULL_MODE_BACK_BIT,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
.depthBiasEnable = VK_FALSE,
.depthBiasConstantFactor = 0.0f,
.depthBiasClamp = 0.0f,
.depthBiasSlopeFactor = 0.0f,
.lineWidth = 1.0f,
};
VkPipelineMultisampleStateCreateInfo multisampling_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.sampleShadingEnable = VK_FALSE,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.minSampleShading = 1.0f,
.pSampleMask = NULL,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
// For one framebuffer
VkPipelineColorBlendAttachmentState color_blend_attachments[1] = {(VkPipelineColorBlendAttachmentState){
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.blendEnable = VK_FALSE,
}};
// For the entire pipeline
VkPipelineColorBlendStateCreateInfo color_blending_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = ARRAY_SIZE(color_blend_attachments),
.pAttachments = color_blend_attachments,
// Blend constants specified heres
};
VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
VkPipelineDynamicStateCreateInfo dynamic_state_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = ARRAY_SIZE(dynamic_states),
.pDynamicStates = dynamic_states,
};
VkDescriptorSetLayoutBinding bindings_for_my_descr_set_layout[] = {
{
// Binding in shader
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
// our shader variable is not an array of descriptors, so this stays 1
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
},
};
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_crinfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = ARRAY_SIZE(bindings_for_my_descr_set_layout),
.pBindings = bindings_for_my_descr_set_layout,
};
VkDescriptorSetLayout my_descriptor_set_layout;
if (vkCreateDescriptorSetLayout(device, &descriptor_set_layout_crinfo, NULL, &my_descriptor_set_layout) != VK_SUCCESS)
abortf("vkCreateDescriptorSetLayout");
VkPipelineLayoutCreateInfo layout_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &my_descriptor_set_layout,
.pushConstantRangeCount = 0,
.pPushConstantRanges = NULL,
};
VkPipelineLayout pipeline_layout;
if (vkCreatePipelineLayout(device, &layout_crinfo, NULL, &pipeline_layout) != VK_SUCCESS)
abortf("vkCreatePipelineLayout");
VkGraphicsPipelineCreateInfo pipeline_crinfo = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = ARRAY_SIZE(shader_stages_crinfo),
.pStages = shader_stages_crinfo,
.pVertexInputState = &vertex_input_crinfo,
.pInputAssemblyState = &input_assembly_crinfo,
.pViewportState = &viewport_state,
.pRasterizationState = &rasterizer_crinfo,
.pMultisampleState = &multisampling_crinfo,
.pDepthStencilState = NULL,
.pColorBlendState = &color_blending_crinfo,
.pDynamicState = &dynamic_state_crinfo,
.layout = pipeline_layout,
.renderPass = render_pass,
.subpass = subpass,
.basePipelineHandle = VK_NULL_HANDLE,
};
VkPipeline pipeline;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_crinfo, NULL, &pipeline) != VK_SUCCESS)
abortf("vkCreateGraphicsPipelines");
vkDestroyShaderModule(device, frag_module, NULL);
vkDestroyShaderModule(device, vert_module, NULL);
return (PipelineHands){.pipeline_layout = pipeline_layout, .pipeline = pipeline, .descriptor_set_layout = my_descriptor_set_layout};
}
// todo: generate this function in l2
VkRenderPass create_render_pass_1(VkDevice logical_device, VkFormat image_format) {
// Color attachments array for our render pass
VkAttachmentDescription all_attachments[1] = { (VkAttachmentDescription){
.format = image_format,
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
} };
// For our one single render subpass
VkAttachmentReference color_attachment_refs[1] = { (VkAttachmentReference){
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
} };
VkSubpassDescription subpasses_descr[1] = { (VkSubpassDescription){
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.colorAttachmentCount = ARRAY_SIZE(color_attachment_refs),
.pColorAttachments = color_attachment_refs,
} };
VkSubpassDependency subpass_dependencies[1] = {
// subpass_0_external
(VkSubpassDependency) {
.srcSubpass = VK_SUBPASS_EXTERNAL,
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = 0,
.dstSubpass = 0,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
}};
VkRenderPassCreateInfo render_pass_crinfo = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = ARRAY_SIZE(all_attachments),
.pAttachments = all_attachments,
.subpassCount = ARRAY_SIZE(subpasses_descr),
.pSubpasses = subpasses_descr,
.dependencyCount = ARRAY_SIZE(subpass_dependencies),
.pDependencies = subpass_dependencies,
};
VkRenderPass render_pass;
if (vkCreateRenderPass(logical_device, &render_pass_crinfo, NULL, &render_pass) != VK_SUCCESS)
abortf("vkCreateRenderPass");
return render_pass;
}
// todo: generate this function in l2
PipelineHands create_graphics_pipeline_1(
VkDevice device, VkRenderPass render_pass, uint32_t subpass
@ -226,7 +369,7 @@ PipelineHands create_graphics_pipeline_1(
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = ARRAY_SIZE(color_blend_attachments),
.pAttachments = color_blend_attachments,
// Blend constants specified heres
// Blend constants specified here
};
VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
@ -253,22 +396,24 @@ PipelineHands create_graphics_pipeline_1(
if (vkCreateDescriptorSetLayout(device, &descriptor_set_layout_crinfo, NULL, &my_descriptor_set_layout) != VK_SUCCESS)
abortf("vkCreateDescriptorSetLayout");
VkPushConstantRange used_region_sz_push_const = {
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.offset = 0, .size = sizeof(vec2)
VkPushConstantRange used_region_sz_push_const[2] = {
{ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.offset = 0, .size = sizeof(Pipeline1PushRangeVertex) },
{ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.offset = sizeof(Pipeline1PushRangeVertex), .size = sizeof(Pipeline1PushRangeFragment) },
};
VkPipelineLayoutCreateInfo layout_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &my_descriptor_set_layout,
.pushConstantRangeCount = 1,
.pPushConstantRanges = &used_region_sz_push_const,
.pushConstantRangeCount = ARRAY_SIZE(used_region_sz_push_const),
.pPushConstantRanges = used_region_sz_push_const,
};
VkPipelineLayout pipeline_layout;
if (vkCreatePipelineLayout(device, &layout_crinfo, NULL, &pipeline_layout) != VK_SUCCESS)
abortf("vkCreatePipelineLayout");
// todo: kill myself (update: still todo (update: still not done )) update: work in progress
// todo: kill myself (update: still todo (update: still not done )) update: work in progress (update: medium priority)
VkGraphicsPipelineCreateInfo pipeline_crinfo = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = ARRAY_SIZE(shader_stages_crinfo),
@ -296,173 +441,6 @@ PipelineHands create_graphics_pipeline_1(
return (PipelineHands){.pipeline_layout = pipeline_layout, .pipeline = pipeline, .descriptor_set_layout = my_descriptor_set_layout};
}
PipelineHands create_graphics_pipeline_0(
VkDevice device, VkRenderPass render_pass, uint32_t subpass
) {
VecU8 vert_bin_code = read_whole_file_or_abort("test_shaders/spv/0/vert.spv");
VecU8 frag_bin_code = read_whole_file_or_abort("test_shaders/spv/0/frag.spv");
VkShaderModule vert_module = margaret_VkShaderModule_new(device, vert_bin_code);
VkShaderModule frag_module = margaret_VkShaderModule_new(device, frag_bin_code);
VecU8_drop(vert_bin_code);
VecU8_drop(frag_bin_code);
VkPipelineShaderStageCreateInfo shader_stages_crinfo[2] = {
margaret_shader_stage_vertex_crinfo(vert_module),
margaret_shader_stage_fragment_crinfo(frag_module)
};
VkVertexInputBindingDescription vertex_bindings[1] = { {
.binding = 0,
.stride = sizeof(OA_Vertex),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
} };
VkVertexInputAttributeDescription vertex_attributes[2] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(OA_Vertex, pos),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(OA_Vertex, tex),
},
};
VkPipelineVertexInputStateCreateInfo vertex_input_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = ARRAY_SIZE(vertex_bindings),
.pVertexBindingDescriptions = vertex_bindings,
.vertexAttributeDescriptionCount = ARRAY_SIZE(vertex_attributes),
.pVertexAttributeDescriptions = vertex_attributes,
};
VkPipelineInputAssemblyStateCreateInfo input_assembly_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE,
};
VkPipelineViewportStateCreateInfo viewport_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
// We are using dynamic viewport and scissors, that is why we do not attach viewport/scissor values
// when creating a rendering pipeline. We will do that later
.viewportCount = 1,
.scissorCount = 1,
};
VkPipelineRasterizationStateCreateInfo rasterizer_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
.depthBiasEnable = VK_FALSE,
.depthBiasConstantFactor = 0.0f,
.depthBiasClamp = 0.0f,
.depthBiasSlopeFactor = 0.0f,
.lineWidth = 1.0f,
};
VkPipelineMultisampleStateCreateInfo multisampling_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.sampleShadingEnable = VK_FALSE,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.minSampleShading = 1.0f,
.pSampleMask = NULL,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
// For one framebuffer
VkPipelineColorBlendAttachmentState color_blend_attachments[1] = {(VkPipelineColorBlendAttachmentState){
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.blendEnable = VK_FALSE,
}};
// For the entire pipeline
VkPipelineColorBlendStateCreateInfo color_blending_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = ARRAY_SIZE(color_blend_attachments),
.pAttachments = color_blend_attachments,
// Blend constants specified heres
};
VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
VkPipelineDynamicStateCreateInfo dynamic_state_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = ARRAY_SIZE(dynamic_states),
.pDynamicStates = dynamic_states,
};
VkDescriptorSetLayoutBinding bindings_for_my_descr_set_layout[] = {
{
// Binding in shader
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
// our shader variable is not an array of descriptors, so this stays 1
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
},
};
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_crinfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = ARRAY_SIZE(bindings_for_my_descr_set_layout),
.pBindings = bindings_for_my_descr_set_layout,
};
VkDescriptorSetLayout my_descriptor_set_layout;
if (vkCreateDescriptorSetLayout(device, &descriptor_set_layout_crinfo, NULL, &my_descriptor_set_layout) != VK_SUCCESS)
abortf("vkCreateDescriptorSetLayout");
VkPipelineLayoutCreateInfo layout_crinfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &my_descriptor_set_layout,
.pushConstantRangeCount = 0,
.pPushConstantRanges = NULL,
};
VkPipelineLayout pipeline_layout;
if (vkCreatePipelineLayout(device, &layout_crinfo, NULL, &pipeline_layout) != VK_SUCCESS)
abortf("vkCreatePipelineLayout");
VkGraphicsPipelineCreateInfo pipeline_crinfo = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = ARRAY_SIZE(shader_stages_crinfo),
.pStages = shader_stages_crinfo,
.pVertexInputState = &vertex_input_crinfo,
.pInputAssemblyState = &input_assembly_crinfo,
.pViewportState = &viewport_state,
.pRasterizationState = &rasterizer_crinfo,
.pMultisampleState = &multisampling_crinfo,
.pDepthStencilState = NULL,
.pColorBlendState = &color_blending_crinfo,
.pDynamicState = &dynamic_state_crinfo,
.layout = pipeline_layout,
.renderPass = render_pass,
.subpass = subpass,
.basePipelineHandle = VK_NULL_HANDLE,
};
// todo: actually use this function
VkPipeline pipeline;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_crinfo, NULL, &pipeline) != VK_SUCCESS)
abortf("vkCreateGraphicsPipelines");
vkDestroyShaderModule(device, frag_module, NULL);
vkDestroyShaderModule(device, vert_module, NULL);
return (PipelineHands){.pipeline_layout = pipeline_layout, .pipeline = pipeline, .descriptor_set_layout = my_descriptor_set_layout};
}
VkFramebuffer create_IT1_framebuffer(VkDevice device, VkImageView IT1_view, VkRenderPass render_pass_0, VkExtent2D MAX_WIN_SIZE) {
VkImageView attachments[1] = {IT1_view};
@ -523,17 +501,17 @@ void reset_and_record_command_buffer_0(
.extent = image_extent,
};
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
for (size_t i = 0; i < scene->oa_objects.len; i++) {
const OA_ObjectOnScene* obj = VecOA_ObjectOnScene_cat(&scene->oa_objects, i);
VkBuffer attached_buffers[1] = { obj->vbo };
for (size_t i = 0; i < scene->models.len; i++) {
const ModelOnScene* models = VecModelOnScene_cat(&scene->models, i);
VkBuffer attached_buffers[1] = { models->vbo };
// We use our whole buffer, no need for offset
VkDeviceSize offsets_in_buffers[1] = {0};
vkCmdBindVertexBuffers(command_buffer, 0, 1, attached_buffers, offsets_in_buffers);
vkCmdBindIndexBuffer(command_buffer, obj->ebo, 0, VK_INDEX_TYPE_UINT32);
vkCmdBindIndexBuffer(command_buffer, models->ebo, 0, VK_INDEX_TYPE_UINT32);
vkCmdBindDescriptorSets(
command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_and_layout->pipeline_layout, 0,
1, &my_descriptor_set, 0, NULL);
vkCmdDrawIndexed(command_buffer, obj->indices, 1, 0, 0, 0);
vkCmdDrawIndexed(command_buffer, models->indexes, 1, 0, 0, 0);
}
vkCmdEndRenderPass(command_buffer);
@ -545,7 +523,7 @@ void reset_and_record_command_buffer_1(
VkCommandBuffer command_buffer, VkRenderPass render_pass_1,
const PipelineHands* pipeline_and_layout_1,
VkFramebuffer swapchain_image_framebuffer, VkExtent2D image_extent,
VkExtent2D max_win_size,
VkExtent2D max_win_size, const Scene* scene,
VkDescriptorSet descriptor_set_for_pipeline_1
) {
if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS)
@ -554,15 +532,12 @@ void reset_and_record_command_buffer_1(
if (vkBeginCommandBuffer(command_buffer, &info_begin) != VK_SUCCESS)
abortf("vkBeginCommandBuffer");
// VkClearValue clear_color[1] = {{.color = scene->color}};
VkRenderPassBeginInfo renderpass_begin = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = render_pass_1,
.framebuffer = swapchain_image_framebuffer,
.renderArea.offset = (VkOffset2D){0, 0},
.renderArea.extent = image_extent,
.clearValueCount = 0,
.pClearValues = NULL,
};
vkCmdBeginRenderPass(command_buffer, &renderpass_begin, VK_SUBPASS_CONTENTS_INLINE);
@ -586,10 +561,20 @@ void reset_and_record_command_buffer_1(
command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_and_layout_1->pipeline_layout, 0,
1, &descriptor_set_for_pipeline_1, 0, NULL);
vec2 region_tex_scale = {(float)image_extent.width / (float)max_win_size.width,
(float)image_extent.height / (float)max_win_size.height};
vkCmdPushConstants(command_buffer, pipeline_and_layout_1->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vec2), &region_tex_scale);
Pipeline1PushRangeVertex reg_and_params_vertex = {.win_scale = {
(float)image_extent.width / (float)max_win_size.width,
(float)image_extent.height / (float)max_win_size.height},
};
Pipeline1PushRangeFragment reg_and_params_fragment = {
.gamma_correction_factor = scene->gamma_correction_factor,
.hdr_factor = scene->hdr_factor,
.lsd_factor = scene->lsd_factor,
.anim_time = scene->anim_time
};
vkCmdPushConstants(command_buffer, pipeline_and_layout_1->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
0, sizeof(Pipeline1PushRangeVertex), &reg_and_params_vertex);
vkCmdPushConstants(command_buffer, pipeline_and_layout_1->pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT,
sizeof(Pipeline1PushRangeVertex), sizeof(Pipeline1PushRangeFragment), &reg_and_params_fragment);
vkCmdDraw(command_buffer, 3, 1, 0, 0);
vkCmdEndRenderPass(command_buffer);
@ -598,6 +583,7 @@ void reset_and_record_command_buffer_1(
}
// todo: add here deletion and recreation of several synchronization primitives
void recreate_swapchain(
VkPhysicalDevice physical_device, VkDevice device, MargaretChosenQueueFamilies queue_fam, VkSurfaceKHR surface,
VkRenderPass render_pass, MargaretSwapchainBundle* swfb) {
@ -616,7 +602,6 @@ void recreate_swapchain(
*swfb = new_swfb;
}
margaret_prep_buffer_mem_info_of_gpu_vbo_Definition(OA_Vertex)
void prepare_shaders() {
int ret = system("./test_shader_compile.sh");
@ -687,65 +672,31 @@ int main() {
MargaretSwapchainBundle swfb = MargaretSwapchainBundle_new(device, queue_fam, swapchain_details, surface, render_pass_1, NULL);
// Filling scene info
const OA_Vertex obj1_vertexes[] = {
(OA_Vertex){ .pos = {-1, -0.5f, 0}, .tex = {0, 1} },
(OA_Vertex){ .pos = {0.3f, -0.5f, 0}, .tex = {1, 1} },
(OA_Vertex){ .pos = {-3.f, 3.f, 0}, .tex = {1, 0} },
(OA_Vertex){ .pos = {-0.5f, .4f, 0}, .tex = {0, 0} },
};
const uint32_t obj1_indices[] = { 0, 2, 1, 0, 3, 2 };
const OA_Vertex obj2_vertexes[] = {
(OA_Vertex){ .pos = {0.9f, 0.9f}, .tex = {1.f, 0} },
(OA_Vertex){ .pos = {0.4f, -0.9f, 0}, .tex = {0, 1.f} },
(OA_Vertex){ .pos = {-0.2f, 1.f}, .tex = {0, 0} },
};
const uint32_t obj2_indices[] = {0, 1, 2};
const U32 wood_texture_width = 100;
const U32 wood_texture_height = 100;
color8rgba wood_texture_data[wood_texture_height][wood_texture_width];
for (U32 y = 0; y < wood_texture_height; y++) {
for (U32 col = 0; col < wood_texture_width; col++) {
wood_texture_data[y][col] = (color8rgba){150, 30, 50, 255};
}
}
for (U32 i = 0; i < 10; i++) {
for (U32 y = 0; y < wood_texture_height; y++) {
U32 col = 3 + i * 10 + ((30 < y + 3 * i && y - i < 60) ? 1 : 0);
wood_texture_data[y][col] = (color8rgba){130, 25, 40, 255};
wood_texture_data[y][col + 1] = (color8rgba){80, 10, 15, 255};
wood_texture_data[y][col + 2] = (color8rgba){70, 11, 12, 255};
wood_texture_data[y][col + 3] = (color8rgba){125, 20, 20, 255};
}
}
for (U32 y = 0; y < 10; y++) {
for (U32 col = 0; col < 10; col++) {
wood_texture_data[13 + y][4 + col] = (color8rgba){140, 50, 20, 255};
}
}
ModelTopology cylinder_1 = generate_one_fourth_of_a_cylinder(10, 2, 6);
ModelTopology cylinder_2 = generate_one_fourth_of_a_cylinder(5, 5, 10);
TextureDataR8G8B8A8 wood_texture_data = generate_wood_texture();
// We have only one staging buffer in host memory (because we don't really need more)
MargaretBufferInMemoryInfo host_mem_buffer = (MargaretBufferInMemoryInfo){ .sz =
MAX_U64(sizeof(obj1_vertexes),
MAX_U64(sizeof(obj1_indices),
MAX_U64(sizeof(obj2_vertexes),
MAX_U64(sizeof(obj2_indices),
MAX_U64(sizeof(MyUbo),
MAX_U64(sizeof(wood_texture_data), 0))))))
MAX_U64(ModelTopology_get_space_needed_for_staging_buffer(&cylinder_1),
MAX_U64(ModelTopology_get_space_needed_for_staging_buffer(&cylinder_2),
MAX_U64(sizeof(Pipeline0UBO),
MAX_U64(TextureDataR8G8B8A8_get_space_needed_for_staging_buffer(&wood_texture_data), 0))))
, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT };
VkDeviceMemory host_mem = margaret_initialize_buffers_and_images(physical_device, device,
(SpanMargaretBufferInMemoryInfo){.data = &host_mem_buffer, .len = 1}, (SpanMargaretImageInMemoryInfo){ 0 },
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
MargaretBufferInMemoryInfo device_mem_buffers[] = {
OA_Vertex_buffer_crinfo_of_gpu_vbo(ARRAY_SIZE(obj1_vertexes)),
margaret_prep_buffer_mem_info_of_gpu_ebo(ARRAY_SIZE(obj1_indices)),
OA_Vertex_buffer_crinfo_of_gpu_vbo(ARRAY_SIZE(obj2_vertexes)),
margaret_prep_buffer_mem_info_of_gpu_ebo(ARRAY_SIZE(obj2_indices)),
margaret_prep_buffer_mem_info_of_gpu_ubo(sizeof(MyUbo)),
Vertex_buffer_crinfo_of_gpu_vbo(cylinder_1.vertices.len),
margaret_prep_buffer_mem_info_of_gpu_ebo(cylinder_1.indexes.len),
Vertex_buffer_crinfo_of_gpu_vbo(cylinder_2.vertices.len),
margaret_prep_buffer_mem_info_of_gpu_ebo(cylinder_2.indexes.len),
margaret_prep_buffer_mem_info_of_gpu_ubo(sizeof(Pipeline0UBO)),
};
MargaretImageInMemoryInfo device_mem_images[] = {
margaret_prep_image_mem_info_of_gpu_texture_rgba(wood_texture_width, wood_texture_height),
margaret_prep_image_mem_info_of_gpu_texture_rgba(wood_texture_data.width,
TextureDataR8G8B8A8_get_height(&wood_texture_data)),
margaret_prep_image_mem_info_of_colorbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, swapchain_details.surface_format.format),
};
VkDeviceMemory device_mem = margaret_initialize_buffers_and_images(physical_device, device,
@ -758,7 +709,7 @@ int main() {
MargaretBufferInMemoryInfo device_ebo_2_buffer = device_mem_buffers[3];
MargaretBufferInMemoryInfo device_ubo_my_buffer = device_mem_buffers[4];
MargaretImageInMemoryInfo device_wood_texture = device_mem_images[0];
MargaretImageInMemoryInfo device_IT1_image = device_mem_images[1]; // todo: use it in my shenanigans
MargaretImageInMemoryInfo device_IT1_image = device_mem_images[1];
VkCommandPool command_pool = margaret_create_resettable_command_pool(device, queue_fam.for_graphics);
VkCommandBuffer rendering_command_buffer_0 = margaret_allocate_command_buffer(device, command_pool);
@ -766,25 +717,38 @@ int main() {
VkCommandBuffer uniform_transfer_command_buffer = margaret_allocate_command_buffer(device, command_pool);
margaret_record_buf_copying_command_buf(device, uniform_transfer_command_buffer,
device_ubo_my_buffer.buffer, host_mem_buffer.buffer, sizeof(MyUbo));
device_ubo_my_buffer.buffer, host_mem_buffer.buffer, sizeof(Pipeline0UBO));
void* host_mem_buffer_mem;
if (vkMapMemory(device, host_mem, 0, VK_WHOLE_SIZE, 0, &host_mem_buffer_mem) != VK_SUCCESS)
abortf("vkMapMemory");
// Now this is what we will do for each buffer: we first memcpy it into mapped region, then we submit a copying command
memcpy(host_mem_buffer_mem, obj1_vertexes, sizeof(obj1_vertexes));
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
device_vbo_1_buffer.buffer, host_mem_buffer.buffer, sizeof(obj1_vertexes));
memcpy(host_mem_buffer_mem, obj1_indices, sizeof(obj1_indices));
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
device_ebo_1_buffer.buffer, host_mem_buffer.buffer, sizeof(obj1_indices));
memcpy(host_mem_buffer_mem, obj2_vertexes, sizeof(obj2_vertexes));
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
device_vbo_2_buffer.buffer, host_mem_buffer.buffer, sizeof(obj2_vertexes));
memcpy(host_mem_buffer_mem, obj2_indices, sizeof(obj2_indices));
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
device_ebo_2_buffer.buffer, host_mem_buffer.buffer, sizeof(obj2_indices));
memcpy(host_mem_buffer_mem, wood_texture_data, sizeof(wood_texture_data));
{
size_t size = cylinder_1.vertices.len * sizeof(Vertex);
memcpy(host_mem_buffer_mem, cylinder_1.vertices.buf, size);
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
device_vbo_1_buffer.buffer, host_mem_buffer.buffer, size);
}
{
size_t size = cylinder_1.indexes.len * sizeof(U32);
memcpy(host_mem_buffer_mem, cylinder_1.indexes.buf, size);
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
device_ebo_1_buffer.buffer, host_mem_buffer.buffer, size);
}
{
size_t size = cylinder_2.vertices.len * sizeof(Vertex);
memcpy(host_mem_buffer_mem, cylinder_2.vertices.buf, size);
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
device_vbo_2_buffer.buffer, host_mem_buffer.buffer, size);
}
{
size_t size = cylinder_2.indexes.len * sizeof(U32);
memcpy(host_mem_buffer_mem, cylinder_2.indexes.buf, size);
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
device_ebo_2_buffer.buffer, host_mem_buffer.buffer, size);
}
memcpy(host_mem_buffer_mem, wood_texture_data.pixels.buf,
TextureDataR8G8B8A8_get_space_needed_for_staging_buffer(&wood_texture_data));
margaret_copy_buffer_to_texture_for_frag_shader_imm(device, command_pool, graphics_queue,
&device_wood_texture, host_mem_buffer.buffer);
// We sent everything we needed. but host_mem_buffer_mem may be used later
@ -794,17 +758,15 @@ int main() {
/* Here we create an image view into a temporary IT1 texture and a framebuffer for scene rendering */
VkImageView IT1_view = margaret_create_view_for_image(device, &device_IT1_image, VK_IMAGE_ASPECT_COLOR_BIT);
// todo: I will get back here soon
VkFramebuffer IT1_framebuffer = create_IT1_framebuffer(device, IT1_view, render_pass_0,
(VkExtent2D){.width = MAX_WIN_WIDTH, .height = MAX_WIN_HEIGHT});
Scene scene;
scene.oa_objects = VecOA_ObjectOnScene_new_zeroinit(2);
*VecOA_ObjectOnScene_at(&scene.oa_objects, 0) = (OA_ObjectOnScene){
.vbo = device_vbo_1_buffer.buffer, .ebo = device_ebo_1_buffer.buffer, .indices = ARRAY_SIZE(obj1_indices) };
*VecOA_ObjectOnScene_at(&scene.oa_objects, 1) = (OA_ObjectOnScene){
.vbo = device_vbo_2_buffer.buffer, .ebo = device_ebo_2_buffer.buffer, .indices = ARRAY_SIZE(obj2_indices) };
// device_vbo/ebo_1/2_buffer won't be used only intrinsically by vulkan, not by us
scene.models = VecModelOnScene_new_zeroinit(2);
*VecModelOnScene_at(&scene.models, 0) = (ModelOnScene){
.vbo = device_vbo_1_buffer.buffer, .ebo = device_ebo_1_buffer.buffer, .indexes = cylinder_1.indexes.len };
// *VecModelOnScene_at(&scene.models, 1) = (ModelOnScene){
// .vbo = device_vbo_2_buffer.buffer, .ebo = device_ebo_2_buffer.buffer, .indexes = cylinder_2.indexes.len };
// Sampler is global for a lot of my future textures
VkSampler my_texture_sampler = margaret_create_sampler(physical_device, device);
@ -817,7 +779,7 @@ int main() {
VkDescriptorBufferInfo buffer_info_for_descriptor_0_in_set_0 = {
.buffer = device_ubo_my_buffer.buffer,
.offset = 0,
.range = sizeof(MyUbo),
.range = sizeof(Pipeline0UBO),
};
VkDescriptorImageInfo image_info_for_descriptor_1_in_set_0 = {
.sampler = my_texture_sampler,
@ -849,7 +811,6 @@ int main() {
.pImageInfo = &image_info_for_descriptor_1_in_set_0,
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_set_for_pipeline_1,
@ -862,18 +823,56 @@ int main() {
};
vkUpdateDescriptorSets(device, ARRAY_SIZE(writes_in_descriptor_sets), writes_in_descriptor_sets, 0, NULL);
CamControlInfo my_cam_control_info = CamControlInfo_new();
// Mainloop
margaret_ns_time start = margaret_clock_gettime_monotonic_raw();
margaret_ns_time prev_key_frame_time = start;
int frame_count_since_key = 0;
margaret_ns_time prev_frame_timestamp = start;
bool pressed_first_0x80[0x80] = {0};
while (true) {
margaret_ns_time frame_A0 = margaret_clock_gettime_monotonic_raw();
float fl = margaret_ns_time_sec_diff(prev_frame_timestamp, frame_A0);
prev_frame_timestamp = frame_A0;
VecXlib_Event events = margaret_read_x_events(x.dpy);
for (size_t i = 0; i < events.len; i++)
Margaret_WEP_update_with_new_event(&wep, VecXlib_Event_cat(&events, i));
if (wep.should_stop)
break;
for (size_t i = 0; i < events.len; i++) {
Xlib_Event* ev = VecXlib_Event_at(&events, i);
// printf("%lu %lu\n", ev->xany.window, wep.win);
if (ev->xany.window != wep.win)
continue;
Margaret_WEP_update_with_new_event(&wep, ev);
if (ev->xany.type == MotionNotify) {
CamControlInfo_update_direction(&my_cam_control_info, wep.width, wep.height, ev->xmotion.x, ev->xmotion.y);
}
if (ev->xany.type == KeyPress) {
KeySym keysym = XLookupKeysym(&ev->xkey, 0);
if (keysym < 0x80)
pressed_first_0x80[keysym] = true;
}
if (ev->xany.type == KeyRelease) {
KeySym keysym = XLookupKeysym(&ev->xkey, 0);
if (keysym < 0x80)
pressed_first_0x80[keysym] = false;
}
}
if (pressed_first_0x80[XK_w])
CamControlInfo_forward(&my_cam_control_info, fl);
if (pressed_first_0x80[XK_s])
CamControlInfo_backward(&my_cam_control_info, fl);
if (pressed_first_0x80[XK_a])
CamControlInfo_left(&my_cam_control_info, fl);
if (pressed_first_0x80[XK_d])
CamControlInfo_right(&my_cam_control_info, fl);
if (pressed_first_0x80[XK_q])
CamControlInfo_down(&my_cam_control_info, fl);
if (pressed_first_0x80[XK_e])
CamControlInfo_up(&my_cam_control_info, fl);
// Rendering
vkWaitForFences(device, 1, &swfb.in_flight_fence, VK_TRUE, UINT64_MAX);
uint32_t ij;
@ -895,12 +894,17 @@ int main() {
vkResetFences(device, 1, &swfb.in_flight_fence);
float ae = sinf(margaret_ns_time_sec_diff(start, frame_A0));
scene.color = (VkClearColorValue){{0.5f, fabsf(ae), .3f, 1.0f}};
vec3 SS = {ae * ae, 0.5f + 0.5f * ae, 0};
float ae = margaret_ns_time_sec_diff(start, frame_A0);
scene.anim_time = ae;
scene.color = (VkClearColorValue){{0.5f, fabsf(sinf(ae)), .3f, 1.0f}};
mat4 projection_matrix = margaret_perspective_projection_fov_mat4((float)wep.width, (float)wep.height,
my_cam_control_info.fov, 0.01f, 1000);
mat4 camera_rotation_matrix = margaret_mat3_to_mat4_transposed(my_cam_control_info.cam_basis);
mat4 camera_translation_matrix = margaret_translation_mat4(vec3_minus(my_cam_control_info.pos));
mat4 t_mat = mat4_mul_mat4(projection_matrix, mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix));
// mat4 t_mat = mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix);
{
*(MyUbo *)host_mem_buffer_mem = (MyUbo){ .s = SS };
*(Pipeline0UBO*)host_mem_buffer_mem = (Pipeline0UBO){.t = t_mat};
VkCommandBuffer command_buffers[1] = { uniform_transfer_command_buffer };
VkSemaphore signaling_semaphores[1] = { swfb.in_frame_transfer_complete };
VkSubmitInfo ubo_copying_cmd_buffer_submit = {
@ -918,7 +922,7 @@ int main() {
reset_and_record_command_buffer_1(rendering_command_buffer_1, render_pass_1, &pipeline_hands_1,
*VecVkFramebuffer_cat(&swfb.framebuffers, ij),
swfb.extent, (VkExtent2D){.width = MAX_WIN_WIDTH, .height = MAX_WIN_HEIGHT}, descriptor_set_for_pipeline_1);
swfb.extent, (VkExtent2D){.width = MAX_WIN_WIDTH, .height = MAX_WIN_HEIGHT}, &scene, descriptor_set_for_pipeline_1);
{
VkSemaphore waiting_for_semaphores[2] = {
@ -1025,7 +1029,9 @@ int main() {
vkDeviceWaitIdle(device);
// The End
// dropping scene
VecOA_ObjectOnScene_drop(scene.oa_objects);
Scene_drop(scene);
ModelTopology_drop(cylinder_1);
ModelTopology_drop(cylinder_2);
// destroying vulkan objects
vkDestroyDescriptorPool(device, descriptor_pool, NULL);
vkDestroySampler(device, my_texture_sampler, NULL);

256
src/l2/tests/r0_assets.h Normal file
View File

@ -0,0 +1,256 @@
#ifndef SPLITTER_DRAFT_SRC_L2_TESTS_R0_ASSETS_H
#define SPLITTER_DRAFT_SRC_L2_TESTS_R0_ASSETS_H
#include "../margaret/graphics_geom.h"
#include "../../l1/core/util.h"
#include <math.h>
typedef struct {
vec3 pos;
vec2 tex;
} Vertex;
/* No offset yet */
typedef struct {
VkBuffer vbo;
VkBuffer ebo;
size_t indexes;
} ModelOnScene;
#define ModelOnScene_drop(vp) {}
#define ModelOnScene_clone(vp) (*(vp))
VecT_trivmove_struct_Definition(ModelOnScene)
VecT_trivmove_method_Definition(ModelOnScene)
VecT_primitive_zeroinit_method_Definition(ModelOnScene)
#define Vertex_drop(vp) {}
#define Vertex_clone(vp) (*(vp))
VecT_trivmove_struct_Definition(Vertex)
VecT_trivmove_method_Definition(Vertex)
VecT_primitive_zeroinit_method_Definition(Vertex)
SpanT_struct_Definition(Vertex)
SpanT_method_Definition(Vertex)
SpanT_VecT_method_Definition(Vertex)
typedef struct {
VecVertex vertices;
VecU32 indexes;
} ModelTopology;
void ModelTopology_drop(ModelTopology self) {
VecVertex_drop(self.vertices);
VecU32_drop(self.indexes);
}
ModelTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) {
assert(k >= 1);
const float a = M_PI_2f / (float)k;
const float l = 2 * r * sin(M_PI_4f / (float)k);
const vec2 v0tex = {r / (2 * r + w), 1 / (2 + k * l)};
const vec2 v1tex = {(r + w) / (2 * r + w), 1 / (2 + k * l)};
const vec2 v2tex = {r / (2 * r + w), 2 / (2 + k * l)};
const vec2 v3tex = {(r + w) / (2 * r + w), 2 / (2 + k * l)};
VecVertex vertices = VecVertex_new(); // todo: reserve 4 * k + 6
VecVertex_append(&vertices, (Vertex){.pos = {0, 0, 0}, .tex = v0tex});
VecVertex_append(&vertices, (Vertex){.pos = {w, 0, 0}, .tex = v1tex});
VecVertex_append(&vertices, (Vertex){.pos = {0, r, 0}, .tex = v2tex});
VecVertex_append(&vertices, (Vertex){.pos = {w, r, 0}, .tex = v3tex});
VecVertex_append(&vertices, (Vertex){.pos = {0, 0, r}, .tex = {r / (2 * r + w), 0}});
VecVertex_append(&vertices, (Vertex){.pos = {w, 0, r}, .tex = {(r + w) / (2 * r + w), 0}});
for (U32 i = 1; i <= k; i++) {
VecVertex_append(&vertices, (Vertex){
.pos = {0, cosf(a * i) * r, sinf(a * i) * r},
.tex = vec2_add_vec2(v0tex, (vec2){r / (2 * r + w) * -sinf(a * i), 1 / (2 + k * l) * cos(a * i)})
});
}
for (U32 i = 1; i <= k; i++) {
VecVertex_append(&vertices, (Vertex){
.pos = {w, cosf(a * i) * r, sinf(a * i) * r},
.tex = vec2_add_vec2(v1tex, (vec2){r / (2 * r + w) * sinf(a * i), 1 / (2 + k * l) * cos(a * i)})
});
}
for (U32 i = 1; i <= k; i++) {
VecVertex_append(&vertices, (Vertex){
.pos = {0, cosf(a * i) * r, sinf(a * i) * r},
.tex = {v2tex.x, v2tex.y + i * l / (2 + k * l)}
});
}
for (U32 i = 1; i <= k; i++) {
VecVertex_append(&vertices, (Vertex){
.pos = {w, cosf(a * i) * r, sinf(a * i) * r},
.tex = {v3tex.x, v3tex.y + i * l / (2 + k * l)}
});
}
VecU32 indexes = VecU32_new(); // todo: reserve 3 * (2+2+2*k+2*k)<
{
U32 _span_0[] = { 5, 0, 1, 5, 4, 0, 1, 0, 3, 3, 0, 2 };
VecU32_append_span(&indexes, (ConstSpanU32){.data = _span_0, .len = ARRAY_SIZE(_span_0)});
}
for (U32 i = 1; i <= k; i++) {
U32 _span_1[] = {
0, 5 + i, i > 1 ? 5 + i - 1 : 2,
1, i > 1 ? 5 + k + i - 1 : 3, 5 + k + i,
i > 1 ? 5 + 2 * k + i - 1 : 2, 5 + 2 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3,
5 + 3 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3, 5 + 2 * k + i
};
VecU32_append_span(&indexes, (ConstSpanU32){.data = _span_1, .len = ARRAY_SIZE(_span_1)});
}
return (ModelTopology){.vertices = vertices, .indexes = indexes};
}
typedef struct {
vec2 win_scale;
} Pipeline1PushRangeVertex;
typedef struct {
float gamma_correction_factor;
float hdr_factor;
float lsd_factor;
float anim_time;
} Pipeline1PushRangeFragment;
typedef struct {
mat4 t;
} Pipeline0UBO;
#define cvec4_drop(vp) {}
#define cvec4_clone(vp) (*(vp))
VecT_trivmove_struct_Definition(cvec4)
VecT_trivmove_method_Definition(cvec4)
VecT_primitive_zeroinit_method_Definition(cvec4)
typedef struct {
// I hate this so much uuuh. Capacity is not actually useful here...
Veccvec4 pixels;
size_t width;
} TextureDataR8G8B8A8;
TextureDataR8G8B8A8 TextureDataR8G8B8A8_new(size_t width, size_t height) {
return (TextureDataR8G8B8A8){.pixels = Veccvec4_new_zeroinit(width * height), .width = width};
}
size_t TextureDataR8G8B8A8_get_height(const TextureDataR8G8B8A8* self) {
return self->pixels.len / self->width;
}
void TextureDataR8G8B8A8_drop(TextureDataR8G8B8A8 self) {
Veccvec4_drop(self.pixels);
}
cvec4* TextureDataR8G8B8A8_at(TextureDataR8G8B8A8* self, size_t x, size_t y) {
assert(x < self->width);
return Veccvec4_at(&self->pixels, x + y * self->width);
}
TextureDataR8G8B8A8 generate_wood_texture() {
const U32 width = 100;
const U32 height = 100;
TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width, height);
for (U32 y = 0; y < width; y++) {
for (U32 col = 0; col < height; col++) {
*TextureDataR8G8B8A8_at(&res, col, y) = (cvec4){150, 30, 50, 255};
}
}
for (U32 i = 0; i < 10; i++) {
for (U32 y = 0; y < height; y++) {
U32 col = 3 + i * 10 + ((30 < y + 3 * i && y - i < 60) ? 1 : 0);
*TextureDataR8G8B8A8_at(&res, col, y) = (cvec4){130, 25, 40, 255};
*TextureDataR8G8B8A8_at(&res, col + 1, y) = (cvec4){80, 10, 15, 255};
*TextureDataR8G8B8A8_at(&res, col + 2, y) = (cvec4){70, 11, 12, 255};
*TextureDataR8G8B8A8_at(&res, col + 3, y) = (cvec4){125, 20, 20, 255};
}
}
for (U32 y = 0; y < 10; y++) {
for (U32 col = 0; col < 10; col++) {
*TextureDataR8G8B8A8_at(&res, col + 4, y + 13) = (cvec4){60, 8, 6, 255};
}
}
return res;
}
size_t ModelTopology_get_space_needed_for_staging_buffer(const ModelTopology* self) {
return MAX_U64(self->vertices.len * sizeof(Vertex), self->indexes.len * sizeof(U32));
}
size_t TextureDataR8G8B8A8_get_space_needed_for_staging_buffer(const TextureDataR8G8B8A8* self) {
return self->pixels.len * sizeof(cvec4);
}
typedef struct {
float fov;
mat3 cam_basis;
vec3 pos;
float speed;
float sensitivity;
float pitch_cap;
} CamControlInfo;
void CamControlInfo_forward(CamControlInfo* self, float fl) {
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.z, -self->speed * fl));
}
void CamControlInfo_backward(CamControlInfo* self, float fl) {
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.z, self->speed * fl));
}
void CamControlInfo_left(CamControlInfo* self, float fl) {
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.x, -self->speed * fl));
}
void CamControlInfo_right(CamControlInfo* self, float fl) {
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.x, self->speed * fl));
}
void CamControlInfo_down(CamControlInfo* self, float fl) {
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal((vec3){0, -1, 0}, self->speed * fl));
}
void CamControlInfo_up(CamControlInfo* self, float fl) {
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal((vec3){0, 1, 0}, self->speed * fl));
}
CamControlInfo CamControlInfo_new() {
return (CamControlInfo){
.fov = 1.5, .cam_basis = margaret_simple_camera_rot_m_basis_in_cols(0, 0, 0), .pos = {0, 0, 0},
.speed = 2.7, .sensitivity = 0.5f * M_PIf / 180, .pitch_cap = M_PI * 0.49
};
}
float clamp_float(float a, float l, float r) {
return (a < l) ? l : ((a <= r) ? a : r);
}
void CamControlInfo_update_direction(CamControlInfo* self, int win_width, int win_height, int pointer_x, int pointer_y) {
float yaw = (float)(win_width / 2 - pointer_x) * self->sensitivity;
float pitch = clamp_float(
(float)(win_height / 2 - pointer_y) * self->sensitivity,
-self->pitch_cap, self->pitch_cap
);
self->cam_basis = margaret_simple_camera_rot_m_basis_in_cols(yaw, pitch, 0);
}
typedef struct {
VecModelOnScene models;
VkClearColorValue color;
float gamma_correction_factor;
float hdr_factor;
float lsd_factor;
float anim_time; // A timer, passed to functions that push push constants
} Scene;
Scene Scene_new() {
return (Scene){.models = VecModelOnScene_new(), .color = {.float32 = {1, 0.5, 0.7}},
.gamma_correction_factor = 2.2, .hdr_factor = 1, .lsd_factor = 0, .anim_time = 0};
}
void Scene_drop(Scene self) {
VecModelOnScene_drop(self.models);
}
#endif

View File

@ -4,6 +4,8 @@ layout(location = 0) in vec2 fsin_tex;
layout(location = 0) out vec4 fin_color;
layout(binding = 1) uniform sampler2D color_tex;
void main(){
fin_color = vec4(fsin_tex, 0, 1);
fin_color = texture(color_tex, fsin_tex);
}

View File

@ -5,10 +5,13 @@ layout(location = 1) in vec2 tex;
layout(location = 0) out vec2 vsout_tex;
layout(binding = 0) uniform ubo {
mat4 t;
};
// todo: add my ubo (location = 0) into the mix
// todo: add my woiod_texture (location = 1) into the mix
void main(){
vsout_tex = tex;
gl_Position = vec4(pos, 1);
gl_Position = t * vec4(pos, 1);
}

View File

@ -5,11 +5,14 @@ layout(location = 0) out vec4 fin_color;
layout(binding = 0) uniform sampler2D prev;
layout(push_constant, std430) uniform pc {
layout(offset = 8) float gamma_correction_factor;
float hdr_factor;
float lsd_factor;
float anim_time;
};
void main() {
vec2 tex_offset = 1.0 / textureSize(prev, 0);
// fin_color = texture(wood_texture, gl_FragCoord.xy * tex_offset);
fin_color = (texture(prev, fsin_tex + tex_offset * vec2(1, 0)) + texture(prev, fsin_tex + tex_offset * vec2(-1, 0)) +
texture(prev, fsin_tex + tex_offset * vec2(0, 1)) + texture(prev, fsin_tex + tex_offset * vec2(0, -1)) - 4 *
texture(prev, fsin_tex + tex_offset * vec2(0, 0))) / 8;
fin_color = texture(prev, gl_FragCoord.xy * tex_offset);
}