Гайд mimgui — Dear ImGui for MoonLoader

Добро пожаловать в гайд по mimgui.
mimgui — это новая графическая библиотека, написанная в результате устаревания предыдущей графической библиотеки Moon ImGui, использующей Dear ImGui v.1.52; использующая в своей основе свежий релиз Dear ImGui v.1.72. Новая библиотека включает в себя все основные возможности фреймворка, а API максимально приближен к оригинальному.

Содержание:


GitHub ImGui:
GitHub mimgui:

Скачать mimgui
Установка: переместить папку mimgui из архива в папку «*Корневая папка с игрой*/moonloader/lib»



Основная информация
В mimgui используется относительно последняя версия ImGui (1.72): на момент написания статьи последняя его версия — 1.79.
Изначально написание этой статьи планировалось после выхода предстоящей версии MoonLoader, в которой должен был быть менеджер зависимостей, и сама библиотека должна была поставляться с помощью функционала МЗ, однако её релиз был отложен на неопределенный срок. В качестве основы используется LuaJit ImGui , который, в свою очередь, в качестве основы использует cimgui.

mimgui разрабатывался с декабря 2018 года, однако, широкую популярность он получил только в июле-августе 2019 года, как раз
в период выхода первой beta-версии MoonLoader 027.

Примеры использования mimgui можно увидеть в самом репозитории, но несмотря на это, в этой теме также отдельно будут добавлены примеры использования.




Примеры использования
Давайте напишем примитивный скрипт с использованием mimgui.

Lua:
local imgui = require 'mimgui' -- Подключаем саму библиотеку

local newFrame = imgui.OnFrame( --[[Сама функция создания фрейма, их может быть сколько вашей душе угодно.
                                    Обратите внимание, что в mimgui рекомендуется создавать отдельный
                                    фрейм для каждого окна, однако это не является обязательным.]]
    function() return true end, -- Определяет, выполняется/отображается ли текущий фрейм.
    function(player)            --[[Сама область, в которой уже будем рисовать элементы.
                                    В функцию в качестве первой переменной передаются список функций
                                    для взаимодействия с локальным игроком и рядом нескольких возможностей.]]
        imgui.Begin("Main Window")  -- Создаём новое окно с заголовком 'Main Window'
        imgui.Text("Hello")         -- Добавляем туда текст 'Hello'
        imgui.End()                 -- Объявляем конец данного окна
    end
)

function main()
    wait(-1)
end

Результат:

Screenshot_1.png


Само собой, это не все возможности ImGui, поэтому немного преобразим наш скрипт: добавим размер, позицию по умолчанию и клавишу активации для показа окна.


Lua:
local imgui = require 'mimgui'
local vkeys = require 'vkeys'       --[[Библиотека со списком индексов клавиш и функциями для
                                        взаимодействия с ними.]]

local wm = require 'windows.message'    -- Список событий для окна игры

local new = imgui.new               --[[Создаём короткий псевдоним для функции,
                                        создающего буфера для различных функций ImGui]]
local renderWindow = new.bool(--[[true/false, по умолч. false]])
local sizeX, sizeY = getScreenResolution()

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5)) -- Укажем положение окна по центру и выставим оффсет 0.5, чтобы рендер шёл от середины окна
        imgui.SetNextWindowSize(imgui.ImVec2(200, 150), imgui.Cond.FirstUseEver) -- Укажем размер
        imgui.Begin("Main Window", renderWindow)
        imgui.Text("Hello")
        imgui.Text(string.format("Current render mode: %s", renderWindow[0]))
        imgui.End()
    end
)

function main()
    addEventHandler('onWindowMessage', function(msg, wparam, lparam) -- Сама функция, в которой будем обрабатывать горячие клавиши. Обратите внимание, что данный способ является наиболее верным в плане оптимизации.
        if msg == wm.WM_KEYDOWN or msg == wm.WM_SYSKEYDOWN then -- Если клавиша нажата
            if wparam == vkeys.VK_X then -- И если это клавиша X
                renderWindow[0] = not renderWindow[0] -- Переключаем состояние рендера
            end
        end
    end)
    wait(-1)
end

Результат:
Screenshot_2.png


