#ifndef HEX_H #define HEX_H #include "gpu.h" #include "camera.h" #include "vulkan/vulkan_core.h" #define MAX_RAYS 10 // Initial capacity, not a hard cap - ensure_highlight_capacity/ // ensure_point_capacity (hex.c) grow HexContext.highlights/points on // demand, same "start small, double when a fixed pool fills up" pattern as // ui.h's CONTAINER_MIN_DRAWABLES/CONTAINER_MIN_STRINGS. The last slot of // whatever the current capacity is stays reserved for the hover preview // (see editor.c). #define MIN_HIGHLIGHTS 16 #define MIN_POINTS 16 #define MAX_LOADED_REGIONS 2500 #define REGION_SIZE 10 #define REGION_HEX_COUNT (3*REGION_SIZE*(REGION_SIZE-1)+1) #define HEX_X 0.75 #define SQRT3 1.732050807568877193176604123436845839023590087890625 #define HEX_Z (SQRT3/2) #define REGION_DIAMETER (2*REGION_SIZE-1) #define REGION_WIDTH (HEX_X*REGION_DIAMETER) #define REGION_HEIGHT (HEX_Z*REGION_DIAMETER) #define max(a, b) ((a > b) ? a : b) #define min(a, b) ((a < b) ? a : b) typedef struct HexCoordStruct { int32_t q; int32_t r; } HexCoord; extern vec3 hex_vertices[]; extern vec3 hex_starts[]; extern vec3 hex_directions[]; extern HexCoord hex_starts_qr[]; extern HexCoord hex_directions_qr[]; extern int hex_indices[]; typedef struct GPUHexStruct { float height[6]; // inner_colors[wedge] feeds the center-role vertex of triangle `wedge` // (see hex.vert's `wedge = gl_VertexIndex / 3`) and, when flat_mask bit // `wedge` is set, *all three* of that triangle's vertices - overriding // the shared outer_colors for a solid fill local to that one wedge. // outer_colors[i] is corner i+1 (matches the existing height[] and // set_vertex_color vertex-1 indexing), shared in meaning (not storage) // with the up-to-2 other hexes touching that same world corner. uint32_t inner_colors[6]; uint32_t outer_colors[6]; uint32_t flat_mask; } GPUHex; typedef struct GPUHexRegionStruct { HexCoord position; int32_t y; uint32_t map; GPUHex hexes[REGION_HEX_COUNT]; } GPUHexRegion; typedef struct HexRegionStruct { VkDeviceAddress address; VkBuffer region; VmaAllocation region_memory; GPUHexRegion data; } HexRegion; typedef struct GPURayStruct { vec4 start; vec4 end; vec4 color; } GPURay; typedef struct GPUHighlightStruct { vec4 color; uint32_t region; uint32_t hex; float offset; // 0xFFFFFFFF (the default/existing behavior) highlights the whole hex; // any other value (0-5) highlights just that one wedge/triangle. uint32_t triangle; } GPUHighlight; typedef struct GPUPointStruct { vec4 color; uint32_t region; uint32_t hex; uint32_t vertex; float size; float offset; } GPUPoint; typedef struct GPUHexContextStruct { uint32_t current_map; VkDeviceAddress rays; VkDeviceAddress points; VkDeviceAddress highlights; VkDeviceAddress regions[MAX_LOADED_REGIONS]; } GPUHexContext; typedef struct HexContextStruct { VkDeviceAddress address[MAX_FRAMES_IN_FLIGHT]; VkBuffer context[MAX_FRAMES_IN_FLIGHT]; VmaAllocation context_memory[MAX_FRAMES_IN_FLIGHT]; VkBuffer rays[MAX_FRAMES_IN_FLIGHT]; VkBuffer points[MAX_FRAMES_IN_FLIGHT]; VkBuffer highlights[MAX_FRAMES_IN_FLIGHT]; VmaAllocation rays_memory[MAX_FRAMES_IN_FLIGHT]; VmaAllocation points_memory[MAX_FRAMES_IN_FLIGHT]; VmaAllocation highlights_memory[MAX_FRAMES_IN_FLIGHT]; // Current allocated size of points[]/highlights[] (in elements, same for // both frames-in-flight) - grows via ensure_point_capacity/ // ensure_highlight_capacity, independent of each other. uint32_t cap_points; uint32_t cap_highlights; GPURay rays_buffer[MAX_RAYS]; mat4 inverse; GraphicsPipeline graphics; GraphicsPipeline highlight_pipeline; GraphicsPipeline point_pipeline; GraphicsPipeline ray_pipeline; HexRegion* regions[MAX_LOADED_REGIONS]; GPUHexContext data; } HexContext; typedef struct HexPushConstantStruct { VkDeviceAddress context; VkDeviceAddress camera; double time; } HexPushConstant; VkResult create_hex_context( RenderContext* gpu, HexContext* context); // Reverse of create_hex_context: destroys the pipelines, every allocated // HexRegion (regardless of who allocated it), and the per-frame storage // buffers. void destroy_hex_context( RenderContext* gpu, HexContext* context); // Grows highlights[]/points[] (both frames-in-flight) to at least `needed` // elements if the current capacity falls short - doubling from whatever // it's at, same pattern as ui.c's container_realloc_drawable_pool/ // container_realloc_string_pool. A no-op if already sufficient. Old // contents aren't preserved (nothing needs them to be - both buffers are // fully rewritten every call to sync_hex_highlights/sync_vertex_points, // see editor.c), so this is just retire-old/create-new/patch-address. VkResult ensure_highlight_capacity(HexContext* context, RenderContext* gpu, uint32_t needed); VkResult ensure_point_capacity(HexContext* context, RenderContext* gpu, uint32_t needed); VkResult set_hex_region( HexRegion* region, HexContext* hex, RenderContext* gpu); VkResult allocate_hex_region( int32_t q, int32_t r, int32_t y, uint32_t map, HexRegion** region, HexContext* hex, RenderContext* gpu); VkResult free_hex_region( uint32_t region_index, HexContext* hex, RenderContext* gpu); void cursor_to_world_ray( RenderContext* gpu, mat4 inverse, double cursor[2], vec4 start, vec4 end); bool ray_world_intersect( float* distance, uint32_t* vertex, // Wedge/triangle index (0-5) at the hit point - see hex.vert's `wedge` // for the matching GPU-side meaning. Always populated on a hit, // independent of edge_only/vertex resolution. uint32_t* triangle, uint32_t* rid, uint32_t* hid, vec4 ray_start, vec4 ray_end, bool edge_only, HexContext* context); // Recomputes the picking-ray inverse matrix (hex->inverse) from a camera's // already-computed proj/view (see camera_update_proj/camera_update_view). // Picking is only ever done against one camera at a time (the interactive // one - see cursor_to_world_ray's full-window assumption), so callers pick // which camera's proj*view this reflects; it isn't tied to any specific one. void update_hex_picking_inverse( Camera* camera, HexContext* hex); void hex_qr(uint32_t hex, HexCoord* world); void region_qr(HexCoord region, HexCoord* world); void hex_add(HexCoord from, HexCoord* to); void hex_index(HexCoord world, HexCoord* region, uint32_t* hex); void hex_vertex_neighbors( uint32_t vertex, HexCoord hex, uint32_t n_vertex[2], HexCoord n_region[2], uint32_t n_hex[2]); void first_matching_region(HexCoord coord, int y, uint32_t* region, HexContext* context); #endif