Moon ImGui — Dear ImGui for MoonLoader

29072770-aef614e2-7c7b-11e7-8861-212c2c416439.png


Это ImGui - самый функциональный и одновременно самый простой GUI-фреймворк из всех, что мне известны.
И теперь каждый из вас сможет использовать его в своих Lua скриптах для MoonLoader.

Представляю вам Moon ImGui - Lua биндинг ImGui для MoonLoader. Он включает все основные возможности фреймворка, а API максимально приближен к оригинальному по мере возможного.
Тут не будут подробно рассматриваться возможности и особенности ImGui, в этой теме будет рассказано и показано как использовать Moon ImGui в Lua. За информацией по самому ImGui сюда:

Начнём с самого элементарного:
Lua:
local imgui = require 'imgui' -- загружаем библиотеку

-- в этой функции осуществляется вся работа с ImGui
-- она вызывается каждый кадр, но только если imgui.Process равен true
function imgui.OnDrawFrame()
  imgui.Begin('My window') -- новое окно с заголовком 'My window'
  imgui.Text('Hello world') -- простой текст внутри этого окна
  imgui.End() -- конец окна
end

function main()
  imgui.Process = true -- ImGui будет обрабатываться, пока imgui.Process равен true
  -- в этом примере мы просто активируем ImGui сразу же после загрузки игры
end
Результат:
upload_2017-11-25_18-29-2.png


Это работает, но что-то не впечатляет, согласитесь. Окно изначально маленькое, показывается сразу при старте и его нельзя закрыть.
Сделаем его побольше, добавим активацию и какое-нибудь действие:
Lua:
local imgui = require 'imgui'
local key = require 'vkeys'

-- одно из основных отличий от оригинального апи
-- все переменные, значения которых записываются в ImGui по указателю, могут использоваться только через специальные типы
local main_window_state = imgui.ImBool(false)
function imgui.OnDrawFrame()
  if main_window_state.v then -- чтение и запись значения такой переменной осуществляется через поле v (или Value)
    imgui.SetNextWindowSize(imgui.ImVec2(150, 200), imgui.Cond.FirstUseEver) -- меняем размер
    -- но для передачи значения по указателю - обязательно напрямую
    -- тут main_window_state передаётся функции imgui.Begin, чтобы можно было отследить закрытие окна нажатием на крестик
    imgui.Begin('My window', main_window_state)
    imgui.Text('Hello world')
    if imgui.Button('Press me') then -- а вот и кнопка с действием
      -- условие будет выполнено при нажатии на неё
      printStringNow('Button pressed!', 1000)
    end
    imgui.End()
  end
end

function main()
  while true do
    wait(0)
    if wasKeyPressed(key.VK_X) then -- активация по нажатию клавиши X
        main_window_state.v = not main_window_state.v -- переключаем статус активности окна, не забываем про .v
    end
    imgui.Process = main_window_state.v -- теперь значение imgui.Process всегда будет задаваться в зависимости от активности основного окна
  end
end
Теперь окно выглядит так и его можно скрыть:
upload_2017-11-25_18-29-17.png


В коде была использована переменная типа ImBool - это один из новых типов, добавленных в Moon ImGui. Такой подход неизбежен, поскольку в луа невозможна передача базовых типов по ссылке. Это не единственное изменение, есть и другие, вам потребуется о них знать. Вот их полный список:

