|  |  |  | @ -7,20 +7,54 @@ | 
		
	
		
			
				|  |  |  |  | #include <math.h> | 
		
	
		
			
				|  |  |  |  | #include <stdlib.h> | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #define COLOR_PICK_CONTAINER_ID 0x03 | 
		
	
		
			
				|  |  |  |  | typedef struct EditorDataStruct {  | 
		
	
		
			
				|  |  |  |  |   uint32_t selected_region; | 
		
	
		
			
				|  |  |  |  | #define COLOR_PICK_CONTAINER_ID 0x02 | 
		
	
		
			
				|  |  |  |  | #define MODE_STRING_CONTAINER_ID 0x01 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32_t clicked_region; | 
		
	
		
			
				|  |  |  |  |   uint32_t clicked_hex; | 
		
	
		
			
				|  |  |  |  |   uint32_t clicked_vertex; | 
		
	
		
			
				|  |  |  |  | typedef enum EditorModeEnum { | 
		
	
		
			
				|  |  |  |  |   MODE_NONE, | 
		
	
		
			
				|  |  |  |  |   MODE_VERTEX, | 
		
	
		
			
				|  |  |  |  |   MODE_NEIGHBOR, | 
		
	
		
			
				|  |  |  |  |   MODE_HEX, | 
		
	
		
			
				|  |  |  |  |   MODE_REGION, | 
		
	
		
			
				|  |  |  |  |   MODE_MAX_ENUM, | 
		
	
		
			
				|  |  |  |  | } EditorMode; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const char* ModeStrings[] = { | 
		
	
		
			
				|  |  |  |  |   "None", | 
		
	
		
			
				|  |  |  |  |   "Vertex", | 
		
	
		
			
				|  |  |  |  |   "Neighbor", | 
		
	
		
			
				|  |  |  |  |   "Hex", | 
		
	
		
			
				|  |  |  |  |   "Region", | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | typedef struct EditorDataStruct EditorData; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | typedef void(*ModeKeyCallback)(EditorData* data, ClientContext* context, int action, int mods); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | typedef struct ModeKeyStruct { | 
		
	
		
			
				|  |  |  |  |   int key; | 
		
	
		
			
				|  |  |  |  |   ModeKeyCallback logic;  | 
		
	
		
			
				|  |  |  |  | } ModeKey; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | struct EditorDataStruct {  | 
		
	
		
			
				|  |  |  |  |   EditorMode mode; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   ModeKey* mode_keys[MODE_MAX_ENUM]; | 
		
	
		
			
				|  |  |  |  |   uint32_t mode_key_counts[MODE_MAX_ENUM]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32_t  selected_max; | 
		
	
		
			
				|  |  |  |  |   uint32_t  selected_count; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32_t* selected_regions; | 
		
	
		
			
				|  |  |  |  |   uint32_t* selected_hexes; | 
		
	
		
			
				|  |  |  |  |   uint32_t* selected_vertices; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   double current_hsv[3]; | 
		
	
		
			
				|  |  |  |  |   vec4 current; | 
		
	
		
			
				|  |  |  |  |   vec4 saved[12]; | 
		
	
		
			
				|  |  |  |  |   char string[10]; | 
		
	
		
			
				|  |  |  |  |   int string_len; | 
		
	
		
			
				|  |  |  |  | } EditorData; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | uint32_t hex_color(vec4 color) { | 
		
	
	
		
			
				
					|  |  |  | @ -475,6 +509,7 @@ SAVED_COLOR_BUTTON_CALLBACK(11); | 
		
	
		
			
				|  |  |  |  |       .button = saved_color_button_callback_##n, \ | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | // TODO: Make load from current state instead of having a default state
 | 
		
	
		
			
				|  |  |  |  | VkResult color_ui(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  |   GPUString strings[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
	
		
			
				
					|  |  |  | @ -691,7 +726,7 @@ VkResult color_ui(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  |     .callback_count = sizeof(callbacks)/sizeof(UICallbacks), | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return create_container(&container, &context->render, &context->ui); | 
		
	
		
			
				|  |  |  |  |   return load_container(&container, &context->render, &context->ui); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult hex_info_ui(ClientContext* context) { | 
		
	
	
		
			
				
					|  |  |  | @ -789,495 +824,252 @@ VkResult hex_info_ui(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  |     .layer_count = 1, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return create_container(&container, &context->render, &context->ui); | 
		
	
		
			
				|  |  |  |  |   return load_container(&container, &context->render, &context->ui); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult region_info_ui(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  | VkResult mode_string_ui(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  |   VkResult result; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   GPUString strings[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .pos = {0, 33}, | 
		
	
		
			
				|  |  |  |  |       .color = {1, 1, 1, 1}, | 
		
	
		
			
				|  |  |  |  |       .size = 32, | 
		
	
		
			
				|  |  |  |  |       .offset = 0, | 
		
	
		
			
				|  |  |  |  |       .length = 0, | 
		
	
		
			
				|  |  |  |  |       .font = 0, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .pos = {0, 33 + 1*40}, | 
		
	
		
			
				|  |  |  |  |       .color = {1, 1, 1, 1}, | 
		
	
		
			
				|  |  |  |  |       .size = 32, | 
		
	
		
			
				|  |  |  |  |       .offset = 11, | 
		
	
		
			
				|  |  |  |  |       .length = 0, | 
		
	
		
			
				|  |  |  |  |       .font = 0, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .pos = {0, 33 + 2*40}, | 
		
	
		
			
				|  |  |  |  |       .color = {1, 1, 1, 1}, | 
		
	
		
			
				|  |  |  |  |       .size = 32, | 
		
	
		
			
				|  |  |  |  |       .offset = 18, | 
		
	
		
			
				|  |  |  |  |       .length = 0, | 
		
	
		
			
				|  |  |  |  |       .font = 0, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .pos = {0, 33 + 3*40}, | 
		
	
		
			
				|  |  |  |  |       .color = {1, 1, 1, 1}, | 
		
	
		
			
				|  |  |  |  |       .size = 32, | 
		
	
		
			
				|  |  |  |  |       .offset = 25, | 
		
	
		
			
				|  |  |  |  |       .length = 0, | 
		
	
		
			
				|  |  |  |  |       .font = 0, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   GPUString string = { | 
		
	
		
			
				|  |  |  |  |     .pos = {0, 32}, | 
		
	
		
			
				|  |  |  |  |     .font = 0, | 
		
	
		
			
				|  |  |  |  |     .size = 32, | 
		
	
		
			
				|  |  |  |  |     .length = strlen(ModeStrings[MODE_NONE]), | 
		
	
		
			
				|  |  |  |  |     .color = {1, 1, 1, 1}, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   GPUDrawable drawables[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .pos = {0, 0}, | 
		
	
		
			
				|  |  |  |  |       .size = {225, 155}, | 
		
	
		
			
				|  |  |  |  |       .color = {{0.4, 0.4, 0.4, 0.8}, {0.4, 0.4, 0.4, 0.8}, {0.4, 0.4, 0.4, 0.8}, {0.4, 0.4, 0.4, 0.8}}, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   uint32_t codes[8]; | 
		
	
		
			
				|  |  |  |  |   VK_RESULT(map_string(ModeStrings[MODE_NONE], codes, 0, 0, &context->ui)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   LayerInput layer = { | 
		
	
		
			
				|  |  |  |  |     .strings = strings, | 
		
	
		
			
				|  |  |  |  |     .num_strings = sizeof(strings)/sizeof(GPUString), | 
		
	
		
			
				|  |  |  |  |     .max_strings = sizeof(strings)/sizeof(GPUString) + 4, | 
		
	
		
			
				|  |  |  |  |     .max_codes = 100, | 
		
	
		
			
				|  |  |  |  |     .drawables = drawables, | 
		
	
		
			
				|  |  |  |  |     .num_drawables = sizeof(drawables)/sizeof(GPUDrawable), | 
		
	
		
			
				|  |  |  |  |     .max_codes = 8, | 
		
	
		
			
				|  |  |  |  |     .codes = codes, | 
		
	
		
			
				|  |  |  |  |     .num_codes = strlen(ModeStrings[MODE_NONE]), | 
		
	
		
			
				|  |  |  |  |     .num_strings = 1, | 
		
	
		
			
				|  |  |  |  |     .strings = &string, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   ContainerInput container = { | 
		
	
		
			
				|  |  |  |  |     .id = 0x01, | 
		
	
		
			
				|  |  |  |  |     .size = {225, 155}, | 
		
	
		
			
				|  |  |  |  |     .offset = {0, 0}, | 
		
	
		
			
				|  |  |  |  |     .anchor = ANCHOR_TOP_RIGHT, | 
		
	
		
			
				|  |  |  |  |     .layers = &layer, | 
		
	
		
			
				|  |  |  |  |     .id = MODE_STRING_CONTAINER_ID, | 
		
	
		
			
				|  |  |  |  |     .layer_count = 1, | 
		
	
		
			
				|  |  |  |  |     .layers = &layer, | 
		
	
		
			
				|  |  |  |  |     .anchor = ANCHOR_TOP_LEFT, | 
		
	
		
			
				|  |  |  |  |     .size = {160, 40}, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return create_container(&container, &context->render, &context->ui); | 
		
	
		
			
				|  |  |  |  |   return load_container(&container, &context->render, &context->ui); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult update_region_info_ui(ClientContext* context) {  | 
		
	
		
			
				|  |  |  |  |   char temp[20]; | 
		
	
		
			
				|  |  |  |  |   VkResult result; | 
		
	
		
			
				|  |  |  |  | VkResult update_mode_string(ClientContext* context, EditorData* data) {  | 
		
	
		
			
				|  |  |  |  |   return update_ui_string(ModeStrings[data->mode], MODE_STRING_CONTAINER_ID, 0, 0, &context->ui, &context->render); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void editor_key_callback(ClientContext* context, int key, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   EditorData* data = context->app_data; | 
		
	
		
			
				|  |  |  |  |   for(uint32_t i = 0; i < data->mode_key_counts[data->mode]; i++) { | 
		
	
		
			
				|  |  |  |  |     if(data->mode_keys[data->mode][i].key == key) { | 
		
	
		
			
				|  |  |  |  |       data->mode_keys[data->mode][i].logic(data, context, action, mods); | 
		
	
		
			
				|  |  |  |  |       return; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if(data->selected_region >= MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |     snprintf(temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x01, 0, 0, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x01, 0, 1, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x01, 0, 2, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x01, 0, 3, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |     HexRegion* selected_region = context->hex.regions[data->selected_region]; | 
		
	
		
			
				|  |  |  |  |     snprintf(temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "Region %4d", data->selected_region); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x01, 0, 0, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "Q: %4d", selected_region->data.position.q); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x01, 0, 1, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "R: %4d", selected_region->data.position.r); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x01, 0, 2, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "Y: %4d", selected_region->data.y); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x01, 0, 3, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  |   for(uint32_t i = 0; i < data->mode_key_counts[MODE_NONE]; i++) { | 
		
	
		
			
				|  |  |  |  |     if(data->mode_keys[MODE_NONE][i].key == key) { | 
		
	
		
			
				|  |  |  |  |       data->mode_keys[MODE_NONE][i].logic(data, context, action, mods); | 
		
	
		
			
				|  |  |  |  |       return; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return VK_SUCCESS; | 
		
	
		
			
				|  |  |  |  | void spin_cam(ClientContext* context, int action, int mods, unsigned int axis, float amount) { | 
		
	
		
			
				|  |  |  |  |   (void)mods; | 
		
	
		
			
				|  |  |  |  |   if(action == GLFW_PRESS) context->spin[axis] += amount; | 
		
	
		
			
				|  |  |  |  |   else if(action == GLFW_RELEASE) context->spin[axis] -= amount; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult update_hex_info_ui(ClientContext* context) {  | 
		
	
		
			
				|  |  |  |  |   char temp[20]; | 
		
	
		
			
				|  |  |  |  |   VkResult result; | 
		
	
		
			
				|  |  |  |  |   EditorData* data = context->app_data; | 
		
	
		
			
				|  |  |  |  | void spin_cam_left(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   spin_cam(context, action, mods, 0, -1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void spin_cam_right(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   spin_cam(context, action, mods, 0, 1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if(data->clicked_region >= MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 0, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 1, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 2, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 3, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 4, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 5, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 6, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         ""); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 7, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |     HexRegion* region = context->hex.regions[data->clicked_region]; | 
		
	
		
			
				|  |  |  |  |     GPUHex* hex = ®ion->data.hexes[data->clicked_hex]; | 
		
	
		
			
				|  |  |  |  |     snprintf(temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "%d-%d", | 
		
	
		
			
				|  |  |  |  |         data->clicked_region, | 
		
	
		
			
				|  |  |  |  |         data->clicked_hex); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 0, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     HexCoord hex_world; | 
		
	
		
			
				|  |  |  |  |     hex_qr(data->clicked_hex, &hex_world); | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "region: %d\n", data->clicked_region); | 
		
	
		
			
				|  |  |  |  |     HexCoord region_coord = {region->data.position.q, region->data.position.r}; | 
		
	
		
			
				|  |  |  |  |     HexCoord region_world; | 
		
	
		
			
				|  |  |  |  |     region_qr(region_coord, ®ion_world); | 
		
	
		
			
				|  |  |  |  |     hex_add(region_world, &hex_world); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "%d, %d, %d, %d", | 
		
	
		
			
				|  |  |  |  |         hex_world.q, | 
		
	
		
			
				|  |  |  |  |         hex_world.r, | 
		
	
		
			
				|  |  |  |  |         region->data.y, | 
		
	
		
			
				|  |  |  |  |         data->clicked_vertex); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 1, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "%02.02f %02.02f %02.02f", | 
		
	
		
			
				|  |  |  |  |         hex->height[0], hex->height[1], hex->height[2]); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 2, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "%02.02f %02.02f %02.02f", | 
		
	
		
			
				|  |  |  |  |         hex->height[3], hex->height[4], hex->height[5]); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 3, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "%08X", | 
		
	
		
			
				|  |  |  |  |         hex->color[0]); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 4, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "%08X %08X", | 
		
	
		
			
				|  |  |  |  |         hex->color[1], hex->color[2]); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 5, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "%08X %08X", | 
		
	
		
			
				|  |  |  |  |         hex->color[3], hex->color[4]); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 6, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     snprintf( | 
		
	
		
			
				|  |  |  |  |         temp, | 
		
	
		
			
				|  |  |  |  |         sizeof(temp), | 
		
	
		
			
				|  |  |  |  |         "%08X %08X", | 
		
	
		
			
				|  |  |  |  |         hex->color[5], hex->color[6]); | 
		
	
		
			
				|  |  |  |  |     VK_RESULT(update_ui_string(temp, 0x02, 0, 7, &context->ui, &context->render)); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | void spin_cam_up(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   spin_cam(context, action, mods, 1, 1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return VK_SUCCESS; | 
		
	
		
			
				|  |  |  |  | void spin_cam_down(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   spin_cam(context, action, mods, 1, -1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | bool editor_key_callback(ClientContext* context, int key, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   uint32_t start, next_region; | 
		
	
		
			
				|  |  |  |  | void move_cam(ClientContext* context, int action, int mods, unsigned int axis, float amount) { | 
		
	
		
			
				|  |  |  |  |   (void)mods; | 
		
	
		
			
				|  |  |  |  |   if(action == GLFW_PRESS) context->velocity[axis] += amount; | 
		
	
		
			
				|  |  |  |  |   else if(action == GLFW_RELEASE) context->velocity[axis] -= amount; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if(action != GLFW_PRESS) return false; | 
		
	
		
			
				|  |  |  |  | void move_cam_up(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   move_cam(context, action, mods, 1, 1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   EditorData* data = context->app_data; | 
		
	
		
			
				|  |  |  |  |   HexRegion* region = NULL; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   switch(key) { | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_EQUAL: | 
		
	
		
			
				|  |  |  |  |     data->selected_region = add_hex_region(context); | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     update_hex_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_MINUS: | 
		
	
		
			
				|  |  |  |  |     if(data->selected_region < MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |       free_hex_region(data->selected_region, &context->hex, &context->render); | 
		
	
		
			
				|  |  |  |  |       start = data->selected_region; | 
		
	
		
			
				|  |  |  |  |       next_region = start; | 
		
	
		
			
				|  |  |  |  |       do { | 
		
	
		
			
				|  |  |  |  |         next_region -= 1; | 
		
	
		
			
				|  |  |  |  |         if(next_region > MAX_LOADED_REGIONS) next_region = MAX_LOADED_REGIONS; | 
		
	
		
			
				|  |  |  |  |         if(next_region != MAX_LOADED_REGIONS && context->hex.regions[next_region] != NULL) break; | 
		
	
		
			
				|  |  |  |  |       } while(next_region != start); | 
		
	
		
			
				|  |  |  |  |       if(next_region == start) { | 
		
	
		
			
				|  |  |  |  |         data->selected_region = MAX_LOADED_REGIONS; | 
		
	
		
			
				|  |  |  |  |       } else { | 
		
	
		
			
				|  |  |  |  |         data->selected_region = next_region; | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |       update_hex_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_LEFT_BRACKET: | 
		
	
		
			
				|  |  |  |  |     start = data->selected_region; | 
		
	
		
			
				|  |  |  |  |     next_region = start; | 
		
	
		
			
				|  |  |  |  |     do { | 
		
	
		
			
				|  |  |  |  |       next_region -= 1; | 
		
	
		
			
				|  |  |  |  |       if(next_region > MAX_LOADED_REGIONS) next_region = MAX_LOADED_REGIONS; | 
		
	
		
			
				|  |  |  |  |       if(next_region != MAX_LOADED_REGIONS && context->hex.regions[next_region] != NULL) break; | 
		
	
		
			
				|  |  |  |  |     } while(next_region != start); | 
		
	
		
			
				|  |  |  |  |     data->selected_region = next_region; | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_RIGHT_BRACKET: | 
		
	
		
			
				|  |  |  |  |     start = data->selected_region; | 
		
	
		
			
				|  |  |  |  |     next_region = start; | 
		
	
		
			
				|  |  |  |  |     do { | 
		
	
		
			
				|  |  |  |  |       next_region += 1; | 
		
	
		
			
				|  |  |  |  |       if(next_region > MAX_LOADED_REGIONS) next_region = 0; | 
		
	
		
			
				|  |  |  |  |       if(next_region != MAX_LOADED_REGIONS && context->hex.regions[next_region] != NULL) break; | 
		
	
		
			
				|  |  |  |  |     } while(next_region != start); | 
		
	
		
			
				|  |  |  |  |     data->selected_region = next_region; | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_I: | 
		
	
		
			
				|  |  |  |  |     if(data->selected_region < MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |       context->hex.regions[data->selected_region]->data.position.q += 1; | 
		
	
		
			
				|  |  |  |  |       add_transfer( | 
		
	
		
			
				|  |  |  |  |           &context->hex.regions[data->selected_region]->data.position, | 
		
	
		
			
				|  |  |  |  |           context->hex.regions[data->selected_region]->region, | 
		
	
		
			
				|  |  |  |  |           offsetof(GPUHexRegion, position), | 
		
	
		
			
				|  |  |  |  |           sizeof(uint32_t), | 
		
	
		
			
				|  |  |  |  |           context->render.current_frame, | 
		
	
		
			
				|  |  |  |  |           &context->render); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_K: | 
		
	
		
			
				|  |  |  |  |     if(data->selected_region < MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |       context->hex.regions[data->selected_region]->data.position.q -= 1; | 
		
	
		
			
				|  |  |  |  |       add_transfer( | 
		
	
		
			
				|  |  |  |  |           &context->hex.regions[data->selected_region]->data.position.q, | 
		
	
		
			
				|  |  |  |  |           context->hex.regions[data->selected_region]->region, | 
		
	
		
			
				|  |  |  |  |           offsetof(GPUHexRegion, position) + offsetof(HexCoord, q), | 
		
	
		
			
				|  |  |  |  |           sizeof(uint32_t), | 
		
	
		
			
				|  |  |  |  |           context->render.current_frame, | 
		
	
		
			
				|  |  |  |  |           &context->render); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_J: | 
		
	
		
			
				|  |  |  |  |     if(data->selected_region < MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |       context->hex.regions[data->selected_region]->data.position.r += 1; | 
		
	
		
			
				|  |  |  |  |       add_transfer( | 
		
	
		
			
				|  |  |  |  |           &context->hex.regions[data->selected_region]->data.position.r, | 
		
	
		
			
				|  |  |  |  |           context->hex.regions[data->selected_region]->region, | 
		
	
		
			
				|  |  |  |  |           offsetof(GPUHexRegion, position) + offsetof(HexCoord, r), | 
		
	
		
			
				|  |  |  |  |           sizeof(uint32_t), | 
		
	
		
			
				|  |  |  |  |           context->render.current_frame, | 
		
	
		
			
				|  |  |  |  |           &context->render); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_L: | 
		
	
		
			
				|  |  |  |  |     if(data->selected_region < MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |       context->hex.regions[data->selected_region]->data.position.r -= 1; | 
		
	
		
			
				|  |  |  |  |       add_transfer( | 
		
	
		
			
				|  |  |  |  |           &context->hex.regions[data->selected_region]->data.position.r, | 
		
	
		
			
				|  |  |  |  |           context->hex.regions[data->selected_region]->region, | 
		
	
		
			
				|  |  |  |  |           offsetof(GPUHexRegion, position) + offsetof(HexCoord, r), | 
		
	
		
			
				|  |  |  |  |           sizeof(uint32_t), | 
		
	
		
			
				|  |  |  |  |           context->render.current_frame, | 
		
	
		
			
				|  |  |  |  |           &context->render); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_O: | 
		
	
		
			
				|  |  |  |  |     if(data->selected_region < MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |       context->hex.regions[data->selected_region]->data.y += 1; | 
		
	
		
			
				|  |  |  |  |       add_transfer( | 
		
	
		
			
				|  |  |  |  |           &context->hex.regions[data->selected_region]->data.y, | 
		
	
		
			
				|  |  |  |  |           context->hex.regions[data->selected_region]->region, | 
		
	
		
			
				|  |  |  |  |           offsetof(GPUHexRegion, y), | 
		
	
		
			
				|  |  |  |  |           sizeof(int32_t), | 
		
	
		
			
				|  |  |  |  |           context->render.current_frame, | 
		
	
		
			
				|  |  |  |  |           &context->render); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_U: | 
		
	
		
			
				|  |  |  |  |     if(data->selected_region < MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |       context->hex.regions[data->selected_region]->data.y -= 1; | 
		
	
		
			
				|  |  |  |  |       add_transfer( | 
		
	
		
			
				|  |  |  |  |           &context->hex.regions[data->selected_region]->data.y, | 
		
	
		
			
				|  |  |  |  |           context->hex.regions[data->selected_region]->region, | 
		
	
		
			
				|  |  |  |  |           offsetof(GPUHexRegion, y), | 
		
	
		
			
				|  |  |  |  |           sizeof(int32_t), | 
		
	
		
			
				|  |  |  |  |           context->render.current_frame, | 
		
	
		
			
				|  |  |  |  |           &context->render); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     update_region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_Y: | 
		
	
		
			
				|  |  |  |  |     if(data->clicked_region < MAX_LOADED_REGIONS && data->clicked_vertex != 0) { | 
		
	
		
			
				|  |  |  |  |       region = context->hex.regions[data->clicked_region]; | 
		
	
		
			
				|  |  |  |  |       float height = region->data.hexes[data->clicked_hex].height[data->clicked_vertex-1] + 0.1;  | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       if(~mods & GLFW_MOD_CONTROL) { | 
		
	
		
			
				|  |  |  |  |         uint32_t n_vertex[2], n_hex[2]; | 
		
	
		
			
				|  |  |  |  |         HexCoord n_region[2]; | 
		
	
		
			
				|  |  |  |  |         HexCoord world, region_center; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         region_qr(region->data.position, ®ion_center); | 
		
	
		
			
				|  |  |  |  |         hex_qr(data->clicked_hex, &world); | 
		
	
		
			
				|  |  |  |  |         hex_add(region_center, &world); | 
		
	
		
			
				|  |  |  |  |         hex_vertex_neighbors(data->clicked_vertex, world, n_vertex, n_region, n_hex);   | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         uint32_t n0, n1; | 
		
	
		
			
				|  |  |  |  |         first_matching_region(n_region[0], region->data.y, &n0, &context->hex); | 
		
	
		
			
				|  |  |  |  |         first_matching_region(n_region[1], region->data.y, &n1, &context->hex); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         if(n0 != MAX_LOADED_REGIONS) set_vertex_height(height, n0, n_hex[0], n_vertex[0], context); | 
		
	
		
			
				|  |  |  |  |         if(n1 != MAX_LOADED_REGIONS) set_vertex_height(height, n1, n_hex[1], n_vertex[1], context); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       set_vertex_height(height, data->clicked_region, data->clicked_hex, data->clicked_vertex, context); | 
		
	
		
			
				|  |  |  |  |       update_hex_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  | void move_cam_down(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   move_cam(context, action, mods, 1, -1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_H: | 
		
	
		
			
				|  |  |  |  |     if(data->clicked_region < MAX_LOADED_REGIONS && data->clicked_vertex != 0) { | 
		
	
		
			
				|  |  |  |  |       region = context->hex.regions[data->clicked_region]; | 
		
	
		
			
				|  |  |  |  |       float height = region->data.hexes[data->clicked_hex].height[data->clicked_vertex-1] - 0.1;  | 
		
	
		
			
				|  |  |  |  | void move_cam_left(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   move_cam(context, action, mods, 0, -1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       if(~mods & GLFW_MOD_CONTROL) { | 
		
	
		
			
				|  |  |  |  |         uint32_t n_vertex[2], n_hex[2]; | 
		
	
		
			
				|  |  |  |  |         HexCoord n_region[2]; | 
		
	
		
			
				|  |  |  |  |         HexCoord world, region_center; | 
		
	
		
			
				|  |  |  |  | void move_cam_right(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   move_cam(context, action, mods, 0, 1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         region_qr(region->data.position, ®ion_center); | 
		
	
		
			
				|  |  |  |  |         hex_qr(data->clicked_hex, &world); | 
		
	
		
			
				|  |  |  |  |         hex_add(region_center, &world); | 
		
	
		
			
				|  |  |  |  |         hex_vertex_neighbors(data->clicked_vertex, world, n_vertex, n_region, n_hex);   | 
		
	
		
			
				|  |  |  |  | void move_cam_forward(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   move_cam(context, action, mods, 2, 1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         uint32_t n0, n1; | 
		
	
		
			
				|  |  |  |  |         first_matching_region(n_region[0], region->data.y, &n0, &context->hex); | 
		
	
		
			
				|  |  |  |  |         first_matching_region(n_region[1], region->data.y, &n1, &context->hex); | 
		
	
		
			
				|  |  |  |  | void move_cam_backwards(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)data; | 
		
	
		
			
				|  |  |  |  |   move_cam(context, action, mods, 2, -1); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         if(n0 != MAX_LOADED_REGIONS) set_vertex_height(height, n0, n_hex[0], n_vertex[0], context); | 
		
	
		
			
				|  |  |  |  |         if(n1 != MAX_LOADED_REGIONS) set_vertex_height(height, n1, n_hex[1], n_vertex[1], context); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       set_vertex_height(height, data->clicked_region, data->clicked_hex, data->clicked_vertex, context); | 
		
	
		
			
				|  |  |  |  |       update_hex_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   case GLFW_KEY_E: | 
		
	
		
			
				|  |  |  |  |     if(data->clicked_region < MAX_LOADED_REGIONS) { | 
		
	
		
			
				|  |  |  |  |       region = context->hex.regions[data->clicked_region]; | 
		
	
		
			
				|  |  |  |  |       uint32_t n_vertex[2], n_hex[2]; | 
		
	
		
			
				|  |  |  |  |       HexCoord n_region[2]; | 
		
	
		
			
				|  |  |  |  |       HexCoord world, region_center; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       if(data->clicked_vertex != 0 && data->clicked_vertex <= 6) { | 
		
	
		
			
				|  |  |  |  |         region_qr(region->data.position, ®ion_center); | 
		
	
		
			
				|  |  |  |  |         hex_qr(data->clicked_hex, &world); | 
		
	
		
			
				|  |  |  |  |         hex_add(region_center, &world); | 
		
	
		
			
				|  |  |  |  |         hex_vertex_neighbors(data->clicked_vertex, world, n_vertex, n_region, n_hex);   | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         uint32_t n0, n1; | 
		
	
		
			
				|  |  |  |  |         first_matching_region(n_region[0], region->data.y, &n0, &context->hex); | 
		
	
		
			
				|  |  |  |  |         first_matching_region(n_region[1], region->data.y, &n1, &context->hex); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         if(n0 != MAX_LOADED_REGIONS) set_vertex_color(data->current, n0, n_hex[0], n_vertex[0], context); | 
		
	
		
			
				|  |  |  |  |         if(n1 != MAX_LOADED_REGIONS) set_vertex_color(data->current, n1, n_hex[1], n_vertex[1], context); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       set_vertex_color(data->current, data->clicked_region, data->clicked_hex, data->clicked_vertex, context); | 
		
	
		
			
				|  |  |  |  |       update_hex_info_ui(context); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  | void clear_mode(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)mods; | 
		
	
		
			
				|  |  |  |  |   if(action == GLFW_PRESS) { | 
		
	
		
			
				|  |  |  |  |     data->mode = MODE_NONE; | 
		
	
		
			
				|  |  |  |  |     update_mode_string(context, data); | 
		
	
		
			
				|  |  |  |  |     data->selected_count = 0; | 
		
	
		
			
				|  |  |  |  |     unload_container(COLOR_PICK_CONTAINER_ID, &context->render, &context->ui); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void enter_vertex_mode(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)mods; | 
		
	
		
			
				|  |  |  |  |   if(action == GLFW_PRESS) { | 
		
	
		
			
				|  |  |  |  |     data->mode = MODE_VERTEX; | 
		
	
		
			
				|  |  |  |  |     update_mode_string(context, data); | 
		
	
		
			
				|  |  |  |  |     data->selected_count = 0; | 
		
	
		
			
				|  |  |  |  |     color_ui(context); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void enter_neighbor_mode(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)mods; | 
		
	
		
			
				|  |  |  |  |   if(action == GLFW_PRESS) { | 
		
	
		
			
				|  |  |  |  |     data->mode = MODE_NEIGHBOR; | 
		
	
		
			
				|  |  |  |  |     update_mode_string(context, data); | 
		
	
		
			
				|  |  |  |  |     data->selected_count = 0; | 
		
	
		
			
				|  |  |  |  |     color_ui(context); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void enter_hex_mode(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)mods; | 
		
	
		
			
				|  |  |  |  |   if(action == GLFW_PRESS) { | 
		
	
		
			
				|  |  |  |  |     data->mode = MODE_HEX; | 
		
	
		
			
				|  |  |  |  |     update_mode_string(context, data); | 
		
	
		
			
				|  |  |  |  |     data->selected_count = 0; | 
		
	
		
			
				|  |  |  |  |     color_ui(context); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return false; | 
		
	
		
			
				|  |  |  |  | void enter_region_mode(EditorData* data, ClientContext* context, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   (void)mods; | 
		
	
		
			
				|  |  |  |  |   if(action == GLFW_PRESS) { | 
		
	
		
			
				|  |  |  |  |     data->mode = MODE_REGION; | 
		
	
		
			
				|  |  |  |  |     update_mode_string(context, data); | 
		
	
		
			
				|  |  |  |  |     data->selected_count = 0; | 
		
	
		
			
				|  |  |  |  |     unload_container(COLOR_PICK_CONTAINER_ID, &context->render, &context->ui); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void editor_startup(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  |   region_info_ui(context); | 
		
	
		
			
				|  |  |  |  |   hex_info_ui(context); | 
		
	
		
			
				|  |  |  |  |   color_ui(context); | 
		
	
		
			
				|  |  |  |  |   mode_string_ui(context); | 
		
	
		
			
				|  |  |  |  |   // TODO: Remove when region mode is implemented
 | 
		
	
		
			
				|  |  |  |  |   add_hex_region(context); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void resize_selected(EditorData* data, unsigned int size) { | 
		
	
		
			
				|  |  |  |  |   uint32_t* new_regions = malloc(sizeof(uint32_t)*size); | 
		
	
		
			
				|  |  |  |  |   uint32_t* new_hexes = malloc(sizeof(uint32_t)*size); | 
		
	
		
			
				|  |  |  |  |   uint32_t* new_vertices = malloc(sizeof(uint32_t)*size); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if(data->selected_regions != NULL) { | 
		
	
		
			
				|  |  |  |  |     memcpy(new_regions, data->selected_regions, data->selected_count); | 
		
	
		
			
				|  |  |  |  |     free(data->selected_regions); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if(data->selected_hexes != NULL) { | 
		
	
		
			
				|  |  |  |  |     memcpy(new_hexes, data->selected_hexes, data->selected_count); | 
		
	
		
			
				|  |  |  |  |     free(data->selected_hexes); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if(data->selected_vertices != NULL) { | 
		
	
		
			
				|  |  |  |  |     memcpy(new_vertices, data->selected_vertices, data->selected_count); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   data->selected_regions = new_regions; | 
		
	
		
			
				|  |  |  |  |   data->selected_hexes = new_hexes; | 
		
	
		
			
				|  |  |  |  |   data->selected_vertices = new_vertices; | 
		
	
		
			
				|  |  |  |  |   data->selected_max = size; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | int main() { | 
		
	
		
			
				|  |  |  |  |   EditorData* data = malloc(sizeof(EditorData)); | 
		
	
		
			
				|  |  |  |  |   memset(data, 0, sizeof(EditorData)); | 
		
	
		
			
				|  |  |  |  |   data->selected_region = MAX_LOADED_REGIONS; | 
		
	
		
			
				|  |  |  |  |   data->clicked_region = MAX_LOADED_REGIONS; | 
		
	
		
			
				|  |  |  |  |   data->clicked_hex = UINT32_MAX; | 
		
	
		
			
				|  |  |  |  |   data->clicked_vertex = UINT32_MAX; | 
		
	
		
			
				|  |  |  |  |   data->selected_count = 0; | 
		
	
		
			
				|  |  |  |  |   resize_selected(data, 1); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   data->mode_key_counts[MODE_NONE] = 15; | 
		
	
		
			
				|  |  |  |  |   for(int i = 0; i < MODE_MAX_ENUM; i++) { | 
		
	
		
			
				|  |  |  |  |     data->mode_keys[i] = malloc(sizeof(ModeKey)*data->mode_key_counts[i]); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Mode Switches 
 | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][0].key = GLFW_KEY_ESCAPE; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][0].logic = clear_mode; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][1].key = GLFW_KEY_V; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][1].logic = enter_vertex_mode; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][2].key = GLFW_KEY_N; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][2].logic = enter_neighbor_mode; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][3].key = GLFW_KEY_H; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][3].logic = enter_hex_mode; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][4].key = GLFW_KEY_R; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][4].logic = enter_region_mode; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Camera Movement
 | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][5].key = GLFW_KEY_SPACE; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][5].logic = move_cam_up; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][6].key = GLFW_KEY_LEFT_SHIFT; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][6].logic = move_cam_down; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][7].key = GLFW_KEY_LEFT; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][7].logic = move_cam_left; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][8].key = GLFW_KEY_RIGHT; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][8].logic = move_cam_right; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][9].key = GLFW_KEY_UP; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][9].logic = move_cam_forward; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][10].key = GLFW_KEY_DOWN; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][10].logic = move_cam_backwards; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Camera Spin
 | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][11].key = GLFW_KEY_A; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][11].logic = spin_cam_left; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][12].key = GLFW_KEY_D; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][12].logic = spin_cam_right; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][13].key = GLFW_KEY_W; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][13].logic = spin_cam_up; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][14].key = GLFW_KEY_S; | 
		
	
		
			
				|  |  |  |  |   data->mode_keys[MODE_NONE][14].logic = spin_cam_down; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return run_app(data, editor_startup, NULL, NULL, editor_key_callback, NULL, NULL, NULL); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					|  |  |  | 
 |