201 lines
6.4 KiB
C
201 lines
6.4 KiB
C
#include "camera.h"
|
|
#include "ui.h"
|
|
#include "render_graph.h"
|
|
|
|
#include <cglm/cam.h>
|
|
#include <math.h>
|
|
#include <stddef.h>
|
|
|
|
static vec3 up = {0, 1, 0};
|
|
|
|
VkResult create_camera(RenderContext* gpu, Camera* camera) {
|
|
VkResult result;
|
|
camera->texture_dynamic = true;
|
|
camera->max_depth = 1;
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
VK_RESULT(create_storage_buffer(
|
|
gpu->allocator,
|
|
0,
|
|
sizeof(GPUCamera),
|
|
&camera->gpu_buffer[i],
|
|
&camera->gpu_buffer_memory[i]));
|
|
camera->gpu_address[i] = buffer_address(gpu->device, camera->gpu_buffer[i]);
|
|
}
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void destroy_camera(RenderContext* gpu, Camera* camera) {
|
|
if(camera->has_texture_target) {
|
|
camera_destroy_texture_target(gpu, NULL, camera);
|
|
}
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
vmaDestroyBuffer(gpu->allocator, camera->gpu_buffer[i], camera->gpu_buffer_memory[i]);
|
|
}
|
|
}
|
|
|
|
void camera_update_view(Camera* camera) {
|
|
vec3 eye = {};
|
|
eye[0] = camera->position[0] + camera->distance*cos(camera->rotation[1])*cos(camera->rotation[0]);
|
|
eye[1] = camera->position[1] + camera->distance*sin(camera->rotation[1]);
|
|
eye[2] = camera->position[2] + camera->distance*cos(camera->rotation[1])*sin(camera->rotation[0]);
|
|
|
|
glm_lookat(eye, camera->position, up, camera->view);
|
|
}
|
|
|
|
void camera_update_proj(Camera* camera, float aspect) {
|
|
glm_perspective(
|
|
PERSPECTIVE_FOVY,
|
|
aspect,
|
|
PERSPECTIVE_NEARZ,
|
|
PERSPECTIVE_FARZ,
|
|
camera->proj);
|
|
}
|
|
|
|
VkResult camera_sync_gpu(Camera* camera, RenderContext* gpu) {
|
|
GPUCamera data;
|
|
glm_mat4_copy(camera->proj, data.proj);
|
|
glm_mat4_copy(camera->view, data.view);
|
|
return add_transfers(&data, camera->gpu_buffer, 0, sizeof(GPUCamera), gpu);
|
|
}
|
|
|
|
VkResult camera_init_texture_target(
|
|
RenderContext* gpu,
|
|
UIContext* ui,
|
|
Camera* camera,
|
|
uint32_t width,
|
|
uint32_t height) {
|
|
VkResult result;
|
|
|
|
camera->texture.width = width;
|
|
camera->texture.height = height;
|
|
|
|
VkExtent2D extent = {width, height};
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
VK_RESULT(create_render_target_texture(gpu, ui, width, height, &camera->texture.texture_slot[i]));
|
|
VK_RESULT(create_depth_image(
|
|
gpu->device,
|
|
gpu->depth_format,
|
|
extent,
|
|
gpu->allocator,
|
|
gpu->extra_graphics_pool,
|
|
gpu->graphics_queue,
|
|
&camera->texture.depth_image[i],
|
|
&camera->texture.depth_image_memory[i],
|
|
&camera->texture.depth_image_view[i]));
|
|
}
|
|
|
|
camera->has_texture_target = true;
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void camera_destroy_texture_target(RenderContext* gpu, UIContext* ui, Camera* camera) {
|
|
(void)ui;
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
vkDestroyImageView(gpu->device, camera->texture.depth_image_view[i], NULL);
|
|
vmaDestroyImage(gpu->allocator, camera->texture.depth_image[i], camera->texture.depth_image_memory[i]);
|
|
// TODO: free camera->texture.texture_slot[i] from the bindless descriptor
|
|
// pool once destroy_render_target_texture is implemented. For now the
|
|
// color slot leaks on destroy - only called from destroy_camera (shutdown).
|
|
}
|
|
camera->has_texture_target = false;
|
|
}
|
|
|
|
VkResult camera_recreate_texture_target(
|
|
Camera* camera,
|
|
RenderContext* gpu,
|
|
UIContext* ui,
|
|
uint32_t width,
|
|
uint32_t height) {
|
|
VkResult result;
|
|
VkExtent2D extent = {width, height};
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
VK_RESULT(recreate_render_target_texture(gpu, ui, camera->texture.texture_slot[i], width, height));
|
|
vkDestroyImageView(gpu->device, camera->texture.depth_image_view[i], NULL);
|
|
vmaDestroyImage(gpu->allocator, camera->texture.depth_image[i], camera->texture.depth_image_memory[i]);
|
|
VK_RESULT(create_depth_image(
|
|
gpu->device, gpu->depth_format, extent, gpu->allocator,
|
|
gpu->extra_graphics_pool, gpu->graphics_queue,
|
|
&camera->texture.depth_image[i],
|
|
&camera->texture.depth_image_memory[i],
|
|
&camera->texture.depth_image_view[i]));
|
|
}
|
|
camera->texture.width = width;
|
|
camera->texture.height = height;
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult camera_display(Camera* camera, Container* container, RenderContext* gpu, UIContext* ui) {
|
|
VkResult result;
|
|
|
|
container_set_camera(container, camera);
|
|
|
|
if(!camera->has_texture_target) {
|
|
uint32_t w, h;
|
|
if(camera->texture_dynamic) {
|
|
VkRect2D rect;
|
|
container_screen_rect(gpu, container, &rect);
|
|
w = rect.extent.width > 0 ? rect.extent.width : 1;
|
|
h = rect.extent.height > 0 ? rect.extent.height : 1;
|
|
} else {
|
|
w = camera->texture.width > 0 ? camera->texture.width : 1;
|
|
h = camera->texture.height > 0 ? camera->texture.height : 1;
|
|
}
|
|
VK_RESULT(camera_init_texture_target(gpu, ui, camera, w, h));
|
|
}
|
|
|
|
if(ui->render_graph != NULL) {
|
|
camera->rg_node = render_graph_add_camera_node(ui->render_graph, camera);
|
|
ui->render_graph_dirty = true;
|
|
} else {
|
|
camera->rg_node = UINT32_MAX;
|
|
}
|
|
|
|
GPUDrawable bg = {
|
|
.pos = {0.0f, 0.0f},
|
|
.size = {container->data.size[0], container->data.size[1]},
|
|
.color = {
|
|
{1.0f, 1.0f, 1.0f, 1.0f},
|
|
{1.0f, 1.0f, 1.0f, 1.0f},
|
|
{1.0f, 1.0f, 1.0f, 1.0f},
|
|
{1.0f, 1.0f, 1.0f, 1.0f},
|
|
},
|
|
.type = DRAWABLE_TYPE_IMAGE,
|
|
.var = camera->texture.texture_slot[0],
|
|
.events = 0,
|
|
.z = -1e30f,
|
|
};
|
|
|
|
uint32_t bg_slot;
|
|
VK_RESULT(ui_create_drawable(container, &bg, gpu, &bg_slot));
|
|
|
|
// ui_create_drawable → add_transfers uploads var=texture_slot[0] to both
|
|
// frames. Override frame 1's var in-place (the coalesce in add_transfer
|
|
// rewrites the staging data without adding a new entry).
|
|
VK_RESULT(add_transfer(
|
|
&camera->texture.texture_slot[1],
|
|
container->drawables[1],
|
|
sizeof(GPUDrawable) * bg_slot + offsetof(GPUDrawable, var),
|
|
sizeof(uint32_t),
|
|
1,
|
|
gpu));
|
|
|
|
container->camera_background_drawable = bg_slot;
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult camera_undisplay(Camera* camera, Container* container, RenderContext* gpu, UIContext* ui) {
|
|
if(ui->render_graph != NULL && camera->rg_node != UINT32_MAX) {
|
|
render_graph_remove_node(ui->render_graph, camera->rg_node);
|
|
camera->rg_node = UINT32_MAX;
|
|
ui->render_graph_dirty = true;
|
|
}
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
if(container->camera_background_drawable != UINT32_MAX) {
|
|
result = ui_destroy_drawable(container, container->camera_background_drawable, gpu);
|
|
container->camera_background_drawable = UINT32_MAX;
|
|
}
|
|
container_set_camera(container, NULL);
|
|
return result;
|
|
}
|