Разница между C++ API и Lua API
ОписаниеВ C++В Lua
Все функции из пространства имён ImGui, как и все типы, и все перечисления находятся в таблице, возвращаемой модулемImGui::Text("text");
ImVec2(0.1f, 2.3f);
imgui.Text("text");
imgui.ImVec2(0.1, 2.3);
Названия перечислений (enum) и их значений лишились префиксов и символа "_" в концеImGuiWindowFlags_NoTitleBarimgui.WindowFlags.NoTitleBar
Значения базовых типов, которые в ImGui записываются по указателю, должны быть использованы через специальные типы: ImBool для bool, ImFloat для float, ImInt для int и unsigned int, ImFloat2-4 для float[2-4], ImInt2-4 для int[2-4]static bool win = false; ImGui::Begin("window", &win);
win = false;
local win = imgui.ImBool(false) imgui.Begin("window", win)
win.v = false
Функции с переменным количеством аргументов для форматирования текста не поддерживают форматирование, используйте string.formatImGui::Text("hey, %s", name)imgui.Text(string.format('hey, %s', name))
Функции InputText и InputTextMultiline принимают ImBuffer вместо char* buf + size_t buf_sizechar buf[256]{};
ImGui::InputText('input', buf, sizeof(buf))
local buf = imgui.ImBuffer(256);
imgui.InputText('input', buf)
Динамические массивы в виде массива указателей + количество элементов заменены таблицамиconst char* items[] = {"1", "2", "3"}; ImGui::ListBox("list", &lb_cur, items, 3)imgui.ListBox('list', lb_cur, {'1', '2', '3'})
Функции с аргументами const char* str_start, const char* str_end, идущими подряд, принимают обычную строкуImGui::TextUnformatted(some_str, some_str + 24)imgui.TextUnformatted(some_str)
Все функции, принимающие калбэк + user_data, принимают ImCallbackvoid swszCb(ImGuiSizeConstraintCallbackData*) {};
ImGui::SetNextWindowSizeConstraints(size_min, size_max, &swszCb, (void*)&my_data)
local swszCb = imgui.ImCallback(function(data) end)
imgui.SetNextWindowSizeConstraints(size_min, size_max, swszCb)
ImFont::CalcTextSizeA,
ImFontAtlas::CustomRect::CalcCustomRectUV,
ImFontAtlas::GetTexDataAsRGBA32,
ImFontAtlas::GetTexDataAsAlpha8,
ImFontAtlas::GlyphRangesBuilder::BuildRanges,
ImGui::ColorConvertRGBtoHSV и
ImGui::ColorConvertHSVtoRGB
возвращают значения вместо изменения по ссылке
float r, g, b;
ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b);
local r, g, b = imgui.ColorConvertHSVtoRGB(h, s, v)
ImGuiIO::IniFilename и ImGuiIO::LogFilename принимают ImBuffer вместо указателя на строкуconst char ini_path[] = "my/path.ini";
ImGui::GetIO().IniFilename = ini_path;
local ini_path = imgui.ImBuffer('my/path.ini')
imgui.GetIO().IniFilename = ini_path
Изменение ImGuiTextEditCallbackData::Buf автоматически обновляет длину и задаёт значение BufDirtys.copy(data.Buf, data.BufSize);
data.BufTextLen = s.length();
data.BufDirty = true;
data.Buf = 'text'

Остальные изменения
  • Добавлено несколько дополнительных функций
    • ImColor::ToU32 - преобразование ImColor в целое
    • ImGui::GetStyleColorU32 вместо ImGui::GetColorU32 для цвета стиля
    • ImGui::PlotLinesEx вместо callback-варианта PlotLines
    • ImGui::PlotHistogramEx вместо callback-варианта PlotHistogram
    • ImDrawList::AddTextEx вместо AddText с дополнительными аргументами
  • Отсутствуют функции
    • Функции, принимающие и возвращающие void*-идентификаторы (например, PushID(void*) и GetID(void*))
    • Функции с va_list-форматированием текста (например, TextV)
Теперь, зная всё это, вы уже можете начать работать с Moon ImGui. За списком функций ImGui и примерами на C++ обращайтесь на официальную страницу.

Но это ещё не всё. Вся работа с текстом в ImGui основана на UTF-8, т.е. текст не ограничен лишь стандартным набором символов. Но т.к. GTA, SAMP и MoonLoader не поддерживают юникод, кодировки необходимо конвертировать.

Работа с другими языками на примере русского
В MoonLoader v.025 были добавлены библиотеки lua-iconv и encoding, они призваны помочь в работе с разными кодировками текста.
Следующий пример показывает как использовать текст на русском в ImGui:
Скрипт должен быть сохранён в кодировке Windows-1251
Lua:
local imgui = require 'imgui'
local encoding = require 'encoding' -- загружаем библиотеку
encoding.default = 'CP1251' -- указываем кодировку по умолчанию, она должна совпадать с кодировкой файла. CP1251 - это Windows-1251
u8 = encoding.UTF8 -- и создаём короткий псевдоним для кодировщика UTF-8

