Last active
December 28, 2024 11:01
-
-
Save sthairno/887740c5ec1a8857e66e30ba179fdc3b to your computer and use it in GitHub Desktop.
imgui_impl_s3d
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Siv3D.hpp> | |
#include <imgui.h> | |
#include "imgui_impl_s3d.h" | |
#include "DearImGuiAddon.hpp" | |
/// @brief アドオンの登録時の初期化処理を記述します。 | |
/// @remark この関数が false を返すとアドオンの登録は失敗します。 | |
/// @return アドオンの初期化に成功した場合 true, それ以外の場合は false | |
bool DearImGuiAddon::init() | |
{ | |
ImGui::CreateContext(); | |
ImGui_Impls3d_Init(); | |
return true; | |
} | |
/// @brief アドオンの毎フレームの更新処理を記述します。 | |
/// @remark この関数が false を返すと `System::Update()` は false を返します。 | |
/// @return アドオンの更新に成功した場合 true, それ以外の場合は false | |
bool DearImGuiAddon::update() | |
{ | |
ImGui_Impls3d_NewFrame(); | |
ImGui::NewFrame(); | |
m_firstFrame = false; | |
return true; | |
} | |
/// @brief アドオンの毎フレームの描画処理を記述します。 | |
void DearImGuiAddon::draw() const | |
{ | |
if (m_firstFrame) | |
{ | |
return; | |
} | |
ImGui::Render(); | |
ImGui_Impls3d_RenderDrawData(::ImGui::GetDrawData()); | |
} | |
DearImGuiAddon::~DearImGuiAddon() | |
{ | |
ImGui_Impls3d_Shutdown(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <imgui.h> | |
class DearImGuiAddon : public ::s3d::IAddon | |
{ | |
public: | |
virtual bool init() override; | |
virtual bool update() override; | |
virtual void draw() const override; | |
virtual ~DearImGuiAddon() override; | |
private: | |
bool m_firstFrame = true; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <imgui.h> // v1.88 | |
#include <Siv3D.hpp> // OpenSiv3D v0.6.5 | |
#include "imgui_impl_s3d.h" | |
struct ImeWindowContext | |
{ | |
Vec2 pos; | |
double lineHeight; | |
}; | |
struct ImGuiImpls3dContext | |
{ | |
std::string clipboardData; | |
uint64 keyDownMinTime = 0; | |
std::array<uint64, 512> keyDownTimeList; | |
Texture fontTexture; | |
Optional<ImeWindowContext> imeWindow; | |
std::unordered_map < ImTextureID, Texture, decltype([](ImTextureID id) { return reinterpret_cast<size_t>(id); }) > textureDic; | |
}; | |
const static std::unordered_map<uint8, ImGuiKey> KeyId2ImGuiKeyDic{ | |
{KeyTab.code(), ImGuiKey_Tab}, | |
{KeyLeft.code(), ImGuiKey_LeftArrow}, | |
{KeyRight.code(), ImGuiKey_RightArrow}, | |
{KeyUp.code(), ImGuiKey_UpArrow}, | |
{KeyDown.code(), ImGuiKey_DownArrow}, | |
{KeyPageUp.code(), ImGuiKey_PageUp}, | |
{KeyPageDown.code(), ImGuiKey_PageDown}, | |
{KeyHome.code(), ImGuiKey_Home}, | |
{KeyEnd.code(), ImGuiKey_End}, | |
{KeyInsert.code(), ImGuiKey_Insert}, | |
{KeyDelete.code(), ImGuiKey_Delete}, | |
{KeyBackspace.code(), ImGuiKey_Backspace}, | |
{KeySpace.code(), ImGuiKey_Space}, | |
{KeyEnter.code(), ImGuiKey_Enter}, | |
{KeyEscape.code(), ImGuiKey_Escape}, | |
{KeyLControl.code(), ImGuiKey_LeftCtrl}, | |
{KeyLShift.code(), ImGuiKey_LeftShift}, | |
{KeyLAlt.code(), ImGuiKey_LeftAlt}, | |
{KeyRControl.code(), ImGuiKey_RightCtrl}, | |
{KeyRShift.code(), ImGuiKey_RightShift}, | |
{KeyRAlt.code(), ImGuiKey_RightAlt}, | |
{Key0.code(), ImGuiKey_0}, | |
{Key1.code(), ImGuiKey_1}, | |
{Key2.code(), ImGuiKey_2}, | |
{Key3.code(), ImGuiKey_3}, | |
{Key4.code(), ImGuiKey_4}, | |
{Key5.code(), ImGuiKey_5}, | |
{Key6.code(), ImGuiKey_6}, | |
{Key7.code(), ImGuiKey_7}, | |
{Key8.code(), ImGuiKey_8}, | |
{Key9.code(), ImGuiKey_9}, | |
{KeyA.code(), ImGuiKey_A}, | |
{KeyB.code(), ImGuiKey_B}, | |
{KeyC.code(), ImGuiKey_C}, | |
{KeyD.code(), ImGuiKey_D}, | |
{KeyE.code(), ImGuiKey_E}, | |
{KeyF.code(), ImGuiKey_F}, | |
{KeyG.code(), ImGuiKey_G}, | |
{KeyH.code(), ImGuiKey_H}, | |
{KeyI.code(), ImGuiKey_I}, | |
{KeyJ.code(), ImGuiKey_J}, | |
{KeyK.code(), ImGuiKey_K}, | |
{KeyL.code(), ImGuiKey_L}, | |
{KeyM.code(), ImGuiKey_M}, | |
{KeyN.code(), ImGuiKey_N}, | |
{KeyO.code(), ImGuiKey_O}, | |
{KeyP.code(), ImGuiKey_P}, | |
{KeyQ.code(), ImGuiKey_Q}, | |
{KeyR.code(), ImGuiKey_R}, | |
{KeyS.code(), ImGuiKey_S}, | |
{KeyT.code(), ImGuiKey_T}, | |
{KeyU.code(), ImGuiKey_U}, | |
{KeyV.code(), ImGuiKey_V}, | |
{KeyW.code(), ImGuiKey_W}, | |
{KeyX.code(), ImGuiKey_X}, | |
{KeyY.code(), ImGuiKey_Y}, | |
{KeyZ.code(), ImGuiKey_Z}, | |
{KeyF1.code(), ImGuiKey_F1}, | |
{KeyF2.code(), ImGuiKey_F2}, | |
{KeyF3.code(), ImGuiKey_F3}, | |
{KeyF4.code(), ImGuiKey_F4}, | |
{KeyF5.code(), ImGuiKey_F5}, | |
{KeyF6.code(), ImGuiKey_F6}, | |
{KeyF7.code(), ImGuiKey_F7}, | |
{KeyF8.code(), ImGuiKey_F8}, | |
{KeyF9.code(), ImGuiKey_F9}, | |
{KeyF10.code(), ImGuiKey_F10}, | |
{KeyF11.code(), ImGuiKey_F11}, | |
{KeyF12.code(), ImGuiKey_F12}, | |
{KeyApostrophe_US.code(), ImGuiKey_Apostrophe}, | |
{KeyComma.code(), ImGuiKey_Comma}, | |
{KeyMinus.code(), ImGuiKey_Minus}, | |
{KeyPeriod.code(), ImGuiKey_Period}, | |
{KeySlash.code(), ImGuiKey_Slash}, | |
{KeySemicolon_US.code(), ImGuiKey_Semicolon}, | |
{KeyEqual_US.code(), ImGuiKey_Equal}, | |
{KeyLBracket.code(), ImGuiKey_LeftBracket}, | |
{KeyBackslash_US.code(), ImGuiKey_Backslash}, | |
{KeyRBracket.code(), ImGuiKey_RightBracket}, | |
{KeyGraveAccent.code(), ImGuiKey_GraveAccent}, | |
{KeyNumLock.code(), ImGuiKey_NumLock}, | |
{KeyPrintScreen.code(), ImGuiKey_PrintScreen}, | |
{KeyPause.code(), ImGuiKey_Pause}, | |
{KeyNum0.code(), ImGuiKey_Keypad0}, | |
{KeyNum1.code(), ImGuiKey_Keypad1}, | |
{KeyNum2.code(), ImGuiKey_Keypad2}, | |
{KeyNum3.code(), ImGuiKey_Keypad3}, | |
{KeyNum4.code(), ImGuiKey_Keypad4}, | |
{KeyNum5.code(), ImGuiKey_Keypad5}, | |
{KeyNum6.code(), ImGuiKey_Keypad6}, | |
{KeyNum7.code(), ImGuiKey_Keypad7}, | |
{KeyNum8.code(), ImGuiKey_Keypad8}, | |
{KeyNum9.code(), ImGuiKey_Keypad9}, | |
{KeyNumDecimal.code(), ImGuiKey_KeypadDecimal}, | |
{KeyNumDivide.code(), ImGuiKey_KeypadDivide}, | |
{KeyNumMultiply.code(), ImGuiKey_KeypadMultiply}, | |
{KeyNumSubtract.code(), ImGuiKey_KeypadSubtract}, | |
{KeyNumAdd.code(), ImGuiKey_KeypadAdd}, | |
{KeyNumEnter.code(), ImGuiKey_KeypadEnter}, | |
{KeyControl.code(), ImGuiKey_ModCtrl}, | |
{KeyShift.code(), ImGuiKey_ModShift}, | |
{KeyAlt.code(), ImGuiKey_ModAlt}, | |
}; | |
inline ImVec2 ToImVec2(Point src) | |
{ | |
return ImVec2{ static_cast<float>(src.x), static_cast<float>(src.y) }; | |
} | |
inline ImVec2 ToImVec2(Float2 src) | |
{ | |
return ImVec2{ src.x, src.y }; | |
} | |
inline ImVec2 ToImVec2(Vec2 src) | |
{ | |
return ImVec2{ static_cast<float>(src.x), static_cast<float>(src.y) }; | |
} | |
inline Float2 ToFloat2(ImVec2 src) | |
{ | |
return Float2{ src.x, src.y }; | |
} | |
static ImGuiKey ToImGuiKey(Input input) | |
{ | |
auto itr = KeyId2ImGuiKeyDic.find(input.code()); | |
return itr == KeyId2ImGuiKeyDic.cend() | |
? ImGuiKey_None | |
: itr->second; | |
} | |
static std::unique_ptr<ImGuiImpls3dContext> Context; | |
static const char* GetClipboardTextCallback(void*) | |
{ | |
Context->clipboardData.clear(); | |
String buff; | |
if (not Clipboard::GetText(buff)) | |
{ | |
return NULL; | |
} | |
Context->clipboardData = Unicode::ToUTF8(buff); | |
return Context->clipboardData.c_str(); | |
} | |
static void SetClipboardTextCallback(void*, const char* text) | |
{ | |
Clipboard::SetText(Unicode::FromUTF8(text)); | |
} | |
static void SetImeDataCallback(ImGuiViewport* viewport, ImGuiPlatformImeData* data) | |
{ | |
if (data->WantVisible) | |
{ | |
Context->imeWindow = ImeWindowContext{ | |
.pos = ToFloat2(data->InputPos), | |
.lineHeight = data->InputLineHeight | |
}; | |
} | |
else | |
{ | |
Context->imeWindow.reset(); | |
} | |
} | |
static void RenderImeWindow() | |
{ | |
if (not Context->imeWindow) | |
{ | |
return; | |
} | |
ImeWindowContext& imeWindow = Context->imeWindow.value(); | |
const auto& font = SimpleGUI::GetFont(); | |
const auto drawableText = font(TextInput::GetEditingText()); | |
const double size = imeWindow.lineHeight * font.fontSize() / (font.fontSize() + font.descender()); | |
drawableText.region(size, imeWindow.pos) | |
.draw(Palette::White); | |
drawableText | |
.draw(size, imeWindow.pos, Palette::Black); | |
} | |
static void CreateFontsTexture() | |
{ | |
ImGuiIO& io = ImGui::GetIO(); | |
unsigned char* pixels; | |
Size size; | |
io.Fonts->GetTexDataAsRGBA32(&pixels, &size.x, &size.y); | |
Image image(size); | |
memcpy_s(image.dataAsUint8(), image.size_bytes(), pixels, size.x * size.y * 4); | |
Texture texture(image); | |
Context->fontTexture = texture; | |
ImTextureID id = ImGui_Impls3d_RegisterTexture(texture); | |
io.Fonts->SetTexID(id); | |
} | |
///// API ///// | |
ImTextureID ImGui_Impls3d_RegisterTexture(Texture& tex) | |
{ | |
ImTextureID id = reinterpret_cast<void*>(tex.id().value()); | |
Context->textureDic.try_emplace(id, tex); | |
return id; | |
} | |
void ImGui_Impls3d_UnregisterTexture(Texture& tex) | |
{ | |
ImTextureID id = reinterpret_cast<void*>(tex.id().value()); | |
Context->textureDic.erase(id); | |
} | |
Texture ImGui_Impls3d_GetTexture(ImTextureID id) | |
{ | |
return Context->textureDic.at(id); | |
} | |
bool ImGui_Impls3d_Init() | |
{ | |
Context = std::make_unique<ImGuiImpls3dContext>(); | |
Context->keyDownTimeList.fill(0); | |
ImGuiIO& io = ImGui::GetIO(); | |
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; | |
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; | |
// io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; | |
io.BackendPlatformName = "imgui_impl_s3d"; | |
io.BackendRendererName = "imgui_impl_s3d"; | |
io.GetClipboardTextFn = &GetClipboardTextCallback; | |
io.SetClipboardTextFn = &SetClipboardTextCallback; | |
io.SetPlatformImeDataFn = &SetImeDataCallback; | |
return true; | |
} | |
void ImGui_Impls3d_Shutdown() | |
{ | |
Context.reset(); | |
} | |
void ImGui_Impls3d_NewFrame() | |
{ | |
if (not Context->fontTexture) | |
{ | |
CreateFontsTexture(); | |
} | |
ImGuiIO& io = ImGui::GetIO(); | |
uint64 currentTime = Time::GetMillisec(); | |
//Display | |
{ | |
io.DisplaySize = ToImVec2(Scene::Size()); | |
io.DeltaTime = Scene::DeltaTime(); | |
} | |
// TextInput | |
{ | |
String editingText = TextInput::GetEditingText(); | |
String input = TextInput::GetRawInput(); | |
if (editingText) | |
{ | |
// 文字変換との競合を防止するため、変換中はキーボード入力を一時的に無効化する | |
Context->keyDownMinTime = currentTime + 100; | |
} | |
if (input) | |
{ | |
io.AddInputCharactersUTF8(Unicode::ToUTF8(input).c_str()); | |
} | |
} | |
//Keyboard | |
{ | |
for (auto key : Keyboard::GetAllInputs()) | |
{ | |
uint64& keyDownTime = Context->keyDownTimeList[key.code()]; | |
if (key.down()) | |
{ | |
keyDownTime = currentTime; | |
} | |
const bool pressed = key.pressed() && keyDownTime >= Context->keyDownMinTime; | |
io.AddKeyEvent(ToImGuiKey(key), pressed); | |
} | |
} | |
//Cursor | |
{ | |
if (io.WantSetMousePos) | |
{ | |
Cursor::SetPos(io.MousePos.x, io.MousePos.y); | |
} | |
if (not (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)) | |
{ | |
if (io.MouseDrawCursor) | |
{ | |
Cursor::RequestStyle(CursorStyle::Hidden); | |
} | |
else | |
{ | |
CursorStyle s3dStyle; | |
switch (ImGui::GetMouseCursor()) | |
{ | |
case ImGuiMouseCursor_None: s3dStyle = CursorStyle::Hidden; break; | |
case ImGuiMouseCursor_Arrow: s3dStyle = CursorStyle::Arrow; break; | |
case ImGuiMouseCursor_TextInput: s3dStyle = CursorStyle::IBeam; break; | |
case ImGuiMouseCursor_ResizeAll: s3dStyle = CursorStyle::ResizeAll; break; | |
case ImGuiMouseCursor_ResizeEW: s3dStyle = CursorStyle::ResizeLeftRight; break; | |
case ImGuiMouseCursor_ResizeNS: s3dStyle = CursorStyle::ResizeUpDown; break; | |
case ImGuiMouseCursor_ResizeNESW: s3dStyle = CursorStyle::ResizeNESW; break; | |
case ImGuiMouseCursor_ResizeNWSE: s3dStyle = CursorStyle::ResizeNWSE; break; | |
case ImGuiMouseCursor_Hand: s3dStyle = CursorStyle::Hand; break; | |
case ImGuiMouseCursor_NotAllowed: s3dStyle = CursorStyle::NotAllowed; break; | |
default: s3dStyle = CursorStyle::Default; break; | |
} | |
Cursor::RequestStyle(s3dStyle); | |
} | |
} | |
} | |
//Mouse | |
{ | |
const Vec2 mousePos = Cursor::PosF(); | |
const Vec2 wheel{ Mouse::WheelH(), Mouse::Wheel() }; | |
io.AddMousePosEvent(mousePos.x, mousePos.y); | |
io.AddMouseWheelEvent(-wheel.x, -wheel.y); | |
for (const Input& input : Mouse::GetAllInputs()) | |
{ | |
io.AddMouseButtonEvent(input.code(), input.pressed()); | |
} | |
if (io.WantCaptureMouse) | |
{ | |
Mouse::ClearLRInput(); | |
} | |
} | |
// Window | |
{ | |
const WindowState& state = Window::GetState(); | |
io.AddFocusEvent(!state.sizeMove && state.focused); | |
} | |
} | |
void ImGui_Impls3d_RenderDrawData(ImDrawData* draw_data) | |
{ | |
RasterizerState rasterizer = RasterizerState::Default2D; | |
rasterizer.scissorEnable = true; | |
Rect prevScissorRect = Graphics2D::GetScissorRect(); | |
for (int n = 0; n < draw_data->CmdListsCount; n++) | |
{ | |
const ImDrawList* cmd_list = draw_data->CmdLists[n]; | |
static Buffer2D sp; | |
sp.vertices.resize(cmd_list->VtxBuffer.Size); | |
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) | |
{ | |
const ImDrawVert& srcVtx = cmd_list->VtxBuffer[i]; | |
Vertex2D& dstVtx = sp.vertices[i]; | |
dstVtx.pos.x = srcVtx.pos.x; | |
dstVtx.pos.y = srcVtx.pos.y; | |
dstVtx.tex.x = srcVtx.uv.x; | |
dstVtx.tex.y = srcVtx.uv.y; | |
const uint8* c = (uint8*)(&srcVtx.col); | |
dstVtx.color = ColorF(Color(c[0], c[1], c[2], c[3])).toFloat4(); | |
} | |
sp.indices.resize(cmd_list->IdxBuffer.Size / 3); | |
memcpy(sp.indices.data(), cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.size_in_bytes()); | |
ScopedRenderStates2D r(rasterizer); | |
// uint32 vtxOffset = 0; | |
uint32 idxOffset = 0; | |
ImVec2 clipOffset = draw_data->DisplayPos; | |
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) | |
{ | |
const ImDrawCmd& pcmd = cmd_list->CmdBuffer[cmd_i]; | |
const uint32 triangleCnt = pcmd.ElemCount / 3; | |
if (pcmd.UserCallback) | |
{ | |
if (pcmd.UserCallback == ImDrawCallback_ResetRenderState) | |
{ | |
Graphics2D::SetScissorRect(prevScissorRect); | |
} | |
else | |
{ | |
pcmd.UserCallback(cmd_list, &pcmd); | |
} | |
} | |
else | |
{ | |
Texture texture = ImGui_Impls3d_GetTexture(pcmd.TextureId); | |
Graphics2D::SetScissorRect(Rect(pcmd.ClipRect.x - clipOffset.x, pcmd.ClipRect.y - clipOffset.y, pcmd.ClipRect.z - pcmd.ClipRect.x, pcmd.ClipRect.w - pcmd.ClipRect.y)); | |
sp.drawSubset(idxOffset, triangleCnt, texture); | |
} | |
idxOffset += triangleCnt; | |
} | |
} | |
Graphics2D::SetScissorRect(prevScissorRect); | |
RenderImeWindow(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
struct imgui_impl_s3d; | |
IMGUI_IMPL_API bool ImGui_Impls3d_Init(); | |
IMGUI_IMPL_API void ImGui_Impls3d_Shutdown(); | |
IMGUI_IMPL_API void ImGui_Impls3d_NewFrame(); | |
IMGUI_IMPL_API void ImGui_Impls3d_RenderDrawData(ImDrawData* draw_data); | |
IMGUI_IMPL_API ImTextureID ImGui_Impls3d_RegisterTexture(Texture& tex); | |
IMGUI_IMPL_API void ImGui_Impls3d_UnregisterTexture(Texture& tex); | |
IMGUI_IMPL_API Texture ImGui_Impls3d_GetTexture(ImTextureID id); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Siv3D.hpp> // OpenSiv3D v0.6.5 | |
#include "DearImGuiAddon.hpp" | |
void Main() | |
{ | |
Addon::Register<DearImGuiAddon>(U"ImGui"); | |
while (System::Update()) | |
{ | |
ImGui::ShowDemoWindow(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment