roleplay/client/include/camera.h

86 lines
3.0 KiB
C

#ifndef CAMERA_H
#define CAMERA_H
#include <cglm/types.h>
#include "gpu.h"
// Forward declaration only (no #include "ui.h") - camera.h and ui.h are
// mutually referential (Container owns a Camera*, Camera targets a
// UIContext's texture pool) and neither needs more than a pointer to the
// other's type.
typedef struct UIContextStruct UIContext;
// GPU mirror of the proj/view a camera pushes to its render target's push
// constant; std430 layout must match shader/camera_common.glsl's Camera
// buffer_reference struct exactly.
typedef struct GPUCameraStruct {
mat4 proj;
mat4 view;
} GPUCamera;
// Orbital camera: looks at `position` from `distance` away, oriented by
// `rotation` (yaw, pitch). `view`/`proj` are derived state, stale until
// camera_update_view/camera_update_proj run - callers are responsible for
// calling them after changing position/rotation/distance, or after the
// camera's target size changes.
//
// A camera's on-screen placement isn't camera state - attach it to a
// Container (container_set_camera, ui.h) and that container's anchor/
// offset/size/z-order (container_order) becomes the camera's viewport and
// draw order, same as every other container. A camera can separately (or
// instead) render into an offscreen texture via camera_init_texture_target,
// for other pipelines/containers to sample.
typedef struct CameraStruct {
vec3 position;
vec2 rotation;
double distance;
mat4 view;
mat4 proj;
bool has_texture_target;
struct {
uint32_t width, height;
// Double-buffered per frame-in-flight: two separate vkQueueSubmits
// aren't hazard-free against each other without extra sync, so this
// mirrors the existing pattern (HexContext/Container GPU buffers)
// rather than adding a new semaphore.
uint32_t texture_slot[MAX_FRAMES_IN_FLIGHT];
VkImage depth_image[MAX_FRAMES_IN_FLIGHT];
VkImageView depth_image_view[MAX_FRAMES_IN_FLIGHT];
VmaAllocation depth_image_memory[MAX_FRAMES_IN_FLIGHT];
} texture;
VkBuffer gpu_buffer[MAX_FRAMES_IN_FLIGHT];
VmaAllocation gpu_buffer_memory[MAX_FRAMES_IN_FLIGHT];
VkDeviceAddress gpu_address[MAX_FRAMES_IN_FLIGHT];
} Camera;
VkResult create_camera(RenderContext* gpu, Camera* camera);
// Frees the GPU buffers create_camera allocated, cascading to
// camera_destroy_texture_target first if a texture target was ever set up.
// Does not free the Camera struct itself (caller-owned - e.g. a stack/
// struct member for the engine's own cameras, malloc'd for script-created
// ones) or touch any Container still pointing at it.
void destroy_camera(RenderContext* gpu, Camera* camera);
void camera_update_view(Camera* camera);
void camera_update_proj(Camera* camera, float aspect);
VkResult camera_sync_gpu(Camera* camera, RenderContext* gpu);
VkResult camera_init_texture_target(
RenderContext* gpu,
UIContext* ui,
Camera* camera,
uint32_t width,
uint32_t height);
void camera_destroy_texture_target(
RenderContext* gpu,
UIContext* ui,
Camera* camera);
#endif