local test_text_buffer = imgui.ImBuffer(256)
function imgui.OnDrawFrame()
  imgui.Begin(u8'Основное окно') -- обратите внимание на u8 перед текстом, это и есть преобразование кодировки
  if imgui.InputText(u8'Вводить текст сюда', test_text_buffer) then -- условие будет срабатывать при изменении текста
    -- здесь первая строка передаётся по-обычному, без u8
    -- но введённый текст при выводе преобразуется обратно из UTF-8 в кодировку по умолчанию, т.е. в Windows-1251
    print('Введённый текст:', u8:decode(test_text_buffer.v)) -- при работе с ImBuffer тоже не забывайте о .v
  end
  imgui.Text(u8'Введённый текст: ' .. test_text_buffer.v) -- но тут обратное преобразование введённого текста не требуется, т.к. текст буфера и так в UTF-8
  imgui.Text(u8(string.format('Текущая дата: %s', os.date()))) -- u8 - это функция, её можно использовать и с неконстантными строками
  imgui.End()
end

function main()
  imgui.Process = true
end
Результат:
upload_2017-11-25_18-29-37.png


Не так уж и сложно, верно? Текст, передаваемый ImGui - кодируем, текст, получаемый из ImGui - декодируем. Если в вашем скрипте много текста на русском для ImGui, но мало текста, выводимого через MoonLoader (в лог или чат SA:MP, к примеру), то можно сделать наоборот - сохранить скрипт в кодировке UTF-8 и не кодировать текст, передаваемый ImGui, а вместо этого кодировать текст при работе с функциями мунлоадера.

Остальные особенности
В Moon ImGui есть несколько дополнительных возможностей. В частности, они реализуют взаимодействие с игрой и управление интерфейсом.
Код:
Параметры
imgui.BeforeDrawFrame = nil  -  опциональный калбэк. Если он задан, будет вызываться каждый кадр перед OnDrawFrame и NewFrame самого ImGui. Его можно использовать для загрузки шрифтов и текстур (будьте осторожны, он вызывается каждый кадр)
imgui.OnDrawFrame = nil  -  основной калбэк для рендера, о нём вы уже знаете
imgui.Process = false  -  только если задано true, имгуи будет обрабатываться и выводиться
imgui.RenderInMenu = false  -  показывать интерфейс в меню паузы, по умолчанию отключено
imgui.ShowCursor = true  -  показывать курсор, по умолчанию включен. Отключение может пригодиться, если нужно рисовать только какой-то оверлей без взаимодействия с ним
imgui.LockPlayer = false  -  отключить управление игроком, пока ImGui активен. Если не задано, то управление игроком будет отключаться только когда ImGui требуется обработать ввод с клавиатуры

Функции
после загрузки новых шрифтов и обязательно вне OnDrawFrame
function imgui.CreateTextureFromFile(path)  -  загрузить текстуру из файла. Возвращает загруженную текстуру или nil в случае неудачи
function imgui.CreateTextureFromMemory(address, size)  -  загрузить текстуру из изображения, хранящегося по указанному адресу в памяти. Возвращает загруженную текстуру или nil в случае неудачи
function imgui.GetTextureFromAddress(address)  -  получить ImGui-совместимую текстуру по адресу памяти
function imgui.ReleaseTexture(texture)  -  выгрузить текстуру, загруженную с помощью CreateTextureFromFile или CreateTextureFromMemory\
function imgui.RebuildFonts()  -  пересобрать внутреннюю текстуру шрифтов. Необходимо использовать
function imgui.SwitchContext()  -  переключить ImGui-контекст на принадлежащий скрипту. В BeforeDrawFrame и OnDrawFrame контекст переключается автоматически, так что в них эту функцию использовать нет нужды.

На этом всё. Во вложениях есть пример с демонстрацией использования всех этих фич, рекомендую посмотреть код и пощупать его в игре. Вот скриншот:

upload_2017-11-25_18-28-12.png

Полезные штуки для разработчиков
FontAwesome 4: https://blast.hk/threads/19292/post-168990
FontAwesome 5: https://blast.hk/threads/19292/post-335148
ImGui Pie: https://blast.hk/threads/19648/post-226145
Внутриигровая песочница: https://blast.hk/threads/19292/post-219453
ImGui Custom (хоткеи и ещё чет): https://blast.hk/threads/22080/
Global notification: https://blast.hk/threads/21619/
Стили:
https://blast.hk/threads/19292/post-260462

Ссылки
Скачать Moon ImGui (Download)
Установка:
распаковать содержимое архива в корневую папку игры.
Требуется MoonLoader v.026 или выше
Официальная страница ImGui
Пример на C++ с применением большинства возможностей (imgui_demo.cpp)
Все функции ImGui (imgui.h. Список поддерживаемых также есть в imgui.lua)
 

Вложения

  • moon imgui demo.lua
    9.2 KB · Просмотры: 121,460
Последнее редактирование:

FYP

Известный
Автор темы
Администратор
1,763
5,915
Lua:
local r, g, b, a = imgui.ImColor(imvec4_color):GetRGBA()
mat:set_color(r, g, b, a)
 

AnWu

https://t.me/anwublog
Всефорумный модератор
4,771
5,377
@FYP еще разочек помоги
Lua:
local car = storeCarCharIsInNoSave(PLAYER_PED)
for_each_vehicle_material(car, function(mat)
local r, g, b, old_a = mat:get_color()
if (r == 0x3C and g == 0xFF and b == 0x00) or (r == 0xFF and g == 0x00 and b == 0xAF) then
sampAddChatMessage(r .. " | " .. g .. " | " .. b .. " | " .. old_a, -1)
colors = imgui.ImColor(r, g, b, old_a):GetVec4()
end
end)
Почему цвет тачки возвращается не верный? Всегда возвращается 60 255 0 255, хотя цвета любые могут быть
 

FYP

Известный
Автор темы
Администратор
1,763
5,915
это такой костыль рокстаров, если цвет r == 0x3C and g == 0xFF and b == 0x00, то он читается не из компонента, а из массива цветов транспорта
 

AnWu

https://t.me/anwublog
Всефорумный модератор
4,771
5,377
это такой костыль рокстаров, если цвет r == 0x3C and g == 0xFF and b == 0x00, то он читается не из компонента, а из массива цветов транспорта
Это конечно здорово, но что делать то. набить ебало рокстар не варик
 
  • Нравится
Реакции: PanSeek

LUCHARE

Известный
Друг
545
697
не будет ничего страшного, если я буду многократно загружать одну и ту же текстуру, не выгружая её?
 

AnWu

