125 lines
4.6 KiB
C
125 lines
4.6 KiB
C
#ifndef CAMERA_H
|
|
#define CAMERA_H
|
|
|
|
#include <cglm/types.h>
|
|
#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];
|
|
|
|
uint32_t rg_node; // handle returned by render_graph_add_camera_node, UINT32_MAX when not registered
|
|
} 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
|