diff --git a/renderer/shaders/ui-pane.vert b/renderer/shaders/ui-pane.vert index 1817567..c3e8234 100644 --- a/renderer/shaders/ui-pane.vert +++ b/renderer/shaders/ui-pane.vert @@ -4,15 +4,23 @@ layout(location = 0) in vec2 inPos; // instance data -layout(location = 1) in vec2 inInstancePos; -layout(location = 2) in vec2 inInstanceScale; +layout(location = 1) in vec3 inInstancePos; +layout(location = 2) in vec3 inInstanceScale; layout(location = 3) in vec4 inInstanceColor; layout(location = 0) out vec4 fragColor; +layout(binding = 0) uniform Camera +{ + mat4 view; + mat4 perspective; + mat4 orthographic; + +} camera; + void main() { - vec2 pos = inPos * inInstanceScale + inInstancePos; - gl_Position = vec4(pos, 0.0, 1.0); + vec3 pos = vec3(inPos, 0.0) * inInstanceScale + inInstancePos; + gl_Position = camera.orthographic * vec4(pos, 1.0); fragColor = inInstanceColor; } diff --git a/renderer/src/renderer.c b/renderer/src/renderer.c index c90eb4b..5af5ebc 100644 --- a/renderer/src/renderer.c +++ b/renderer/src/renderer.c @@ -44,6 +44,14 @@ typedef struct vulkan_buffer } vulkan_buffer; +typedef struct renderer_camera +{ + f32 view[16]; + f32 perspective[16]; + f32 orthographic[16]; + +} renderer_camera; + typedef struct mesh { vulkan_buffer vertex_buffer; @@ -116,6 +124,13 @@ typedef struct vulkan_context } single_submit_context; + renderer_camera camera; + vulkan_buffer camera_uniform_buffers[MAX_FRAMES_IN_FLIGHT]; + u8 update_camera_uniform_counter; + VkDescriptorSetLayout camera_descriptor_set_layout; + VkDescriptorPool camera_descriptor_pool; + VkDescriptorSet camera_descriptor_sets[MAX_FRAMES_IN_FLIGHT]; + hash_table mesh_pipelines; } vulkan_context; @@ -1326,12 +1341,10 @@ static u8 init_vulkan_staging_buffer(vulkan_buffer* buffer, VkDeviceSize byte_si } // uniform buffer, CPU accessible memory -/* static u8 init_vulkan_uniform_buffer(vulkan_buffer* buffer, VkDeviceSize byte_size) { return init_vulkan_buffer(buffer, byte_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); } -*/ // vertex buffer, device memory static u8 init_vulkan_vertex_buffer(vulkan_buffer* buffer, VkDeviceSize byte_size) @@ -1400,6 +1413,148 @@ static u8 copy_vulkan_buffer(vulkan_buffer* dst, vulkan_buffer* src, VkDeviceSiz return 1; } +static void shutdown_camera() +{ + vkDestroyDescriptorPool(context.device.logical, context.camera_descriptor_pool, context.allocator); + + vkDestroyDescriptorSetLayout(context.device.logical, context.camera_descriptor_set_layout, context.allocator); + + for (u8 i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + shutdown_vulkan_buffer(context.camera_uniform_buffers + i); +} + +static u8 init_camera() +{ + // camera data + const f32 id_mat4[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + memcpy(context.camera.view, id_mat4, sizeof(f32) * 16); + memcpy(context.camera.perspective, id_mat4, sizeof(f32) * 16); + memcpy(context.camera.orthographic, id_mat4, sizeof(f32) * 16); + context.update_camera_uniform_counter = 0; + + // uniform buffers + for (u8 i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { + vulkan_buffer* uniform_buffer = context.camera_uniform_buffers + i; + if (!init_vulkan_uniform_buffer(uniform_buffer, sizeof(renderer_camera)) || + !map_vulkan_buffer(uniform_buffer, 0, sizeof(renderer_camera), 0)) // persistent mapping + { + trace_log(LOG_ERROR, "Failed to create Vulkan camera; failed to setup the uniform buffers."); + return 0; + } + memcpy(uniform_buffer->mapped, &context.camera, sizeof(renderer_camera)); + } + + // descriptor set layout + const VkDescriptorSetLayoutBinding camera_layout_binding = + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .pImmutableSamplers = NULL + }; + const VkDescriptorSetLayoutCreateInfo descriptor_layout_info = + { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = 1, + .pBindings = &camera_layout_binding, + .flags = 0, + .pNext = NULL + }; + if (vkCreateDescriptorSetLayout(context.device.logical, &descriptor_layout_info, context.allocator, &context.camera_descriptor_set_layout) != VK_SUCCESS) + { + trace_log(LOG_ERROR, "Failed to create Vulkan camera; failed to create descriptor set layout."); + return 0; + } + + // descriptor pool + const VkDescriptorPoolSize pool_size = + { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = MAX_FRAMES_IN_FLIGHT + }; + const VkDescriptorPoolCreateInfo descriptor_pool_info = + { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .poolSizeCount = 1, + .pPoolSizes = &pool_size, + .maxSets = MAX_FRAMES_IN_FLIGHT, + .flags = 0, + .pNext = NULL + }; + if (vkCreateDescriptorPool(context.device.logical, &descriptor_pool_info, context.allocator, &context.camera_descriptor_pool) != VK_SUCCESS) + { + trace_log(LOG_ERROR, "Failed to create Vulkan camera; failed to create descriptor pool."); + return 0; + } + + // descriptor sets + VkDescriptorSetLayout* descriptor_set_layouts = malloc(MAX_FRAMES_IN_FLIGHT * sizeof(VkDescriptorSetLayout)); + for (u8 i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + descriptor_set_layouts[i] = context.camera_descriptor_set_layout; + const VkDescriptorSetAllocateInfo alloc_info = + { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = context.camera_descriptor_pool, + .descriptorSetCount = MAX_FRAMES_IN_FLIGHT, + .pSetLayouts = descriptor_set_layouts, + .pNext = NULL + }; + if (vkAllocateDescriptorSets(context.device.logical, &alloc_info, context.camera_descriptor_sets) != VK_SUCCESS) + { + trace_log(LOG_ERROR, "Failed to create Vulkan camera; failed to allocated descriptor sets"); + return 0; + } + for (u8 i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { + const VkDescriptorBufferInfo buffer_info = + { + .buffer = context.camera_uniform_buffers[i].handle, + .offset = 0, + .range = sizeof(renderer_camera) + }; + const VkWriteDescriptorSet write = + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = context.camera_descriptor_sets[i], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .pBufferInfo = &buffer_info, + .pImageInfo = NULL, + .pTexelBufferView = NULL, + .pNext = NULL + }; + vkUpdateDescriptorSets(context.device.logical, 1, &write, 0, NULL); + } + + free(descriptor_set_layouts); + trace_log(LOG_DEBUG, "Successfully created Vulkan camera."); + signal_for_shutdown(shutdown_camera); + + return 1; +} + +void set_camera_view(const f32* view) +{ + memcpy(context.camera.view, view, sizeof(f32) * 16); + context.update_camera_uniform_counter= MAX_FRAMES_IN_FLIGHT; +} + +void set_camera_perspective_projection(const f32* perspective) +{ + memcpy(context.camera.perspective, perspective, sizeof(f32) * 16); + context.update_camera_uniform_counter = MAX_FRAMES_IN_FLIGHT; +} + +void set_camera_orthographic_projection(const f32* orthographic) +{ + memcpy(context.camera.orthographic, orthographic, sizeof(f32) * 16); + context.update_camera_uniform_counter = MAX_FRAMES_IN_FLIGHT; +} + static u8 init_mesh(mesh* msh, const mesh_geometry* geometry, vertex_input_type geometry_type, const mesh_instance_data* instance_data, vertex_input_type instance_type) { VkDeviceSize geometry_vertices_byte_size = 0, instance_data_byte_size = 0; @@ -1426,8 +1581,8 @@ static u8 init_mesh(mesh* msh, const mesh_geometry* geometry, vertex_input_type case VERTEX_INPUT_TYPE_POS2: *ds = count * sizeof(pos2); break; - case VERTEX_INPUT_TYPE_POS2_POS2_COLOR4: - *ds = count * sizeof(pos2_pos2_color4); + case VERTEX_INPUT_TYPE_POS3_POS3_COLOR4: + *ds = count * sizeof(pos3_pos3_color4); break; default: trace_log(LOG_ERROR, "Failed to create mesh; invalid vertex type (binding = %d).", i); @@ -1575,17 +1730,17 @@ static u8 init_mesh_pipeline(mesh_pipeline* pipeline, const mesh_pipeline_templa attribute_descriptions = darray_pushback(attribute_descriptions, attributes, 1); } break; - case VERTEX_INPUT_TYPE_POS2_POS2_COLOR4: + case VERTEX_INPUT_TYPE_POS3_POS3_COLOR4: { const VkVertexInputBindingDescription binding = { - .binding = i, .stride = sizeof(pos2_pos2_color4), .inputRate = input_rate + .binding = i, .stride = sizeof(pos3_pos3_color4), .inputRate = input_rate }; const VkVertexInputAttributeDescription attributes[] = { - (VkVertexInputAttributeDescription){ .location = idx, .binding = i, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(pos2_pos2_color4, posa) }, - (VkVertexInputAttributeDescription){ .location = idx + 1, .binding = i, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(pos2_pos2_color4, posb) }, - (VkVertexInputAttributeDescription){ .location = idx + 2, .binding = i, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(pos2_pos2_color4, color) } + (VkVertexInputAttributeDescription){ .location = idx, .binding = i, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(pos3_pos3_color4, posa) }, + (VkVertexInputAttributeDescription){ .location = idx + 1, .binding = i, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(pos3_pos3_color4, posb) }, + (VkVertexInputAttributeDescription){ .location = idx + 2, .binding = i, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(pos3_pos3_color4, color) } }; binding_descriptions = darray_pushback(binding_descriptions, &binding, 1); attribute_descriptions = darray_pushback(attribute_descriptions, attributes, 3); @@ -1631,7 +1786,7 @@ static u8 init_mesh_pipeline(mesh_pipeline* pipeline, const mesh_pipeline_templa .polygonMode = VK_POLYGON_MODE_FILL, .lineWidth = 1.0f, .cullMode = VK_CULL_MODE_BACK_BIT, - .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .frontFace = VK_FRONT_FACE_CLOCKWISE, .rasterizerDiscardEnable = VK_FALSE, .depthClampEnable = VK_FALSE, .depthBiasEnable = VK_FALSE, @@ -1691,12 +1846,12 @@ static u8 init_mesh_pipeline(mesh_pipeline* pipeline, const mesh_pipeline_templa .pNext = NULL }; - // layout + // layout; TO DO probably need something in the pipeline template to make this better const VkPipelineLayoutCreateInfo layout_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .setLayoutCount = 0, - .pSetLayouts = NULL, + .setLayoutCount = 1, + .pSetLayouts = &context.camera_descriptor_set_layout, .pushConstantRangeCount = 0, .pPushConstantRanges = NULL, .flags = 0, @@ -1786,18 +1941,21 @@ static void shutdown_mesh_pipeline(mesh_pipeline* pipeline) } u8 draw_mesh_pipeline(const char* name) -{ +{ + // bind pipeline + VkCommandBuffer command_buffer = context.frames[context.current_frame].command_buffer; mesh_pipeline* pipeline = hash_table_lookup(&context.mesh_pipelines, name); if (!pipeline) { trace_log(LOG_ERROR, "Failed to draw mesh pipeline '%s'; lookup failed." , name); return 0; } - - VkCommandBuffer command_buffer = context.frames[context.current_frame].command_buffer; vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); - for (u32 i = 0; i < pipeline->meshes.slot_count; i++) + // bind camera descriptor set (set 0) + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->layout, 0, 1, context.camera_descriptor_sets + context.current_frame, 0, NULL); + + for (u32 i = 0; i < pipeline->meshes.slot_count; i++) for (hash_table_entry* entry = pipeline->meshes.entries[i]; entry != NULL; entry = entry->next) { mesh* msh = entry->data; @@ -1927,6 +2085,7 @@ u8 init_vulkan() if (!init_command_pool()) return 0; if (!init_frame_data()) return 0; if (!init_single_submit_context()) return 0; + if (!init_camera()) return 0; init_hash_table(&context.mesh_pipelines, 8, sizeof(mesh_pipeline), basic_hash); @@ -1978,6 +2137,14 @@ u8 begin_render_frame() } else if (acquire_next_image_result != VK_SUCCESS && acquire_next_image_result != VK_SUBOPTIMAL_KHR) return 0; + + // update camera uniform buffer + if (context.update_camera_uniform_counter) + { + vulkan_buffer* uniform_buffer = context.camera_uniform_buffers + context.current_frame; + memcpy(uniform_buffer->mapped, &context.camera, sizeof(renderer_camera)); + context.update_camera_uniform_counter--; + } vkResetFences(context.device.logical, 1, &frame->in_flight_fence); diff --git a/renderer/src/renderer.h b/renderer/src/renderer.h index dedd480..bd91a8c 100644 --- a/renderer/src/renderer.h +++ b/renderer/src/renderer.h @@ -43,7 +43,7 @@ typedef struct window_event typedef enum { VERTEX_INPUT_TYPE_POS2, - VERTEX_INPUT_TYPE_POS2_POS2_COLOR4 + VERTEX_INPUT_TYPE_POS3_POS3_COLOR4 } vertex_input_type; @@ -53,13 +53,13 @@ typedef struct pos2 } pos2; -typedef struct pos2_pos2_color4 +typedef struct pos3_pos3_color4 { - f32 posa[2]; - f32 posb[2]; + f32 posa[3]; + f32 posb[3]; f32 color[4]; -} pos2_pos2_color4; +} pos3_pos3_color4; typedef struct mesh_geometry { @@ -105,6 +105,10 @@ void shutdown_window(); u8 is_window_open(); void poll_window_input(); +void set_camera_view(const f32* view); +void set_camera_perspective_projection(const f32* perspective); +void set_camera_orthographic_projection(const f32* orthographic); + u8 draw_mesh_pipeline(const char* name); u8 insert_mesh_pipeline(const mesh_pipeline_template* template); u8 remove_mesh_pipeline(const char* name); diff --git a/sof.asd b/sof.asd index 9238679..ef7a91e 100644 --- a/sof.asd +++ b/sof.asd @@ -15,8 +15,9 @@ ((:module "src" :components ((:file "package") - (:file "main") (:module "math" :components ((:file "vec") - (:file "quat"))))))) + (:file "quat") + (:file "mat"))) + (:file "main"))))) diff --git a/src/main.lisp b/src/main.lisp index 669eac6..5596203 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -41,7 +41,7 @@ You should have received a copy of the GNU General Public License along with Sha (cffi:defcenum vertex-input-type :vertex-input-type-pos2 - :vertex-input-type-pos2-pos2-color4) + :vertex-input-type-pos3-pos3-color4) (cffi:defcstruct (%pos2 :class c-pos2) (pos :float :count 2)) @@ -73,64 +73,72 @@ You should have received a copy of the GNU General Public License along with Sha (cffi:mem-aref pos :float 0) (aref (pos2-pos ,value) 0) (cffi:mem-aref pos :float 1) (aref (pos2-pos ,value) 1)))) -(cffi:defcstruct (%pos2-pos2-color4 :class c-pos2-pos2-color4) - (posa :float :count 2) - (posb :float :count 2) +(cffi:defcstruct (%pos3-pos3-color4 :class c-pos3-pos3-color4) + (posa :float :count 3) + (posb :float :count 3) (color :float :count 4)) -(defstruct pos2-pos2-color4 - (posa (vector 0.0 0.0)) - (posb (vector 0.0 0.0)) +(defstruct pos3-pos3-color4 + (posa (vector 0.0 0.0 0.0)) + (posb (vector 0.0 0.0 0.0)) (color (vector 0.0 0.0 0.0 0.0))) -(defmethod cffi:translate-from-foreign (ptr (type c-pos2-pos2-color4)) - (cffi:with-foreign-slots ((posa posb color) ptr (:struct %pos2-pos2-color4)) - (make-pos2-pos2-color4 +(defmethod cffi:translate-from-foreign (ptr (type c-pos3-pos3-color4)) + (cffi:with-foreign-slots ((posa posb color) ptr (:struct %pos3-pos3-color4)) + (make-pos3-pos3-color4 :posa (vector (cffi:mem-aref posa :float 0) - (cffi:mem-aref posa :float 1)) + (cffi:mem-aref posa :float 1) + (cffi:mem-aref posa :float 2)) :posb (vector (cffi:mem-aref posb :float 0) - (cffi:mem-aref posb :float 1)) + (cffi:mem-aref posb :float 1) + (cffi:mem-aref posb :float 2)) :color (vector (cffi:mem-aref color :float 0) (cffi:mem-aref color :float 1) (cffi:mem-aref color :float 2) - (cffi:mem-aref color :float 4))))) + (cffi:mem-aref color :float 3))))) -(defmethod cffi:expand-from-foreign (ptr (type c-pos2-pos2-color4)) - `(cffi:with-foreign-slots ((posa posb color) ,ptr (:struct %pos2-pos2-color4)) - (make-pos2-pos2-color4 +(defmethod cffi:expand-from-foreign (ptr (type c-pos3-pos3-color4)) + `(cffi:with-foreign-slots ((posa posb color) ,ptr (:struct %pos3-pos3-color4)) + (make-pos3-pos3-color4 :posa (vector (cffi:mem-aref posa :float 0) - (cffi:mem-aref posa :float 1)) + (cffi:mem-aref posa :float 1) + (cffi:mem-aref posa :float 2)) :posb (vector (cffi:mem-aref posb :float 0) - (cffi:mem-aref posb :float 1)) + (cffi:mem-aref posb :float 1) + (cffi:mem-aref posb :float 2)) :color (vector (cffi:mem-aref color :float 0) (cffi:mem-aref color :float 1) (cffi:mem-aref color :float 2) - (cffi:mem-aref color :float 4))))) + (cffi:mem-aref color :float 3))))) -(defmethod cffi:translate-into-foreign-memory (value (type c-pos2-pos2-color4) ptr) - (cffi:with-foreign-slots ((posa posb color) ptr (:struct %pos2-pos2-color4)) +(defmethod cffi:translate-into-foreign-memory (value (type c-pos3-pos3-color4) ptr) + (cffi:with-foreign-slots ((posa posb color) ptr (:struct %pos3-pos3-color4)) (setf - (cffi:mem-aref posa :float 0) (aref (pos2-pos2-color4-posa value) 0) - (cffi:mem-aref posa :float 1) (aref (pos2-pos2-color4-posa value) 1) - (cffi:mem-aref posb :float 0) (aref (pos2-pos2-color4-posb value) 0) - (cffi:mem-aref posb :float 1) (aref (pos2-pos2-color4-posb value) 1) - (cffi:mem-aref color :float 0) (aref (pos2-pos2-color4-color value) 0) - (cffi:mem-aref color :float 1) (aref (pos2-pos2-color4-color value) 1) - (cffi:mem-aref color :float 2) (aref (pos2-pos2-color4-color value) 2) - (cffi:mem-aref color :float 3) (aref (pos2-pos2-color4-color value) 3)))) + (cffi:mem-aref posa :float 0) (aref (pos3-pos3-color4-posa value) 0) + (cffi:mem-aref posa :float 1) (aref (pos3-pos3-color4-posa value) 1) + (cffi:mem-aref posa :float 2) (aref (pos3-pos3-color4-posa value) 2) + (cffi:mem-aref posb :float 0) (aref (pos3-pos3-color4-posb value) 0) + (cffi:mem-aref posb :float 1) (aref (pos3-pos3-color4-posb value) 1) + (cffi:mem-aref posb :float 2) (aref (pos3-pos3-color4-posb value) 2) + (cffi:mem-aref color :float 0) (aref (pos3-pos3-color4-color value) 0) + (cffi:mem-aref color :float 1) (aref (pos3-pos3-color4-color value) 1) + (cffi:mem-aref color :float 2) (aref (pos3-pos3-color4-color value) 2) + (cffi:mem-aref color :float 3) (aref (pos3-pos3-color4-color value) 3)))) -(defmethod cffi:expand-into-foreign-memory (value (type c-pos2-pos2-color4) ptr) - `(cffi:with-foreign-slots ((posa posb color) ,ptr (:struct %pos2-pos2-color4)) +(defmethod cffi:expand-into-foreign-memory (value (type c-pos3-pos3-color4) ptr) + `(cffi:with-foreign-slots ((posa posb color) ,ptr (:struct %pos3-pos3-color4)) (setf - (cffi:mem-aref posa :float 0) (aref (pos2-pos2-color4-posa ,value) 0) - (cffi:mem-aref posa :float 1) (aref (pos2-pos2-color4-posa ,value) 1) - (cffi:mem-aref posb :float 0) (aref (pos2-pos2-color4-posb ,value) 0) - (cffi:mem-aref posb :float 1) (aref (pos2-pos2-color4-posb ,value) 1) - (cffi:mem-aref color :float 0) (aref (pos2-pos2-color4-color ,value) 0) - (cffi:mem-aref color :float 1) (aref (pos2-pos2-color4-color ,value) 1) - (cffi:mem-aref color :float 2) (aref (pos2-pos2-color4-color ,value) 2) - (cffi:mem-aref color :float 3) (aref (pos2-pos2-color4-color ,value) 3)))) + (cffi:mem-aref posa :float 0) (aref (pos3-pos3-color4-posa ,value) 0) + (cffi:mem-aref posa :float 1) (aref (pos3-pos3-color4-posa ,value) 1) + (cffi:mem-aref posa :float 2) (aref (pos3-pos3-color4-posa ,value) 2) + (cffi:mem-aref posb :float 0) (aref (pos3-pos3-color4-posb ,value) 0) + (cffi:mem-aref posb :float 1) (aref (pos3-pos3-color4-posb ,value) 1) + (cffi:mem-aref posb :float 2) (aref (pos3-pos3-color4-posb ,value) 2) + (cffi:mem-aref color :float 0) (aref (pos3-pos3-color4-color ,value) 0) + (cffi:mem-aref color :float 1) (aref (pos3-pos3-color4-color ,value) 1) + (cffi:mem-aref color :float 2) (aref (pos3-pos3-color4-color ,value) 2) + (cffi:mem-aref color :float 3) (aref (pos3-pos3-color4-color ,value) 3)))) (cffi:defcstruct %mesh-geometry (vertices :pointer) @@ -200,6 +208,32 @@ You should have received a copy of the GNU General Public License along with Sha (cffi:defcfun ("poll_window_input" poll-window-input) :void) +(cffi:defcfun ("set_camera_view" %set-camera-view) :void + (view :pointer)) + +(cffi:defcfun ("set_camera_perspective_projection" %set-camera-perspective-projection) :void + (perspective :pointer)) + +(cffi:defcfun ("set_camera_orthographic_projection" %set-camera-orthographic-projection) :void + (orthographic :pointer)) + +(defmacro set-camera-helper (camera-mat4 camera-setter) + `(cffi:with-foreign-object (c-mat4 :float 16) + (dotimes (i 4) + (dotimes (j 4) + (setf (cffi:mem-aref c-mat4 :float (+ j (* i 4))) + (float (aref (aref ,camera-mat4 i) j) 1.0)))) + (funcall ,camera-setter c-mat4))) + +(defun set-camera-view (view) + (set-camera-helper view #'%set-camera-view)) + +(defun set-camera-perspective-projection (perspective) + (set-camera-helper perspective #'%set-camera-perspective-projection)) + +(defun set-camera-orthographic-projection (orthographic) + (set-camera-helper orthographic #'%set-camera-orthographic-projection)) + (cffi:defcfun ("draw_mesh_pipeline" draw-mesh-pipeline) :boolean (name :string)) @@ -245,15 +279,29 @@ You should have received a copy of the GNU General Public License along with Sha (defparameter *frame-time* 0.016) (defparameter *max-frame-time* 0.250) +(defparameter *view-mat4* *id-mat4*) +(defparameter *perspective-mat4* *id-mat4*) +(defparameter *orthographic-mat4* *id-mat4*) +(defparameter *perspective-near-plane* 0.1) +(defparameter *perspective-far-plane* 10.0) +(defparameter *orthographic-near-plane* 0.1) +(defparameter *orthographic-far-plane* 10.0) + (defun init-game (name width height) (setf *game-running?* (when (init-window name width height) (when (init-vulkan) t))) + (setf + *perspective-mat4* (perspective-projection (/ pi 4) (/ width height) *perspective-near-plane* *perspective-far-plane*) + *orthographic-mat4* (orthographic-projection width height *orthographic-near-plane* *orthographic-far-plane*)) + (set-camera-perspective-projection *perspective-mat4*) + (set-camera-orthographic-projection *orthographic-mat4*) + (insert-mesh-pipeline "ui-pane" (cffi:foreign-enum-value 'vertex-input-type :vertex-input-type-pos2) - (cffi:foreign-enum-value 'vertex-input-type :vertex-input-type-pos2-pos2-color4)) + (cffi:foreign-enum-value 'vertex-input-type :vertex-input-type-pos3-pos3-color4)) (cffi:with-foreign-object (quad-vertices '(:struct %pos2) 4) (setf @@ -276,12 +324,12 @@ You should have received a copy of the GNU General Public License along with Sha vertex-count 4 indices quad-indices index-count 6) - (cffi:with-foreign-object (quad-instances '(:struct %pos2-pos2-color4) 2) + (cffi:with-foreign-object (quad-instances '(:struct %pos3-pos3-color4) 2) (setf - (cffi:mem-aref quad-instances '(:struct %pos2-pos2-color4) 0) - (make-pos2-pos2-color4 :posa (vector -0.5 0.5) :posb (vector 0.25 0.25) :color (vector 0.7 0.0 0.0 1.0)) - (cffi:mem-aref quad-instances '(:struct %pos2-pos2-color4) 1) - (make-pos2-pos2-color4 :posa (vector 0.5 0.5) :posb (vector 0.4 0.4) :color (vector 0.0 0.5 0.5 0.6))) + (cffi:mem-aref quad-instances '(:struct %pos3-pos3-color4) 0) + (make-pos3-pos3-color4 :posa (vector 10.0 10.0 1.0) :posb (vector 100.0 100.0 10.0) :color (vector 0.7 0.0 0.0 1.0)) + (cffi:mem-aref quad-instances '(:struct %pos3-pos3-color4) 1) + (make-pos3-pos3-color4 :posa (vector 200.0 200.0 1.0) :posb (vector 100.0 100.0 10.0) :color (vector 1.0 0.4 0.4 0.6))) (cffi:with-foreign-object (instance-data '(:struct %mesh-instance-data)) (cffi:with-foreign-slots ((instances instance-count) instance-data (:struct %mesh-instance-data)) (setf @@ -295,7 +343,12 @@ You should have received a copy of the GNU General Public License along with Sha (defun process-window-resize (handle) (cffi:with-foreign-slots ((window-resize) handle (:union %window-event-handle)) - (format t "~a, ~a" (second window-resize) (fourth window-resize)))) + (let ((width (second window-resize)) (height (fourth window-resize))) + (setf + *perspective-mat4* (perspective-projection (/ pi 4) (/ width height) *perspective-near-plane* *perspective-far-plane*) + *orthographic-mat4* (orthographic-projection width height *orthographic-near-plane* *orthographic-far-plane*)) + (set-camera-perspective-projection *perspective-mat4*) + (set-camera-orthographic-projection *orthographic-mat4*)))) (defun process-window-input () (poll-window-input) @@ -323,7 +376,7 @@ You should have received a copy of the GNU General Public License along with Sha #+slynk (with-simple-restart (continue-game "Continue") (let ((connection (or slynk::*emacs-connection* (slynk::default-connection)))) - (when connection (slynk::handle-requests connection t)))) + (when connection (slynk::process-requests t)))) (let ((dt (/ (float (- curr-time prev-time)) internal-time-units-per-second))) diff --git a/src/math/mat.lisp b/src/math/mat.lisp index 20e924b..78fd612 100644 --- a/src/math/mat.lisp +++ b/src/math/mat.lisp @@ -43,9 +43,10 @@ You should have received a copy of the GNU General Public License along with Sha (defun diag->mat2 (d) (diag->mat d 2)) (defun diag->mat3 (d) (diag->mat d 3)) (defun diag->mat4 (d) (diag->mat d 4)) -(defconstant +id-mat2+ (diag->mat2 #(1 1))) -(defconstant +id-mat3+ (diag->mat3 #(1 1 1))) -(defconstant +id-mat4+ (diag->mat4 #(1 1 1 1))) + +(defparameter *id-mat2* (diag->mat2 #(1 1))) +(defparameter *id-mat3* (diag->mat3 #(1 1 1))) +(defparameter *id-mat4* (diag->mat4 #(1 1 1 1))) (defmacro transpose-mat (m dim) `(vector @@ -73,11 +74,11 @@ You should have received a copy of the GNU General Public License along with Sha (defmacro mult-mat-diag (m d dim) `(vector ,@(loop for i from 0 below dim - collect `(scaled-vec3 (aref ,m ,i) (aref ,d ,i))))) + collect `(scale-vec3 (aref ,m ,i) (aref ,d ,i))))) (defun mult-mat2-diag (m d) (mult-mat-diag m d 2)) (defun mult-mat3-diag (m d) (mult-mat-diag m d 3)) -(defun mult-mat3-diag (m d) (mult-mat-diag m d 4)) +(defun mult-mat4-diag (m d) (mult-mat-diag m d 4)) (defmacro mult-mat-vec (m v dim) `(vector @@ -115,10 +116,10 @@ You should have received a copy of the GNU General Public License along with Sha (left (normalize-vec3 (cross-vec3 world-up-dir forward))) (up (cross-vec3 forward left))) (vector - (vector 1 (- (dot-vec3 left camera-pos)) (- (dot-vec3 up camera-pos)) (- (dot-vec3 forward camera-pos))) - (vector 0 (aref left 0) (aref up 0) (aref forward 0)) - (vector 0 (aref left 1) (aref up 1) (aref forward 1)) - (vector 0 (aref left 2) (aref up 2) (aref forward 2))))) + (vector (aref left 0) (aref up 0) (aref forward 0) 0) + (vector (aref left 1) (aref up 1) (aref forward 1) 0) + (vector (aref left 2) (aref up 2) (aref forward 2) 0) + (vector (- (dot-vec3 left camera-pos)) (- (dot-vec3 up camera-pos)) (- (dot-vec3 forward camera-pos)) 1)))) (defun perspective-projection (fov ratio near far) @@ -126,16 +127,16 @@ You should have received a copy of the GNU General Public License along with Sha We are projecting onto the near plane and choosing a reverse-z convention: higher depth values correspond to closer positions." (let ((cot-fov (/ 1 (tan (/ fov 2))))) (vector - (vector 0 0 0 (/ (* near far) (- far near))) - (vector 0 cot-fov 0 0) - (vector 0 0 (- (/ cot-fov ratio)) 0) - (vector 1 0 0 (/ near (- near far)))))) + (vector cot-fov 0 0 0) + (vector 0 (- (/ cot-fov ratio)) 0 0) + (vector 0 0 (/ near (- near far)) 1) + (vector 0 0 (/ (* near far) (- far near)) 0)))) -(defun orthographic-projecion (width height near far) +(defun orthographic-projection (width height near far) "This maps a rectangular prism [0, width]x[0, height]x[near, far] to the rectangular prism [-1, 1]x[1, -1]x[1, 0] (Vulkan clip space). We are choosing a reverse-z convention: higher depth values correspond to closer positions." (vector - (vector 1 -1 1 (/ far (- far near))) - (vector 0 (/ 2 width) 0 0) - (vector 0 0 (- (/ 2 height)) 0) - (vector 0 0 0 (/ 1 (- near far))))) + (vector (/ 2 width) 0 0 0) + (vector 0 (- (/ 2 height)) 0 0) + (vector 0 0 (/ 1 (- near far)) 0) + (vector -1 1 (/ far (- far near)) 1))) diff --git a/src/math/quat.lisp b/src/math/quat.lisp index 7308c7b..5e7405a 100644 --- a/src/math/quat.lisp +++ b/src/math/quat.lisp @@ -20,20 +20,20 @@ You should have received a copy of the GNU General Public License along with Sha (defun mult-quat (q1 q2) (vector - (- (* (aref q1 0) (aref q2 0)) - (+ (* (aref q1 1) (aref q2 1)) (* (aref q1 2) (aref q2 2)) (* (aref q1 3) (aref q2 3)))) (- - (+ (* (aref q1 0) (aref q2 1)) (* (aref q1 1) (aref q2 0)) (* (aref q1 2) (aref q2 3))) - (* (aref q1 3) (aref q2 2))) + (+ (* (aref q1 3) (aref q2 0)) (* (aref q1 0) (aref q2 3)) (* (aref q1 1) (aref q2 2))) + (* (aref q1 2) (aref q2 1))) (- - (+ (* (aref q1 0) (aref q2 2)) (* (aref q1 2) (aref q2 0)) (* (aref q1 3) (aref q2 1))) - (* (aref q1 1) (aref q2 3))) + (+ (* (aref q1 3) (aref q2 1)) (* (aref q1 1) (aref q2 3)) (* (aref q1 2) (aref q2 0))) + (* (aref q1 0) (aref q2 2))) (- - (+ (* (aref q1 0) (aref q2 3)) (* (aref q1 3) (aref q2 0)) (* (aref q1 1) (aref q2 2))) - (* (aref q1 2) (aref q2 1))))) + (+ (* (aref q1 3) (aref q2 2)) (* (aref q1 2) (aref q2 3)) (* (aref q1 0) (aref q2 1))) + (* (aref q1 1) (aref q2 0))) + (- (* (aref q1 3) (aref q2 3)) + (+ (* (aref q1 0) (aref q2 0)) (* (aref q1 1) (aref q2 1)) (* (aref q1 2) (aref q2 2)))))) (defun conjugate-quat (q) - (vector (aref q 0) (- (aref q 1)) (- (aref q 2)) (- (aref q 3)))) + (vector (- (aref q 0)) (- (aref q 1)) (- (aref q 2) (aref q 3)))) (defmacro quat->versor (q) "Normalize a quaternion. A unit quaternion is also called a versor." @@ -44,12 +44,12 @@ You should have received a copy of the GNU General Public License along with Sha (let* ((sine-angle (sin angle)) (cosine-angle (cos angle)) (v (scale-vec3 (normalize-vec3 axis) sine-angle))) - (concatenate 'vector (vector cosine-angle) v))) + (concatenate 'vector v (vector cosine-angle)))) -(defconstant +id-versor+ (vector 1 0 0 0)) +(defparameter *id-versor* (vector 0 0 0 1)) (defun slerp-versor (vrs1 vrs2 l) - "Spherical interpolation along the shortest path. If the inputs are versors, the output is a versor." + "Spherical interpolation of two versors along the shortest path. If the inputs are versors, the output is a versor." (let ((cosine-angle (dot-vec4 vrs1 vrs2)) (vrs vrs2)) (when (< cosine-angle 0) (setf diff --git a/src/package.lisp b/src/package.lisp index 9f1d639..4aeb2ed 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -39,7 +39,7 @@ #:conjugate-quat #:quat->versor #:axis-angle->versor - #:+id-versor+ + #:*id-versor* #:slerp-versor)) (defpackage #:sof-mat @@ -54,9 +54,9 @@ #:diag->mat2 #:diag->mat3 #:diag->mat4 - #:+id-mat2+ - #:+id-mat3+ - #:+id-mat4+ + #:*id-mat2* + #:*id-mat3* + #:*id-mat4* #:transpose-mat2 #:transpose-mat3 #:transpose-mat4 @@ -85,6 +85,9 @@ (:use #:cl #:cffi + #:sof-vec + #:sof-quat + #:sof-mat #:sof-transform) (:export #:main))