imgui

FORK: Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
git clone https://git.neptards.moe/neptards/imgui.git
Log | Files | Refs

main.cpp (10250B)


      1 // Dear ImGui: standalone example application for Emscripten, using GLFW + WebGPU
      2 // (Emscripten is a C++-to-javascript compiler, used to publish executables for the web. See https://emscripten.org/)
      3 // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
      4 // Read online: https://github.com/ocornut/imgui/tree/master/docs
      5 
      6 #include "imgui.h"
      7 #include "imgui_impl_glfw.h"
      8 #include "imgui_impl_wgpu.h"
      9 #include <stdio.h>
     10 #include <emscripten.h>
     11 #include <emscripten/html5.h>
     12 #include <emscripten/html5_webgpu.h>
     13 #include <GLFW/glfw3.h>
     14 #include <webgpu/webgpu.h>
     15 #include <webgpu/webgpu_cpp.h>
     16 
     17 // Global WebGPU required states
     18 static WGPUDevice    wgpu_device = NULL;
     19 static WGPUSurface   wgpu_surface = NULL;
     20 static WGPUSwapChain wgpu_swap_chain = NULL;
     21 static int           wgpu_swap_chain_width = 0;
     22 static int           wgpu_swap_chain_height = 0;
     23 
     24 // States tracked across render frames
     25 static bool show_demo_window = true;
     26 static bool show_another_window = false;
     27 static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
     28 
     29 // Forward declarations
     30 static bool init_wgpu();
     31 static void main_loop(void* window);
     32 static void print_glfw_error(int error, const char* description);
     33 static void print_wgpu_error(WGPUErrorType error_type, const char* message, void*);
     34 
     35 int main(int, char**)
     36 {
     37     glfwSetErrorCallback(print_glfw_error);
     38     if (!glfwInit())
     39         return 1;
     40 
     41     // Make sure GLFW does not initialize any graphics context.
     42     // This needs to be done explicitly later
     43     glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
     44 
     45     GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+WebGPU example", NULL, NULL);
     46     if (!window)
     47     {
     48         glfwTerminate();
     49         return 1;
     50     }
     51 
     52     // Initialize the WebGPU environment
     53     if (!init_wgpu())
     54     {
     55         if (window)
     56             glfwDestroyWindow(window);
     57         glfwTerminate();
     58         return 1;
     59     }
     60     glfwShowWindow(window);
     61 
     62     // Setup Dear ImGui context
     63     IMGUI_CHECKVERSION();
     64     ImGui::CreateContext();
     65     ImGuiIO& io = ImGui::GetIO(); (void)io;
     66     //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
     67     //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
     68 
     69     // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file.
     70     // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage.
     71     io.IniFilename = NULL;
     72 
     73     // Setup Dear ImGui style
     74     ImGui::StyleColorsDark();
     75     //ImGui::StyleColorsClassic();
     76 
     77     // Setup Platform/Renderer backends
     78     ImGui_ImplGlfw_InitForOther(window, true);
     79     ImGui_ImplWGPU_Init(wgpu_device, 3, WGPUTextureFormat_RGBA8Unorm);
     80 
     81     // Load Fonts
     82     // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
     83     // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
     84     // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
     85     // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
     86     // - Read 'docs/FONTS.md' for more instructions and details.
     87     // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
     88     // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details.
     89     //io.Fonts->AddFontDefault();
     90 #ifndef IMGUI_DISABLE_FILE_FUNCTIONS
     91     io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f);
     92     //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f);
     93     //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f);
     94     //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f);
     95     //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
     96     //IM_ASSERT(font != NULL);
     97 #endif
     98 
     99     // This function will directly return and exit the main function.
    100     // Make sure that no required objects get cleaned up.
    101     // This way we can use the browsers 'requestAnimationFrame' to control the rendering.
    102     emscripten_set_main_loop_arg(main_loop, window, 0, false);
    103 
    104     return 0;
    105 }
    106 
    107 static bool init_wgpu()
    108 {
    109     wgpu_device = emscripten_webgpu_get_device();
    110     if (!wgpu_device)
    111         return false;
    112 
    113     wgpuDeviceSetUncapturedErrorCallback(wgpu_device, print_wgpu_error, NULL);
    114 
    115     // Use C++ wrapper due to misbehavior in Emscripten.
    116     // Some offset computation for wgpuInstanceCreateSurface in JavaScript
    117     // seem to be inline with struct alignments in the C++ structure
    118     wgpu::SurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {};
    119     html_surface_desc.selector = "#canvas";
    120 
    121     wgpu::SurfaceDescriptor surface_desc = {};
    122     surface_desc.nextInChain = &html_surface_desc;
    123 
    124     // Use 'null' instance
    125     wgpu::Instance instance = {};
    126     wgpu_surface = instance.CreateSurface(&surface_desc).Release();
    127 
    128     return true;
    129 }
    130 
    131 static void main_loop(void* window)
    132 {
    133     glfwPollEvents();
    134 
    135     int width, height;
    136     glfwGetFramebufferSize((GLFWwindow*) window, &width, &height);
    137 
    138     // React to changes in screen size
    139     if (width != wgpu_swap_chain_width && height != wgpu_swap_chain_height)
    140     {
    141         ImGui_ImplWGPU_InvalidateDeviceObjects();
    142 
    143         if (wgpu_swap_chain)
    144             wgpuSwapChainRelease(wgpu_swap_chain);
    145 
    146         wgpu_swap_chain_width = width;
    147         wgpu_swap_chain_height = height;
    148 
    149         WGPUSwapChainDescriptor swap_chain_desc = {};
    150         swap_chain_desc.usage = WGPUTextureUsage_RenderAttachment;
    151         swap_chain_desc.format = WGPUTextureFormat_RGBA8Unorm;
    152         swap_chain_desc.width = width;
    153         swap_chain_desc.height = height;
    154         swap_chain_desc.presentMode = WGPUPresentMode_Fifo;
    155         wgpu_swap_chain = wgpuDeviceCreateSwapChain(wgpu_device, wgpu_surface, &swap_chain_desc);
    156 
    157         ImGui_ImplWGPU_CreateDeviceObjects();
    158     }
    159 
    160     // Start the Dear ImGui frame
    161     ImGui_ImplWGPU_NewFrame();
    162     ImGui_ImplGlfw_NewFrame();
    163     ImGui::NewFrame();
    164 
    165     // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
    166     if (show_demo_window)
    167         ImGui::ShowDemoWindow(&show_demo_window);
    168 
    169     // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
    170     {
    171         static float f = 0.0f;
    172         static int counter = 0;
    173 
    174         ImGui::Begin("Hello, world!");                                // Create a window called "Hello, world!" and append into it.
    175 
    176         ImGui::Text("This is some useful text.");                     // Display some text (you can use a format strings too)
    177         ImGui::Checkbox("Demo Window", &show_demo_window);            // Edit bools storing our window open/close state
    178         ImGui::Checkbox("Another Window", &show_another_window);
    179 
    180         ImGui::SliderFloat("float", &f, 0.0f, 1.0f);                  // Edit 1 float using a slider from 0.0f to 1.0f
    181         ImGui::ColorEdit3("clear color", (float*)&clear_color);       // Edit 3 floats representing a color
    182 
    183         if (ImGui::Button("Button"))                                  // Buttons return true when clicked (most widgets return true when edited/activated)
    184             counter++;
    185         ImGui::SameLine();
    186         ImGui::Text("counter = %d", counter);
    187 
    188         ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
    189         ImGui::End();
    190     }
    191 
    192     // 3. Show another simple window.
    193     if (show_another_window)
    194     {
    195         ImGui::Begin("Another Window", &show_another_window);         // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
    196         ImGui::Text("Hello from another window!");
    197         if (ImGui::Button("Close Me"))
    198             show_another_window = false;
    199         ImGui::End();
    200     }
    201     
    202     // Rendering
    203     ImGui::Render();
    204 
    205     WGPURenderPassColorAttachment color_attachments = {};
    206     color_attachments.loadOp = WGPULoadOp_Clear;
    207     color_attachments.storeOp = WGPUStoreOp_Store;
    208     color_attachments.clearColor = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w };
    209     color_attachments.view = wgpuSwapChainGetCurrentTextureView(wgpu_swap_chain);
    210     WGPURenderPassDescriptor render_pass_desc = {};
    211     render_pass_desc.colorAttachmentCount = 1;
    212     render_pass_desc.colorAttachments = &color_attachments;
    213     render_pass_desc.depthStencilAttachment = NULL;
    214 
    215     WGPUCommandEncoderDescriptor enc_desc = {};
    216     WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(wgpu_device, &enc_desc);
    217 
    218     WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &render_pass_desc);
    219     ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass);
    220     wgpuRenderPassEncoderEndPass(pass);
    221 
    222     WGPUCommandBufferDescriptor cmd_buffer_desc = {};
    223     WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish(encoder, &cmd_buffer_desc);
    224     WGPUQueue queue = wgpuDeviceGetQueue(wgpu_device);
    225     wgpuQueueSubmit(queue, 1, &cmd_buffer);
    226 }
    227 
    228 static void print_glfw_error(int error, const char* description)
    229 {
    230     printf("Glfw Error %d: %s\n", error, description);
    231 }
    232 
    233 static void print_wgpu_error(WGPUErrorType error_type, const char* message, void*)
    234 {
    235     const char* error_type_lbl = "";
    236     switch (error_type)
    237     {
    238     case WGPUErrorType_Validation:  error_type_lbl = "Validation"; break;
    239     case WGPUErrorType_OutOfMemory: error_type_lbl = "Out of memory"; break;
    240     case WGPUErrorType_Unknown:     error_type_lbl = "Unknown"; break;
    241     case WGPUErrorType_DeviceLost:  error_type_lbl = "Device lost"; break;
    242     default:                        error_type_lbl = "Unknown";
    243     }
    244     printf("%s error: %s\n", error_type_lbl, message);
    245 }