Но, ведь ничего не изменилось: размер тот же, положение то же самое: в левом верхнем углу, почему?
Дело в том, что mimgui умеет сохранять данные окон по их индексу. Индексы окон — это их заголовки, поэтому заголовки также следует делать уникальными.
Если вам необходимы одинаковые названия окон, то достаточно после названия окна добавить ##уникальное_значение, не беспокойтесь, он не будет виден. Обратите внимание, что это следует делать во всех случаях: InputText(Multiline), InputInt, Button и так далее; абсолютно во всех, иначе работать у вас будет только первая кнопка/инпут.

Хорошо, с индексом разобрались, возможно, вам понадобится убрать автоматическое запоминание, давайте выключим:


Lua:
local imgui = require 'mimgui'
local vkeys = require 'vkeys'

local wm = require 'windows.message'
local new = imgui.new

local renderWindow = new.bool()
local sizeX, sizeY = getScreenResolution()

imgui.OnInitialize(function()   --[[Функция, вызывающаяся один раз за период жизни скрипта.
                                    Обратите внимание, что пока никакое ImGui окно ни разу не показывалось,
                                    функция не вызовется и это может вызвать ошибки об отсутствии
                                    каких-либо переменных, если вы их здесь объявили.
                                    Поэтому, здесь следует просто изменять значения по умолчанию, например:
                                    цвет элементов, "сохранять ли настройки и в какой файл"
                                    Либо подгружать картинки, необходимые для показа окнам ImGui
                                    Если вы за пределами ImGui попытаетесь подгрузить картинку, вы поймаете ошибку.]]

    -- Выключаем сохранение. По умолчанию: moonloader/config/mimgui/%scriptfilename%.ini
    imgui.GetIO().IniFilename = nil
end)

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
        imgui.SetNextWindowSize(imgui.ImVec2(200, 150), imgui.Cond.FirstUseEver)
        imgui.Begin("Main Window", renderWindow)
        imgui.Text("Hello")
        imgui.Text(string.format("Current render mode: %s", renderWindow[0]))
        imgui.End()
    end
)

function main()
    addEventHandler('onWindowMessage', function(msg, wparam, lparam)
        if msg == wm.WM_KEYDOWN or msg == wm.WM_SYSKEYDOWN then
            if wparam == vkeys.VK_X then
                renderWindow[0] = not renderWindow[0]
            end
        end
    end)
    wait(-1)
end

Теперь окно увеличилось, отображается по центру и его можно скрыть:
Screenshot_3.png


Давайте теперь напишем что-то на русском языке:
Lua:
local imgui = require 'mimgui'
local ffi = require 'ffi' -- Подключаем библиотеку ffi для использования возможностей Си (C)
local vkeys = require 'vkeys'

local wm = require 'windows.message'
local new, str, sizeof = imgui.new, ffi.string, ffi.sizeof

local renderWindow = new.bool()
local inputField = new.char[256 --[[Указываем размер]]](--[[Здесь можно указать какой-либо текст]])
local sizeX, sizeY = getScreenResolution()

imgui.OnInitialize(function()
    imgui.GetIO().IniFilename = nil
end)

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
        imgui.SetNextWindowSize(imgui.ImVec2(200, 150), imgui.Cond.FirstUseEver)
        imgui.Begin("Main Window", renderWindow)
        imgui.Text("Hello")
        imgui.Text(string.format("Current render mode: %s", renderWindow[0]))
        if imgui.InputText("Привет", inputField, sizeof(inputField)) then
            -- Первое: уникальное название инпута, второе: само поле, третье: максимальная длина текста/размер инпута.
            print(str(inputField)) -- Читаем значение инпута через функцию str
        end
        if imgui.Button("Очистить поле") then
            imgui.StrCopy(inputField, '') -- Можно вписать какое-либо значение в инпут, при желании.
        end
        imgui.End()
    end
)

function main()
    addEventHandler('onWindowMessage', function(msg, wparam, lparam)
        if msg == wm.WM_KEYDOWN or msg == wm.WM_SYSKEYDOWN then
            if wparam == vkeys.VK_X then
                renderWindow[0] = not renderWindow[0]
            end
        end
    end)
    wait(-1)
end

Результат:
Screenshot_4.png


Мы видим здесь каракули и вопросительные знаки, почему это происходит?

