230 lines
6.9 KiB
C
230 lines
6.9 KiB
C
#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/ensure_region_capacity (hex.c) grow their
|
|
// respective buffers on demand, same "start small, double when full"
|
|
// pattern as ui.h's CONTAINER_MIN_DRAWABLES/CONTAINER_MIN_STRINGS.
|
|
// The last highlight/point slot is reserved for the hover preview (editor.c).
|
|
#define MIN_HIGHLIGHTS 16
|
|
#define MIN_POINTS 16
|
|
#define MIN_REGIONS 16
|
|
#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; // device address of VkDeviceAddress[] region list
|
|
} 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];
|
|
VkBuffer regions_buf[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];
|
|
VmaAllocation regions_mem[MAX_FRAMES_IN_FLIGHT];
|
|
|
|
// Current allocated size (in elements) for each sub-buffer.
|
|
// All grow on demand via ensure_*_capacity; regions also tracks the
|
|
// highest occupied slot (max_active_slot) to bound the draw call.
|
|
uint32_t cap_points;
|
|
uint32_t cap_highlights;
|
|
uint32_t cap_regions;
|
|
uint32_t active_region_count;
|
|
uint32_t max_active_slot;
|
|
|
|
GPURay rays_buffer[MAX_RAYS];
|
|
|
|
mat4 inverse;
|
|
|
|
GraphicsPipeline graphics;
|
|
GraphicsPipeline highlight_pipeline;
|
|
GraphicsPipeline point_pipeline;
|
|
GraphicsPipeline ray_pipeline;
|
|
|
|
HexRegion** 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 ensure_region_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
|