Skip to content

Commit

Permalink
imgui bindings: add font_atlas_add_font_from_file_ttf / font_atlas_gl…
Browse files Browse the repository at this point in the history
…yph_ranges_xxx

+ examples
  • Loading branch information
pthom committed Nov 29, 2022
1 parent 0beae6a commit 23871b1
Show file tree
Hide file tree
Showing 7 changed files with 320 additions and 113 deletions.
12 changes: 9 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ set(CMAKE_CXX_STANDARD 17)
if (IMGUI_BUNDLE_WITH_IMMVISION)
add_compile_definitions(IMGUI_BUNDLE_WITH_IMMVISION)
endif()
if (IMGUI_BUNDLE_BUILD_PYTHON)
add_compile_definitions(IMGUI_BUNDLE_BUILD_PYTHON)
endif()


#########################################################################
Expand All @@ -67,17 +70,20 @@ endif()
#########################################################################
# Main library (imgui_bundle)
#########################################################################
add_library(imgui_bundle STATIC src/imgui_bundle/imgui_bundle.cpp src/imgui_bundle/imgui_bundle.h)
file(GLOB imgui_bundle_sources src/imgui_bundle/*.cpp src/imgui_bundle/*.h)
add_library(imgui_bundle STATIC ${imgui_bundle_sources})
target_include_directories(imgui_bundle PUBLIC src)


#########################################################################
# Build external libraries
#########################################################################
include(cmake/add_simple_library.cmake) # Tooling to build libraries and link them to imgui_bundle
# Build hello_imgui
# Build imgui + hello_imgui
include(cmake/add_hello_imgui.cmake)
add_hello_imgui()
if (IMGUI_BUNDLE_BUILD_PYTHON)
target_compile_definitions(imgui PUBLIC IMGUI_BUNDLE_BUILD_PYTHON)
endif()
# Build implot
add_simple_external_library_with_sources(implot implot)
target_compile_definitions(implot PRIVATE "IMPLOT_CUSTOM_NUMERIC_TYPES=(signed char)(unsigned char)(signed short)(unsigned short)(signed int)(unsigned int)(signed long)(unsigned long)(signed long long)(unsigned long long)(float)(double)(long double)")
Expand Down
62 changes: 54 additions & 8 deletions bindings/imgui_bundle/demos/demos_hello_imgui/demo_docking.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,70 @@ class RocketState(Enum):
rocket_state: RocketState = RocketState.Init


# MyLoadFonts: demonstrate
# * how to load additional fonts
# * how to use assets from the local assets/ folder
"""
Font loading:
We have two options: either we use hello imgui, or we load manually
(see my_load_fonts_via_hello_imgui() and my_load_fonts_manually() below).
"""

gAkronimFont: imgui.ImFont


def my_load_fonts():
def my_load_fonts_via_hello_imgui():
# hello_imgui can load font and merge them with font awesome automatically.
# It will load them from the assets/ folder.

global gAkronimFont

# First, we load the default fonts (the font that was loaded first is the default font)
hello_imgui.ImGuiDefaultSettings.load_default_font_with_font_awesome_icons()
# HelloImGui::ImGuiDefaultSettings::LoadDefaultFont_WithFontAwesomeIcons(); # issue / embedded namespace

# Then we load a second font from
# Since this font is in a local assets/ folder, it was embedded automatically
font_filename = "fonts/Akronim-Regular.ttf"
gAkronimFont = hello_imgui.load_font_ttf_with_font_awesome_icons(font_filename, 40.0)


def my_load_fonts_manually():
# Load font manually.
# We need to use font_atlas_add_font_from_file_ttf instead of ImFont.add_font_from_file_ttf
global gAkronimFont

# first, we load the default font (it will not include icons)
imgui.get_io().fonts.add_font_default()

# Load a font and merge icons into it
# i. load the font...
this_dir = os.path.dirname(__file__)
font_atlas = imgui.get_io().fonts
# We need to take into account the global font scale!
font_size_pixel = 40 / imgui.get_io().font_global_scale
font_filename = this_dir + "/../assets/fonts/Akronim-Regular.ttf"
glyph_range = imgui.font_atlas_glyph_ranges_default(font_atlas)
gAkronimFont = imgui.font_atlas_add_font_from_file_ttf(
font_atlas=imgui.get_io().fonts,
filename=font_filename,
size_pixels=font_size_pixel,
glyph_ranges_as_int_list=glyph_range,
)
# ii. ... Aad merge icons into the previous font
from imgui_bundle import icons_fontawesome
font_filename = this_dir + "/../assets/fonts/fontawesome-webfont.ttf"
font_config = imgui.ImFontConfig()
font_config.merge_mode = True
icons_range = [icons_fontawesome.ICON_MIN_FA, icons_fontawesome.ICON_MAX_FA, 0]
gAkronimFont = imgui.font_atlas_add_font_from_file_ttf(
font_atlas,
filename=font_filename,
size_pixels=font_size_pixel,
glyph_ranges_as_int_list=icons_range,
font_cfg=font_config,
)


def my_load_fonts():
my_load_fonts_manually()
# my_load_fonts_via_hello_imgui()


# CommandGui: the widgets on the left panel
def command_gui(state: AppState):
# Note, you can also show the tweak theme widgets via:
Expand Down
52 changes: 34 additions & 18 deletions bindings/imgui_bundle/demos/imgui_example_glfw_opengl3.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
imgui_bundle can be used without hello imgui, and you can configure and run imgui, opengl and glfw (or sdl, etc.) manually,
as shown here.
"""

import os.path
import sys
import platform
import OpenGL.GL as GL # type: ignore
Expand Down Expand Up @@ -99,19 +99,35 @@ def main():
# //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
# //IM_ASSERT(font != NULL);

imgui.get_io().fonts.add_font_default()
font_filename = "/Users/pascal/dvp/OpenSource/ImGuiWork/litgen/demos/litgen/imgui_bundle/bindings/imgui_bundle/assets/fonts/SourceCodePro-Regular.ttf"
# Load font example, with a merged font for icons
# ------------------------------------------------
# i. Load default font
font_atlas = imgui.get_io().fonts
font_atlas.add_font_default()
this_dir = os.path.dirname(__file__)
font_size_pixel = 48.0
# i. Load another font...
font_filename = this_dir + "/assets/fonts/Akronim-Regular.ttf"
glyph_range = imgui.font_atlas_glyph_ranges_default(font_atlas)
custom_font = imgui.font_atlas_add_font_from_file_ttf(
imgui.get_io().fonts,
font_filename,
48.,
None,
#FONT_CONFIG,
# glyph_ranges_as_int_list=[ 0x20, 500, 0 ]
font_atlas=imgui.get_io().fonts,
filename=font_filename,
size_pixels=font_size_pixel,
glyph_ranges_as_int_list=glyph_range,
)
# ii. ... And merge icons into the previous font
from imgui_bundle import icons_fontawesome
font_filename = this_dir + "/assets/fonts/fontawesome-webfont.ttf"
font_config = imgui.ImFontConfig()
font_config.merge_mode = True
icons_range = [icons_fontawesome.ICON_MIN_FA, icons_fontawesome.ICON_MAX_FA, 0]
custom_font = imgui.font_atlas_add_font_from_file_ttf(
font_atlas,
filename=font_filename,
size_pixels=font_size_pixel,
glyph_ranges_as_int_list=icons_range,
font_cfg=font_config,
)
# imgui.get_io().fonts.build()
print(id(custom_font))


# Our state
show_demo_window = True
Expand All @@ -135,12 +151,6 @@ def main():
imgui_backends.glfw_new_frame()
imgui.new_frame()

_id = id(custom_font)
imgui.push_font(custom_font)
imgui.text("ALLO")
imgui.pop_font()


# 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!).
if show_demo_window:
show_demo_window = imgui.show_demo_window(show_demo_window)
Expand All @@ -152,6 +162,12 @@ def show_simple_window():
# static int counter = 0;
imgui.begin("Hello, world!") # Create a window called "Hello, world!" and append into it.

# Demo custom font
_id = id(custom_font)
imgui.push_font(custom_font)
imgui.text("Hello " + icons_fontawesome.ICON_FA_SMILE)
imgui.pop_font()

imgui.text("This is some useful text.") # Display some text (you can use a format strings too)
_, show_demo_window = imgui.checkbox(
"Demo Window", show_demo_window
Expand Down
28 changes: 28 additions & 0 deletions bindings/imgui_bundle/imgui/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,34 @@ def font_atlas_add_font_from_file_ttf(
"""
pass

def font_atlas_glyph_ranges_default(font_atlas: ImFontAtlas):
"""Basic Latin, Extended Latin"""
pass
def font_atlas_glyph_ranges_greek(font_atlas: ImFontAtlas):
"""Default + Greek and Coptic"""
pass
def font_atlas_glyph_ranges_korean(font_atlas: ImFontAtlas):
"""Default + Korean characters"""
pass
def font_atlas_glyph_ranges_japanese(font_atlas: ImFontAtlas):
"""Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs"""
pass
def font_atlas_glyph_ranges_chinese_full(font_atlas: ImFontAtlas):
"""Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs"""
pass
def font_atlas_glyph_ranges_chinese_simplified_common(font_atlas: ImFontAtlas):
"""Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese"""
pass
def font_atlas_glyph_ranges_cyrillic(font_atlas: ImFontAtlas):
"""Default + about 400 Cyrillic characters"""
pass
def font_atlas_glyph_ranges_thai(font_atlas: ImFontAtlas):
"""Default + Thai characters"""
pass
def font_atlas_glyph_ranges_vietnamese(font_atlas: ImFontAtlas):
"""Default + Vietnamese characters"""
pass


#-----------------------------------------------------------------------------
# [SECTION] Forward declarations and basic types
Expand Down
121 changes: 37 additions & 84 deletions bindings/pybind_imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,33 @@
#include "imgui_toggle/imgui_toggle.h"
#include "misc/cpp/imgui_stdlib.h"
#include "imgui_docking_internal_types.h"
#include "imgui_bundle/patch_imgui.h"
#include "litgen_glue_code.h"

namespace py = pybind11;


// GetTexDataAsAlpha8 & GetTexDataAsAlpha8
// ===> Hack pyClassImFontAtlas
// ````cpp
// struct ImFontAtlas {
// IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);
// IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);
pybind11::array font_atlas_get_tex_data_as_rgba32(ImFontAtlas* self)
{
unsigned char *pixels;
int width, height, bytes_per_pixel;
self->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
std::vector<std::size_t> shape = {(size_t) height, (size_t) width, (size_t) bytes_per_pixel};
auto r = pybind11::array(
pybind11::format_descriptor<uint8_t>::format(),
shape,
pixels
);
return r;
};


void py_init_module_imgui_main(py::module& m)
{

Expand All @@ -24,88 +46,11 @@ void py_init_module_imgui_main(py::module& m)
m.attr("FLT_MIN") = (float)FLT_MIN;
m.attr("FLT_MAX") = (float)FLT_MAX;

// ImGuiIO::IniFilename & LogFilename
// Those are bare pointers with no storage for a string. Having an autogenerated binding is hopeless...
//
// struct ImGuiIO {
// ...
// const char* IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions.
// const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
//
// Let's hack a storage
std::string iniFilename, logFilename;
iniFilename.reserve(640); // <s> 640 bytes should be enough for anyone, since we are back to the 1970's </s>
logFilename.reserve(640);
// And provide an alternative API
m.def("set_io_ini_filename", [&iniFilename](const std::string& filename) {
iniFilename = filename;
ImGui::GetIO().IniFilename = iniFilename.c_str();
});
m.def("set_io_log_filename", [&logFilename](const std::string& filename) {
logFilename = filename;
ImGui::GetIO().LogFilename = logFilename.c_str();
});

// GetTexDataAsAlpha8 & GetTexDataAsAlpha8
// ===> Hack pyClassImFontAtlas
// ````cpp
// struct ImFontAtlas {
// IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);
// IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);
auto fontAtlas_GetTexDataAsRGBA32 = [](ImFontAtlas& self) -> py::array
{
unsigned char* pixels;
int width, height, bytes_per_pixel;
self.GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
std::vector<std::size_t> shape = { (size_t)(width * height * bytes_per_pixel) };
auto r = py::array(
pybind11::format_descriptor<uint8_t>::format(),
shape,
pixels
);
return r;
};
m.def("font_atlas_get_tex_data_as_rgba32_experimental", fontAtlas_GetTexDataAsRGBA32);


// IMGUI_API ImFont* AddFontFromFileTTF(
// const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL,
// const ImWchar* glyph_ranges = NULL);
auto fontAtlas_AddFontFromFileTTF = [](
ImFontAtlas& self,
const char* filename,
float size_pixels,
const ImFontConfig* font_cfg = NULL,
std::optional<std::vector<int>> glyph_ranges_as_int_list = std::nullopt)
{
// from imgui.h doc:
// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the
// atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data.
static std::vector<std::vector<ImWchar>> all_glyph_ranges;

std::vector<ImWchar> glyph_range_this_call;
if (glyph_ranges_as_int_list.has_value())
{
for (int x : *glyph_ranges_as_int_list)
glyph_range_this_call.push_back((ImWchar) x);
glyph_range_this_call.push_back(0); // Add a final zero, in case the user forgot
all_glyph_ranges.push_back(glyph_range_this_call); // "make sure that your array persist up until the atlas is build"
}

ImFont *font;
if (glyph_ranges_as_int_list.has_value())
font = self.AddFontFromFileTTF(filename, size_pixels, font_cfg, glyph_range_this_call.data());
else
font = self.AddFontFromFileTTF(filename, size_pixels, font_cfg);

unsigned char* out_pixels;
// int out_width, out_height, out_bytes_per_pixel;
// ImGui::GetIO().Fonts->GetTexDataAsRGBA32(&out_pixels, &out_width, &out_height, &out_bytes_per_pixel);
// ImGui::GetIO().Fonts->Build();
// printf("IsBuilt=%i\n", ImGui::GetIO().Fonts->IsBuilt());
return font;
};
m.def("font_atlas_add_font_from_file_ttf", fontAtlas_AddFontFromFileTTF,
m.def("set_io_ini_filename", PatchImGui::set_imgui_io_filename);
m.def("set_io_log_filename", PatchImGui::set_imgui_log_filename);
m.def("font_atlas_get_tex_data_as_rgba32", font_atlas_get_tex_data_as_rgba32);

m.def("font_atlas_add_font_from_file_ttf", PatchImGui::font_atlas_add_font_from_file_ttf,
py::arg("font_atlas"),
py::arg("filename"),
py::arg("size_pixels"),
Expand All @@ -114,6 +59,16 @@ void py_init_module_imgui_main(py::module& m)
py::return_value_policy::reference
);

m.def("font_atlas_glyph_ranges_default", PatchImGui::font_atlas_glyph_ranges_default, py::arg("font_atlas"));
m.def("font_atlas_glyph_ranges_greek", PatchImGui::font_atlas_glyph_ranges_greek, py::arg("font_atlas"));
m.def("font_atlas_glyph_ranges_korean", PatchImGui::font_atlas_glyph_ranges_korean, py::arg("font_atlas"));
m.def("font_atlas_glyph_ranges_japanese", PatchImGui::font_atlas_glyph_ranges_japanese, py::arg("font_atlas"));
m.def("font_atlas_glyph_ranges_chinese_full", PatchImGui::font_atlas_glyph_ranges_chinese_full, py::arg("font_atlas"));
m.def("font_atlas_glyph_ranges_chinese_simplified_common", PatchImGui::font_atlas_glyph_ranges_chinese_simplified_common, py::arg("font_atlas"));
m.def("font_atlas_glyph_ranges_cyrillic", PatchImGui::font_atlas_glyph_ranges_cyrillic, py::arg("font_atlas"));
m.def("font_atlas_glyph_ranges_thai", PatchImGui::font_atlas_glyph_ranges_thai, py::arg("font_atlas"));
m.def("font_atlas_glyph_ranges_vietnamese", PatchImGui::font_atlas_glyph_ranges_vietnamese, py::arg("font_atlas"));


// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AUTOGENERATED CODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// <litgen_pydef> // Autogenerated code below! Do not edit!
Expand Down Expand Up @@ -4330,6 +4285,4 @@ void py_init_module_imgui_main(py::module& m)

// </litgen_pydef> // Autogenerated code end
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AUTOGENERATED CODE END !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

pyClassImFontAtlas.def("add_font_from_file_ttf_experimental", fontAtlas_AddFontFromFileTTF);
}

0 comments on commit 23871b1

Please sign in to comment.