Работа с другими языками на примере русского
В MoonLoader 025 были добавлены библиотеки lua-iconv и encoding, они призваны помочь в работе с разными кодировками текста.
Следующий пример показывает, как использовать текст на русском в ImGui:
Скрипт должен быть сохранён в кодировке Windows-1251 (конкретно для данного примера)
Если в вашем скрипте имеется огромный код с использованием ImGui и мало взаимодействия с функциями MoonLoader'a либо SAMPFUNCS'a, то вы при желании можете сохранить ваш скрипт в UTF-8 и вам не придётся проделывать все эти операции.


Lua:
local imgui = require 'mimgui'
local ffi = require 'ffi'
local vkeys = require 'vkeys'
local encoding = require 'encoding' --[[Подключаем библиотеку для чтения/записи данных с кодировкой,
                                        отличающейся от кодировки нашего скрипта.]]

encoding.default = 'CP1251'         --[[Указываем кодировку по умолчанию. Обратите внимание,
                                        что она должна совпадать с кодировкой вашего скрипта.]]
local u8 = encoding.UTF8            -- И создаём короткий псевдоним для кодировщика UTF-8

local wm = require 'windows.message'
local new, str, sizeof = imgui.new, ffi.string, ffi.sizeof

local renderWindow, freezePlayer, removeCursor = new.bool(), new.bool(), new.bool()
local inputField = new.char[256](--[[Здесь также следует кодировать информацию!]])
local sizeX, sizeY = getScreenResolution()

imgui.OnInitialize(function()
    imgui.GetIO().IniFilename = nil
end)

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
        imgui.SetNextWindowSize(imgui.ImVec2(220, 200), imgui.Cond.FirstUseEver)
        imgui.Begin("Main Window", renderWindow)
        imgui.Text("Hello")
        imgui.Text(string.format("Current render mode: %s", renderWindow[0]))
        if imgui.InputText(u8"Привет", inputField, sizeof(inputField)) then
            -- Кодируем название инпута
            print(u8:decode(str(inputField))) -- Декодируем в Windows-1251
        end
        if imgui.Button(u8"Очистить поле") then -- Кодируем название кнопки
            imgui.StrCopy(inputField, '')
        end
        if imgui.Checkbox(u8'Заморозить игрока', freezePlayer) then -- Кодируем название кнопки
            player.LockPlayer = freezePlayer[0]
        end
        if imgui.Checkbox(u8'Скрыть курсор', removeCursor) then -- Кодируем название кнопки
            player.HideCursor = removeCursor[0]
        end
        if player.HideCursor then
            imgui.Text(u8'Курсор скрыт') -- Кодируем выводимый текст
        end
        imgui.End()
    end
)

function main()
    addEventHandler('onWindowMessage', function(msg, wparam, lparam)
        if msg == wm.WM_KEYDOWN or msg == wm.WM_SYSKEYDOWN then
            if wparam == vkeys.VK_X then
                renderWindow[0] = not renderWindow[0]
            end
        end
    end)
    wait(-1)
end

Результат:
Screenshot_5.png


В примерах не было затронуто наличие "префрейма" (BeforeFrame), применение его и остальных возможностей вы можете увидеть в репозитории по ссылке:




Главные различия между ImGui C++ API и mimgui Lua API

