chore: CRLF to LF

This commit is contained in:
smpn2
2022-12-16 23:18:35 +09:00
parent b7a60638a4
commit 6c914266d9
725 changed files with 131020 additions and 131020 deletions
+44 -44
View File
@@ -1,44 +1,44 @@
#include "extensions.h"
#include <cmath>
#include "external/imgui/imgui.h"
namespace ImGui {
void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
void Knob(float fraction, float size, float thickness, float pos_x, float pos_y) {
// get values
auto radius = size * 0.5f;
auto pos = ImGui::GetCursorScreenPos();
if (pos_x >= 0) pos.x = pos_x;
if (pos_y >= 0) pos.y = pos_y;
auto center = ImVec2(pos.x + radius, pos.y + radius);
auto draw_list = ImGui::GetWindowDrawList();
// dummy for spacing knob with other content
if (pos_x < 0 && pos_y < 0) {
ImGui::Dummy(ImVec2(size, size));
}
// draw knob
auto angle = (fraction + 0.25f) * (3.141592f * 2);
draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32(ImGuiCol_FrameBg), 16);
draw_list->AddLine(center,
ImVec2(center.x + cosf(angle) * radius, center.y + sinf(angle) * radius),
ImGui::GetColorU32(ImGuiCol_PlotHistogram),
thickness);
}
}
#include "extensions.h"
#include <cmath>
#include "external/imgui/imgui.h"
namespace ImGui {
void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
void Knob(float fraction, float size, float thickness, float pos_x, float pos_y) {
// get values
auto radius = size * 0.5f;
auto pos = ImGui::GetCursorScreenPos();
if (pos_x >= 0) pos.x = pos_x;
if (pos_y >= 0) pos.y = pos_y;
auto center = ImVec2(pos.x + radius, pos.y + radius);
auto draw_list = ImGui::GetWindowDrawList();
// dummy for spacing knob with other content
if (pos_x < 0 && pos_y < 0) {
ImGui::Dummy(ImVec2(size, size));
}
// draw knob
auto angle = (fraction + 0.25f) * (3.141592f * 2);
draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32(ImGuiCol_FrameBg), 16);
draw_list->AddLine(center,
ImVec2(center.x + cosf(angle) * radius, center.y + sinf(angle) * radius),
ImGui::GetColorU32(ImGuiCol_PlotHistogram),
thickness);
}
}
+8 -8
View File
@@ -1,8 +1,8 @@
#pragma once
namespace ImGui {
void HelpMarker(const char* desc);
void Knob(float fraction, float size, float thickness = 2.f,
float pos_x = -1.f, float pos_y = -1.f);
}
#pragma once
namespace ImGui {
void HelpMarker(const char* desc);
void Knob(float fraction, float size, float thickness = 2.f,
float pos_x = -1.f, float pos_y = -1.f);
}
+360 -360
View File
@@ -1,360 +1,360 @@
// dear imgui: Renderer for DirectX9
// This needs to be used along with a Platform Binding (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
#include "impl_dx9.h"
#include <algorithm>
// DirectX
#include <d3d9.h>
#include "external/imgui/imgui.h"
// allow std::min use
#ifdef min
#undef min
#endif
// DirectX data
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
// Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data) {
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Create and grow buffers if needed
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) {
if (g_pVB) {
g_pVB->Release();
g_pVB = NULL;
}
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(ImDrawVert),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
return;
}
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) {
if (g_pIB) {
g_pIB->Release();
g_pIB = NULL;
}
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32,
D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
return;
}
// Backup the DX9 state
IDirect3DStateBlock9 *d3d9_state_block = NULL;
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
return;
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
D3DMATRIX last_world, last_view, last_projection;
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
// Copy all vertices into a single contiguous buffer
ImDrawVert *vtx_dst;
ImDrawIdx *idx_dst;
if (g_pVB->Lock(0, (UINT) (draw_data->TotalVtxCount * sizeof(ImDrawVert)), (void **) &vtx_dst,
D3DLOCK_DISCARD) < 0)
return;
if (g_pIB->Lock(0, (UINT) (draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void **) &idx_dst,
D3DLOCK_DISCARD) < 0)
return;
for (int n = 0; n < draw_data->CmdListsCount; n++) {
const ImDrawList *cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
g_pVB->Unlock();
g_pIB->Unlock();
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(ImDrawVert));
g_pd3dDevice->SetIndices(g_pIB);
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
// Setup viewport
D3DVIEWPORT9 vp;
vp.X = vp.Y = 0;
vp.Width = (DWORD) draw_data->DisplaySize.x;
vp.Height = (DWORD) draw_data->DisplaySize.y;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
g_pd3dDevice->SetViewport(&vp);
g_pd3dDevice->SetPixelShader(nullptr);
g_pd3dDevice->SetVertexShader(nullptr);
D3DCAPS9 caps {};
if (FAILED(g_pd3dDevice->GetDeviceCaps(&caps))) {
caps.NumSimultaneousRTs = 0UL;
}
IDirect3DSurface9 *back_buffer = nullptr;
IDirect3DSurface9 *depth_stencil = nullptr;
IDirect3DSurface9 *render_targets[8];
// save all previous render target state
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
if (FAILED(g_pd3dDevice->GetRenderTarget(target, &render_targets[target]))) {
render_targets[target] = nullptr;
}
}
// get the previous depth stencil
if (FAILED(g_pd3dDevice->GetDepthStencilSurface(&depth_stencil))) {
depth_stencil = nullptr;
}
// set the back buffer as the current render target
if (SUCCEEDED(g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer))) {
g_pd3dDevice->SetRenderTarget(0, back_buffer);
g_pd3dDevice->SetDepthStencilSurface(nullptr);
for (size_t target = 1; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
g_pd3dDevice->SetRenderTarget(target, nullptr);
}
} else {
back_buffer = nullptr;
}
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
// Setup orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
{
float L = draw_data->DisplayPos.x + 0.5f;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
float T = draw_data->DisplayPos.y + 0.5f;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
D3DMATRIX mat_identity = {{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}};
D3DMATRIX mat_projection =
{{{
2.0f / (R - L), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f / (T - B), 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
(L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
}}};
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
}
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++) {
const ImDrawList *cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL) {
pcmd->UserCallback(cmd_list, pcmd);
} else {
const RECT r = {(LONG) (pcmd->ClipRect.x - clip_off.x), (LONG) (pcmd->ClipRect.y - clip_off.y),
(LONG) (pcmd->ClipRect.z - clip_off.x), (LONG) (pcmd->ClipRect.w - clip_off.y)};
auto texture = reinterpret_cast<IDirect3DBaseTexture9 *>(pcmd->TextureId);
g_pd3dDevice->SetTexture(0, texture);
g_pd3dDevice->SetScissorRect(&r);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
pcmd->VtxOffset + global_vtx_offset, 0,
(UINT) cmd_list->VtxBuffer.Size,
pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
if (back_buffer) {
back_buffer->Release();
back_buffer = nullptr;
}
// restore previous depth stencil
if (depth_stencil) {
g_pd3dDevice->SetDepthStencilSurface(depth_stencil);
depth_stencil->Release();
depth_stencil = nullptr;
}
// restore all render target state
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
auto render_target = render_targets[target];
if (render_target) {
g_pd3dDevice->SetRenderTarget(target, render_target);
render_target->Release();
}
}
// restore the DX9 transform
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
// restore the DX9 state
d3d9_state_block->Apply();
d3d9_state_block->Release();
}
bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device) {
// Setup back-end capabilities flags
auto &io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx9";
// We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
g_pd3dDevice = device;
g_pd3dDevice->AddRef();
return true;
}
void ImGui_ImplDX9_Shutdown() {
ImGui_ImplDX9_InvalidateDeviceObjects();
if (g_pd3dDevice) {
g_pd3dDevice->Release();
g_pd3dDevice = NULL;
}
}
static bool ImGui_ImplDX9_CreateFontsTexture() {
// Build texture atlas
ImGuiIO &io = ImGui::GetIO();
unsigned char *pixels;
int width, height, bytes_per_pixel;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
// Upload texture to graphics system
g_FontTexture = NULL;
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
return false;
D3DLOCKED_RECT tex_locked_rect;
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
return false;
for (int y = 0; y < height; y++)
memcpy((unsigned char *) tex_locked_rect.pBits + tex_locked_rect.Pitch * y,
pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
g_FontTexture->UnlockRect(0);
// Store our identifier
io.Fonts->TexID = (ImTextureID) g_FontTexture;
return true;
}
bool ImGui_ImplDX9_CreateDeviceObjects() {
if (!g_pd3dDevice) {
return false;
}
return ImGui_ImplDX9_CreateFontsTexture();
}
void ImGui_ImplDX9_InvalidateDeviceObjects() {
if (!g_pd3dDevice)
return;
if (g_pVB) {
g_pVB->Release();
g_pVB = NULL;
}
if (g_pIB) {
g_pIB->Release();
g_pIB = NULL;
}
if (g_FontTexture) {
g_FontTexture->Release();
g_FontTexture = NULL;
ImGui::GetIO().Fonts->TexID = NULL;
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
}
void ImGui_ImplDX9_NewFrame() {
if (!g_FontTexture) {
ImGui_ImplDX9_CreateDeviceObjects();
}
IDirect3DSwapChain9 *swap_chain = nullptr;
if (SUCCEEDED(g_pd3dDevice->GetSwapChain(0, &swap_chain))) {
auto &io = ImGui::GetIO();
D3DPRESENT_PARAMETERS present_params {};
if (SUCCEEDED(swap_chain->GetPresentParameters(&present_params))) {
if (present_params.BackBufferWidth != 0 && present_params.BackBufferHeight != 0) {
io.DisplaySize.x = static_cast<float>(present_params.BackBufferWidth);
io.DisplaySize.y = static_cast<float>(present_params.BackBufferHeight);
} else {
RECT rect {};
GetClientRect(present_params.hDeviceWindow, &rect);
io.DisplaySize.x = static_cast<float>(rect.right - rect.left);
io.DisplaySize.y = static_cast<float>(rect.bottom - rect.top);
}
}
swap_chain->Release();
}
}
// dear imgui: Renderer for DirectX9
// This needs to be used along with a Platform Binding (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
#include "impl_dx9.h"
#include <algorithm>
// DirectX
#include <d3d9.h>
#include "external/imgui/imgui.h"
// allow std::min use
#ifdef min
#undef min
#endif
// DirectX data
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
// Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data) {
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Create and grow buffers if needed
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) {
if (g_pVB) {
g_pVB->Release();
g_pVB = NULL;
}
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(ImDrawVert),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
return;
}
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) {
if (g_pIB) {
g_pIB->Release();
g_pIB = NULL;
}
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32,
D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
return;
}
// Backup the DX9 state
IDirect3DStateBlock9 *d3d9_state_block = NULL;
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
return;
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
D3DMATRIX last_world, last_view, last_projection;
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
// Copy all vertices into a single contiguous buffer
ImDrawVert *vtx_dst;
ImDrawIdx *idx_dst;
if (g_pVB->Lock(0, (UINT) (draw_data->TotalVtxCount * sizeof(ImDrawVert)), (void **) &vtx_dst,
D3DLOCK_DISCARD) < 0)
return;
if (g_pIB->Lock(0, (UINT) (draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void **) &idx_dst,
D3DLOCK_DISCARD) < 0)
return;
for (int n = 0; n < draw_data->CmdListsCount; n++) {
const ImDrawList *cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
g_pVB->Unlock();
g_pIB->Unlock();
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(ImDrawVert));
g_pd3dDevice->SetIndices(g_pIB);
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
// Setup viewport
D3DVIEWPORT9 vp;
vp.X = vp.Y = 0;
vp.Width = (DWORD) draw_data->DisplaySize.x;
vp.Height = (DWORD) draw_data->DisplaySize.y;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
g_pd3dDevice->SetViewport(&vp);
g_pd3dDevice->SetPixelShader(nullptr);
g_pd3dDevice->SetVertexShader(nullptr);
D3DCAPS9 caps {};
if (FAILED(g_pd3dDevice->GetDeviceCaps(&caps))) {
caps.NumSimultaneousRTs = 0UL;
}
IDirect3DSurface9 *back_buffer = nullptr;
IDirect3DSurface9 *depth_stencil = nullptr;
IDirect3DSurface9 *render_targets[8];
// save all previous render target state
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
if (FAILED(g_pd3dDevice->GetRenderTarget(target, &render_targets[target]))) {
render_targets[target] = nullptr;
}
}
// get the previous depth stencil
if (FAILED(g_pd3dDevice->GetDepthStencilSurface(&depth_stencil))) {
depth_stencil = nullptr;
}
// set the back buffer as the current render target
if (SUCCEEDED(g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer))) {
g_pd3dDevice->SetRenderTarget(0, back_buffer);
g_pd3dDevice->SetDepthStencilSurface(nullptr);
for (size_t target = 1; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
g_pd3dDevice->SetRenderTarget(target, nullptr);
}
} else {
back_buffer = nullptr;
}
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
// Setup orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
{
float L = draw_data->DisplayPos.x + 0.5f;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
float T = draw_data->DisplayPos.y + 0.5f;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
D3DMATRIX mat_identity = {{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}};
D3DMATRIX mat_projection =
{{{
2.0f / (R - L), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f / (T - B), 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
(L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
}}};
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
}
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++) {
const ImDrawList *cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL) {
pcmd->UserCallback(cmd_list, pcmd);
} else {
const RECT r = {(LONG) (pcmd->ClipRect.x - clip_off.x), (LONG) (pcmd->ClipRect.y - clip_off.y),
(LONG) (pcmd->ClipRect.z - clip_off.x), (LONG) (pcmd->ClipRect.w - clip_off.y)};
auto texture = reinterpret_cast<IDirect3DBaseTexture9 *>(pcmd->TextureId);
g_pd3dDevice->SetTexture(0, texture);
g_pd3dDevice->SetScissorRect(&r);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
pcmd->VtxOffset + global_vtx_offset, 0,
(UINT) cmd_list->VtxBuffer.Size,
pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
if (back_buffer) {
back_buffer->Release();
back_buffer = nullptr;
}
// restore previous depth stencil
if (depth_stencil) {
g_pd3dDevice->SetDepthStencilSurface(depth_stencil);
depth_stencil->Release();
depth_stencil = nullptr;
}
// restore all render target state
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
auto render_target = render_targets[target];
if (render_target) {
g_pd3dDevice->SetRenderTarget(target, render_target);
render_target->Release();
}
}
// restore the DX9 transform
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
// restore the DX9 state
d3d9_state_block->Apply();
d3d9_state_block->Release();
}
bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device) {
// Setup back-end capabilities flags
auto &io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx9";
// We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
g_pd3dDevice = device;
g_pd3dDevice->AddRef();
return true;
}
void ImGui_ImplDX9_Shutdown() {
ImGui_ImplDX9_InvalidateDeviceObjects();
if (g_pd3dDevice) {
g_pd3dDevice->Release();
g_pd3dDevice = NULL;
}
}
static bool ImGui_ImplDX9_CreateFontsTexture() {
// Build texture atlas
ImGuiIO &io = ImGui::GetIO();
unsigned char *pixels;
int width, height, bytes_per_pixel;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
// Upload texture to graphics system
g_FontTexture = NULL;
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
return false;
D3DLOCKED_RECT tex_locked_rect;
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
return false;
for (int y = 0; y < height; y++)
memcpy((unsigned char *) tex_locked_rect.pBits + tex_locked_rect.Pitch * y,
pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
g_FontTexture->UnlockRect(0);
// Store our identifier
io.Fonts->TexID = (ImTextureID) g_FontTexture;
return true;
}
bool ImGui_ImplDX9_CreateDeviceObjects() {
if (!g_pd3dDevice) {
return false;
}
return ImGui_ImplDX9_CreateFontsTexture();
}
void ImGui_ImplDX9_InvalidateDeviceObjects() {
if (!g_pd3dDevice)
return;
if (g_pVB) {
g_pVB->Release();
g_pVB = NULL;
}
if (g_pIB) {
g_pIB->Release();
g_pIB = NULL;
}
if (g_FontTexture) {
g_FontTexture->Release();
g_FontTexture = NULL;
ImGui::GetIO().Fonts->TexID = NULL;
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
}
void ImGui_ImplDX9_NewFrame() {
if (!g_FontTexture) {
ImGui_ImplDX9_CreateDeviceObjects();
}
IDirect3DSwapChain9 *swap_chain = nullptr;
if (SUCCEEDED(g_pd3dDevice->GetSwapChain(0, &swap_chain))) {
auto &io = ImGui::GetIO();
D3DPRESENT_PARAMETERS present_params {};
if (SUCCEEDED(swap_chain->GetPresentParameters(&present_params))) {
if (present_params.BackBufferWidth != 0 && present_params.BackBufferHeight != 0) {
io.DisplaySize.x = static_cast<float>(present_params.BackBufferWidth);
io.DisplaySize.y = static_cast<float>(present_params.BackBufferHeight);
} else {
RECT rect {};
GetClientRect(present_params.hDeviceWindow, &rect);
io.DisplaySize.x = static_cast<float>(rect.right - rect.left);
io.DisplaySize.y = static_cast<float>(rect.bottom - rect.top);
}
}
swap_chain->Release();
}
}
+25 -25
View File
@@ -1,25 +1,25 @@
// dear imgui: Renderer for DirectX9
// This needs to be used along with a Platform Binding (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
#pragma once
#include "external/imgui/imgui.h"
struct IDirect3DDevice9;
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device);
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data);
// Use if you want to reset your rendering device without losing ImGui state.
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
// dear imgui: Renderer for DirectX9
// This needs to be used along with a Platform Binding (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
#pragma once
#include "external/imgui/imgui.h"
struct IDirect3DDevice9;
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device);
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data);
// Use if you want to reset your rendering device without losing ImGui state.
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
+10 -10
View File
@@ -1,10 +1,10 @@
#pragma once
#include <windows.h>
#include "external/imgui/imgui.h"
IMGUI_IMPL_API bool ImGui_ImplSpice_Init(HWND hWnd);
IMGUI_IMPL_API void ImGui_ImplSpice_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSpice_UpdateDisplaySize();
IMGUI_IMPL_API bool ImGui_ImplSpice_UpdateMouseCursor();
IMGUI_IMPL_API void ImGui_ImplSpice_NewFrame();
#pragma once
#include <windows.h>
#include "external/imgui/imgui.h"
IMGUI_IMPL_API bool ImGui_ImplSpice_Init(HWND hWnd);
IMGUI_IMPL_API void ImGui_ImplSpice_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSpice_UpdateDisplaySize();
IMGUI_IMPL_API bool ImGui_ImplSpice_UpdateMouseCursor();
IMGUI_IMPL_API void ImGui_ImplSpice_NewFrame();
+65 -65
View File
@@ -1,65 +1,65 @@
// Original File By Emil Ernerfeldt 2018
// https://github.com/emilk/imgui_software_renderer
// LICENSE:
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
// WHAT:
// This is a software renderer for Dear ImGui.
// It is decently fast, but has a lot of room for optimization.
// The goal was to get something fast and decently accurate in not too many lines of code.
// LIMITATIONS:
// * It is not pixel-perfect, but it is good enough for must use cases.
// * It does not support painting with any other texture than the default font texture.
#pragma once
#include <cstdint>
namespace imgui_sw {
struct SwOptions
{
bool optimize_text = true; // No reason to turn this off.
bool optimize_rectangles = true; // No reason to turn this off.
};
struct Stats
{
int uniform_triangle_pixels = 0;
int textured_triangle_pixels = 0;
int gradient_triangle_pixels = 0;
int font_pixels = 0;
double uniform_rectangle_pixels = 0;
double textured_rectangle_pixels = 0;
double gradient_rectangle_pixels = 0;
double gradient_textured_rectangle_pixels = 0;
};
/// Optional: tweak ImGui style to make it render faster.
void make_style_fast();
/// Undo what make_style_fast did.
void restore_style();
/// Call once a the start of your program.
void bind_imgui_painting();
/// The buffer is assumed to follow how ImGui packs pixels, i.e. ABGR by default.
/// Change with IMGUI_USE_BGRA_PACKED_COLOR.
/// If width/height differs from ImGui::GetIO().DisplaySize then
/// the function scales the UI to fit the given pixel buffer.
void paint_imgui(uint32_t* pixels, int width_pixels, int height_pixels, const SwOptions& options = {});
/// Free the resources allocated by bind_imgui_painting.
void unbind_imgui_painting();
/// Show ImGui controls for rendering options if you want to.
bool show_options(SwOptions* io_options);
/// Show rendering stats in an ImGui window if you want to.
void show_stats();
Stats get_stats();
} // namespace imgui_sw
// Original File By Emil Ernerfeldt 2018
// https://github.com/emilk/imgui_software_renderer
// LICENSE:
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
// WHAT:
// This is a software renderer for Dear ImGui.
// It is decently fast, but has a lot of room for optimization.
// The goal was to get something fast and decently accurate in not too many lines of code.
// LIMITATIONS:
// * It is not pixel-perfect, but it is good enough for must use cases.
// * It does not support painting with any other texture than the default font texture.
#pragma once
#include <cstdint>
namespace imgui_sw {
struct SwOptions
{
bool optimize_text = true; // No reason to turn this off.
bool optimize_rectangles = true; // No reason to turn this off.
};
struct Stats
{
int uniform_triangle_pixels = 0;
int textured_triangle_pixels = 0;
int gradient_triangle_pixels = 0;
int font_pixels = 0;
double uniform_rectangle_pixels = 0;
double textured_rectangle_pixels = 0;
double gradient_rectangle_pixels = 0;
double gradient_textured_rectangle_pixels = 0;
};
/// Optional: tweak ImGui style to make it render faster.
void make_style_fast();
/// Undo what make_style_fast did.
void restore_style();
/// Call once a the start of your program.
void bind_imgui_painting();
/// The buffer is assumed to follow how ImGui packs pixels, i.e. ABGR by default.
/// Change with IMGUI_USE_BGRA_PACKED_COLOR.
/// If width/height differs from ImGui::GetIO().DisplaySize then
/// the function scales the UI to fit the given pixel buffer.
void paint_imgui(uint32_t* pixels, int width_pixels, int height_pixels, const SwOptions& options = {});
/// Free the resources allocated by bind_imgui_painting.
void unbind_imgui_painting();
/// Show ImGui controls for rendering options if you want to.
bool show_options(SwOptions* io_options);
/// Show rendering stats in an ImGui window if you want to.
void show_stats();
Stats get_stats();
} // namespace imgui_sw
+100 -100
View File
@@ -1,100 +1,100 @@
#pragma once
#include <memory>
#include <mutex>
#include <vector>
#include <windows.h>
#include <d3d9.h>
#include "external/imgui/imgui.h"
namespace overlay {
class Window;
enum class OverlayRenderer {
D3D9,
SOFTWARE,
};
// settings
extern bool ENABLED;
class SpiceOverlay {
public:
D3DDEVICE_CREATION_PARAMETERS creation_parameters {};
D3DADAPTER_IDENTIFIER9 adapter_identifier {};
bool hotkeys_enable = true;
explicit SpiceOverlay(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device);
explicit SpiceOverlay(HWND hWnd);
~SpiceOverlay();
void window_add(Window *wnd);
void new_frame();
void render();
void update();
void toggle_active(bool overlay_key = false);
void set_active(bool active);
bool get_active();
bool has_focus();
bool hotkeys_triggered();
static bool update_cursor();
static void reset_invalidate();
static void reset_recreate();
void input_char(unsigned int c, bool rawinput = false);
uint32_t *sw_get_pixel_data(int *width, int *height);
inline bool uses_window(HWND hWnd) {
return this->hWnd == hWnd;
}
inline bool uses_context(IDirect3D9 *other) {
return this->d3d == other;
}
inline bool uses_device(IDirect3DDevice9 *other) {
return this->device == other;
}
inline IDirect3DDevice9 *get_device() {
return this->device;
}
// renderer
OverlayRenderer renderer;
float total_elapsed = 0.f;
private:
HWND hWnd = nullptr;
// D3D9
IDirect3D9 *d3d = nullptr;
IDirect3DDevice9 *device = nullptr;
// software
std::vector<uint32_t> pixel_data;
size_t pixel_data_width = 0;
size_t pixel_data_height = 0;
std::vector<std::unique_ptr<Window>> windows;
Window *window_fps = nullptr;
bool active = false;
bool toggle_down = false;
bool rawinput_char = true;
bool hotkey_toggle = false;
bool hotkey_toggle_last = false;
void init();
};
// global
extern std::mutex OVERLAY_MUTEX;
extern std::unique_ptr<overlay::SpiceOverlay> OVERLAY;
// synchronized helpers
void create_d3d9(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device);
void create_software(HWND hWnd);
void destroy(HWND hWnd = nullptr);
}
#pragma once
#include <memory>
#include <mutex>
#include <vector>
#include <windows.h>
#include <d3d9.h>
#include "external/imgui/imgui.h"
namespace overlay {
class Window;
enum class OverlayRenderer {
D3D9,
SOFTWARE,
};
// settings
extern bool ENABLED;
class SpiceOverlay {
public:
D3DDEVICE_CREATION_PARAMETERS creation_parameters {};
D3DADAPTER_IDENTIFIER9 adapter_identifier {};
bool hotkeys_enable = true;
explicit SpiceOverlay(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device);
explicit SpiceOverlay(HWND hWnd);
~SpiceOverlay();
void window_add(Window *wnd);
void new_frame();
void render();
void update();
void toggle_active(bool overlay_key = false);
void set_active(bool active);
bool get_active();
bool has_focus();
bool hotkeys_triggered();
static bool update_cursor();
static void reset_invalidate();
static void reset_recreate();
void input_char(unsigned int c, bool rawinput = false);
uint32_t *sw_get_pixel_data(int *width, int *height);
inline bool uses_window(HWND hWnd) {
return this->hWnd == hWnd;
}
inline bool uses_context(IDirect3D9 *other) {
return this->d3d == other;
}
inline bool uses_device(IDirect3DDevice9 *other) {
return this->device == other;
}
inline IDirect3DDevice9 *get_device() {
return this->device;
}
// renderer
OverlayRenderer renderer;
float total_elapsed = 0.f;
private:
HWND hWnd = nullptr;
// D3D9
IDirect3D9 *d3d = nullptr;
IDirect3DDevice9 *device = nullptr;
// software
std::vector<uint32_t> pixel_data;
size_t pixel_data_width = 0;
size_t pixel_data_height = 0;
std::vector<std::unique_ptr<Window>> windows;
Window *window_fps = nullptr;
bool active = false;
bool toggle_down = false;
bool rawinput_char = true;
bool hotkey_toggle = false;
bool hotkey_toggle_last = false;
void init();
};
// global
extern std::mutex OVERLAY_MUTEX;
extern std::unique_ptr<overlay::SpiceOverlay> OVERLAY;
// synchronized helpers
void create_d3d9(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device);
void create_software(HWND hWnd);
void destroy(HWND hWnd = nullptr);
}
+44 -44
View File
@@ -1,44 +1,44 @@
#include "acio_status_buffers.h"
#include "overlay/imgui/extensions.h"
#include "external/imgui/imgui_memory_editor.h"
namespace overlay::windows {
ACIOStatusBuffers::ACIOStatusBuffers(SpiceOverlay *overlay, acio::ACIOModule *module)
: Window(overlay), module(module) {
this->title = module->name + " Status Buffers";
this->init_size = ImVec2(600, 400);
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
this->active = true;
// configure editor defaults
this->editor = new MemoryEditor();
this->editor->OptShowDataPreview = true;
this->editor->PreviewDataType = MemoryEditor::DataType::DataType_U16;
}
ACIOStatusBuffers::~ACIOStatusBuffers() {
// kill editor
delete this->editor;
}
void ACIOStatusBuffers::build_content() {
// freeze checkbox
if (module->status_buffer_freeze) {
ImGui::Checkbox("Freeze", module->status_buffer_freeze);
ImGui::SameLine();
ImGui::HelpMarker("Prevent automatic modifications to the buffer.");
ImGui::Separator();
}
// draw editor
this->editor->DrawContents(
this->module->status_buffer,
this->module->status_buffer_size);
}
}
#include "acio_status_buffers.h"
#include "overlay/imgui/extensions.h"
#include "external/imgui/imgui_memory_editor.h"
namespace overlay::windows {
ACIOStatusBuffers::ACIOStatusBuffers(SpiceOverlay *overlay, acio::ACIOModule *module)
: Window(overlay), module(module) {
this->title = module->name + " Status Buffers";
this->init_size = ImVec2(600, 400);
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
this->active = true;
// configure editor defaults
this->editor = new MemoryEditor();
this->editor->OptShowDataPreview = true;
this->editor->PreviewDataType = MemoryEditor::DataType::DataType_U16;
}
ACIOStatusBuffers::~ACIOStatusBuffers() {
// kill editor
delete this->editor;
}
void ACIOStatusBuffers::build_content() {
// freeze checkbox
if (module->status_buffer_freeze) {
ImGui::Checkbox("Freeze", module->status_buffer_freeze);
ImGui::SameLine();
ImGui::HelpMarker("Prevent automatic modifications to the buffer.");
ImGui::Separator();
}
// draw editor
this->editor->DrawContents(
this->module->status_buffer,
this->module->status_buffer_size);
}
}
+22 -22
View File
@@ -1,22 +1,22 @@
#pragma once
#include "overlay/window.h"
#include "acio/acio.h"
struct MemoryEditor;
namespace overlay::windows {
class ACIOStatusBuffers : public Window {
public:
ACIOStatusBuffers(SpiceOverlay *overlay, acio::ACIOModule *module);
~ACIOStatusBuffers() override;
void build_content() override;
private:
acio::ACIOModule *module;
MemoryEditor *editor;
};
}
#pragma once
#include "overlay/window.h"
#include "acio/acio.h"
struct MemoryEditor;
namespace overlay::windows {
class ACIOStatusBuffers : public Window {
public:
ACIOStatusBuffers(SpiceOverlay *overlay, acio::ACIOModule *module);
~ACIOStatusBuffers() override;
void build_content() override;
private:
acio::ACIOModule *module;
MemoryEditor *editor;
};
}
+260 -260
View File
@@ -1,260 +1,260 @@
#include <games/io.h>
#include "card_manager.h"
#include "external/rapidjson/document.h"
#include "external/rapidjson/writer.h"
#include "misc/eamuse.h"
#include "util/utils.h"
#include "util/fileutils.h"
using namespace rapidjson;
namespace overlay::windows {
CardManager::CardManager(SpiceOverlay *overlay) : Window(overlay) {
this->title = "Card Manager";
this->init_size = ImVec2(300, 200);
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
this->toggle_button = games::OverlayButtons::ToggleCardManager;
this->config_path = std::string(getenv("APPDATA")) + "\\spicetools_card_manager.json";
if (fileutils::file_exists(this->config_path)) {
this->config_load();
}
}
CardManager::~CardManager() {
}
void CardManager::build_content() {
// get window size
auto window_size = ImGui::GetWindowSize();
// name field
ImGui::InputTextWithHint("Card Name", "Main Card",
this->name_buffer, std::size(this->name_buffer));
// card field
ImGui::InputTextWithHint("Card ID", "E0040123456789AB",
this->card_buffer,
std::size(this->card_buffer),
ImGuiInputTextFlags_CharsHexadecimal
| ImGuiInputTextFlags_CharsUppercase);
// add card button
if (strlen(this->card_buffer) == 16) {
if (ImGui::Button("Add Card", ImVec2(-1.f, 0.f))) {
// save entry
CardEntry entry {
.name = this->name_buffer,
.id = this->card_buffer
};
this->cards.emplace_back(entry);
this->config_dirty = true;
// clear input fields
memset(this->name_buffer, 0, sizeof(this->name_buffer));
memset(this->card_buffer, 0, sizeof(this->card_buffer));
}
} else {
ImGui::Text("Enter card identifier...");
}
// cards area
ImGui::Separator();
if (ImGui::BeginChild("cards", ImVec2(0, window_size.y - 128))) {
for (auto &card : this->cards) {
// get card name
std::string card_name = card.name;
if (card.name.size() > 0) {
card_name += " - ";
}
card_name += card.id;
// draw entry
ImGui::PushID(&card);
if (ImGui::Selectable(card_name.c_str(), card.selected)) {
// unselect other cards
for (auto &card_disable : this->cards) {
card_disable.selected = false;
}
// mark this card as the selected one
card.selected = true;
}
ImGui::PopID();
}
}
ImGui::EndChild();
// insert P1 button
if (ImGui::Button("Insert P1")) {
auto card = this->cards_get_selected();
uint8_t card_bin[8];
if (card && card->id.length() == 16 && hex2bin(card->id.c_str(), card_bin)) {
eamuse_card_insert(0, card_bin);
}
}
// insert P2 button
if (eamuse_get_game_keypads() > 1) {
ImGui::SameLine();
if (ImGui::Button("Insert P2")) {
auto card = this->cards_get_selected();
uint8_t card_bin[8];
if (card && card->id.length() == 16 && hex2bin(card->id.c_str(), card_bin)) {
eamuse_card_insert(1, card_bin);
}
}
}
// save button
if (this->config_dirty) {
ImGui::SameLine();
if (ImGui::Button("Save")) {
this->config_save();
}
}
}
CardEntry *CardManager::cards_get_selected() {
// iterate cards
for (auto &card : this->cards) {
// check if selected and return pointer
if (card.selected) {
return &card;
}
}
// no card selected
return nullptr;
}
void CardManager::config_load() {
log_info("cardmanager", "loading config");
// clear cards
this->cards.clear();
// read config file
std::string config = fileutils::text_read(this->config_path);
if (!config.empty()) {
// parse document
Document doc;
doc.Parse(config.c_str());
// check parse error
auto error = doc.GetParseError();
if (error) {
log_warning("cardmanager", "config parse error: {}", error);
}
// verify root is a dict
if (doc.IsObject()) {
// find pages
auto pages = doc.FindMember("pages");
if (pages != doc.MemberEnd() && pages->value.IsArray()) {
// iterate pages
for (auto &page : pages->value.GetArray()) {
if (page.IsObject()) {
// get cards
auto cards = page.FindMember("cards");
if (cards != doc.MemberEnd() && cards->value.IsArray()) {
// iterate cards
for (auto &card : cards->value.GetArray()) {
if (card.IsObject()) {
// find attributes
auto name = card.FindMember("name");
if (name == doc.MemberEnd() || !name->value.IsString()) {
log_warning("cardmanager", "card name not found");
continue;
}
auto id = card.FindMember("id");
if (id == doc.MemberEnd() || !id->value.IsString()) {
log_warning("cardmanager", "card id not found");
continue;
}
// save entry
CardEntry entry {
.name = name->value.GetString(),
.id = id->value.GetString()
};
this->cards.emplace_back(entry);
} else {
log_warning("cardmanager", "card is not an object");
}
}
} else {
log_warning("cardmanager", "cards not found or not an array");
}
} else {
log_warning("cardmanager", "page is not an object");
}
}
} else {
log_warning("cardmanager", "pages not found or not an array");
}
}
}
}
void CardManager::config_save() {
log_info("cardmanager", "saving config");
// create document
Document doc;
doc.Parse(
"{"
" \"pages\": ["
" {"
" \"cards\": ["
" ]"
" }"
" ]"
"}"
);
// check parse error
auto error = doc.GetParseError();
if (error) {
log_warning("cardmanager", "template parse error: {}", error);
}
// add cards
auto &cards = doc["pages"][0]["cards"];
for (auto &entry : this->cards) {
Value card(kObjectType);
card.AddMember("name", StringRef(entry.name.c_str()), doc.GetAllocator());
card.AddMember("id", StringRef(entry.id.c_str()), doc.GetAllocator());
cards.PushBack(card, doc.GetAllocator());
}
// build JSON
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
doc.Accept(writer);
// save to file
if (fileutils::text_write(this->config_path, buffer.GetString())) {
this->config_dirty = false;
} else {
log_warning("cardmanager", "unable to save config file to {}", this->config_path);
}
}
}
#include <games/io.h>
#include "card_manager.h"
#include "external/rapidjson/document.h"
#include "external/rapidjson/writer.h"
#include "misc/eamuse.h"
#include "util/utils.h"
#include "util/fileutils.h"
using namespace rapidjson;
namespace overlay::windows {
CardManager::CardManager(SpiceOverlay *overlay) : Window(overlay) {
this->title = "Card Manager";
this->init_size = ImVec2(300, 200);
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
this->toggle_button = games::OverlayButtons::ToggleCardManager;
this->config_path = std::string(getenv("APPDATA")) + "\\spicetools_card_manager.json";
if (fileutils::file_exists(this->config_path)) {
this->config_load();
}
}
CardManager::~CardManager() {
}
void CardManager::build_content() {
// get window size
auto window_size = ImGui::GetWindowSize();
// name field
ImGui::InputTextWithHint("Card Name", "Main Card",
this->name_buffer, std::size(this->name_buffer));
// card field
ImGui::InputTextWithHint("Card ID", "E0040123456789AB",
this->card_buffer,
std::size(this->card_buffer),
ImGuiInputTextFlags_CharsHexadecimal
| ImGuiInputTextFlags_CharsUppercase);
// add card button
if (strlen(this->card_buffer) == 16) {
if (ImGui::Button("Add Card", ImVec2(-1.f, 0.f))) {
// save entry
CardEntry entry {
.name = this->name_buffer,
.id = this->card_buffer
};
this->cards.emplace_back(entry);
this->config_dirty = true;
// clear input fields
memset(this->name_buffer, 0, sizeof(this->name_buffer));
memset(this->card_buffer, 0, sizeof(this->card_buffer));
}
} else {
ImGui::Text("Enter card identifier...");
}
// cards area
ImGui::Separator();
if (ImGui::BeginChild("cards", ImVec2(0, window_size.y - 128))) {
for (auto &card : this->cards) {
// get card name
std::string card_name = card.name;
if (card.name.size() > 0) {
card_name += " - ";
}
card_name += card.id;
// draw entry
ImGui::PushID(&card);
if (ImGui::Selectable(card_name.c_str(), card.selected)) {
// unselect other cards
for (auto &card_disable : this->cards) {
card_disable.selected = false;
}
// mark this card as the selected one
card.selected = true;
}
ImGui::PopID();
}
}
ImGui::EndChild();
// insert P1 button
if (ImGui::Button("Insert P1")) {
auto card = this->cards_get_selected();
uint8_t card_bin[8];
if (card && card->id.length() == 16 && hex2bin(card->id.c_str(), card_bin)) {
eamuse_card_insert(0, card_bin);
}
}
// insert P2 button
if (eamuse_get_game_keypads() > 1) {
ImGui::SameLine();
if (ImGui::Button("Insert P2")) {
auto card = this->cards_get_selected();
uint8_t card_bin[8];
if (card && card->id.length() == 16 && hex2bin(card->id.c_str(), card_bin)) {
eamuse_card_insert(1, card_bin);
}
}
}
// save button
if (this->config_dirty) {
ImGui::SameLine();
if (ImGui::Button("Save")) {
this->config_save();
}
}
}
CardEntry *CardManager::cards_get_selected() {
// iterate cards
for (auto &card : this->cards) {
// check if selected and return pointer
if (card.selected) {
return &card;
}
}
// no card selected
return nullptr;
}
void CardManager::config_load() {
log_info("cardmanager", "loading config");
// clear cards
this->cards.clear();
// read config file
std::string config = fileutils::text_read(this->config_path);
if (!config.empty()) {
// parse document
Document doc;
doc.Parse(config.c_str());
// check parse error
auto error = doc.GetParseError();
if (error) {
log_warning("cardmanager", "config parse error: {}", error);
}
// verify root is a dict
if (doc.IsObject()) {
// find pages
auto pages = doc.FindMember("pages");
if (pages != doc.MemberEnd() && pages->value.IsArray()) {
// iterate pages
for (auto &page : pages->value.GetArray()) {
if (page.IsObject()) {
// get cards
auto cards = page.FindMember("cards");
if (cards != doc.MemberEnd() && cards->value.IsArray()) {
// iterate cards
for (auto &card : cards->value.GetArray()) {
if (card.IsObject()) {
// find attributes
auto name = card.FindMember("name");
if (name == doc.MemberEnd() || !name->value.IsString()) {
log_warning("cardmanager", "card name not found");
continue;
}
auto id = card.FindMember("id");
if (id == doc.MemberEnd() || !id->value.IsString()) {
log_warning("cardmanager", "card id not found");
continue;
}
// save entry
CardEntry entry {
.name = name->value.GetString(),
.id = id->value.GetString()
};
this->cards.emplace_back(entry);
} else {
log_warning("cardmanager", "card is not an object");
}
}
} else {
log_warning("cardmanager", "cards not found or not an array");
}
} else {
log_warning("cardmanager", "page is not an object");
}
}
} else {
log_warning("cardmanager", "pages not found or not an array");
}
}
}
}
void CardManager::config_save() {
log_info("cardmanager", "saving config");
// create document
Document doc;
doc.Parse(
"{"
" \"pages\": ["
" {"
" \"cards\": ["
" ]"
" }"
" ]"
"}"
);
// check parse error
auto error = doc.GetParseError();
if (error) {
log_warning("cardmanager", "template parse error: {}", error);
}
// add cards
auto &cards = doc["pages"][0]["cards"];
for (auto &entry : this->cards) {
Value card(kObjectType);
card.AddMember("name", StringRef(entry.name.c_str()), doc.GetAllocator());
card.AddMember("id", StringRef(entry.id.c_str()), doc.GetAllocator());
cards.PushBack(card, doc.GetAllocator());
}
// build JSON
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
doc.Accept(writer);
// save to file
if (fileutils::text_write(this->config_path, buffer.GetString())) {
this->config_dirty = false;
} else {
log_warning("cardmanager", "unable to save config file to {}", this->config_path);
}
}
}
+33 -33
View File
@@ -1,33 +1,33 @@
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
struct CardEntry {
std::string name = "unnamed";
std::string id = "E004000000000000";
bool selected = false;
};
class CardManager : public Window {
public:
CardManager(SpiceOverlay *overlay);
~CardManager() override;
void build_content() override;
private:
std::string config_path;
bool config_dirty = false;
std::vector<CardEntry> cards;
char name_buffer[65] {};
char card_buffer[17] {};
CardEntry *cards_get_selected();
void config_load();
void config_save();
};
}
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
struct CardEntry {
std::string name = "unnamed";
std::string id = "E004000000000000";
bool selected = false;
};
class CardManager : public Window {
public:
CardManager(SpiceOverlay *overlay);
~CardManager() override;
void build_content() override;
private:
std::string config_path;
bool config_dirty = false;
std::vector<CardEntry> cards;
char name_buffer[65] {};
char card_buffer[17] {};
CardEntry *cards_get_selected();
void config_load();
void config_save();
};
}
+53 -53
View File
@@ -1,53 +1,53 @@
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class Control : public Window {
public:
Control(SpiceOverlay *overlay);
~Control() override;
void build_content() override;
private:
// state
char card_input[17] {};
// other windows
bool demo_open = false;
bool metrics_open = false;
std::vector<float> cpu_values;
// memory editor
bool memory_editor_open = false;
int memory_editor_selection = -1;
std::vector<std::pair<std::string, HMODULE>> memory_editor_modules;
std::vector<const char*> memory_editor_names;
ImGuiTextFilter memory_editor_filter;
// pane views
void top_row_buttons();
void img_gui_view();
void avs_info_view();
void acio_view();
void cpu_view();
void graphics_view();
void buttons_view();
void analogs_view();
void lights_view();
void cards_view();
void coin_view();
void control_view();
void api_view();
void raw_input_view();
void touch_view();
void lcd_view();
void about_view();
void ddr_timing_view();
void iidx_effectors_view();
};
}
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class Control : public Window {
public:
Control(SpiceOverlay *overlay);
~Control() override;
void build_content() override;
private:
// state
char card_input[17] {};
// other windows
bool demo_open = false;
bool metrics_open = false;
std::vector<float> cpu_values;
// memory editor
bool memory_editor_open = false;
int memory_editor_selection = -1;
std::vector<std::pair<std::string, HMODULE>> memory_editor_modules;
std::vector<const char*> memory_editor_names;
ImGuiTextFilter memory_editor_filter;
// pane views
void top_row_buttons();
void img_gui_view();
void avs_info_view();
void acio_view();
void cpu_view();
void graphics_view();
void buttons_view();
void analogs_view();
void lights_view();
void cards_view();
void coin_view();
void control_view();
void api_view();
void raw_input_view();
void touch_view();
void lcd_view();
void about_view();
void ddr_timing_view();
void iidx_effectors_view();
};
}
+22 -22
View File
@@ -1,22 +1,22 @@
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class EADevWindow : public Window {
public:
EADevWindow(SpiceOverlay *overlay);
~EADevWindow() override;
void build_content() override;
static void automap_hook(void *user, const char *data);
private:
bool automap_autoscroll = true;
bool automap_scroll_to_bottom = false;
std::vector<std::string> automap_data;
};
}
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class EADevWindow : public Window {
public:
EADevWindow(SpiceOverlay *overlay);
~EADevWindow() override;
void build_content() override;
static void automap_hook(void *user, const char *data);
private:
bool automap_autoscroll = true;
bool automap_scroll_to_bottom = false;
std::vector<std::string> automap_data;
};
}
+29 -29
View File
@@ -1,29 +1,29 @@
#include "fps.h"
namespace overlay::windows {
FPS::FPS(SpiceOverlay *overlay) : Window(overlay) {
this->title = "FPS & Frame Time";
this->flags = ImGuiWindowFlags_NoTitleBar
| ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_AlwaysAutoResize
| ImGuiWindowFlags_NoDecoration
| ImGuiWindowFlags_NoFocusOnAppearing
| ImGuiWindowFlags_NoNavFocus
| ImGuiWindowFlags_NoNavInputs;
this->bg_alpha = 0.4f;
}
const ImVec2 FPS::initial_pos() {
return ImVec2(ImGui::GetIO().DisplaySize.x - 100, 10);
}
void FPS::build_content() {
// frame timers
ImGuiIO &io = ImGui::GetIO();
ImGui::Text("FPS: %.1f", io.Framerate);
ImGui::Text("FT: %.2fms", 1000 / io.Framerate);
}
}
#include "fps.h"
namespace overlay::windows {
FPS::FPS(SpiceOverlay *overlay) : Window(overlay) {
this->title = "FPS & Frame Time";
this->flags = ImGuiWindowFlags_NoTitleBar
| ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_AlwaysAutoResize
| ImGuiWindowFlags_NoDecoration
| ImGuiWindowFlags_NoFocusOnAppearing
| ImGuiWindowFlags_NoNavFocus
| ImGuiWindowFlags_NoNavInputs;
this->bg_alpha = 0.4f;
}
const ImVec2 FPS::initial_pos() {
return ImVec2(ImGui::GetIO().DisplaySize.x - 100, 10);
}
void FPS::build_content() {
// frame timers
ImGuiIO &io = ImGui::GetIO();
ImGui::Text("FPS: %.1f", io.Framerate);
ImGui::Text("FT: %.2fms", 1000 / io.Framerate);
}
}
+15 -15
View File
@@ -1,15 +1,15 @@
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class FPS : public Window {
public:
FPS(SpiceOverlay *overlay);
const ImVec2 initial_pos() override;
void build_content() override;
};
}
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class FPS : public Window {
public:
FPS(SpiceOverlay *overlay);
const ImVec2 initial_pos() override;
void build_content() override;
};
}
+31 -31
View File
@@ -1,31 +1,31 @@
#ifndef SPICETOOLS_OVERLAY_WINDOWS_IIDX_SUB_H
#define SPICETOOLS_OVERLAY_WINDOWS_IIDX_SUB_H
#include <optional>
#include <windows.h>
#include <d3d9.h>
#include "overlay/window.h"
namespace overlay::windows {
class IIDXSubScreen : public Window {
public:
IIDXSubScreen(SpiceOverlay *overlay);
void build_content() override;
private:
bool build_texture(IDirect3DSurface9 *surface);
void draw_texture();
std::optional<std::string> status_message = std::nullopt;
IDirect3DDevice9 *device = nullptr;
IDirect3DTexture9 *texture = nullptr;
ImVec2 texture_size;
};
}
#endif // SPICETOOLS_OVERLAY_WINDOWS_IIDX_SUB_H
#ifndef SPICETOOLS_OVERLAY_WINDOWS_IIDX_SUB_H
#define SPICETOOLS_OVERLAY_WINDOWS_IIDX_SUB_H
#include <optional>
#include <windows.h>
#include <d3d9.h>
#include "overlay/window.h"
namespace overlay::windows {
class IIDXSubScreen : public Window {
public:
IIDXSubScreen(SpiceOverlay *overlay);
void build_content() override;
private:
bool build_texture(IDirect3DSurface9 *surface);
void draw_texture();
std::optional<std::string> status_message = std::nullopt;
IDirect3DDevice9 *device = nullptr;
IDirect3DTexture9 *texture = nullptr;
ImVec2 texture_size;
};
}
#endif // SPICETOOLS_OVERLAY_WINDOWS_IIDX_SUB_H
+94 -94
View File
@@ -1,94 +1,94 @@
#include <games/io.h>
#include "keypad.h"
#include "misc/eamuse.h"
#include "util/logging.h"
namespace overlay::windows {
Keypad::Keypad(SpiceOverlay *overlay, size_t unit) : Window(overlay), unit(unit) {
this->title = "Keypad P" + to_string(unit + 1);
this->flags = ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_AlwaysAutoResize;
switch (this->unit) {
case 0: {
this->toggle_button = games::OverlayButtons::ToggleVirtualKeypadP1;
this->init_pos = ImVec2(
26,
ImGui::GetIO().DisplaySize.y - 264);
break;
}
case 1: {
this->toggle_button = games::OverlayButtons::ToggleVirtualKeypadP2;
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x - 220,
ImGui::GetIO().DisplaySize.y - 264);
break;
}
}
}
Keypad::~Keypad() {
// reset overrides
eamuse_set_keypad_overrides_overlay(this->unit, 0);
}
void Keypad::build_content() {
// buttons
static const struct {
const char *text;
int flag;
} BUTTONS[] = {
{ "7", 1 << EAM_IO_KEYPAD_7 },
{ "8", 1 << EAM_IO_KEYPAD_8 },
{ "9", 1 << EAM_IO_KEYPAD_9 },
{ "4", 1 << EAM_IO_KEYPAD_4 },
{ "5", 1 << EAM_IO_KEYPAD_5 },
{ "6", 1 << EAM_IO_KEYPAD_6 },
{ "1", 1 << EAM_IO_KEYPAD_1 },
{ "2", 1 << EAM_IO_KEYPAD_2 },
{ "3", 1 << EAM_IO_KEYPAD_3 },
{ "0", 1 << EAM_IO_KEYPAD_0 },
{ "00", 1 << EAM_IO_KEYPAD_00 },
{ ".", 1 << EAM_IO_KEYPAD_DECIMAL },
{ "Insert Card", 1 << EAM_IO_INSERT },
};
// reset overrides
eamuse_set_keypad_overrides_overlay(this->unit, 0);
// build grid
for (size_t i = 0; i < std::size(BUTTONS); i++) {
auto &button = BUTTONS[i];
// push id and alignment
ImGui::PushID(4096 + i);
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f));
// add selectable (fill last line)
if (i == std::size(BUTTONS) - 1) {
ImGui::Selectable(button.text, false, 0, ImVec2(112, 32));
} else {
ImGui::Selectable(button.text, false, 0, ImVec2(32, 32));
}
// mouse down handler
if (ImGui::IsItemHovered() && ImGui::IsAnyMouseDown()) {
eamuse_set_keypad_overrides_overlay(this->unit, button.flag);
}
// pop id and alignment
ImGui::PopStyleVar();
ImGui::PopID();
// line join
if ((i % 3) < 2) {
ImGui::SameLine();
}
}
}
}
#include <games/io.h>
#include "keypad.h"
#include "misc/eamuse.h"
#include "util/logging.h"
namespace overlay::windows {
Keypad::Keypad(SpiceOverlay *overlay, size_t unit) : Window(overlay), unit(unit) {
this->title = "Keypad P" + to_string(unit + 1);
this->flags = ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_AlwaysAutoResize;
switch (this->unit) {
case 0: {
this->toggle_button = games::OverlayButtons::ToggleVirtualKeypadP1;
this->init_pos = ImVec2(
26,
ImGui::GetIO().DisplaySize.y - 264);
break;
}
case 1: {
this->toggle_button = games::OverlayButtons::ToggleVirtualKeypadP2;
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x - 220,
ImGui::GetIO().DisplaySize.y - 264);
break;
}
}
}
Keypad::~Keypad() {
// reset overrides
eamuse_set_keypad_overrides_overlay(this->unit, 0);
}
void Keypad::build_content() {
// buttons
static const struct {
const char *text;
int flag;
} BUTTONS[] = {
{ "7", 1 << EAM_IO_KEYPAD_7 },
{ "8", 1 << EAM_IO_KEYPAD_8 },
{ "9", 1 << EAM_IO_KEYPAD_9 },
{ "4", 1 << EAM_IO_KEYPAD_4 },
{ "5", 1 << EAM_IO_KEYPAD_5 },
{ "6", 1 << EAM_IO_KEYPAD_6 },
{ "1", 1 << EAM_IO_KEYPAD_1 },
{ "2", 1 << EAM_IO_KEYPAD_2 },
{ "3", 1 << EAM_IO_KEYPAD_3 },
{ "0", 1 << EAM_IO_KEYPAD_0 },
{ "00", 1 << EAM_IO_KEYPAD_00 },
{ ".", 1 << EAM_IO_KEYPAD_DECIMAL },
{ "Insert Card", 1 << EAM_IO_INSERT },
};
// reset overrides
eamuse_set_keypad_overrides_overlay(this->unit, 0);
// build grid
for (size_t i = 0; i < std::size(BUTTONS); i++) {
auto &button = BUTTONS[i];
// push id and alignment
ImGui::PushID(4096 + i);
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f));
// add selectable (fill last line)
if (i == std::size(BUTTONS) - 1) {
ImGui::Selectable(button.text, false, 0, ImVec2(112, 32));
} else {
ImGui::Selectable(button.text, false, 0, ImVec2(32, 32));
}
// mouse down handler
if (ImGui::IsItemHovered() && ImGui::IsAnyMouseDown()) {
eamuse_set_keypad_overrides_overlay(this->unit, button.flag);
}
// pop id and alignment
ImGui::PopStyleVar();
ImGui::PopID();
// line join
if ((i % 3) < 2) {
ImGui::SameLine();
}
}
}
}
+19 -19
View File
@@ -1,19 +1,19 @@
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class Keypad : public Window {
private:
size_t unit = 0;
public:
Keypad(SpiceOverlay *overlay, size_t unit);
~Keypad() override;
void build_content() override;
};
}
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class Keypad : public Window {
private:
size_t unit = 0;
public:
Keypad(SpiceOverlay *overlay, size_t unit);
~Keypad() override;
void build_content() override;
};
}
+122 -122
View File
@@ -1,122 +1,122 @@
#include "log.h"
#include "util/utils.h"
#include "util/fileutils.h"
#include "games/io.h"
namespace overlay::windows {
Log::Log(SpiceOverlay *overlay) : Window(overlay) {
this->title = "Log";
this->toggle_button = games::OverlayButtons::ToggleLog;
this->init_size = ImVec2(
ImGui::GetIO().DisplaySize.x * 0.8f,
ImGui::GetIO().DisplaySize.y * 0.8f);
this->size_min = ImVec2(250, 200);
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
// read existing contents from file
if (LOG_FILE_PATH.length() > 0) {
auto contents = fileutils::text_read(LOG_FILE_PATH);
if (contents.length() > 0) {
this->log_hook(this, contents, logger::Style::DEFAULT, contents);
}
}
// add log hook
logger::hook_add(&log_hook, this);
}
Log::~Log() {
// remove log hook
logger::hook_remove(&log_hook, this);
}
void Log::clear() {
// lock and clear the data vector
std::lock_guard<std::mutex> lock(this->log_data_m);
this->log_data.clear();
}
void Log::build_content() {
// clear button
if (ImGui::Button("Clear")) {
this->clear();
}
// autoscroll option
ImGui::SameLine();
ImGui::Checkbox("Autoscroll", &this->autoscroll);
// filter
ImGui::SameLine();
this->filter.Draw("Filter", -50.f);
// log area
ImGui::Separator();
ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
// iterate log data
this->log_data_m.lock();
for (auto &data : log_data) {
// ignore empty lines and check filter
if (data.first != "\r\n" && this->filter.PassFilter(data.first.c_str())) {
// decide on color
ImVec4 col(1.f, 1.f, 1.f, 1.f);
switch (data.second) {
case logger::GREY:
col = ImVec4(0.6f, 0.6f, 0.6f, 1.f);
break;
case logger::YELLOW:
col = ImVec4(1.f, 1.f, 0.f, 1.f);
break;
case logger::RED:
col = ImVec4(1.f, 0.f, 0.f, 1.f);
break;
case logger::DEFAULT:
default:
break;
}
// draw text
ImGui::TextColored(col, "%s", data.first.c_str());
}
}
this->log_data_m.unlock();
// automatic scrolling to bottom
if (scroll_to_bottom) {
scroll_to_bottom = false;
ImGui::SetScrollHereY(1.f);
}
// end log area
ImGui::EndChild();
}
bool Log::log_hook(void *user, const std::string &data, logger::Style style, std::string &out) {
// get reference from user pointer
auto This = reinterpret_cast<Log *>(user);
// copy log data
This->log_data_m.lock();
This->log_data.emplace_back(data, style);
This->log_data_m.unlock();
// autoscroll
if (This->autoscroll) {
This->scroll_to_bottom = true;
}
// don't replace log data
return false;
}
}
#include "log.h"
#include "util/utils.h"
#include "util/fileutils.h"
#include "games/io.h"
namespace overlay::windows {
Log::Log(SpiceOverlay *overlay) : Window(overlay) {
this->title = "Log";
this->toggle_button = games::OverlayButtons::ToggleLog;
this->init_size = ImVec2(
ImGui::GetIO().DisplaySize.x * 0.8f,
ImGui::GetIO().DisplaySize.y * 0.8f);
this->size_min = ImVec2(250, 200);
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
// read existing contents from file
if (LOG_FILE_PATH.length() > 0) {
auto contents = fileutils::text_read(LOG_FILE_PATH);
if (contents.length() > 0) {
this->log_hook(this, contents, logger::Style::DEFAULT, contents);
}
}
// add log hook
logger::hook_add(&log_hook, this);
}
Log::~Log() {
// remove log hook
logger::hook_remove(&log_hook, this);
}
void Log::clear() {
// lock and clear the data vector
std::lock_guard<std::mutex> lock(this->log_data_m);
this->log_data.clear();
}
void Log::build_content() {
// clear button
if (ImGui::Button("Clear")) {
this->clear();
}
// autoscroll option
ImGui::SameLine();
ImGui::Checkbox("Autoscroll", &this->autoscroll);
// filter
ImGui::SameLine();
this->filter.Draw("Filter", -50.f);
// log area
ImGui::Separator();
ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
// iterate log data
this->log_data_m.lock();
for (auto &data : log_data) {
// ignore empty lines and check filter
if (data.first != "\r\n" && this->filter.PassFilter(data.first.c_str())) {
// decide on color
ImVec4 col(1.f, 1.f, 1.f, 1.f);
switch (data.second) {
case logger::GREY:
col = ImVec4(0.6f, 0.6f, 0.6f, 1.f);
break;
case logger::YELLOW:
col = ImVec4(1.f, 1.f, 0.f, 1.f);
break;
case logger::RED:
col = ImVec4(1.f, 0.f, 0.f, 1.f);
break;
case logger::DEFAULT:
default:
break;
}
// draw text
ImGui::TextColored(col, "%s", data.first.c_str());
}
}
this->log_data_m.unlock();
// automatic scrolling to bottom
if (scroll_to_bottom) {
scroll_to_bottom = false;
ImGui::SetScrollHereY(1.f);
}
// end log area
ImGui::EndChild();
}
bool Log::log_hook(void *user, const std::string &data, logger::Style style, std::string &out) {
// get reference from user pointer
auto This = reinterpret_cast<Log *>(user);
// copy log data
This->log_data_m.lock();
This->log_data.emplace_back(data, style);
This->log_data_m.unlock();
// autoscroll
if (This->autoscroll) {
This->scroll_to_bottom = true;
}
// don't replace log data
return false;
}
}
+28 -28
View File
@@ -1,28 +1,28 @@
#pragma once
#include <mutex>
#include "overlay/window.h"
#include "launcher/logger.h"
namespace overlay::windows {
class Log : public Window {
private:
std::vector<std::pair<std::string, logger::Style>> log_data;
std::mutex log_data_m;
ImGuiTextFilter filter;
bool scroll_to_bottom = true;
bool autoscroll = true;
void clear();
public:
Log(SpiceOverlay *overlay);
~Log() override;
void build_content() override;
static bool log_hook(void *user, const std::string &data, logger::Style style, std::string &out);
};
}
#pragma once
#include <mutex>
#include "overlay/window.h"
#include "launcher/logger.h"
namespace overlay::windows {
class Log : public Window {
private:
std::vector<std::pair<std::string, logger::Style>> log_data;
std::mutex log_data_m;
ImGuiTextFilter filter;
bool scroll_to_bottom = true;
bool autoscroll = true;
void clear();
public:
Log(SpiceOverlay *overlay);
~Log() override;
void build_content() override;
static bool log_hook(void *user, const std::string &data, logger::Style style, std::string &out);
};
}
+129 -129
View File
@@ -1,129 +1,129 @@
#include "midi.h"
#include "launcher/launcher.h"
#include "util/logging.h"
namespace overlay::windows {
static std::string midi_cmd_str(uint8_t cmd) {
const char *name = "UNKNOWN";
switch (cmd) {
case 0x8:
name = "NOTE OFF";
break;
case 0x9:
name = "NOTE ON";
break;
case 0xA:
name = "POLY.PRESS.";
break;
case 0xB:
name = "CTRL CHANGE";
break;
case 0xC:
name = "PRG CHANGE";
break;
case 0xD:
name = "CHAN.PRESS.";
break;
case 0xE:
name = "PITCH BEND";
break;
case 0xF:
name = "SYSTEM";
break;
}
return fmt::format("{} (0x{:2X})", name, cmd);
}
MIDIWindow::MIDIWindow(SpiceOverlay *overlay) : Window(overlay) {
this->title = "MIDI Control";
this->init_size = ImVec2(
ImGui::GetIO().DisplaySize.x * 0.8f,
ImGui::GetIO().DisplaySize.y * 0.8f);
this->size_min = ImVec2(250, 200);
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
this->active = true;
// add hook for receiving midi messages
RI_MGR->add_callback_midi(this, MIDIWindow::midi_hook);
}
MIDIWindow::~MIDIWindow() {
RI_MGR->remove_callback_midi(this, MIDIWindow::midi_hook);
}
void MIDIWindow::build_content() {
// reset button
if (ImGui::Button("Reset")) {
this->midi_data.clear();
}
// autoscroll checkbox
ImGui::SameLine();
ImGui::Checkbox("Autoscroll", &this->autoscroll);
// log section
ImGui::BeginChild("MidiLog", ImVec2(), false);
// header
ImGui::Columns(5, "MidiLogColumns", true);
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Device"); ImGui::NextColumn();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Command"); ImGui::NextColumn();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Channel"); ImGui::NextColumn();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Data 1"); ImGui::NextColumn();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Data 2"); ImGui::NextColumn();
// data
ImGui::Separator();
for (auto &data : this->midi_data) {
// set color
srand(data.device->id * 2111);
float hue = ((float) rand()) / ((float) RAND_MAX);
ImGui::PushStyleColor(ImGuiCol_Text, ImColor::HSV(hue, 0.8f, 0.8f, 1.f).Value);
// data cells
ImGui::Text("%i: %s", (int) data.device->id, data.device->desc.c_str());
ImGui::NextColumn();
ImGui::Text("%s", midi_cmd_str(data.cmd).c_str());
ImGui::NextColumn();
ImGui::Text("0x%02X - %i", data.ch, data.ch);
ImGui::NextColumn();
ImGui::Text("0x%02X", data.b1);
ImGui::NextColumn();
ImGui::Text("0x%02X", data.b2);
ImGui::NextColumn();
// clean up
ImGui::PopStyleColor();
}
// autoscroll
if (this->autoscroll_apply) {
this->autoscroll_apply = false;
ImGui::SetScrollHereY(1.f);
}
// clean up section
ImGui::Columns();
ImGui::EndChild();
}
void MIDIWindow::midi_hook(void *user, rawinput::Device *device,
uint8_t cmd, uint8_t ch, uint8_t b1, uint8_t b2) {
auto This = (MIDIWindow*) user;
This->midi_data.emplace_back(MIDIData {
.device = device,
.cmd = cmd,
.ch = ch,
.b1 = b1,
.b2 = b2,
});
if (This->autoscroll) {
This->autoscroll_apply = true;
}
}
}
#include "midi.h"
#include "launcher/launcher.h"
#include "util/logging.h"
namespace overlay::windows {
static std::string midi_cmd_str(uint8_t cmd) {
const char *name = "UNKNOWN";
switch (cmd) {
case 0x8:
name = "NOTE OFF";
break;
case 0x9:
name = "NOTE ON";
break;
case 0xA:
name = "POLY.PRESS.";
break;
case 0xB:
name = "CTRL CHANGE";
break;
case 0xC:
name = "PRG CHANGE";
break;
case 0xD:
name = "CHAN.PRESS.";
break;
case 0xE:
name = "PITCH BEND";
break;
case 0xF:
name = "SYSTEM";
break;
}
return fmt::format("{} (0x{:2X})", name, cmd);
}
MIDIWindow::MIDIWindow(SpiceOverlay *overlay) : Window(overlay) {
this->title = "MIDI Control";
this->init_size = ImVec2(
ImGui::GetIO().DisplaySize.x * 0.8f,
ImGui::GetIO().DisplaySize.y * 0.8f);
this->size_min = ImVec2(250, 200);
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
this->active = true;
// add hook for receiving midi messages
RI_MGR->add_callback_midi(this, MIDIWindow::midi_hook);
}
MIDIWindow::~MIDIWindow() {
RI_MGR->remove_callback_midi(this, MIDIWindow::midi_hook);
}
void MIDIWindow::build_content() {
// reset button
if (ImGui::Button("Reset")) {
this->midi_data.clear();
}
// autoscroll checkbox
ImGui::SameLine();
ImGui::Checkbox("Autoscroll", &this->autoscroll);
// log section
ImGui::BeginChild("MidiLog", ImVec2(), false);
// header
ImGui::Columns(5, "MidiLogColumns", true);
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Device"); ImGui::NextColumn();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Command"); ImGui::NextColumn();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Channel"); ImGui::NextColumn();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Data 1"); ImGui::NextColumn();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Data 2"); ImGui::NextColumn();
// data
ImGui::Separator();
for (auto &data : this->midi_data) {
// set color
srand(data.device->id * 2111);
float hue = ((float) rand()) / ((float) RAND_MAX);
ImGui::PushStyleColor(ImGuiCol_Text, ImColor::HSV(hue, 0.8f, 0.8f, 1.f).Value);
// data cells
ImGui::Text("%i: %s", (int) data.device->id, data.device->desc.c_str());
ImGui::NextColumn();
ImGui::Text("%s", midi_cmd_str(data.cmd).c_str());
ImGui::NextColumn();
ImGui::Text("0x%02X - %i", data.ch, data.ch);
ImGui::NextColumn();
ImGui::Text("0x%02X", data.b1);
ImGui::NextColumn();
ImGui::Text("0x%02X", data.b2);
ImGui::NextColumn();
// clean up
ImGui::PopStyleColor();
}
// autoscroll
if (this->autoscroll_apply) {
this->autoscroll_apply = false;
ImGui::SetScrollHereY(1.f);
}
// clean up section
ImGui::Columns();
ImGui::EndChild();
}
void MIDIWindow::midi_hook(void *user, rawinput::Device *device,
uint8_t cmd, uint8_t ch, uint8_t b1, uint8_t b2) {
auto This = (MIDIWindow*) user;
This->midi_data.emplace_back(MIDIData {
.device = device,
.cmd = cmd,
.ch = ch,
.b1 = b1,
.b2 = b2,
});
if (This->autoscroll) {
This->autoscroll_apply = true;
}
}
}
+30 -30
View File
@@ -1,30 +1,30 @@
#pragma once
#include "rawinput/rawinput.h"
#include "overlay/window.h"
namespace overlay::windows {
struct MIDIData {
rawinput::Device *device;
uint8_t cmd, ch;
uint8_t b1, b2;
};
class MIDIWindow : public Window {
public:
MIDIWindow(SpiceOverlay *overlay);
~MIDIWindow() override;
void build_content() override;
static void midi_hook(void *user, rawinput::Device *device,
uint8_t cmd, uint8_t ch, uint8_t b1, uint8_t b2);
private:
std::vector<MIDIData> midi_data;
bool autoscroll = true;
bool autoscroll_apply = false;
};
}
#pragma once
#include "rawinput/rawinput.h"
#include "overlay/window.h"
namespace overlay::windows {
struct MIDIData {
rawinput::Device *device;
uint8_t cmd, ch;
uint8_t b1, b2;
};
class MIDIWindow : public Window {
public:
MIDIWindow(SpiceOverlay *overlay);
~MIDIWindow() override;
void build_content() override;
static void midi_hook(void *user, rawinput::Device *device,
uint8_t cmd, uint8_t ch, uint8_t b1, uint8_t b2);
private:
std::vector<MIDIData> midi_data;
bool autoscroll = true;
bool autoscroll_apply = false;
};
}
+81 -81
View File
@@ -1,81 +1,81 @@
#include <games/io.h>
#include "screen_resize.h"
#include "cfg/screen_resize.h"
#include "misc/eamuse.h"
#include "util/logging.h"
namespace overlay::windows {
ScreenResize::ScreenResize(SpiceOverlay *overlay) : Window(overlay) {
this->title = "Screen Resize";
this->flags = ImGuiWindowFlags_AlwaysAutoResize;
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
this->toggle_button = games::OverlayButtons::ToggleScreenResize;
this->toggle_screen_resize = games::OverlayButtons::ScreenResize;
}
ScreenResize::~ScreenResize() {
}
void ScreenResize::build_content() {
// enable checkbox
ImGui::Checkbox("Enable Screen Resize", &cfg::SCREENRESIZE->enable_screen_resize);
if (cfg::SCREENRESIZE->enable_screen_resize) {
// general settings
ImGui::Checkbox("Enable Linear Filter", &cfg::SCREENRESIZE->enable_linear_filter);
ImGui::InputInt("X Offset", &cfg::SCREENRESIZE->offset_x);
ImGui::InputInt("Y Offset", &cfg::SCREENRESIZE->offset_y);
// aspect ratio
ImGui::Checkbox("Keep Aspect Ratio", &cfg::SCREENRESIZE->keep_aspect_ratio);
if (cfg::SCREENRESIZE->keep_aspect_ratio) {
if (ImGui::SliderFloat("Scale", &cfg::SCREENRESIZE->scale_x, 0.65f, 2.0f)) {
cfg::SCREENRESIZE->scale_y = cfg::SCREENRESIZE->scale_x;
}
} else {
ImGui::SliderFloat("Width Scale", &cfg::SCREENRESIZE->scale_x, 0.65f, 2.0f);
ImGui::SliderFloat("Height Scale", &cfg::SCREENRESIZE->scale_y, 0.65f, 2.0f);
}
// reset button
if (ImGui::Button("Reset")) {
cfg::SCREENRESIZE->offset_x = 0;
cfg::SCREENRESIZE->offset_y = 0;
cfg::SCREENRESIZE->scale_x = 1;
cfg::SCREENRESIZE->scale_y = 1;
}
}
// load button
ImGui::SameLine();
if (ImGui::Button("Load")) {
cfg::SCREENRESIZE->config_load();
}
// save button
ImGui::SameLine();
if (ImGui::Button("Save")) {
cfg::SCREENRESIZE->config_save();
}
}
void ScreenResize::update() {
Window::update();
if (this->toggle_screen_resize != ~0u) {
auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game());
bool toggle_screen_resize_new = overlay_buttons
&& this->overlay->hotkeys_triggered()
&& GameAPI::Buttons::getState(RI_MGR, overlay_buttons->at(this->toggle_screen_resize));
if (toggle_screen_resize_new && !this->toggle_screen_resize_state) {
cfg::SCREENRESIZE->enable_screen_resize = !cfg::SCREENRESIZE->enable_screen_resize;
}
this->toggle_screen_resize_state = toggle_screen_resize_new;
}
}
}
#include <games/io.h>
#include "screen_resize.h"
#include "cfg/screen_resize.h"
#include "misc/eamuse.h"
#include "util/logging.h"
namespace overlay::windows {
ScreenResize::ScreenResize(SpiceOverlay *overlay) : Window(overlay) {
this->title = "Screen Resize";
this->flags = ImGuiWindowFlags_AlwaysAutoResize;
this->init_pos = ImVec2(
ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2,
ImGui::GetIO().DisplaySize.y / 2 - this->init_size.y / 2);
this->toggle_button = games::OverlayButtons::ToggleScreenResize;
this->toggle_screen_resize = games::OverlayButtons::ScreenResize;
}
ScreenResize::~ScreenResize() {
}
void ScreenResize::build_content() {
// enable checkbox
ImGui::Checkbox("Enable Screen Resize", &cfg::SCREENRESIZE->enable_screen_resize);
if (cfg::SCREENRESIZE->enable_screen_resize) {
// general settings
ImGui::Checkbox("Enable Linear Filter", &cfg::SCREENRESIZE->enable_linear_filter);
ImGui::InputInt("X Offset", &cfg::SCREENRESIZE->offset_x);
ImGui::InputInt("Y Offset", &cfg::SCREENRESIZE->offset_y);
// aspect ratio
ImGui::Checkbox("Keep Aspect Ratio", &cfg::SCREENRESIZE->keep_aspect_ratio);
if (cfg::SCREENRESIZE->keep_aspect_ratio) {
if (ImGui::SliderFloat("Scale", &cfg::SCREENRESIZE->scale_x, 0.65f, 2.0f)) {
cfg::SCREENRESIZE->scale_y = cfg::SCREENRESIZE->scale_x;
}
} else {
ImGui::SliderFloat("Width Scale", &cfg::SCREENRESIZE->scale_x, 0.65f, 2.0f);
ImGui::SliderFloat("Height Scale", &cfg::SCREENRESIZE->scale_y, 0.65f, 2.0f);
}
// reset button
if (ImGui::Button("Reset")) {
cfg::SCREENRESIZE->offset_x = 0;
cfg::SCREENRESIZE->offset_y = 0;
cfg::SCREENRESIZE->scale_x = 1;
cfg::SCREENRESIZE->scale_y = 1;
}
}
// load button
ImGui::SameLine();
if (ImGui::Button("Load")) {
cfg::SCREENRESIZE->config_load();
}
// save button
ImGui::SameLine();
if (ImGui::Button("Save")) {
cfg::SCREENRESIZE->config_save();
}
}
void ScreenResize::update() {
Window::update();
if (this->toggle_screen_resize != ~0u) {
auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game());
bool toggle_screen_resize_new = overlay_buttons
&& this->overlay->hotkeys_triggered()
&& GameAPI::Buttons::getState(RI_MGR, overlay_buttons->at(this->toggle_screen_resize));
if (toggle_screen_resize_new && !this->toggle_screen_resize_state) {
cfg::SCREENRESIZE->enable_screen_resize = !cfg::SCREENRESIZE->enable_screen_resize;
}
this->toggle_screen_resize_state = toggle_screen_resize_new;
}
}
}
+19 -19
View File
@@ -1,19 +1,19 @@
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class ScreenResize : public Window {
public:
ScreenResize(SpiceOverlay *overlay);
~ScreenResize() override;
void build_content() override;
void update();
private:
size_t toggle_screen_resize = ~0u;
bool toggle_screen_resize_state = false;
};
}
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class ScreenResize : public Window {
public:
ScreenResize(SpiceOverlay *overlay);
~ScreenResize() override;
void build_content() override;
void update();
private:
size_t toggle_screen_resize = ~0u;
bool toggle_screen_resize_state = false;
};
}
+218 -218
View File
@@ -1,218 +1,218 @@
#include "vr.h"
#include "misc/vrutil.h"
#include "util/logging.h"
#include "games/io.h"
#include "games/drs/drs.h"
#include "avs/game.h"
#include "overlay/imgui/extensions.h"
namespace overlay::windows {
VRWindow::VRWindow(SpiceOverlay *overlay) : Window(overlay) {
this->title = "VR";
this->flags = ImGuiWindowFlags_None;
this->toggle_button = games::OverlayButtons::ToggleVRControl;
this->init_size = ImVec2(500, 800);
this->size_min = ImVec2(250, 200);
}
VRWindow::~VRWindow() {
}
void VRWindow::build_content() {
ImGui::BeginTabBar("VRTabBar");
if (ImGui::BeginTabItem("Info")) {
build_info();
ImGui::EndTabItem();
}
if (avs::game::is_model("REC")) {
if (ImGui::BeginTabItem("Dancefloor")) {
build_dancefloor();
}
}
}
void VRWindow::build_info() {
// status
auto status = vrutil::STATUS;
switch (status) {
case vrutil::VRStatus::Disabled:
ImGui::TextColored(
ImVec4(0.4f, 0.4f, 0.4f, 1.f),
"Disabled");
if (ImGui::Button("Start")) {
vrutil::init();
if (avs::game::is_model("REC")) {
games::drs::start_vr();
}
}
break;
case vrutil::VRStatus::Error:
ImGui::TextColored(
ImVec4(0.8f, 0.1f, 0.1f, 1.f),
"Error");
if (ImGui::Button("Restart")) {
vrutil::shutdown();
vrutil::init();
}
break;
case vrutil::VRStatus::Running:
ImGui::TextColored(
ImVec4(0.1f, 0.8f, 0.1f, 1.f),
"Running");
if (ImGui::Button("Stop")) {
vrutil::shutdown();
}
break;
}
// rescan
if (ImGui::Button("Rescan Devices")) {
vrutil::scan(true);
}
// data table header
ImGui::Columns(2);
ImGui::Text("Device");
ImGui::NextColumn();
ImGui::Text("Position");
ImGui::NextColumn();
ImGui::Separator();
// HMD/Left/Right data
vr::TrackedDevicePose_t hmd_pose, left_pose, right_pose;
vr::VRControllerState_t left_state, right_state;
vrutil::get_hmd_pose(&hmd_pose);
vrutil::get_con_pose(vrutil::INDEX_LEFT, &left_pose, &left_state);
vrutil::get_con_pose(vrutil::INDEX_RIGHT, &right_pose, &right_state);
auto hmd_pos = vrutil::get_translation(hmd_pose.mDeviceToAbsoluteTracking);
auto left_pos = vrutil::get_translation(left_pose.mDeviceToAbsoluteTracking);
auto right_pos = vrutil::get_translation(right_pose.mDeviceToAbsoluteTracking);
ImGui::Text("HMD");
ImGui::NextColumn();
ImGui::TextUnformatted(fmt::format(
"X={:3f} Y={:3f} Z={:3f}",
hmd_pos.x, hmd_pos.y, hmd_pos.z).c_str());
ImGui::NextColumn();
ImGui::Text("Left");
ImGui::NextColumn();
ImGui::TextUnformatted(fmt::format(
"X={:3f} Y={:3f} Z={:3f}",
left_pos.x, left_pos.y, left_pos.z).c_str());
ImGui::NextColumn();
ImGui::Text("Right");
ImGui::NextColumn();
ImGui::TextUnformatted(fmt::format(
"X={:3f} Y={:3f} Z={:3f}",
right_pos.x, right_pos.y, right_pos.z).c_str());
ImGui::NextColumn();
}
void VRWindow::build_dancefloor() {
ImGui::Separator();
// settings
ImGui::DragFloat3("Scale", &games::drs::VR_SCALE[0], 0.1f);
ImGui::DragFloat3("Offset", &games::drs::VR_OFFSET[0], 0.1f);
ImGui::DragFloat("Rotation", &games::drs::VR_ROTATION, 0.5f);
for (int i = 0; i < (int) std::size(games::drs::VR_FOOTS); ++i) {
auto &foot = games::drs::VR_FOOTS[i];
ImGui::Separator();
ImGui::PushID(&foot);
ImGui::Text("%s Foot", i == 0 ? "Left" : "Right");
ImGui::InputInt("Device Index", (int*) &foot.index, 1, 1);
ImGui::DragFloat("Length", &foot.length,
0.005f, 0.001f, 1000.f);
ImGui::DragFloat("Size Base", &foot.size_base,
0.005f, 0.001f, 1000.f);
ImGui::DragFloat("Size Scale", &foot.size_scale,
0.005f, 0.001f, 1000.f);
ImGui::DragFloat4("Rotation Quat", &foot.rotation.x, 0.001f, -1, 1);
if (ImGui::Button("Calibrate")) {
vr::TrackedDevicePose_t pose;
vr::VRControllerState_t state;
vrutil::get_con_pose(foot.get_index(), &pose, &state);
foot.length = foot.height + 0.02f;
auto pose_rot = vrutil::get_rotation(pose.mDeviceToAbsoluteTracking.m);
foot.rotation = linalg::qmul(linalg::qinv(pose_rot),
vrutil::get_rotation((float) M_PI * -0.5f, 0, 0));
}
ImGui::SameLine();
ImGui::HelpMarker("Place the controller to the lower part of your leg "
"and press this button to auto calibrate angle and length");
ImGui::PopID();
}
// prepare view
auto draw_list = ImGui::GetWindowDrawList();
auto canvas_pos = ImGui::GetCursorScreenPos();
auto canvas_size = ImGui::GetContentRegionAvail();
float offset_x = canvas_size.x * 0.5f;
float offset_y = canvas_size.y * 0.1f;
float off_x = offset_x + canvas_pos.x;
float off_y = offset_y + canvas_pos.y;
float scale = std::min(canvas_size.x, canvas_size.y) / 60;
// axis
draw_list->AddLine(
ImVec2(canvas_pos.x, off_y),
ImVec2(canvas_pos.x + canvas_size.x, off_y),
ImColor(255, 0, 0, 128));
draw_list->AddLine(
ImVec2(off_x, canvas_pos.y),
ImVec2(off_x, canvas_pos.y + canvas_size.y),
ImColor(0, 255, 0, 128));
// tiles
for (int x = 0; x < 38; x++) {
for (int y = 0; y < 49; y++) {
auto &led = games::drs::DRS_TAPELED[x + y * 38];
ImColor color((int) led[0], (int) led[1], (int) led[2]);
ImVec2 p1((x - 19) * scale + off_x, (y + 0) * scale + off_y);
ImVec2 p2((x - 18) * scale + off_x, (y + 1) * scale + off_y);
draw_list->AddRectFilled(p1, p2, color, 0.f);
}
}
// foots
const float foot_box = 2.f * scale;
for (auto &foot : games::drs::VR_FOOTS) {
vr::TrackedDevicePose_t pose;
vr::VRControllerState_t state;
vrutil::get_con_pose(foot.get_index(), &pose, &state);
if (pose.bPoseIsValid) {
// position
auto pos = vrutil::get_translation(pose.mDeviceToAbsoluteTracking);
pos = foot.to_world(pos);
pos.x -= 19;
pos *= scale;
ImColor color(255, 0, 255);
if (foot.event.type == games::drs::DRS_DOWN
|| (foot.event.type == games::drs::DRS_MOVE)) {
auto size_factor = foot.event.width / (foot.size_base + foot.size_scale);
color = ImColor((int) (size_factor * 127) + 128, 0, 0);
}
ImVec2 p1(pos.x + off_x - foot_box * 0.5f,
pos.y + off_y - foot_box * 0.5f);
ImVec2 p2(pos.x + off_x + foot_box * 0.5f,
pos.y + off_y + foot_box * 0.5f);
draw_list->AddRectFilled(p1, p2, color, 0.f);
// direction
auto direction = -linalg::qzdir(linalg::qmul(
vrutil::get_rotation(pose.mDeviceToAbsoluteTracking.m),
foot.rotation));
direction = linalg::aliases::float3 {
-direction.z, direction.x, direction.y
};
auto end = pos + direction * foot.length * scale;
draw_list->AddLine(
ImVec2(pos.x + off_x, pos.y + off_y),
ImVec2(end.x + off_x, end.y + off_y),
ImColor(0, 255, 0));
}
}
}
}
#include "vr.h"
#include "misc/vrutil.h"
#include "util/logging.h"
#include "games/io.h"
#include "games/drs/drs.h"
#include "avs/game.h"
#include "overlay/imgui/extensions.h"
namespace overlay::windows {
VRWindow::VRWindow(SpiceOverlay *overlay) : Window(overlay) {
this->title = "VR";
this->flags = ImGuiWindowFlags_None;
this->toggle_button = games::OverlayButtons::ToggleVRControl;
this->init_size = ImVec2(500, 800);
this->size_min = ImVec2(250, 200);
}
VRWindow::~VRWindow() {
}
void VRWindow::build_content() {
ImGui::BeginTabBar("VRTabBar");
if (ImGui::BeginTabItem("Info")) {
build_info();
ImGui::EndTabItem();
}
if (avs::game::is_model("REC")) {
if (ImGui::BeginTabItem("Dancefloor")) {
build_dancefloor();
}
}
}
void VRWindow::build_info() {
// status
auto status = vrutil::STATUS;
switch (status) {
case vrutil::VRStatus::Disabled:
ImGui::TextColored(
ImVec4(0.4f, 0.4f, 0.4f, 1.f),
"Disabled");
if (ImGui::Button("Start")) {
vrutil::init();
if (avs::game::is_model("REC")) {
games::drs::start_vr();
}
}
break;
case vrutil::VRStatus::Error:
ImGui::TextColored(
ImVec4(0.8f, 0.1f, 0.1f, 1.f),
"Error");
if (ImGui::Button("Restart")) {
vrutil::shutdown();
vrutil::init();
}
break;
case vrutil::VRStatus::Running:
ImGui::TextColored(
ImVec4(0.1f, 0.8f, 0.1f, 1.f),
"Running");
if (ImGui::Button("Stop")) {
vrutil::shutdown();
}
break;
}
// rescan
if (ImGui::Button("Rescan Devices")) {
vrutil::scan(true);
}
// data table header
ImGui::Columns(2);
ImGui::Text("Device");
ImGui::NextColumn();
ImGui::Text("Position");
ImGui::NextColumn();
ImGui::Separator();
// HMD/Left/Right data
vr::TrackedDevicePose_t hmd_pose, left_pose, right_pose;
vr::VRControllerState_t left_state, right_state;
vrutil::get_hmd_pose(&hmd_pose);
vrutil::get_con_pose(vrutil::INDEX_LEFT, &left_pose, &left_state);
vrutil::get_con_pose(vrutil::INDEX_RIGHT, &right_pose, &right_state);
auto hmd_pos = vrutil::get_translation(hmd_pose.mDeviceToAbsoluteTracking);
auto left_pos = vrutil::get_translation(left_pose.mDeviceToAbsoluteTracking);
auto right_pos = vrutil::get_translation(right_pose.mDeviceToAbsoluteTracking);
ImGui::Text("HMD");
ImGui::NextColumn();
ImGui::TextUnformatted(fmt::format(
"X={:3f} Y={:3f} Z={:3f}",
hmd_pos.x, hmd_pos.y, hmd_pos.z).c_str());
ImGui::NextColumn();
ImGui::Text("Left");
ImGui::NextColumn();
ImGui::TextUnformatted(fmt::format(
"X={:3f} Y={:3f} Z={:3f}",
left_pos.x, left_pos.y, left_pos.z).c_str());
ImGui::NextColumn();
ImGui::Text("Right");
ImGui::NextColumn();
ImGui::TextUnformatted(fmt::format(
"X={:3f} Y={:3f} Z={:3f}",
right_pos.x, right_pos.y, right_pos.z).c_str());
ImGui::NextColumn();
}
void VRWindow::build_dancefloor() {
ImGui::Separator();
// settings
ImGui::DragFloat3("Scale", &games::drs::VR_SCALE[0], 0.1f);
ImGui::DragFloat3("Offset", &games::drs::VR_OFFSET[0], 0.1f);
ImGui::DragFloat("Rotation", &games::drs::VR_ROTATION, 0.5f);
for (int i = 0; i < (int) std::size(games::drs::VR_FOOTS); ++i) {
auto &foot = games::drs::VR_FOOTS[i];
ImGui::Separator();
ImGui::PushID(&foot);
ImGui::Text("%s Foot", i == 0 ? "Left" : "Right");
ImGui::InputInt("Device Index", (int*) &foot.index, 1, 1);
ImGui::DragFloat("Length", &foot.length,
0.005f, 0.001f, 1000.f);
ImGui::DragFloat("Size Base", &foot.size_base,
0.005f, 0.001f, 1000.f);
ImGui::DragFloat("Size Scale", &foot.size_scale,
0.005f, 0.001f, 1000.f);
ImGui::DragFloat4("Rotation Quat", &foot.rotation.x, 0.001f, -1, 1);
if (ImGui::Button("Calibrate")) {
vr::TrackedDevicePose_t pose;
vr::VRControllerState_t state;
vrutil::get_con_pose(foot.get_index(), &pose, &state);
foot.length = foot.height + 0.02f;
auto pose_rot = vrutil::get_rotation(pose.mDeviceToAbsoluteTracking.m);
foot.rotation = linalg::qmul(linalg::qinv(pose_rot),
vrutil::get_rotation((float) M_PI * -0.5f, 0, 0));
}
ImGui::SameLine();
ImGui::HelpMarker("Place the controller to the lower part of your leg "
"and press this button to auto calibrate angle and length");
ImGui::PopID();
}
// prepare view
auto draw_list = ImGui::GetWindowDrawList();
auto canvas_pos = ImGui::GetCursorScreenPos();
auto canvas_size = ImGui::GetContentRegionAvail();
float offset_x = canvas_size.x * 0.5f;
float offset_y = canvas_size.y * 0.1f;
float off_x = offset_x + canvas_pos.x;
float off_y = offset_y + canvas_pos.y;
float scale = std::min(canvas_size.x, canvas_size.y) / 60;
// axis
draw_list->AddLine(
ImVec2(canvas_pos.x, off_y),
ImVec2(canvas_pos.x + canvas_size.x, off_y),
ImColor(255, 0, 0, 128));
draw_list->AddLine(
ImVec2(off_x, canvas_pos.y),
ImVec2(off_x, canvas_pos.y + canvas_size.y),
ImColor(0, 255, 0, 128));
// tiles
for (int x = 0; x < 38; x++) {
for (int y = 0; y < 49; y++) {
auto &led = games::drs::DRS_TAPELED[x + y * 38];
ImColor color((int) led[0], (int) led[1], (int) led[2]);
ImVec2 p1((x - 19) * scale + off_x, (y + 0) * scale + off_y);
ImVec2 p2((x - 18) * scale + off_x, (y + 1) * scale + off_y);
draw_list->AddRectFilled(p1, p2, color, 0.f);
}
}
// foots
const float foot_box = 2.f * scale;
for (auto &foot : games::drs::VR_FOOTS) {
vr::TrackedDevicePose_t pose;
vr::VRControllerState_t state;
vrutil::get_con_pose(foot.get_index(), &pose, &state);
if (pose.bPoseIsValid) {
// position
auto pos = vrutil::get_translation(pose.mDeviceToAbsoluteTracking);
pos = foot.to_world(pos);
pos.x -= 19;
pos *= scale;
ImColor color(255, 0, 255);
if (foot.event.type == games::drs::DRS_DOWN
|| (foot.event.type == games::drs::DRS_MOVE)) {
auto size_factor = foot.event.width / (foot.size_base + foot.size_scale);
color = ImColor((int) (size_factor * 127) + 128, 0, 0);
}
ImVec2 p1(pos.x + off_x - foot_box * 0.5f,
pos.y + off_y - foot_box * 0.5f);
ImVec2 p2(pos.x + off_x + foot_box * 0.5f,
pos.y + off_y + foot_box * 0.5f);
draw_list->AddRectFilled(p1, p2, color, 0.f);
// direction
auto direction = -linalg::qzdir(linalg::qmul(
vrutil::get_rotation(pose.mDeviceToAbsoluteTracking.m),
foot.rotation));
direction = linalg::aliases::float3 {
-direction.z, direction.x, direction.y
};
auto end = pos + direction * foot.length * scale;
draw_list->AddLine(
ImVec2(pos.x + off_x, pos.y + off_y),
ImVec2(end.x + off_x, end.y + off_y),
ImColor(0, 255, 0));
}
}
}
}
+17 -17
View File
@@ -1,17 +1,17 @@
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class VRWindow : public Window {
public:
VRWindow(SpiceOverlay *overlay);
~VRWindow() override;
void build_content() override;
void build_info();
void build_dancefloor();
};
}
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class VRWindow : public Window {
public:
VRWindow(SpiceOverlay *overlay);
~VRWindow() override;
void build_content() override;
void build_info();
void build_dancefloor();
};
}
+19 -19
View File
@@ -1,19 +1,19 @@
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class WndManagerWindow : public Window {
public:
WndManagerWindow(SpiceOverlay *overlay);
~WndManagerWindow() override;
void build_content() override;
private:
int window_current = -1;
};
}
#pragma once
#include "overlay/window.h"
namespace overlay::windows {
class WndManagerWindow : public Window {
public:
WndManagerWindow(SpiceOverlay *overlay);
~WndManagerWindow() override;
void build_content() override;
private:
int window_current = -1;
};
}