Added Camera

Set up uniform buffers for the camera. The camera still lacks a proper
controller on the lisp side, but you can create the matrix data in lisp.
The projection matrices use the "reverse-z" trick. When setting up depth
buffering in the (near) future, this needs to be considered.
This commit is contained in:
FroggyGreen 2024-05-15 23:04:51 -05:00
parent 207de345f7
commit 29b7e4b50b
8 changed files with 346 additions and 109 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -15,8 +15,9 @@
((:module "src"
:components
((:file "package")
(:file "main")
(:module "math"
:components
((:file "vec")
(:file "quat")))))))
(:file "quat")
(:file "mat")))
(:file "main")))))

View File

@ -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)))

View File

@ -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)))

View File

@ -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

View File

@ -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))