Initial commit
This commit is contained in:
commit
48a86027ba
16 changed files with 80801 additions and 0 deletions
3714
src/cached/cimgui.cpp
Normal file
3714
src/cached/cimgui.cpp
Normal file
File diff suppressed because it is too large
Load diff
3861
src/cached/cimgui.h
Normal file
3861
src/cached/cimgui.h
Normal file
File diff suppressed because it is too large
Load diff
69600
src/cached/cimgui.json
Normal file
69600
src/cached/cimgui.json
Normal file
File diff suppressed because it is too large
Load diff
107
src/cached/cimgui_impl_vulkan.cpp
Normal file
107
src/cached/cimgui_impl_vulkan.cpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// THIS FILE HAS BEEN AUTO-GENERATED BY THE 'DEAR BINDINGS' GENERATOR.
|
||||
// **DO NOT EDIT DIRECTLY**
|
||||
// https://github.com/dearimgui/dear_bindings
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_vulkan.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// Wrap this in a namespace to keep it separate from the C++ API
|
||||
namespace cimgui
|
||||
{
|
||||
#include "cimgui_impl_vulkan.h"
|
||||
}
|
||||
|
||||
// By-value struct conversions
|
||||
|
||||
// Function stubs
|
||||
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
CIMGUI_IMPL_API bool cimgui::cImGui_ImplVulkan_Init(cimgui::ImGui_ImplVulkan_InitInfo* info)
|
||||
{
|
||||
return ::ImGui_ImplVulkan_Init(reinterpret_cast<::ImGui_ImplVulkan_InitInfo*>(info));
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkan_Shutdown(void)
|
||||
{
|
||||
::ImGui_ImplVulkan_Shutdown();
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkan_NewFrame(void)
|
||||
{
|
||||
::ImGui_ImplVulkan_NewFrame();
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkan_RenderDrawData(cimgui::ImDrawData* draw_data, VkCommandBuffer command_buffer)
|
||||
{
|
||||
::ImGui_ImplVulkan_RenderDrawData(reinterpret_cast<::ImDrawData*>(draw_data), command_buffer);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkan_RenderDrawDataEx(cimgui::ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline)
|
||||
{
|
||||
::ImGui_ImplVulkan_RenderDrawData(reinterpret_cast<::ImDrawData*>(draw_data), command_buffer, pipeline);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API bool cimgui::cImGui_ImplVulkan_CreateFontsTexture(void)
|
||||
{
|
||||
return ::ImGui_ImplVulkan_CreateFontsTexture();
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkan_DestroyFontsTexture(void)
|
||||
{
|
||||
::ImGui_ImplVulkan_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
|
||||
{
|
||||
::ImGui_ImplVulkan_SetMinImageCount(min_image_count);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API VkDescriptorSet cimgui::cImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout)
|
||||
{
|
||||
return ::ImGui_ImplVulkan_AddTexture(sampler, image_view, image_layout);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set)
|
||||
{
|
||||
::ImGui_ImplVulkan_RemoveTexture(descriptor_set);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API bool cimgui::cImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction (*loader_func)(const char* function_name, void* user_data))
|
||||
{
|
||||
return ::ImGui_ImplVulkan_LoadFunctions(loader_func);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API bool cimgui::cImGui_ImplVulkan_LoadFunctionsEx(PFN_vkVoidFunction (*loader_func)(const char* function_name, void* user_data), void* user_data)
|
||||
{
|
||||
return ::ImGui_ImplVulkan_LoadFunctions(loader_func, user_data);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, cimgui::ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
|
||||
{
|
||||
::ImGui_ImplVulkanH_CreateOrResizeWindow(instance, physical_device, device, reinterpret_cast<::ImGui_ImplVulkanH_Window*>(wd), queue_family, allocator, w, h, min_image_count);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API void cimgui::cImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, cimgui::ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
::ImGui_ImplVulkanH_DestroyWindow(instance, device, reinterpret_cast<::ImGui_ImplVulkanH_Window*>(wd), allocator);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API VkSurfaceFormatKHR cimgui::cImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
|
||||
{
|
||||
return ::ImGui_ImplVulkanH_SelectSurfaceFormat(physical_device, surface, request_formats, request_formats_count, request_color_space);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API VkPresentModeKHR cimgui::cImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count)
|
||||
{
|
||||
return ::ImGui_ImplVulkanH_SelectPresentMode(physical_device, surface, request_modes, request_modes_count);
|
||||
}
|
||||
|
||||
CIMGUI_IMPL_API int cimgui::cImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode)
|
||||
{
|
||||
return ::ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(present_mode);
|
||||
}
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
198
src/cached/cimgui_impl_vulkan.h
Normal file
198
src/cached/cimgui_impl_vulkan.h
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
// THIS FILE HAS BEEN AUTO-GENERATED BY THE 'DEAR BINDINGS' GENERATOR.
|
||||
// **DO NOT EDIT DIRECTLY**
|
||||
// https://github.com/dearimgui/dear_bindings
|
||||
|
||||
// dear imgui: Renderer Backend for Vulkan
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [x] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
|
||||
|
||||
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
|
||||
// See imgui_impl_vulkan.cpp file for details.
|
||||
|
||||
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
|
||||
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
|
||||
// You will use those if you want to use this rendering backend in your engine/app.
|
||||
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
|
||||
// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
|
||||
// Read comments in imgui_impl_vulkan.h.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "cimgui.h"
|
||||
// [Configuration] in order to use a custom Vulkan function loader:
|
||||
// (1) You'll need to disable default Vulkan function prototypes.
|
||||
// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag.
|
||||
// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit:
|
||||
// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file
|
||||
// - Or as a compilation flag in your build system
|
||||
// - Or uncomment here (not recommended because you'd be modifying imgui sources!)
|
||||
// - Do not simply add it in a .cpp file!
|
||||
// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function.
|
||||
// If you have no idea what this is, leave it alone!
|
||||
//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
|
||||
|
||||
// Convenience support for Volk
|
||||
// (you can also technically use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().)
|
||||
//#define IMGUI_IMPL_VULKAN_USE_VOLK
|
||||
|
||||
#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES)&&!defined(VK_NO_PROTOTYPES)
|
||||
#define VK_NO_PROTOTYPES
|
||||
#endif // #if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES)&&!defined(VK_NO_PROTOTYPES)
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)&&!defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif // #if defined(VK_USE_PLATFORM_WIN32_KHR)&&!defined(NOMINMAX)
|
||||
// Vulkan includes
|
||||
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
|
||||
#include <volk.h>
|
||||
#else
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif // #ifdef IMGUI_IMPL_VULKAN_USE_VOLK
|
||||
#if defined(VK_VERSION_1_3)|| defined(VK_KHR_dynamic_rendering)
|
||||
#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
#endif // #if defined(VK_VERSION_1_3)|| defined(VK_KHR_dynamic_rendering)
|
||||
// Initialization data, for ImGui_ImplVulkan_Init()
|
||||
// - VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||
// and must contain a pool size large enough to hold an ImGui VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor.
|
||||
// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure.
|
||||
// [Please zero-clear before use!]
|
||||
typedef struct ImGui_ImplVulkan_InitInfo_t
|
||||
{
|
||||
VkInstance Instance;
|
||||
VkPhysicalDevice PhysicalDevice;
|
||||
VkDevice Device;
|
||||
uint32_t QueueFamily;
|
||||
VkQueue Queue;
|
||||
VkDescriptorPool DescriptorPool; // See requirements in note above
|
||||
VkRenderPass RenderPass; // Ignored if using dynamic rendering
|
||||
uint32_t MinImageCount; // >= 2
|
||||
uint32_t ImageCount; // >= MinImageCount
|
||||
VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT
|
||||
|
||||
// (Optional)
|
||||
VkPipelineCache PipelineCache;
|
||||
uint32_t Subpass;
|
||||
|
||||
// (Optional) Dynamic Rendering
|
||||
// Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3.
|
||||
bool UseDynamicRendering;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo;
|
||||
#endif // #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
// (Optional) Allocation, Debugging
|
||||
const VkAllocationCallbacks* Allocator;
|
||||
void (*CheckVkResultFn)(VkResult err);
|
||||
VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory.
|
||||
} ImGui_ImplVulkan_InitInfo;
|
||||
|
||||
typedef struct ImDrawData_t ImDrawData;
|
||||
// Called by user code
|
||||
CIMGUI_IMPL_API bool cImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info);
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkan_Shutdown(void);
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkan_NewFrame(void);
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer); // Implied pipeline = VK_NULL_HANDLE
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkan_RenderDrawDataEx(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline /* = VK_NULL_HANDLE */);
|
||||
CIMGUI_IMPL_API bool cImGui_ImplVulkan_CreateFontsTexture(void);
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkan_DestroyFontsTexture(void);
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
|
||||
|
||||
// Register a texture (VkDescriptorSet == ImTextureID)
|
||||
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem
|
||||
// Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
|
||||
CIMGUI_IMPL_API VkDescriptorSet cImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set);
|
||||
|
||||
// Optional: load Vulkan functions with a custom function loader
|
||||
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
|
||||
CIMGUI_IMPL_API bool cImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction (*loader_func)(const char* function_name, void* user_data)); // Implied user_data = nullptr
|
||||
CIMGUI_IMPL_API bool cImGui_ImplVulkan_LoadFunctionsEx(PFN_vkVoidFunction (*loader_func)(const char* function_name, void* user_data), void* user_data /* = nullptr */);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Internal / Miscellaneous Vulkan Helpers
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
|
||||
//-------------------------------------------------------------------------
|
||||
// You probably do NOT need to use or care about those functions.
|
||||
// Those functions only exist because:
|
||||
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
|
||||
// 2) the multi-viewport / platform window implementation needs them internally.
|
||||
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
|
||||
// but it is too much code to duplicate everywhere so we exceptionally expose them.
|
||||
//
|
||||
// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
|
||||
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
|
||||
// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
typedef struct ImGui_ImplVulkanH_Frame_t ImGui_ImplVulkanH_Frame;
|
||||
typedef struct ImGui_ImplVulkanH_Window_t ImGui_ImplVulkanH_Window;
|
||||
|
||||
// Helpers
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
CIMGUI_IMPL_API void cImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator);
|
||||
CIMGUI_IMPL_API VkSurfaceFormatKHR cImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
|
||||
CIMGUI_IMPL_API VkPresentModeKHR cImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
|
||||
CIMGUI_IMPL_API int cImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
|
||||
|
||||
// Helper structure to hold the data needed by one rendering frame
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||
// [Please zero-clear before use!]
|
||||
typedef struct ImGui_ImplVulkanH_Frame_t
|
||||
{
|
||||
VkCommandPool CommandPool;
|
||||
VkCommandBuffer CommandBuffer;
|
||||
VkFence Fence;
|
||||
VkImage Backbuffer;
|
||||
VkImageView BackbufferView;
|
||||
VkFramebuffer Framebuffer;
|
||||
} ImGui_ImplVulkanH_Frame;
|
||||
|
||||
typedef struct ImGui_ImplVulkanH_FrameSemaphores_t
|
||||
{
|
||||
VkSemaphore ImageAcquiredSemaphore;
|
||||
VkSemaphore RenderCompleteSemaphore;
|
||||
} ImGui_ImplVulkanH_FrameSemaphores;
|
||||
|
||||
// Helper structure to hold the data needed by one rendering context into one OS window
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||
typedef struct ImGui_ImplVulkanH_Window_t
|
||||
{
|
||||
int Width;
|
||||
int Height;
|
||||
VkSwapchainKHR Swapchain;
|
||||
VkSurfaceKHR Surface;
|
||||
VkSurfaceFormatKHR SurfaceFormat;
|
||||
VkPresentModeKHR PresentMode;
|
||||
VkRenderPass RenderPass;
|
||||
bool UseDynamicRendering;
|
||||
bool ClearEnable;
|
||||
VkClearValue ClearValue;
|
||||
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
|
||||
uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
|
||||
uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR
|
||||
uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
|
||||
ImGui_ImplVulkanH_Frame* Frames;
|
||||
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
|
||||
} ImGui_ImplVulkanH_Window;
|
||||
#endif// #ifndef IMGUI_DISABLE
|
||||
#ifdef __cplusplus
|
||||
} // End of extern "C" block
|
||||
#endif
|
||||
2063
src/cached/cimgui_impl_vulkan.json
Normal file
2063
src/cached/cimgui_impl_vulkan.json
Normal file
File diff suppressed because it is too large
Load diff
971
src/generate.zig
Normal file
971
src/generate.zig
Normal file
|
|
@ -0,0 +1,971 @@
|
|||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Declarations = std.StringArrayHashMap(struct { is_opaque: bool });
|
||||
const max_size = 5000000;
|
||||
|
||||
// The header type we'll parse from JSON. Fields are only included as needed.
|
||||
// practice, etc.
|
||||
const Header = struct {
|
||||
defines: []Define,
|
||||
typedefs: []Typedef,
|
||||
enums: []Enum,
|
||||
structs: []const Struct,
|
||||
functions: []Function,
|
||||
|
||||
const Define = struct {
|
||||
name: []const u8,
|
||||
content: ?[]const u8 = null,
|
||||
is_internal: bool,
|
||||
conditionals: []const Conditional = &.{},
|
||||
};
|
||||
|
||||
const Typedef = struct {
|
||||
name: []const u8,
|
||||
type: Type,
|
||||
conditionals: []const Conditional = &.{},
|
||||
};
|
||||
|
||||
const Enum = struct {
|
||||
name: []const u8,
|
||||
storage_type: StorageType = .{ .declaration = .int },
|
||||
is_flags_enum: bool,
|
||||
elements: []const Element,
|
||||
is_internal: bool,
|
||||
conditionals: []const Conditional = &.{},
|
||||
|
||||
const Element = struct {
|
||||
name: []const u8,
|
||||
value: i64,
|
||||
is_count: bool,
|
||||
is_internal: bool,
|
||||
conditionals: []const Conditional = &.{},
|
||||
};
|
||||
|
||||
const StorageType = struct {
|
||||
declaration: enum { int, ImU8 },
|
||||
};
|
||||
};
|
||||
|
||||
const Struct = struct {
|
||||
name: []const u8,
|
||||
is_anonymous: bool,
|
||||
kind: enum { @"struct", @"union" },
|
||||
forward_declaration: bool,
|
||||
fields: []const Field,
|
||||
conditionals: []const Conditional = &.{},
|
||||
|
||||
const Field = struct {
|
||||
name: []const u8,
|
||||
is_anonymous: bool,
|
||||
type: Type,
|
||||
width: ?usize = null,
|
||||
default_value: ?std.json.Value = null,
|
||||
conditionals: []const Conditional = &.{},
|
||||
};
|
||||
};
|
||||
|
||||
const Function = struct {
|
||||
original_class: ?[]const u8 = null,
|
||||
name: []const u8,
|
||||
arguments: []const Argument = &.{},
|
||||
return_type: Type,
|
||||
conditionals: []const Conditional = &.{},
|
||||
|
||||
const Argument = struct {
|
||||
type: ?Type = null,
|
||||
is_varargs: bool,
|
||||
is_instance_pointer: bool,
|
||||
default_value: ?[]const u8 = null,
|
||||
};
|
||||
};
|
||||
|
||||
// `dear_bindings` doesn't parse these for us, it just forwards the c preprocessor strings.
|
||||
// This is a whitelist of the current values so that we can react appropriately as new values
|
||||
// are added.
|
||||
const Conditional = struct {
|
||||
condition: enum { ifdef, ifndef, @"if", ifnot },
|
||||
expression: enum {
|
||||
IMGUI_DISABLE_OBSOLETE_FUNCTIONS,
|
||||
IMGUI_DISABLE_OBSOLETE_KEYIO,
|
||||
IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT,
|
||||
IMGUI_USE_WCHAR32,
|
||||
ImTextureID,
|
||||
ImDrawIdx,
|
||||
ImDrawCallback,
|
||||
CIMGUI_API,
|
||||
CIMGUI_IMPL_API,
|
||||
@"defined(_MSC_VER)&&!defined(__clang__)&&!defined(__INTEL_COMPILER)&&!defined(IMGUI_DEBUG_PARANOID)",
|
||||
@"defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS)&&!defined(IMGUI_DISABLE_OBSOLETE_KEYIO)",
|
||||
IMGUI_DEFINE_MATH_OPERATORS,
|
||||
IM_COL32_R_SHIFT,
|
||||
IMGUI_USE_BGRA_PACKED_COLOR,
|
||||
IM_DRAWLIST_TEX_LINES_WIDTH_MAX,
|
||||
@"defined(IMGUI_DISABLE_METRICS_WINDOW)&&!defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS)&&!defined(IMGUI_DISABLE_DEBUG_TOOLS)",
|
||||
@"defined(IMGUI_HAS_IMSTR)",
|
||||
IMGUI_HAS_IMSTR,
|
||||
@"defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES)&&!defined(VK_NO_PROTOTYPES)",
|
||||
@"defined(VK_USE_PLATFORM_WIN32_KHR)&&!defined(NOMINMAX)",
|
||||
@"defined(VK_VERSION_1_3)|| defined(VK_KHR_dynamic_rendering)",
|
||||
IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING,
|
||||
},
|
||||
};
|
||||
|
||||
const Type = struct {
|
||||
type_details: ?Details = null,
|
||||
description: Description,
|
||||
|
||||
const Details = struct {
|
||||
flavour: enum { function_pointer },
|
||||
arguments: []const struct {
|
||||
type: Type,
|
||||
is_array: bool,
|
||||
is_varargs: bool,
|
||||
},
|
||||
return_type: *Type,
|
||||
};
|
||||
|
||||
const Description = struct {
|
||||
kind: enum { Type, Function, Array, Pointer, Builtin, User },
|
||||
storage_classes: []const enum { @"const" } = &.{},
|
||||
inner_type: ?*Description = null,
|
||||
bounds: ?[]const u8 = null, // Literal or variable
|
||||
builtin_type: ?Builtin = null,
|
||||
name: ?[]const u8 = null,
|
||||
|
||||
const Builtin = enum {
|
||||
void,
|
||||
char,
|
||||
unsigned_char,
|
||||
short,
|
||||
unsigned_short,
|
||||
int,
|
||||
unsigned_int,
|
||||
long,
|
||||
unsigned_long,
|
||||
long_long,
|
||||
unsigned_long_long,
|
||||
float,
|
||||
double,
|
||||
long_double,
|
||||
bool,
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
// Allocator and command line args
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||
.thread_safe = false,
|
||||
}){};
|
||||
defer std.debug.assert(gpa.deinit() == .ok);
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var args = try std.process.argsWithAllocator(allocator);
|
||||
std.debug.assert(args.skip());
|
||||
const in_path = args.next().?;
|
||||
const out_path = args.next().?;
|
||||
const prefix_path = args.next();
|
||||
const postfix_path = args.next();
|
||||
std.debug.assert(args.next() == null);
|
||||
|
||||
const out = try std.fs.cwd().createFile(out_path, .{});
|
||||
defer out.close();
|
||||
var buf = std.io.bufferedWriter(out.writer());
|
||||
const writer = buf.writer();
|
||||
|
||||
// Write the prefix
|
||||
if (prefix_path) |p| {
|
||||
const prefix_source = try std.fs.cwd().readFileAlloc(allocator, p, max_size);
|
||||
defer allocator.free(prefix_source);
|
||||
try writer.writeAll(prefix_source);
|
||||
try writer.writeAll("\n// End of prefix\n\n");
|
||||
}
|
||||
|
||||
// Write the source
|
||||
{
|
||||
const source = try std.fs.cwd().readFileAlloc(allocator, in_path, max_size);
|
||||
defer allocator.free(source);
|
||||
|
||||
const header = try std.json.parseFromSlice(Header, allocator, source, .{
|
||||
.ignore_unknown_fields = true,
|
||||
});
|
||||
defer header.deinit();
|
||||
|
||||
// We need the list of declarations up front.
|
||||
var declarations = try getDeclarations(allocator, &header.value);
|
||||
defer declarations.deinit();
|
||||
|
||||
// Write all defines as private constants.
|
||||
try writeDefines(writer, &header.value);
|
||||
|
||||
// Write all typedefs as private constants.
|
||||
try writeTypedefs(writer, &header.value, &declarations);
|
||||
|
||||
// Write all cimgui functions as private extern functions.
|
||||
try writeExternFunctions(writer, &header.value, &declarations);
|
||||
|
||||
// Alias cimgui free functions under Zig friendly names.
|
||||
try writeFreeFunctions(writer, &header.value);
|
||||
|
||||
// Get a list of cimgui methods. These were already written as externs, and can be aliased
|
||||
// when we write their respective types.
|
||||
var methods = try Methods.get(allocator, &header.value);
|
||||
defer methods.deinit();
|
||||
|
||||
// Write cimgui enums as Zig enums.
|
||||
try writeEnums(allocator, writer, &header.value);
|
||||
|
||||
// Write cimgui structs as Zig structs and unions.
|
||||
try writeStructs(writer, &header.value, &declarations, &methods);
|
||||
|
||||
// Write helpers used by the other generated code.
|
||||
try writeHelpers(writer);
|
||||
}
|
||||
|
||||
// Write the postfix
|
||||
if (postfix_path) |p| {
|
||||
const postfix_source = try std.fs.cwd().readFileAlloc(allocator, p, max_size);
|
||||
defer allocator.free(postfix_source);
|
||||
try writer.writeAll("\n// Start of postfix\n\n");
|
||||
try writer.writeAll(postfix_source);
|
||||
}
|
||||
|
||||
// Flush and exit
|
||||
try buf.flush();
|
||||
}
|
||||
|
||||
fn getDeclarations(allocator: Allocator, header: *const Header) !Declarations {
|
||||
var declarations = Declarations.init(allocator);
|
||||
errdefer declarations.deinit();
|
||||
for (header.structs) |ty| {
|
||||
if (skip(ty.conditionals)) continue;
|
||||
|
||||
// Check if we're a forward decl, or a packed struct.
|
||||
//
|
||||
// We *could* write out the Zig code to pack them by passing the widths in when writing
|
||||
// the type (and overwriting number types with the actual width, asserting otherwise.)
|
||||
//
|
||||
// However, we'd need to decide the correct backing type for the packed struct to make
|
||||
// it compatible with C. I'm also not 100% what the guarantees are for packed struct
|
||||
// layout in C.
|
||||
var is_opaque = false;
|
||||
if (ty.forward_declaration) {
|
||||
is_opaque = true;
|
||||
} else if (ty.kind == .@"struct") {
|
||||
for (ty.fields) |field| if (field.width != null) {
|
||||
is_opaque = true;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
const trimmed = std.mem.trimRight(u8, ty.name, "_");
|
||||
try declarations.put(trimmed, .{ .is_opaque = is_opaque });
|
||||
}
|
||||
|
||||
for (header.enums) |e| {
|
||||
if (e.is_internal) continue;
|
||||
if (skip(e.conditionals)) continue;
|
||||
|
||||
const trimmed = std.mem.trimRight(u8, e.name, "_");
|
||||
try declarations.put(trimmed, .{ .is_opaque = false });
|
||||
}
|
||||
|
||||
return declarations;
|
||||
}
|
||||
|
||||
fn writeDefines(writer: anytype, header: *const Header) !void {
|
||||
for (header.defines) |define| {
|
||||
if (define.is_internal) continue;
|
||||
if (skip(define.conditionals)) continue;
|
||||
if (define.content) |content| {
|
||||
try writer.print("const {s} = {s};\n", .{ define.name, content });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn writeTypedefs(writer: anytype, header: *const Header, declarations: *const Declarations) !void {
|
||||
for (header.typedefs) |typedef| {
|
||||
// Skip typedefs skipped by the preprocessor
|
||||
if (skip(typedef.conditionals)) continue;
|
||||
|
||||
// Skip duplicate declarations (e.g. naming enums as ints in C)
|
||||
if (declarations.contains(typedef.name)) continue;
|
||||
|
||||
// Write the typedef
|
||||
try writer.writeAll("const ");
|
||||
try writeTypeName(writer, typedef.name);
|
||||
try writer.writeAll(" = ");
|
||||
try writeType(writer, typedef.type, declarations, .{});
|
||||
try writer.writeAll(";\n");
|
||||
}
|
||||
}
|
||||
|
||||
fn writeExternFunctions(
|
||||
writer: anytype,
|
||||
header: *const Header,
|
||||
declarations: *const Declarations,
|
||||
) !void {
|
||||
for (header.functions) |function| {
|
||||
if (skip(function.conditionals)) continue;
|
||||
if (argsContainsVaList(function.arguments)) continue;
|
||||
|
||||
try writer.print("extern fn {s}(", .{function.name});
|
||||
for (function.arguments) |argument| {
|
||||
if (argument.type) |ty| {
|
||||
std.debug.assert(!argument.is_varargs);
|
||||
try writeType(writer, ty, declarations, .{
|
||||
.is_instance_pointer = argument.is_instance_pointer,
|
||||
.is_argument = true,
|
||||
.default_null = if (argument.default_value) |d| std.mem.eql(u8, d, "NULL") else false,
|
||||
});
|
||||
} else {
|
||||
std.debug.assert(argument.is_varargs);
|
||||
try writer.writeAll("...");
|
||||
}
|
||||
try writer.writeAll(", ");
|
||||
}
|
||||
try writer.writeAll(") callconv(.C) ");
|
||||
try writeType(writer, function.return_type, declarations, .{ .is_result = true });
|
||||
try writer.writeAll(";\n");
|
||||
}
|
||||
}
|
||||
|
||||
fn argsContainsVaList(arguments: []const Header.Function.Argument) bool {
|
||||
for (arguments) |argument| {
|
||||
if (argument.type) |ty| {
|
||||
if (ty.description.name) |name| {
|
||||
if (std.mem.eql(u8, name, "va_list")) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn writeFreeFunctions(writer: anytype, header: *const Header) !void {
|
||||
for (header.functions) |function| {
|
||||
if (skip(function.conditionals)) continue;
|
||||
if (function.original_class != null) continue;
|
||||
if (argsContainsVaList(function.arguments)) continue;
|
||||
|
||||
try writer.writeAll("pub const ");
|
||||
try writeFunctionName(writer, function.name);
|
||||
try writer.print(" = {s};\n", .{function.name});
|
||||
}
|
||||
}
|
||||
|
||||
const Methods = struct {
|
||||
types: std.StringArrayHashMap(std.ArrayList([]const u8)),
|
||||
|
||||
fn get(allocator: Allocator, header: *const Header) !Methods {
|
||||
// Initialize an empty method list for each type
|
||||
var types = std.StringArrayHashMap(std.ArrayList([]const u8)).init(allocator);
|
||||
errdefer types.deinit();
|
||||
errdefer for (types.values()) |methods| {
|
||||
methods.deinit();
|
||||
};
|
||||
for (header.structs) |ty| {
|
||||
const methods = std.ArrayList([]const u8).init(allocator);
|
||||
errdefer methods.deinit();
|
||||
try types.put(ty.name, methods);
|
||||
}
|
||||
|
||||
// Fill in the method lists
|
||||
for (header.functions) |function| {
|
||||
if (skip(function.conditionals)) continue;
|
||||
if (argsContainsVaList(function.arguments)) continue;
|
||||
|
||||
if (function.original_class) |class| {
|
||||
const methods = types.getPtr(class).?;
|
||||
try methods.append(function.name);
|
||||
}
|
||||
}
|
||||
|
||||
return .{ .types = types };
|
||||
}
|
||||
|
||||
fn deinit(self: *Methods) void {
|
||||
for (self.types.values()) |methods| {
|
||||
methods.deinit();
|
||||
}
|
||||
self.types.deinit();
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
fn writeEnums(allocator: Allocator, writer: anytype, header: *const Header) !void {
|
||||
for (header.enums) |e| {
|
||||
if (e.is_internal) continue;
|
||||
if (skip(e.conditionals)) continue;
|
||||
|
||||
try writer.writeAll("pub const ");
|
||||
try writeTypeName(writer, e.name);
|
||||
try writer.writeAll(" = ");
|
||||
|
||||
if (e.is_flags_enum) {
|
||||
try writeFlagsEnum(writer, e);
|
||||
} else {
|
||||
try writeNormalEnum(allocator, writer, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn writeFlagsEnum(writer: anytype, e: Header.Enum) !void {
|
||||
const backing, const backing_bits = switch (e.storage_type.declaration) {
|
||||
.int => .{"c_int", @typeInfo(c_int).Int.bits},
|
||||
.ImU8 => .{"u8", 8},
|
||||
};
|
||||
try writer.print("packed struct({s}) {{\n", .{backing});
|
||||
var current_offset: usize = 0;
|
||||
var padding_i: usize = 0;
|
||||
for (e.elements) |element| {
|
||||
// Skip internal elements, and elements discarded by preprocessor
|
||||
if (skip(element.conditionals)) continue;
|
||||
if (element.is_internal) continue;
|
||||
if (element.value == 0) continue;
|
||||
|
||||
// Calculate the offset of this element
|
||||
const offset = std.math.log2(@as(usize, @intCast(element.value)));
|
||||
|
||||
// Sometimes at the end of flag sets, elements are defined that are combinations of
|
||||
// existing flags. Skip these--the only reasonable representation would be constants, but
|
||||
// they're hard to compose in Zig so it's not worth it.
|
||||
if (offset < current_offset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add padding to get this element to the correct offset
|
||||
const padding = offset - current_offset;
|
||||
if (padding > 0) {
|
||||
try writer.print(" __padding{}: u{} = 0,\n", .{ padding_i, padding });
|
||||
padding_i += 1;
|
||||
current_offset = offset;
|
||||
}
|
||||
|
||||
// Write the element
|
||||
try writer.writeAll(" ");
|
||||
try writeElementName(writer, e.name, element.name);
|
||||
try writer.writeAll(": bool = false,\n");
|
||||
current_offset += 1;
|
||||
}
|
||||
|
||||
// Add padding at end to make total type the correct size
|
||||
const padding = backing_bits - current_offset;
|
||||
if (padding > 0) {
|
||||
try writer.print(" __padding{}: u{} = 0,\n", .{ padding_i, padding });
|
||||
}
|
||||
|
||||
try writer.writeAll("};\n");
|
||||
}
|
||||
|
||||
fn writeNormalEnum(allocator: Allocator, writer: anytype, e: Header.Enum) !void {
|
||||
var values = std.AutoArrayHashMap(i64, void).init(allocator);
|
||||
defer values.deinit();
|
||||
|
||||
try writer.writeAll("enum(");
|
||||
switch (e.storage_type.declaration) {
|
||||
.int => try writer.writeAll("c_int"),
|
||||
.ImU8 => try writer.writeAll("u8"),
|
||||
}
|
||||
try writer.writeAll(") {\n");
|
||||
|
||||
// Write elements
|
||||
for (e.elements) |element| {
|
||||
// Skip internal and count
|
||||
if (element.is_internal) continue;
|
||||
if (element.is_count) continue;
|
||||
if (skip(element.conditionals)) continue;
|
||||
|
||||
// We skip duplicate values, these are sometimes present e.g. in the keys enum which
|
||||
// contains the mods enum and therefore two "none" options that are identical.
|
||||
if (values.contains(element.value)) continue;
|
||||
try values.put(element.value, {});
|
||||
|
||||
// Write the element
|
||||
try writer.writeAll(" ");
|
||||
try writeElementName(writer, e.name, element.name);
|
||||
try writer.print(" = {},\n", .{element.value});
|
||||
}
|
||||
|
||||
// Write constants since they're used internally, but keep them private
|
||||
for (e.elements) |element| {
|
||||
if (element.is_count) {
|
||||
try writer.writeAll(" const ");
|
||||
try writeElementName(writer, e.name, element.name);
|
||||
try writer.print(" = {};\n", .{element.value});
|
||||
}
|
||||
}
|
||||
|
||||
try writer.writeAll("};\n");
|
||||
}
|
||||
|
||||
fn writeStructs(
|
||||
writer: anytype,
|
||||
header: *const Header,
|
||||
declarations: *const Declarations,
|
||||
methods: *const Methods,
|
||||
) !void {
|
||||
for (header.structs) |ty| {
|
||||
// Skip structs skipped by the preprocessor. We don't skip structs marked as internal,
|
||||
// because many of these appear to be generally useful (it may be set incorrectly in the
|
||||
// JSON?)
|
||||
if (skip(ty.conditionals)) continue;
|
||||
|
||||
// Write the struct
|
||||
try writer.writeAll("pub const ");
|
||||
try writeTypeName(writer, ty.name);
|
||||
try writer.writeAll(" = ");
|
||||
|
||||
// If we're opaque, don't try to fill out the struct fields
|
||||
if (declarations.get(ty.name).?.is_opaque) {
|
||||
try writer.writeAll("opaque {};\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Declare the struct or union
|
||||
switch (ty.kind) {
|
||||
.@"struct" => try writer.writeAll("extern struct {\n"),
|
||||
.@"union" => try writer.writeAll("extern union {\n"),
|
||||
}
|
||||
|
||||
// Fill in the fields
|
||||
for (ty.fields) |field| {
|
||||
// Skip fields skipped by the preprocessor.
|
||||
if (skip(field.conditionals)) continue;
|
||||
|
||||
// Not yet used, but when it is we want to start using it. Safe to disable this assert
|
||||
// if you're just trying to get things working with a different version.
|
||||
if (field.default_value != null) @panic("unimplemented");
|
||||
|
||||
// Write the field.
|
||||
try writer.writeAll(" ");
|
||||
if (field.is_anonymous) {
|
||||
try writer.writeAll("data");
|
||||
} else {
|
||||
try writeFieldName(writer, field.name);
|
||||
}
|
||||
try writer.writeAll(": ");
|
||||
try writeType(writer, field.type, declarations, .{});
|
||||
try writer.writeAll(",\n");
|
||||
}
|
||||
|
||||
// Alias all relevant methods into the type.
|
||||
const method_names = methods.types.getPtr(ty.name).?;
|
||||
for (method_names.items) |name| {
|
||||
try writer.writeAll(" pub const ");
|
||||
try writeFunctionName(writer, name[ty.name.len + 1..]);
|
||||
try writer.print(" = {s};\n", .{name});
|
||||
}
|
||||
|
||||
try writer.writeAll("};\n");
|
||||
}
|
||||
}
|
||||
|
||||
fn writeHelpers(writer: anytype) !void {
|
||||
try writer.writeAll(
|
||||
\\fn toUsize(v: anytype) usize {
|
||||
\\ if (@typeInfo(@TypeOf(v)) == .Enum) return @intFromEnum(v);
|
||||
\\ return @intCast(v);
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
// Type hints aren't required, but they help us figure out the best pointer types to use.
|
||||
const WriteTypeHints = packed struct {
|
||||
is_instance_pointer: bool = false,
|
||||
is_argument: bool = false,
|
||||
default_null: bool = false,
|
||||
is_result: bool = false,
|
||||
};
|
||||
|
||||
// Write a cimgui type as a Zig type.
|
||||
fn writeType(
|
||||
writer: anytype,
|
||||
ty: Header.Type,
|
||||
declarations: *const Declarations,
|
||||
hints: WriteTypeHints,
|
||||
) @TypeOf(writer).Error!void {
|
||||
// Handle function pointers which are stored separately.
|
||||
if (ty.type_details) |details| switch (details.flavour) {
|
||||
.function_pointer => return writeFunctionPointer(writer, details, declarations),
|
||||
};
|
||||
|
||||
// Handle all other types
|
||||
switch (ty.description.kind) {
|
||||
.Builtin => return writeBuiltinType(writer, ty.description.builtin_type.?),
|
||||
.Array => return writeArrayType(writer, ty.description, declarations),
|
||||
.Pointer => return writePointerType(writer, ty, declarations, hints),
|
||||
.User => try writeTypeName(writer, ty.description.name.?),
|
||||
.Type, .Function => @panic("unimplemented"),
|
||||
}
|
||||
}
|
||||
|
||||
fn writeFunctionPointer(
|
||||
writer: anytype,
|
||||
details: Header.Type.Details,
|
||||
declarations: *const Declarations,
|
||||
) !void {
|
||||
try writer.writeAll("*const fn(");
|
||||
for (details.arguments) |argument| {
|
||||
try writeType(writer, argument.type, declarations, .{});
|
||||
try writer.writeAll(", ");
|
||||
}
|
||||
try writer.writeAll(") callconv(.C) ");
|
||||
try writeType(writer, details.return_type.*, declarations, .{});
|
||||
}
|
||||
|
||||
fn writeBuiltinType(writer: anytype, builtin_type: Header.Type.Description.Builtin) !void {
|
||||
switch (builtin_type) {
|
||||
.void => try writer.writeAll("void"),
|
||||
.char, .unsigned_char => try writer.writeAll("u8"),
|
||||
.short => try writer.writeAll("c_short"),
|
||||
.unsigned_short => try writer.writeAll("c_ushort"),
|
||||
.int => try writer.writeAll("c_int"),
|
||||
.unsigned_int => try writer.writeAll("c_uint"),
|
||||
.long => try writer.writeAll("c_long"),
|
||||
.unsigned_long => try writer.writeAll("c_ulong"),
|
||||
.long_long => try writer.writeAll("c_longlong"),
|
||||
.unsigned_long_long => try writer.writeAll("c_ulonglong"),
|
||||
.float => try writer.writeAll("f32"),
|
||||
.double => try writer.writeAll("f64"),
|
||||
.long_double => try writer.writeAll("c_longdouble"),
|
||||
.bool => try writer.writeAll("bool"),
|
||||
}
|
||||
}
|
||||
|
||||
fn writeArrayType(
|
||||
writer: anytype,
|
||||
description: Header.Type.Description,
|
||||
declarations: *const Declarations,
|
||||
) !void {
|
||||
if (description.bounds) |bounds| {
|
||||
try writeArrayBounds(writer, bounds);
|
||||
} else {
|
||||
try writer.writeAll("[*]");
|
||||
}
|
||||
try writeType(
|
||||
writer,
|
||||
.{ .description = description.inner_type.?.* },
|
||||
declarations,
|
||||
.{},
|
||||
);
|
||||
}
|
||||
|
||||
// Array bounds sometimes include expressions, so we need to tokenize them and convert the
|
||||
// expressions to Zig syntax.
|
||||
fn writeArrayBounds(writer: anytype, bounds: []const u8) !void {
|
||||
try writer.writeByte('[');
|
||||
var token_start: usize = 0;
|
||||
while (token_start < bounds.len) {
|
||||
// Calculate token start
|
||||
if (bounds[token_start] == ' ') {
|
||||
token_start += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Special handling for one character tokens
|
||||
switch (bounds[token_start]) {
|
||||
'(' => {
|
||||
const token = bounds[token_start .. token_start + 1];
|
||||
token_start += 1;
|
||||
try writer.writeAll(token);
|
||||
continue;
|
||||
},
|
||||
'+', '/' => {
|
||||
const token = bounds[token_start .. token_start + 1];
|
||||
token_start += 1;
|
||||
try writer.print(" {s} ", .{token});
|
||||
continue;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
// Calculate token end
|
||||
var token_end = token_start + 1;
|
||||
while (token_end < bounds.len) : (token_end += 1) {
|
||||
switch (bounds[token_end]) {
|
||||
' ', '+', ')', '/' => break,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
const token = bounds[token_start..token_end];
|
||||
token_start = token_end;
|
||||
|
||||
// As of the time of writing, tokens here are either numbers or enum values.
|
||||
if (std.mem.indexOfScalar(u8, token, '_')) |underscore| {
|
||||
// If it's all uppercase, it's a define. Otherwise it's an enum.
|
||||
const is_define = for (token) |c| {
|
||||
switch (c) {
|
||||
'a'...'z' => break false,
|
||||
else => {},
|
||||
}
|
||||
} else true;
|
||||
|
||||
if (is_define) {
|
||||
try writer.writeAll(token);
|
||||
} else {
|
||||
try writer.writeAll("toUsize(");
|
||||
const type_name = token[0..underscore];
|
||||
try writeTypeName(writer, type_name);
|
||||
try writer.writeByte('.');
|
||||
try writeElementName(writer, type_name, token);
|
||||
try writer.writeAll(")");
|
||||
}
|
||||
} else {
|
||||
// Otherwise, just write the value as is.
|
||||
try writer.writeAll(token);
|
||||
}
|
||||
}
|
||||
try writer.writeByte(']');
|
||||
}
|
||||
|
||||
fn writePointerType(
|
||||
writer: anytype,
|
||||
ty: Header.Type,
|
||||
declarations: *const Declarations,
|
||||
hints: WriteTypeHints,
|
||||
) !void {
|
||||
// Check if we're a pointer to an opaque type
|
||||
var is_opaque = false;
|
||||
if (ty.description.inner_type.?.name) |name| {
|
||||
if (declarations.get(name)) |decl| {
|
||||
is_opaque = decl.is_opaque;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we're a pointer to void
|
||||
const is_void = ty.description.inner_type.?.builtin_type == .void;
|
||||
|
||||
// Check if we're a string
|
||||
const is_string = b: {
|
||||
if (ty.description.inner_type.?.builtin_type != .char) break :b false;
|
||||
for (ty.description.inner_type.?.*.storage_classes) |storage_class| switch (storage_class) {
|
||||
.@"const" => break :b true,
|
||||
};
|
||||
break :b false;
|
||||
};
|
||||
|
||||
// Use the hints to decide what kind of pointer we are
|
||||
if (is_string) {
|
||||
// We currently write all strings as c pointers since some are null terminated, and some are
|
||||
// not.
|
||||
try writer.writeAll("[*c]");
|
||||
} else if (hints.is_instance_pointer) {
|
||||
// We assume all instance pointers do *not* allow null.
|
||||
std.debug.assert(!hints.default_null);
|
||||
try writer.writeByte('*');
|
||||
} else if (hints.is_argument) {
|
||||
// Arguments are assumed to be single value pointers, because many value pointers when
|
||||
// passed as arguments get marked as arrays and handled separately from pointers.
|
||||
if (hints.default_null) {
|
||||
// If the default value is set to null, we must be nullable. Otherwise we conservatively
|
||||
// assume null is not allowed, which tends to be correct in practice more often than
|
||||
// not.
|
||||
try writer.writeByte('?');
|
||||
}
|
||||
try writer.writeByte('*');
|
||||
} else if (hints.is_result) {
|
||||
// Results are assumed to be single value pointers, since otherwise, we'd have no way of
|
||||
// knowing the length. We conservatively assume these are nullable since we have no way of
|
||||
// knowing. Ideally dear bindings would mark this eventually (there is a field for it but
|
||||
// it is unused), if it becomes annoying we can always add a whitelist.
|
||||
try writer.writeAll("?*");
|
||||
} else {
|
||||
// If we've reached this case, we're a struct field, and we don't know whether it's many
|
||||
// value or nullable. We fall back to a c pointer so that the user can decide how to
|
||||
// interpret it with less friction, unless it's an opaque type in which case that's not
|
||||
// allowed so we assume it's a nullable single value pointer.
|
||||
if (is_opaque or is_void) {
|
||||
try writer.writeAll("?*");
|
||||
} else {
|
||||
try writer.writeAll("[*c]");
|
||||
}
|
||||
}
|
||||
|
||||
// Write any storage classes
|
||||
for (ty.description.inner_type.?.*.storage_classes) |storage_class| switch (storage_class) {
|
||||
.@"const" => try writer.writeAll("const "),
|
||||
};
|
||||
|
||||
// Write the actual type
|
||||
if (is_void) {
|
||||
// Treat pointers to c void as pointers to anyopaque
|
||||
try writer.writeAll("anyopaque");
|
||||
} else {
|
||||
try writeType(
|
||||
writer,
|
||||
.{ .description = ty.description.inner_type.?.* },
|
||||
declarations,
|
||||
.{},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if we should skip due to a conditional
|
||||
fn skip(conditionals: []const Header.Conditional) bool {
|
||||
for (conditionals) |conditional| {
|
||||
const defined = switch (conditional.expression) {
|
||||
.IMGUI_DISABLE_OBSOLETE_FUNCTIONS,
|
||||
.IMGUI_DISABLE_OBSOLETE_KEYIO,
|
||||
.CIMGUI_API,
|
||||
.CIMGUI_IMPL_API,
|
||||
.@"defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES)&&!defined(VK_NO_PROTOTYPES)",
|
||||
.@"defined(VK_USE_PLATFORM_WIN32_KHR)&&!defined(NOMINMAX)",
|
||||
.IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING,
|
||||
.@"defined(VK_VERSION_1_3)|| defined(VK_KHR_dynamic_rendering)",
|
||||
=> true,
|
||||
.IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT,
|
||||
.IMGUI_USE_WCHAR32,
|
||||
.ImTextureID,
|
||||
.ImDrawIdx,
|
||||
.ImDrawCallback,
|
||||
.@"defined(_MSC_VER)&&!defined(__clang__)&&!defined(__INTEL_COMPILER)&&!defined(IMGUI_DEBUG_PARANOID)",
|
||||
.@"defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS)&&!defined(IMGUI_DISABLE_OBSOLETE_KEYIO)",
|
||||
.IMGUI_DEFINE_MATH_OPERATORS,
|
||||
.IM_COL32_R_SHIFT,
|
||||
.IMGUI_USE_BGRA_PACKED_COLOR,
|
||||
.IM_DRAWLIST_TEX_LINES_WIDTH_MAX,
|
||||
.@"defined(IMGUI_DISABLE_METRICS_WINDOW)&&!defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS)&&!defined(IMGUI_DISABLE_DEBUG_TOOLS)",
|
||||
.@"defined(IMGUI_HAS_IMSTR)",
|
||||
.IMGUI_HAS_IMSTR,
|
||||
=> false,
|
||||
};
|
||||
switch (conditional.condition) {
|
||||
.ifdef, .@"if" => if (!defined) return true,
|
||||
.ifndef, .ifnot => if (defined) return true,
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Converts a cimgui type name to a Zig type name
|
||||
fn writeTypeName(writer: anytype, raw: []const u8) !void {
|
||||
// These are considered user types
|
||||
if (std.mem.eql(u8, raw, "size_t")) {
|
||||
try writer.writeAll("usize");
|
||||
return;
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, raw, "uint32_t")) {
|
||||
try writer.writeAll("u32");
|
||||
return;
|
||||
}
|
||||
|
||||
// We skip all declarations that contain `va_list`, so this shouldn't trigger.
|
||||
if (std.mem.eql(u8, raw, "va_list")) unreachable;
|
||||
|
||||
// Remove prefixes
|
||||
var name = raw;
|
||||
{
|
||||
// Imgui prefixes
|
||||
{
|
||||
const prefixes: []const []const u8 = &.{ "ImGui", "Im" };
|
||||
for (prefixes) |prefix| {
|
||||
if (std.mem.startsWith(u8, name, prefix)) {
|
||||
name = name[prefix.len..];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Backend prefixes
|
||||
{
|
||||
const prefixes: []const []const u8 = &.{ "_ImplVulkanH", "_ImplVulkan" };
|
||||
for (prefixes) |prefix| {
|
||||
if (std.mem.startsWith(u8, name, prefix)) {
|
||||
name = name[prefix.len..];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (name) |c| switch (c) {
|
||||
'_' => {},
|
||||
else => try writer.writeByte(c),
|
||||
};
|
||||
}
|
||||
|
||||
// Convert a cimgui field name to a Zig field name
|
||||
fn writeFieldName(writer: anytype, name: []const u8) !void {
|
||||
var escape = false;
|
||||
for (name, 0..) |c, i| {
|
||||
switch (c) {
|
||||
'0'...'9' => {
|
||||
if (i == 0) {
|
||||
escape = true;
|
||||
try writer.writeAll("@\"");
|
||||
} else switch (name[i - 1]) {
|
||||
'0'...'9' => {},
|
||||
else => try writer.writeByte('_'),
|
||||
}
|
||||
try writer.writeByte(c);
|
||||
},
|
||||
'a'...'z' => try writer.writeByte(c),
|
||||
'A'...'Z' => {
|
||||
if (i > 0) switch (name[i - 1]) {
|
||||
'A'...'Z', '_' => {},
|
||||
else => try writer.writeByte('_'),
|
||||
};
|
||||
try writer.writeByte(c + 32);
|
||||
},
|
||||
'_' => if (i != name.len - 1) try writer.writeByte('_'),
|
||||
else => std.debug.panic("unexpected char in name: {c}", .{c}),
|
||||
}
|
||||
}
|
||||
if (escape) try writer.writeAll("\"");
|
||||
}
|
||||
|
||||
// Convert a cimgui element name to a Zig element name
|
||||
fn writeElementName(writer: anytype, type_name: []const u8, raw: []const u8) !void {
|
||||
var name = if (std.mem.startsWith(u8, raw, type_name)) raw[type_name.len..] else raw;
|
||||
name = if (std.mem.startsWith(u8, name, "ImGui")) name["ImGui".len..] else name;
|
||||
name = if (name[0] == '_') name[1..] else name;
|
||||
try writeFieldName(writer, name);
|
||||
}
|
||||
|
||||
// Write a cimgui function name as a Zig function name
|
||||
fn writeFunctionName(writer: anytype, raw: []const u8) !void {
|
||||
var name = raw;
|
||||
|
||||
// Imgui prefixes
|
||||
{
|
||||
const prefixes: []const []const u8 = &.{ "cImGui_ImplVulkan", "ImGui", "Im" };
|
||||
for (prefixes) |prefix| {
|
||||
if (std.mem.startsWith(u8, name, prefix)) {
|
||||
name = name[prefix.len..];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name[0] == '_') name = name[1..];
|
||||
|
||||
// Lowercase the first set of contiguous capital letters
|
||||
var i: usize = 0;
|
||||
while (i < name.len and name[i] >= 'A' and name[i] <= 'Z') : (i += 1) {
|
||||
try writer.writeByte(name[i] + 32);
|
||||
}
|
||||
|
||||
// The rest of the string is usually already camelcase, write it as is unless we encounter an
|
||||
// underscore in which case we should skip it an uppercase the next letter.
|
||||
if (i < name.len) {
|
||||
var uppercase_next = false;
|
||||
for (name[i..]) |c| {
|
||||
// If we're an underscore, skip it and uppercase the next letter
|
||||
if (c == '_') {
|
||||
uppercase_next = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Write the next character, adjusting the case as necessary
|
||||
switch (c) {
|
||||
'a'...'z' => try writer.writeByte(if (uppercase_next) c - 32 else c),
|
||||
else => try writer.writeByte(c),
|
||||
}
|
||||
uppercase_next = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/templates/cimgui_postfix.zig.template
Normal file
8
src/templates/cimgui_postfix.zig.template
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// It's unclear to me where the generator gets this define (maybe it's directly from the original
|
||||
// cpp header?), so we generate it manually.
|
||||
pub fn col32(r: u32, g: u32, b: u32, a: u32) u32 {
|
||||
return a << IM_COL32_A_SHIFT |
|
||||
b << IM_COL32_B_SHIFT |
|
||||
g << IM_COL32_G_SHIFT |
|
||||
r << IM_COL32_R_SHIFT;
|
||||
}
|
||||
0
src/templates/cimgui_prefix.zig.template
Normal file
0
src/templates/cimgui_prefix.zig.template
Normal file
2
src/templates/impl_vulkan_postfix.zig.template
Normal file
2
src/templates/impl_vulkan_postfix.zig.template
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
};
|
||||
}
|
||||
68
src/templates/impl_vulkan_prefix.zig.template
Normal file
68
src/templates/impl_vulkan_prefix.zig.template
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
const Options = struct {
|
||||
PFNvkVoidFunction: type,
|
||||
VkAllocationCallbacks: type,
|
||||
VkClearValue: type,
|
||||
VkColorSpaceKHR: type,
|
||||
VkCommandBuffer: type,
|
||||
VkCommandPool: type,
|
||||
VkDescriptorPool: type,
|
||||
VkDescriptorSet: type,
|
||||
VkDevice: type,
|
||||
VkDeviceSize: type,
|
||||
VkFence: type,
|
||||
VkFramebuffer: type,
|
||||
VkImage: type,
|
||||
VkImageLayout: type,
|
||||
VkImageView: type,
|
||||
VkInstance: type,
|
||||
VkPhysicalDevice: type,
|
||||
VkPipeline: type,
|
||||
VkPipelineCache: type,
|
||||
VkPipelineRenderingCreateInfoKHR: type,
|
||||
VkPresentModeKHR: type,
|
||||
VkQueue: type,
|
||||
VkRenderPass: type,
|
||||
VkResult: type,
|
||||
VkSampleCountFlagBits: type,
|
||||
VkSampler: type,
|
||||
VkSemaphore: type,
|
||||
VkSurfaceFormatKHR: type,
|
||||
VkSurfaceKHR: type,
|
||||
VkSwapchainKHR: type,
|
||||
VkFormat: type,
|
||||
};
|
||||
|
||||
pub fn get(options: Options) type {
|
||||
const VkFormat = options.VkFormat;
|
||||
const PFNvkVoidFunction = options.PFNvkVoidFunction;
|
||||
const VkAllocationCallbacks = options.VkAllocationCallbacks;
|
||||
const VkClearValue = options.VkClearValue;
|
||||
const VkColorSpaceKHR = options.VkColorSpaceKHR;
|
||||
const VkCommandBuffer = options.VkCommandBuffer;
|
||||
const VkCommandPool = options.VkCommandPool;
|
||||
const VkDescriptorPool = options.VkDescriptorPool;
|
||||
const VkDescriptorSet = options.VkDescriptorSet;
|
||||
const VkDevice = options.VkDevice;
|
||||
const VkDeviceSize = options.VkDeviceSize;
|
||||
const VkFence = options.VkFence;
|
||||
const VkFramebuffer = options.VkFramebuffer;
|
||||
const VkImage = options.VkImage;
|
||||
const VkImageLayout = options.VkImageLayout;
|
||||
const VkImageView = options.VkImageView;
|
||||
const VkInstance = options.VkInstance;
|
||||
const VkPhysicalDevice = options.VkPhysicalDevice;
|
||||
const VkPipeline = options.VkInstance;
|
||||
const VkPipelineCache = options.VkPipelineCache;
|
||||
const VkPipelineRenderingCreateInfoKHR = options.VkPipelineRenderingCreateInfoKHR;
|
||||
const VkPresentModeKHR = options.VkPresentModeKHR;
|
||||
const VkQueue = options.VkQueue;
|
||||
const VkRenderPass = options.VkRenderPass;
|
||||
const VkResult = options.VkResult;
|
||||
const VkSampleCountFlagBits = options.VkSampleCountFlagBits;
|
||||
const VkSampler = options.VkSampler;
|
||||
const VkSemaphore = options.VkSemaphore;
|
||||
const VkSurfaceFormatKHR = options.VkSurfaceFormatKHR;
|
||||
const VkSurfaceKHR = options.VkSurfaceKHR;
|
||||
const VkSwapchainKHR = options.VkSwapchainKHR;
|
||||
|
||||
return struct {
|
||||
Loading…
Add table
Add a link
Reference in a new issue