#ifndef CAMERA_H #define CAMERA_H #include #include "gpu.h" // Forward declarations 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; typedef struct ContainerStruct Container; // 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; // When true, texture dimensions are derived from the first display container // at camera_display() time (and on recreate_framebuffer). Set by // create_camera; cleared when cam:set_size(w,h) fixes explicit dimensions. bool texture_dynamic; // Reserved for future cyclic self-reference support (max render recursion // depth for cameras that display themselves). Default 1 = no recursion. uint32_t max_depth; 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); // Resizes an existing texture target in-place: replaces the per-frame color // images and depth images at the SAME texture slot indices, so descriptor // bindings (and drawable var fields) remain valid without consuming new slots. // Caller must ensure the GPU is idle (e.g. vkDeviceWaitIdle) before calling. VkResult camera_recreate_texture_target( Camera* camera, RenderContext* gpu, UIContext* ui, uint32_t width, uint32_t height); // Attaches camera to container as a background IMAGE drawable. Creates the // texture target on first call (sizing from container if texture_dynamic). // Multiple containers can display the same camera - each gets its own drawable. VkResult camera_display( Camera* camera, Container* container, RenderContext* gpu, UIContext* ui); // Removes the background IMAGE drawable from container and clears its camera // pointer. The texture target (and the camera itself) are unaffected. VkResult camera_undisplay( Camera* camera, Container* container, RenderContext* gpu, UIContext* ui); #endif