ОписаниеВ C++ ImGuiВ Lua mimgui
Все функции из пространства имён ImGui, как и все типы, и все перечисления находятся в таблице, возвращаемой модулем​
ImGui::Text("text");
ImVec2(0.1f, 2.3f);
imgui.Text("text")
imgui.ImVec2(0.1, 2.3)
Названия перечислений (enum) и их значений лишились префиксов и символа "_" в концеImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResizeimgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoResize
Значения базовых типов, которые в ImGui записываются по указателю, должны быть использованы через ffistatic bool win = false;
ImGui::Begin("window", &win);
win = false;
local win = imgui.new.bool(false)
imgui.Begin("window", win)
win[0] = false
Использование функций InputText и InputTextMultilinechar buf[256];
ImGui::InputText('input', buf, IM_ARRAYSIZE(buf))
local buf = imgui.new.char[256]()
imgui.InputText('input', buf, ffi.sizeof(buf))
Динамические массивы в виде массива указателей следует объявлять через fficonst char* items[] = {"1", "2", "3"};
ImGui::ListBox("list", &lb_cur, items, 3)
local itemsList = {"1", "2", "3"}
local current = imgui.new.int(0)
local items = imgui.new['const char*'][#itemsList](itemsList)
imgui.ListBoxStr_arr("list", current, items, #itemsList)


Главные различия между MoonImGui и mimgui
Для взаимодействия с ImGui теперь используется встроенная в LuaJIT библиотека ffi, а не самописные функции. Поэтому, получается так, что когда мы пишем код, мы "пишем код" на С++. Поэтому, добавленные в MoonImGui типы: ImBool, ImBuffer, ImInt, ImFloat, ImCallback не требуются, и им на замену пришли встроенные и не встроенные в Си типы:

ТипИспользование в MoonImGuiИспользование в mimgui
Bool​
local bool = imgui.ImBool(true/false)​
local bool = imgui.new.bool(true/false)​
Int​
local int = imgui.ImInt(5)​
local int = imgui.new.int(5)​
Char​
local buffer = imgui.ImBuffer(128, "hello")​
local buffer = imgui.new.char[128]("hello")​
Float​
local float = imgui.ImFloat(5.12)​
local float = imgui.new.float(5.12)​
Callback​
local test = function(data) print("hey") return 0 end
local callback = imgui.ImCallback(test)​
local test = function(data) print("hey") return 0 end
local callback = ffi.cast('int (*)(ImGuiInputTextCallbackData* data)', test)​

Следует отметить, что получение исходных значений так же подверглось изменению. Если раньше исходное значение можно было получить через ключ v (buffer.v; int.v), то в mimgui они получаются с помощью нулевого индекса (int[0]; float[0]; bool[0]), а для типа Char значение необходимо получать через ffi.string (ffi.string(buffer)). Не нужно бояться внесёнными в API изменениям, они очень легко осваиваются и для ежедневного кодинга не нужно вникать в их работу.




Отличительные способности mimgui Lua
В разработке
 
Последнее редактирование:

Hatiko

Известный
Проверенный
1,472
611
могут быть погрешности
При конвертировании из float в int погрешность максимум в единицу +/- может быть из-за округление до целых, ты физически не сможешь это распознать. А ты когда сохраняешь float число, оно как бы тоже имеет погрешность, т.к. ты сохраняешь не полное число, а округлённое до сотых.
 

Cosmo

Известный
Друг
646
2,597
Хотелось бы узнать как менять стиль прямо из игры, в Imgui можно было в любом месте пихнуть apply_custom_style() в любом месте кода и стиль обновится, а тут так уже не сработает. В репозитории фипа ничего по этому вопросу не нашёл.
У меня есть один основной цвет на всю тему и я хочу его менять через colorEdit4 в реальном времени (так как это реализовано в imgui.ShowStyleEditor() например)

Lua:
--> Конфиг
color = 0xFF3333AA

--> Переменные
mc = imgui.ColorConvertU32ToFloat4(cfg['main'].style.color)
mcEdit = imgui.new.float[4](mc.x, mc.y, mc.z, mc.w)

--> В OnFrame
if imgui.ColorEdit4('##MainColor', mcEdit, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.NoLabel + imgui.ColorEditFlags.NoTooltip) then
mc = imgui.ImVec4(mcEdit[0], mcEdit[1], mcEdit[2], mcEdit[3])
local u32 = imgui.ColorConvertFloat4ToU32(mc)
cfg['main'].style.color = u32
-- theme() - так бы я сделал в обычном имгуи
end

--> В OnInitialize
function theme()
    imgui.SwitchContext()
    local style = imgui.GetStyle()
    local colors = style.Colors
    local clr = imgui.Col
    local ImVec4 = imgui.ImVec4
    local ImVec2 = imgui.ImVec2

    style.WindowPadding         = imgui.ImVec2(8, 8)
    style.WindowRounding        = 15
    style.ChildRounding           = 15
    style.FramePadding          = imgui.ImVec2(5, 3)
    style.FrameRounding         = 3.0
    style.ItemSpacing           = imgui.ImVec2(5, 4)
    style.ItemInnerSpacing      = imgui.ImVec2(4, 4)
    style.IndentSpacing         = 21
    style.ScrollbarSize         = 10.0
    style.ScrollbarRounding     = 13
    style.GrabMinSize           = 8
    style.GrabRounding          = 1
    style.WindowTitleAlign      = imgui.ImVec2(0.5, 0.5)
    style.ButtonTextAlign       = imgui.ImVec2(0.5, 0.5)

    colors[clr.Text]                                = ImVec4(1.00, 1.00, 1.00, 1.00)
    colors[clr.TextDisabled]                        = ImVec4(0.80, 0.80, 0.80, 0.50)
    colors[clr.WindowBg]                            = ImVec4(0.09, 0.09, 0.09, 1.00)
    colors[clr.ChildBg]                               = ImVec4(0.09, 0.09, 0.09, 1.00)
    colors[clr.PopupBg]                             = ImVec4(0.10, 0.10, 0.10, 1.00)
    colors[clr.Border]                              = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.BorderShadow]                        = ImVec4(0.00, 0.60, 0.00, 0.00)
    colors[clr.FrameBg]                             = ImVec4(0.20, 0.20, 0.20, 1.00)
    colors[clr.FrameBgHovered]                      = ImVec4(mc.x, mc.y, mc.z, 0.50)
    colors[clr.FrameBgActive]                       = ImVec4(mc.x, mc.y, mc.z, 0.80)
    colors[clr.TitleBg]                             = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.TitleBgActive]                       = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.TitleBgCollapsed]                    = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.MenuBarBg]                           = ImVec4(0.14, 0.14, 0.14, 1.00)
    colors[clr.ScrollbarBg]                         = ImVec4(mc.x, mc.y, mc.z, 0.50)
    colors[clr.ScrollbarGrab]                       = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.ScrollbarGrabHovered]                = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.ScrollbarGrabActive]                 = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.CheckMark]                           = ImVec4(1.00, 1.00, 1.00, 1.00)
    colors[clr.SliderGrab]                          = ImVec4(mc.x, mc.y, mc.z, 0.70)
    colors[clr.SliderGrabActive]                    = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.Button]                              = ImVec4(mc.x, mc.y, mc.z, 0.50)
    colors[clr.ButtonHovered]                       = ImVec4(mc.x, mc.y, mc.z, 0.80)
    colors[clr.ButtonActive]                        = ImVec4(mc.x, mc.y, mc.z, 0.90)
    colors[clr.Header]                              = ImVec4(1.00, 1.00, 1.00, 0.20)
    colors[clr.HeaderHovered]                       = ImVec4(1.00, 1.00, 1.00, 0.20)
    colors[clr.HeaderActive]                        = ImVec4(1.00, 1.00, 1.00, 0.30)
    colors[clr.TextSelectedBg]                      = ImVec4(mc.x, mc.y, mc.z, 0.90)
