|  |  |  | @ -19,11 +19,6 @@ | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #define max(a, b) ((a > b) ? a : b) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | typedef struct GPURayStruct { | 
		
	
		
			
				|  |  |  |  |   vec4 a; | 
		
	
		
			
				|  |  |  |  |   vec4 b; | 
		
	
		
			
				|  |  |  |  | } GPURay; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | typedef struct ClientContextStruct { | 
		
	
		
			
				|  |  |  |  |   GLFWwindow* window; | 
		
	
		
			
				|  |  |  |  |   RenderContext* render; | 
		
	
	
		
			
				
					|  |  |  | @ -34,7 +29,7 @@ typedef struct ClientContextStruct { | 
		
	
		
			
				|  |  |  |  |   uint32_t clicked_element; | 
		
	
		
			
				|  |  |  |  |   int32_t  clicked_hex[2]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vec2    cursor; | 
		
	
		
			
				|  |  |  |  |   double  cursor[2]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vec3    position; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -51,12 +46,8 @@ typedef struct ClientContextStruct { | 
		
	
		
			
				|  |  |  |  |   float   zoom_speed; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   mat4 inverse; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   GraphicsPipeline ray_pipeline; | 
		
	
		
			
				|  |  |  |  |   VkBuffer ray; | 
		
	
		
			
				|  |  |  |  |   VkDeviceAddress ray_address; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation ray_memory; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vec4 cursor_ray[2]; | 
		
	
		
			
				|  |  |  |  |   vec4 click_ray[2];  | 
		
	
		
			
				|  |  |  |  | } ClientContext; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void* network_thread(void* data) { | 
		
	
	
		
			
				
					|  |  |  | @ -69,170 +60,9 @@ void* network_thread(void* data) { | 
		
	
		
			
				|  |  |  |  | vec3 zero = {0, 0, 0}; | 
		
	
		
			
				|  |  |  |  | vec3 up = {0, 1, 0}; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult create_ray_pipeline(RenderContext* gpu, GraphicsPipeline* pipeline) { | 
		
	
		
			
				|  |  |  |  |   VkResult result; | 
		
	
		
			
				|  |  |  |  |   VkShaderModule vert_shader = load_shader_file("shader/ray.vert.spv", gpu->device); | 
		
	
		
			
				|  |  |  |  |   VkShaderModule frag_shader = load_shader_file("shader/ray.frag.spv", gpu->device); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineShaderStageCreateInfo stages[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |       .stage = VK_SHADER_STAGE_VERTEX_BIT, | 
		
	
		
			
				|  |  |  |  |       .pName = "main", | 
		
	
		
			
				|  |  |  |  |       .module = vert_shader, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |       .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | 
		
	
		
			
				|  |  |  |  |       .pName = "main", | 
		
	
		
			
				|  |  |  |  |       .module = frag_shader, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPushConstantRange push = { | 
		
	
		
			
				|  |  |  |  |     .size = 2*sizeof(VkDeviceAddress), | 
		
	
		
			
				|  |  |  |  |     .offset = 0, | 
		
	
		
			
				|  |  |  |  |     .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineLayoutCreateInfo layout_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .pPushConstantRanges = &push, | 
		
	
		
			
				|  |  |  |  |     .pushConstantRangeCount = 1, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VK_RESULT(vkCreatePipelineLayout(gpu->device, &layout_info, NULL, &pipeline->layout)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineVertexInputStateCreateInfo vertex_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineInputAssemblyStateCreateInfo input_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST, | 
		
	
		
			
				|  |  |  |  |     .primitiveRestartEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkViewport viewport = { | 
		
	
		
			
				|  |  |  |  |     .x = 0.0f, | 
		
	
		
			
				|  |  |  |  |     .y = 0.0f, | 
		
	
		
			
				|  |  |  |  |     .width = (float)(100), | 
		
	
		
			
				|  |  |  |  |     .height = (float)(100), | 
		
	
		
			
				|  |  |  |  |     .minDepth = 0.0f, | 
		
	
		
			
				|  |  |  |  |     .maxDepth = 1.0f, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkRect2D scissor = { | 
		
	
		
			
				|  |  |  |  |     .offset = { | 
		
	
		
			
				|  |  |  |  |       .x = 0, | 
		
	
		
			
				|  |  |  |  |       .y = 0, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |     .extent = { | 
		
	
		
			
				|  |  |  |  |       .width = 100, | 
		
	
		
			
				|  |  |  |  |       .height = 100, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineViewportStateCreateInfo viewport_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .viewportCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pViewports = &viewport, | 
		
	
		
			
				|  |  |  |  |     .scissorCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pScissors = &scissor, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineRasterizationStateCreateInfo raster_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .depthClampEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |     .rasterizerDiscardEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |     .polygonMode = VK_POLYGON_MODE_FILL, | 
		
	
		
			
				|  |  |  |  |     .lineWidth = 1.0f, | 
		
	
		
			
				|  |  |  |  |     .cullMode = VK_CULL_MODE_BACK_BIT, | 
		
	
		
			
				|  |  |  |  |     .frontFace = VK_FRONT_FACE_CLOCKWISE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineColorBlendAttachmentState blend_attachments = { | 
		
	
		
			
				|  |  |  |  |     .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | 
		
	
		
			
				|  |  |  |  |     .blendEnable = VK_TRUE, | 
		
	
		
			
				|  |  |  |  |     .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, | 
		
	
		
			
				|  |  |  |  |     .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, | 
		
	
		
			
				|  |  |  |  |     .colorBlendOp = VK_BLEND_OP_ADD, | 
		
	
		
			
				|  |  |  |  |     .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | 
		
	
		
			
				|  |  |  |  |     .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | 
		
	
		
			
				|  |  |  |  |     .alphaBlendOp = VK_BLEND_OP_ADD, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineColorBlendStateCreateInfo blend_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .logicOpEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |     .logicOp = VK_LOGIC_OP_COPY, | 
		
	
		
			
				|  |  |  |  |     .attachmentCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pAttachments = &blend_attachments, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkDynamicState dynamic_states[] = { | 
		
	
		
			
				|  |  |  |  |     VK_DYNAMIC_STATE_VIEWPORT, | 
		
	
		
			
				|  |  |  |  |     VK_DYNAMIC_STATE_SCISSOR, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineDynamicStateCreateInfo dynamic_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .dynamicStateCount = sizeof(dynamic_states)/sizeof(VkDynamicState), | 
		
	
		
			
				|  |  |  |  |     .pDynamicStates = dynamic_states, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineMultisampleStateCreateInfo multisample_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .sampleShadingEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |     .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | 
		
	
		
			
				|  |  |  |  |     .minSampleShading = 1.0f, | 
		
	
		
			
				|  |  |  |  |     .pSampleMask = 0, | 
		
	
		
			
				|  |  |  |  |     .alphaToCoverageEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |     .alphaToOneEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineDepthStencilStateCreateInfo depth_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .depthTestEnable = VK_TRUE, | 
		
	
		
			
				|  |  |  |  |     .depthWriteEnable = VK_TRUE, | 
		
	
		
			
				|  |  |  |  |     .depthCompareOp = VK_COMPARE_OP_LESS, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkGraphicsPipelineCreateInfo pipeline_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .layout = pipeline->layout, | 
		
	
		
			
				|  |  |  |  |     .stageCount = sizeof(stages)/sizeof(VkPipelineShaderStageCreateInfo), | 
		
	
		
			
				|  |  |  |  |     .pStages = stages, | 
		
	
		
			
				|  |  |  |  |     .pVertexInputState = &vertex_info, | 
		
	
		
			
				|  |  |  |  |     .pInputAssemblyState = &input_info, | 
		
	
		
			
				|  |  |  |  |     .pViewportState = &viewport_info, | 
		
	
		
			
				|  |  |  |  |     .pRasterizationState = &raster_info, | 
		
	
		
			
				|  |  |  |  |     .pColorBlendState = &blend_info, | 
		
	
		
			
				|  |  |  |  |     .pDynamicState = &dynamic_info, | 
		
	
		
			
				|  |  |  |  |     .pMultisampleState = &multisample_info, | 
		
	
		
			
				|  |  |  |  |     .pDepthStencilState = &depth_info, | 
		
	
		
			
				|  |  |  |  |     .renderPass = gpu->render_pass, | 
		
	
		
			
				|  |  |  |  |     .subpass = 0, | 
		
	
		
			
				|  |  |  |  |     .basePipelineHandle = VK_NULL_HANDLE, | 
		
	
		
			
				|  |  |  |  |     .basePipelineIndex = -1, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return vkCreateGraphicsPipelines(gpu->device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &pipeline->pipeline); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult main_thread(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  |   VkResult result; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VK_RESULT(create_ray_pipeline(context->render, &context->ray_pipeline)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VK_RESULT(create_storage_buffer( | 
		
	
		
			
				|  |  |  |  |         context->render->allocator, | 
		
	
		
			
				|  |  |  |  |         0, | 
		
	
		
			
				|  |  |  |  |         sizeof(GPURay), | 
		
	
		
			
				|  |  |  |  |         &context->ray, | 
		
	
		
			
				|  |  |  |  |         &context->ray_memory)); | 
		
	
		
			
				|  |  |  |  |   context->ray_address = buffer_address(context->render->device, context->ray); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   GPUString strings[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .pos = {0, 32}, | 
		
	
	
		
			
				
					|  |  |  | @ -272,8 +102,8 @@ VkResult main_thread(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32_t region = 0; | 
		
	
		
			
				|  |  |  |  |   for(int32_t q = 0; q < 1; q++) { | 
		
	
		
			
				|  |  |  |  |     for(int32_t r = 0; r < 1; r++) { | 
		
	
		
			
				|  |  |  |  |   for(int32_t q = -10; q < 10; q++) { | 
		
	
		
			
				|  |  |  |  |     for(int32_t r = -10; r < 10; r++) { | 
		
	
		
			
				|  |  |  |  |       VK_RESULT(create_hex_region(q, r, ®ions[region], context->hex, context->render)); | 
		
	
		
			
				|  |  |  |  |       for(uint32_t i = 0; i < REGION_HEX_COUNT; i++) { | 
		
	
		
			
				|  |  |  |  |         for(uint32_t h = 0; h < 6; h++) { | 
		
	
	
		
			
				
					|  |  |  | @ -414,7 +244,7 @@ VkResult main_thread(ClientContext* context) { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     //
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     VkResult result = draw_frame(context->render, context->ui, context->hex, context->ray_pipeline, context->ray_address, frame_time); | 
		
	
		
			
				|  |  |  |  |     VkResult result = draw_frame(context->render, context->ui, context->hex, frame_time); | 
		
	
		
			
				|  |  |  |  |     if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |       fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result)); | 
		
	
		
			
				|  |  |  |  |       glfwDestroyWindow(context->window); | 
		
	
	
		
			
				
					|  |  |  | @ -475,6 +305,25 @@ bool contains(double* point, GPUContainer* container, GPUDrawable* rect) { | 
		
	
		
			
				|  |  |  |  |          (point[1] >= container->offset[1] && point[1] <= container->offset[1] + container->size[1]); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void cursor_to_world_ray(ClientContext* context, double cursor[2], vec4 start, vec4 end) { | 
		
	
		
			
				|  |  |  |  |   vec4 transformed_start = { | 
		
	
		
			
				|  |  |  |  |     cursor[0]*context->render->window_scale[0]*2/context->render->swapchain_extent.width - 1, | 
		
	
		
			
				|  |  |  |  |     cursor[1]*context->render->window_scale[1]*2/context->render->swapchain_extent.height - 1, | 
		
	
		
			
				|  |  |  |  |     0, | 
		
	
		
			
				|  |  |  |  |     1.0 | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vec4 transformed_end = { | 
		
	
		
			
				|  |  |  |  |     PERSPECTIVE_FARZ*(cursor[0]*context->render->window_scale[0]*2/context->render->swapchain_extent.width - 1), | 
		
	
		
			
				|  |  |  |  |     PERSPECTIVE_FARZ*(cursor[1]*context->render->window_scale[1]*2/context->render->swapchain_extent.height - 1), | 
		
	
		
			
				|  |  |  |  |     PERSPECTIVE_FARZ, | 
		
	
		
			
				|  |  |  |  |     PERSPECTIVE_FARZ, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   glm_mat4_mulv(context->inverse, transformed_start, start); | 
		
	
		
			
				|  |  |  |  |   glm_mat4_mulv(context->inverse, transformed_end, end); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { | 
		
	
		
			
				|  |  |  |  |   ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -495,24 +344,7 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) | 
		
	
		
			
				|  |  |  |  |     break; | 
		
	
		
			
				|  |  |  |  |   case GLFW_MOUSE_BUTTON_LEFT: | 
		
	
		
			
				|  |  |  |  |     if(action == GLFW_PRESS) { | 
		
	
		
			
				|  |  |  |  |       vec4 start = { | 
		
	
		
			
				|  |  |  |  |         cursor[0]*context->render->window_scale[0]*2/context->render->swapchain_extent.width - 1, | 
		
	
		
			
				|  |  |  |  |         cursor[1]*context->render->window_scale[1]*2/context->render->swapchain_extent.height - 1, | 
		
	
		
			
				|  |  |  |  |         0, | 
		
	
		
			
				|  |  |  |  |         1.0 | 
		
	
		
			
				|  |  |  |  |       }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       vec4 end = { | 
		
	
		
			
				|  |  |  |  |         PERSPECTIVE_FARZ*(cursor[0]*context->render->window_scale[0]*2/context->render->swapchain_extent.width - 1), | 
		
	
		
			
				|  |  |  |  |         PERSPECTIVE_FARZ*(cursor[1]*context->render->window_scale[1]*2/context->render->swapchain_extent.height - 1), | 
		
	
		
			
				|  |  |  |  |         PERSPECTIVE_FARZ, | 
		
	
		
			
				|  |  |  |  |         PERSPECTIVE_FARZ, | 
		
	
		
			
				|  |  |  |  |       }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       vec4 rays[2] = {}; | 
		
	
		
			
				|  |  |  |  |       glm_mat4_mulv(context->inverse, start, rays[0]); | 
		
	
		
			
				|  |  |  |  |       glm_mat4_mulv(context->inverse, end, rays[1]); | 
		
	
		
			
				|  |  |  |  |       add_transfer(rays, context->ray, 0, 2*sizeof(vec4), context->render->current_frame, context->render); | 
		
	
		
			
				|  |  |  |  |       cursor_to_world_ray(context, cursor, context->click_ray[0], context->click_ray[1]); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       for(int32_t c = context->ui->max_containers - 1; c >= 0; c--) { | 
		
	
		
			
				|  |  |  |  |         if(context->ui->containers[c].id == 0x00000000) { | 
		
	
	
		
			
				
					|  |  |  | @ -551,10 +383,10 @@ void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) { | 
		
	
		
			
				|  |  |  |  |   if(context->camera_mode == true) { | 
		
	
		
			
				|  |  |  |  |     context->cur_spin[0] = (xpos - context->cursor[0])/context->render->swapchain_extent.width*-100; | 
		
	
		
			
				|  |  |  |  |     context->cur_spin[1] = (ypos - context->cursor[1])/context->render->swapchain_extent.height*100; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     context->cursor[0] = xpos; | 
		
	
		
			
				|  |  |  |  |     context->cursor[1] = ypos; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   context->cursor[0] = xpos; | 
		
	
		
			
				|  |  |  |  |   context->cursor[1] = ypos; | 
		
	
		
			
				|  |  |  |  |   cursor_to_world_ray(context, context->cursor, context->cursor_ray[0], context->cursor_ray[1]); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | int main() { | 
		
	
	
		
			
				
					|  |  |  | 
 |