Skip to content
mozahzah edited this page Jan 23, 2025 · 24 revisions
IELogo

Welcome to the IECore Wiki!

IECore is a open-source library designed for Windows and macOS applications that leverages ImGui as its user interface. The library includes an abstracted renderer class, robust logging and assertion features, as well as useful utilities and ImGui extension logic.
Currently, only Vulkan is implemented as a rendering backend, but support for additional backends will be added in the future.


Prerequisites

Installing Vulkan

To compile IECore, the Vulkan SDK must be installed. For Linux, Windows and macOS, visit the LunarG Vulkan SDK Getting Started website here. Make sure to select your current operating system from the options provided on the site.

Note

You only need to install the Core Vulkan Library. No other components are required.

Test if Vulkan is Properly Installed: To test the installation, open PowerShell and run the following command:

vulkaninfo

If this command runs successfully, then Vulkan is properly installed and you are good to go.

Important

After the installation is complete, ensure that the Vulkan SDK bin directory is added to the PATH system environment variable. Additionally, make sure that the VK_SDK_PATH and VULKAN_SDK environment variables are properly defined.

Installing GLFW3

In addition to vulkan, you need to have GLFW3 installed. For GLFW3, visit the installing GLFW here to download and set up the library. Ensure you follow the installation instructions for your operating system to properly integrate GLFW3 with your development environment.

Installing Freetype

In addition you need to install freetype. For Freetype, visit the installing Freetype here to download and set up the library. Ensure you follow the installation instructions for your operating system to properly integrate Freetype with your development environment.


Getting Started

Launch your preferred terminal and navigate to a empty working directory.
Clone IECore to the working directory.

git clone https://github.com/mozahzah/IECore.git
cd IECore

IECore uses CMake as its build system. To get started, ensure you have CMake installed and follow these steps:

  1. Make sure IECore and all of its submodules are synced:

    git submodule update --init --recursive .
    git pull --recurse
  2. Generate Build Files:

    cmake -S . -B ./build

    This command creates a ./build directory where all the CMake-generated files will be placed.

  3. Build IECore:

    cmake --build ./build

    After building, you can find the executable and library dependencies in the ./build/bin directory including IECore.dll.

  4. Run the Example:
    Locate and double-click IECoreExample.exe in the ./build/bin/ or ./build/bin/<config> directory or run

    ./build/bin/IECoreExample.exe
    :: ./build/bin/Debug/IECoreExample.exe
    :: ./build/bin/Release/IECoreExample.exe

    to verify that the window and ImGui demo window are working correctly.

Integrating IECore

To integrate the built IECore library into your application:

  1. Include IECore in Your Project:
    Add the IECore directory to your application's project directory or if your application is using Git simply call:

    git submodule add https://github.com/mozahzah/IECore.git ThirdParty/IEcore
    git submodule init .
  2. Update CMakeLists.txt:
    In your application's CMakeLists.txt, include IECore by adding:

    add_subdirectory(<path_to_IEcore>)
    # Example: add_subdirectory(ThirdParty/IEcore)
    target_link_libraries(<your-target> PUBLIC IECore)

    Alternatively, you can link against the DLL using other methods if preferred.

  3. Build IECore:
    Make sure IECore.dll and IECore.lib are in the expected directories

  4. Verify Integration:
    Add IECore directory to your includes Include the IECore.h file in your application and verify the integration by compiling with:

    #include "IECore.h"
    
    int main()
    {
        IEResult Result(IEResult::Type::Success, "Successfully linked IECore");
        const bool Pass = Result;
    
        return 0;
    };

Code Example

You can find this same example file here IECoreExample

Simple Demo App Class

In a simple demo app class, ensure that you instantiate IERenderer. In this example, we use IERenderer_Vulkan.
Additionally, provide a getter for easy access to the renderer instance.

Create an OnPreFrameRender() function that will serve as the entry point for the app's logic. Optionally, you can include an OnPostFrameRender() function.

Code:

#include "IECore.h"

class DemoApp
{
public:
    DemoApp() : m_Renderer(std::make_unique<IERenderer_Vulkan>()) {}
    IERenderer& GetRenderer() { return *m_Renderer; }

public:
    void OnPreFrameRender()
    {
        ImGui::ShowDemoWindow();
        //...
    }

    void OnPostFrameRender()
    {
        //...
    }

private:
    std::unique_ptr<IERenderer> m_Renderer;
};

Initializing and Using IECore

Main Function Setup

In your main function or entry point, ensure you:

  1. Initialize IERenderer via IERenderer::Initialize().
  2. Create an ImGui context.
  3. Call IERenderer::PostImGuiContextCreated().

Now you are ready to start your application's main loop.

Main Loop Breakdown:

The while loop can loop on whether the app is running using IERenderer::IsAppRunning().

Inside the while loop we must do the following:

  1. Create a New Frame:

    Renderer.CheckAndResizeSwapChain();
    Renderer.NewFrame();
    ImGui::NewFrame();
  2. Call the Apps OnPreFrameRender:

    App.OnPreFrameRender();
  3. Render and Present the Frame:

    ImGui::Render();
    Renderer.RenderFrame(*ImGui::GetDrawData());
    Renderer.PresentFrame();

Code:

int main()
{
    DemoApp App;

    IERenderer& Renderer = App.GetRenderer();
    if (Renderer.Initialize(std::string("DemoApp")))
    {
        if (ImGuiContext* const CreatedImGuiContext = ImGui::CreateContext())
        {
            ImGuiIO& IO = ImGui::GetIO();
            IO.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_IsSRGB;
            if (Renderer.PostImGuiContextCreated())
            {
                ImGui::IEStyle::StyleIE();
                IO.IniFilename = nullptr;
                IO.LogFilename = nullptr;

                IEClock::time_point StartFrameTime = IEClock::now();
                IEDurationMs CapturedDeltaTime = IEDurationMs::zero();

                while (Renderer.IsAppRunning())
                {
                    StartFrameTime = IEClock::now();

                    Renderer.CheckAndResizeSwapChain();
                    Renderer.NewFrame();
                    ImGui::NewFrame();

                    // On Pre Frame Render
                    // Pre-Frame App Code Goes Here
                    App.OnPreFrameRender();
                    Renderer.DrawTelemetry();
                    // On Pre Frame Render
                    
                    ImGui::Render();
                    Renderer.RenderFrame(*ImGui::GetDrawData());
                    Renderer.PresentFrame();

                    // On Post Frame Render
                    // Post-Frame App Code Goes Here
                    App.OnPostFrameRender();
                    // On Post Frame Render

                    CapturedDeltaTime = std::chrono::duration_cast<IEDurationMs>(IEClock::now() - StartFrameTime);
                    // Captured delta time can be used to enforce a fixed frame rate

                    if (Renderer.IsAppWindowOpen())
                    {
                        Renderer.WaitEventsTimeout(0.1f);
                    }
                    else
                    {
                        Renderer.WaitEvents();
                    }
                }
            }
        }

        Renderer.Deinitialize();
    }

    return 0;
}