end

Разобрался. Если стиль уже загружен в OnInitialize, то потом можно как и в Dear Imgui, подгружать стиль из любого места в коде. Но почему то раньше я этого сделать не мог и скрипт крашился. Но это с большой вероятностью мои косяки
 
Последнее редактирование:

AkrD1338

Участник
80
14
как скачать...
не понимаю как скачать гит хаба , кидает на сурс
 

Tema05

Известный
1,441
401
Хотелось бы узнать как менять стиль прямо из игры, в Imgui можно было в любом месте пихнуть apply_custom_style() в любом месте кода и стиль обновится, а тут так уже не сработает. В репозитории фипа ничего по этому вопросу не нашёл.
У меня есть один основной цвет на всю тему и я хочу его менять через colorEdit4 в реальном времени (так как это реализовано в imgui.ShowStyleEditor() например)

Lua:
--> Конфиг
color = 0xFF3333AA

--> Переменные
mc = imgui.ColorConvertU32ToFloat4(cfg['main'].style.color)
mcEdit = imgui.new.float[4](mc.x, mc.y, mc.z, mc.w)

--> В OnFrame
if imgui.ColorEdit4('##MainColor', mcEdit, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.NoLabel + imgui.ColorEditFlags.NoTooltip) then
mc = imgui.ImVec4(mcEdit[0], mcEdit[1], mcEdit[2], mcEdit[3])
local u32 = imgui.ColorConvertFloat4ToU32(mc)
cfg['main'].style.color = u32
-- theme() - так бы я сделал в обычном имгуи
end