https://t.me/anwublog
Всефорумный модератор
4,771
5,377
Как правильно использовать ColorEdit4?
Lua:
local colors = imgui.ImColor(0, 0, 0, 255):GetVec4()
function imgui.OnDrawFrame()
if(wMainState.v)then
local sw, sh = getScreenResolution()
imgui.SetNextWindowPos(imgui.ImVec2(sw * 0.77, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
imgui.SetNextWindowSize(imgui.ImVec2(300, 300), imgui.Cond.FirstUseEver)
imgui.Begin(u8'Тюнинг', _, imgui.WindowFlags.NoResize + imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoMove + imgui.WindowFlags.NoBringToFrontOnFocus)
if isCharInAnyCar(PLAYER_PED) then
if(imgui.ColorPicker3("##carColor", colors))then
local car = storeCarCharIsInNoSave(PLAYER_PED)
local new_r, new_g, new_b = math.random(0, 255), math.random(0, 255), math.random(0, 255)
for_each_vehicle_material(car, function(mat)
local r, g, b, old_a = mat:get_color()
if (r == 0x3C and g == 0xFF and b == 0x00) or (r == 0xFF and g == 0x00 and b == 0xAF) then
local r, g, b, a = imgui.ImColor(colors):GetRGBA()
mat:set_color(r, g, b, old_a)
end
end)
end
end
imgui.End()
end
end

ColorPicker тоже что и ColorEdit, 3 и 4 отличаются лишь наличием прозрачности цвета.
 
  • Нравится
Реакции: kmsfax

AnWu

https://t.me/anwublog
Всефорумный модератор
4,771
5,377
Lua:
GetWindowDrawList()
Что это? Что за ImDrawList?
 

Dark_Knight

Me, me and me.
Друг
4,081
2,099
Короче, тут у меня были траблы с использованием сранного Атом(автокомплит в нем полная хуйня) и некоторые моменты мне были не понятны, хоть Фип закомментировал часть кода. Решил себе сделать такой список функций(thanks for pairs). Пока только названия без параметров и что возвращает. По мере возможностей буду обновлять коль не забью болт.
Lua:
boolean DisableInput
boolean LockPlayer
boolean Process
boolean RenderInMenu
boolean ShowCursor
function AlignTextToFramePadding
function Begin
function BeginChild
function BeginChildFrame
function BeginGroup
function BeginMainMenuBar
function BeginMenu
function BeginMenuBar
function BeginPopup
function BeginPopupContextItem
function BeginPopupContextVoid
function BeginPopupContextWindow
function BeginPopupModal
function BeginTooltip
function Bullet
function BulletText
function Button
function CalcItemRectClosestPoint
function CalcItemWidth
function CalcListClipping
function CalcTextSize
function CaptureKeyboardFromApp
function CaptureMouseFromApp
function Checkbox
function CheckboxFlags
function CloseCurrentPopup
function CollapsingHeader
function ColorButton
function ColorConvertFloat4ToU32
function ColorConvertHSVtoRGB
function ColorConvertRGBtoHSV
function ColorConvertU32ToFloat4
function ColorEdit3
function ColorEdit4
function ColorPicker3
function ColorPicker4
function Columns
function Combo
function CreateTextureFromFile
function CreateTextureFromMemory
function DragFloat
function DragFloat2
function DragFloat3
function DragFloat4
function DragFloatRange2
function DragInt
function DragInt2
function DragInt3
function DragInt4
function DragIntRange2
function Dummy
function End
function EndChild
function EndChildFrame
function EndGroup
function EndMainMenuBar
function EndMenu
function EndMenuBar
function EndPopup
function EndTooltip
function GetClipboardText
function GetColorU32
function GetColumnIndex
function GetColumnOffset
function GetColumnWidth
function GetColumnsCount
function GetContentRegionAvail
function GetContentRegionAvailWidth
function GetContentRegionMax
function GetCursorPos
function GetCursorPosX
function GetCursorPosY
function GetCursorScreenPos
function GetCursorStartPos
function GetDrawData
function GetFont
function GetFontSize
function GetFontTexUvWhitePixel
function GetFrameCount
function GetID
function GetIO
function GetItemRectMax
function GetItemRectMin
function GetItemRectSize
function GetItemsLineHeightWithSpacing
function GetKeyIndex
function GetKeyPressedAmount
function GetMouseCursor
function GetMouseDragDelta
function GetMousePos
function GetMousePosOnOpeningCurrentPopup
function GetScrollMaxX
function GetScrollMaxY
function GetScrollX
function GetScrollY
function GetStateStorage
function GetStyle
function GetStyleColorName
function GetStyleColorU32
function GetStyleColorVec4
function GetTextLineHeight
function GetTextLineHeightWithSpacing
function GetTextureFromAddress
function GetTime
function GetTreeNodeToLabelSpacing
function GetVersion
function GetWindowContentRegionMax
function GetWindowContentRegionMin
function GetWindowContentRegionWidth
function GetWindowDrawList
function GetWindowHeight
function GetWindowPos
function GetWindowSize
function GetWindowWidth
function IM_COL32
function Image
function ImageButton
function Indent
function InputFloat
function InputFloat2
function InputFloat3
function InputFloat4
function InputInt
function InputInt2
function InputInt3
function InputInt4
function InputText
function InputTextMultiline
function InvisibleButton
function IsAnyItemActive
function IsAnyItemHovered
function IsAnyWindowHovered
function IsItemActive
function IsItemClicked
function IsItemHovered
function IsItemVisible
function IsKeyDown
function IsKeyPressed
function IsKeyReleased
function IsMouseClicked
function IsMouseDoubleClicked
function IsMouseDown
function IsMouseDragging
function IsMouseHoveringRect
function IsMousePosValid
function IsMouseReleased
function IsPopupOpen
function IsRectVisible
function IsRootWindowFocused
function IsRootWindowOrAnyChildFocused
function IsRootWindowOrAnyChildHovered
function IsWindowAppearing
function IsWindowCollapsed
function IsWindowFocused
function IsWindowHovered
function LabelText
function ListBox
function ListBoxFooter
function ListBoxHeader
function LogButtons
function LogFinish
function LogText
function LogToClipboard
function LogToFile
function LogToTTY
function MenuItem
function NewLine
function NextColumn
function OpenPopup
function OpenPopupOnItemClick
function PlotHistogram
function PlotHistogramEx
function PlotLines
function PlotLinesEx
function PopAllowKeyboardFocus
function PopButtonRepeat
function PopClipRect
function PopFont
function PopID
function PopItemWidth
function PopStyleColor
function PopStyleVar
function PopTextWrapPos
function ProgressBar
function PushAllowKeyboardFocus
function PushButtonRepeat
function PushClipRect
function PushFont
function PushID
function PushItemWidth
function PushStyleColor
function PushStyleVar
function PushTextWrapPos
function RadioButton
function RebuildFonts
function ReleaseTexture
function ResetMouseDragDelta
function SameLine
function Selectable
function Separator
function SetClipboardText
function SetColorEditOptions
function SetColumnOffset
function SetColumnWidth
function SetCursorPos
function SetCursorPosX
function SetCursorPosY
function SetCursorScreenPos
function SetItemAllowOverlap
function SetKeyboardFocusHere
function SetMouseCursor
function SetNextTreeNodeOpen
function SetNextWindowCollapsed
function SetNextWindowContentSize
function SetNextWindowContentWidth
function SetNextWindowFocus
function SetNextWindowPos
function SetNextWindowSize
function SetNextWindowSizeConstraints
function SetScrollFromPosY
function SetScrollHere
function SetScrollX
function SetScrollY
function SetStateStorage
function SetTooltip
function SetWindowCollapsed
function SetWindowFocus
function SetWindowFontScale
function SetWindowPos
function SetWindowSize
function ShowMetricsWindow
function ShowStyleEditor
function ShowTestWindow
function ShowUserGuide
function SliderAngle
function SliderFloat
function SliderFloat2
function SliderFloat3
function SliderFloat4
function SliderInt
function SliderInt2
function SliderInt3
function SliderInt4
function SmallButton
function Spacing
function StyleColorsClassic
function SwitchContext
function Text
function TextColored
function TextDisabled
function TextUnformatted
function TextWrapped
function TreeAdvanceToLabelPos
function TreeNode
function TreeNodeEx
function TreePop
function TreePush
function Unindent
function VSliderFloat
function VSliderInt
function Value
number IM_COL32_BLACK
number IM_COL32_BLACK_TRANS
number IM_COL32_WHITE
string _VERSION
table Col
table ColorEditFlags
table Cond
table HoveredFlags
table ImBool
table ImBuffer
table ImCallback
table ImColor
table ImDrawCmd
table ImDrawData
table ImDrawList
table ImDrawVert
table ImFloat
table ImFloat2
table ImFloat3
table ImFloat4
table ImFont
table ImFontAtlas
table ImFontAtlasCustomRect
table ImFontAtlasGlyphRangesBuilder
table ImFontConfig
table ImFontGlyph
table ImGlyphRanges
table ImGuiListClipper
table ImGuiRenderer
table ImGuiStorage
table ImGuiStyle
table ImGuiTextFilter
table ImInt
table ImInt2
table ImInt3
table ImInt4
table ImVec2
table ImVec4
table InputDeviceType
table InputTextFlags
table Key
table MouseCursor
table SelectableFlags
table StyleVar
table TreeNodeFlags
table WindowFlags
table _ImGuiIO
table _ImGuiSizeConstraintCallbackData
table _ImGuiTextEditCallbackData
 
  • Нравится
Реакции: xdswd