--> В OnInitialize
function theme()
    imgui.SwitchContext()
    local style = imgui.GetStyle()
    local colors = style.Colors
    local clr = imgui.Col
    local ImVec4 = imgui.ImVec4
    local ImVec2 = imgui.ImVec2

    style.WindowPadding         = imgui.ImVec2(8, 8)
    style.WindowRounding        = 15
    style.ChildRounding           = 15
    style.FramePadding          = imgui.ImVec2(5, 3)
    style.FrameRounding         = 3.0
    style.ItemSpacing           = imgui.ImVec2(5, 4)
    style.ItemInnerSpacing      = imgui.ImVec2(4, 4)
    style.IndentSpacing         = 21
    style.ScrollbarSize         = 10.0
    style.ScrollbarRounding     = 13
    style.GrabMinSize           = 8
    style.GrabRounding          = 1
    style.WindowTitleAlign      = imgui.ImVec2(0.5, 0.5)
    style.ButtonTextAlign       = imgui.ImVec2(0.5, 0.5)

    colors[clr.Text]                                = ImVec4(1.00, 1.00, 1.00, 1.00)
    colors[clr.TextDisabled]                        = ImVec4(0.80, 0.80, 0.80, 0.50)
    colors[clr.WindowBg]                            = ImVec4(0.09, 0.09, 0.09, 1.00)
    colors[clr.ChildBg]                               = ImVec4(0.09, 0.09, 0.09, 1.00)
    colors[clr.PopupBg]                             = ImVec4(0.10, 0.10, 0.10, 1.00)
    colors[clr.Border]                              = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.BorderShadow]                        = ImVec4(0.00, 0.60, 0.00, 0.00)
    colors[clr.FrameBg]                             = ImVec4(0.20, 0.20, 0.20, 1.00)
    colors[clr.FrameBgHovered]                      = ImVec4(mc.x, mc.y, mc.z, 0.50)
    colors[clr.FrameBgActive]                       = ImVec4(mc.x, mc.y, mc.z, 0.80)
    colors[clr.TitleBg]                             = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.TitleBgActive]                       = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.TitleBgCollapsed]                    = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.MenuBarBg]                           = ImVec4(0.14, 0.14, 0.14, 1.00)
    colors[clr.ScrollbarBg]                         = ImVec4(mc.x, mc.y, mc.z, 0.50)
    colors[clr.ScrollbarGrab]                       = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.ScrollbarGrabHovered]                = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.ScrollbarGrabActive]                 = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.CheckMark]                           = ImVec4(1.00, 1.00, 1.00, 1.00)
    colors[clr.SliderGrab]                          = ImVec4(mc.x, mc.y, mc.z, 0.70)
    colors[clr.SliderGrabActive]                    = ImVec4(mc.x, mc.y, mc.z, 1.00)
    colors[clr.Button]                              = ImVec4(mc.x, mc.y, mc.z, 0.50)
    colors[clr.ButtonHovered]                       = ImVec4(mc.x, mc.y, mc.z, 0.80)
    colors[clr.ButtonActive]                        = ImVec4(mc.x, mc.y, mc.z, 0.90)
    colors[clr.Header]                              = ImVec4(1.00, 1.00, 1.00, 0.20)
    colors[clr.HeaderHovered]                       = ImVec4(1.00, 1.00, 1.00, 0.20)
    colors[clr.HeaderActive]                        = ImVec4(1.00, 1.00, 1.00, 0.30)
    colors[clr.TextSelectedBg]                      = ImVec4(mc.x, mc.y, mc.z, 0.90)
end
А разве нельзя просто прописать imgui.GetStyle().Colors[imgui.Col.Text] = imgui.ImVec4(mcEdit[0], mcEdit[1], mcEdit[2], mcEdit[3])?
Со стилями прокатывало. Менять так цвет пока не пробовал.
 

Hatiko

Известный
Проверенный
1,472
611
100*100*100*100>255*255*255*255 гениально.
Как раз таки используя float значения округлённые до сотых погрешность будет больше, т..к на 1 сотую приходится 2,55 значения оттенка, а если учитывать три основных канала, то вообще 7,65 теряешь оттенков. Конечно ты их не увидишь, но факт погрешностей больше. Так что , либо использовать прямую конвертацию, где большой диапазон float используется, либо нужно будет брать больше чисел после запятой.