mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 14:50:41 -07:00
Initial commit for GitHub migration based on spice2x-25-03-03
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
#undef CINTERFACE
|
||||
|
||||
#include "generic_sub.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "games/io.h"
|
||||
#include "cfg/screen_resize.h"
|
||||
#include "hooks/graphics/backends/d3d9/d3d9_backend.h"
|
||||
#include "hooks/graphics/backends/d3d9/d3d9_device.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/utils.h"
|
||||
#include "touch/touch.h"
|
||||
|
||||
int GENERIC_SUB_WINDOW_X = 0;
|
||||
int GENERIC_SUB_WINDOW_Y = 0;
|
||||
int GENERIC_SUB_WINDOW_WIDTH = 0;
|
||||
int GENERIC_SUB_WINDOW_HEIGHT = 0;
|
||||
bool GENERIC_SUB_WINDOW_FULLSIZE = false;
|
||||
|
||||
// #define OVERLAYDBG 1
|
||||
|
||||
namespace overlay::windows {
|
||||
|
||||
const ImVec4 YELLOW(1.f, 1.f, 0.f, 1.f);
|
||||
const ImVec4 WHITE(1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
GenericSubScreen::GenericSubScreen(SpiceOverlay *overlay) : Window(overlay), device(overlay->get_device()) {
|
||||
this->remove_window_padding = true;
|
||||
// ImGuiWindowFlags_NoBackground is needed as the background is drawn on top of the subscreen image
|
||||
this->flags = ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoBackground |
|
||||
ImGuiWindowFlags_NoDocking;
|
||||
|
||||
this->size_max = ImVec2(ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y);
|
||||
this->size_min = ImVec2(240, 135 + ImGui::GetFrameHeight());
|
||||
this->init_size = size_min;
|
||||
this->resize_callback = keep_16_by_9;
|
||||
|
||||
this->toggle_button = games::OverlayButtons::ToggleSubScreen;
|
||||
this->texture_width = 0;
|
||||
this->texture_height = 0;
|
||||
|
||||
overlay->set_subscreen_mouse_handler([this](LONG *x, LONG *y) -> bool {
|
||||
// convert to normalized form (relative window coordinates 0.f-1.f)
|
||||
ImVec2 xy;
|
||||
|
||||
// log_misc("sub::overlay", "mouse handler {} {}", to_string(*x), to_string(*y));
|
||||
// log_misc("sub::overlay", "spicetouch coords {} {} {} {}", to_string(SPICETOUCH_TOUCH_X), to_string(SPICETOUCH_TOUCH_Y), to_string(SPICETOUCH_TOUCH_WIDTH), to_string(SPICETOUCH_TOUCH_HEIGHT));
|
||||
|
||||
float ratio_x, ratio_y;
|
||||
|
||||
if (GRAPHICS_WINDOWED) {
|
||||
// input coords are relative to spicetouch wnd
|
||||
ratio_x = (float)*x / SPICETOUCH_TOUCH_WIDTH;
|
||||
ratio_y = (float)*y / SPICETOUCH_TOUCH_HEIGHT;
|
||||
} else {
|
||||
// inputs coords are relative to (0,0) for non-windowed mode
|
||||
ratio_x = (float)*x / ImGui::GetIO().DisplaySize.x;
|
||||
ratio_y = (float)*y / ImGui::GetIO().DisplaySize.y;
|
||||
}
|
||||
// log_misc("sub::overlay", "game coords {} {}", to_string(ratio_x), to_string(ratio_y));
|
||||
|
||||
// transform to subscreen overlay coords
|
||||
if (!GENERIC_SUB_WINDOW_FULLSIZE) {
|
||||
ratio_x = (ratio_x * ImGui::GetIO().DisplaySize.x - GENERIC_SUB_WINDOW_X) / GENERIC_SUB_WINDOW_WIDTH;
|
||||
ratio_y = (ratio_y * ImGui::GetIO().DisplaySize.y - GENERIC_SUB_WINDOW_Y) / GENERIC_SUB_WINDOW_HEIGHT;
|
||||
// log_misc("sub::overlay", "overlay coords {} {} {} {}", to_string(GENERIC_SUB_WINDOW_X), to_string(GENERIC_SUB_WINDOW_Y), to_string(GENERIC_SUB_WINDOW_WIDTH), to_string(GENERIC_SUB_WINDOW_HEIGHT));
|
||||
}
|
||||
|
||||
xy.x = ratio_x;
|
||||
xy.y = ratio_y;
|
||||
// log_misc("sub::overlay", "ratio {} {}", to_string(xy.x), to_string(xy.y));
|
||||
|
||||
// x/y can be outside of window
|
||||
if (xy.x < 0.f || 1.f < xy.x || xy.y < 0.f || 1.f < xy.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// call into child
|
||||
this->touch_transform(xy, x, y);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void GenericSubScreen::touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) {}
|
||||
|
||||
void GenericSubScreen::build_content() {
|
||||
if (this->disabled_message.has_value()) {
|
||||
this->flags &= ~ImGuiWindowFlags_NoBackground;
|
||||
ImGui::TextColored(YELLOW, "%s", this->disabled_message.value().c_str());
|
||||
return;
|
||||
}
|
||||
this->draw_texture();
|
||||
|
||||
#if OVERLAYDBG
|
||||
if (this->status_message.has_value()) {
|
||||
log_warning("sub::overlay", "{}", this->status_message.value().c_str());
|
||||
}
|
||||
if (this->status_message.has_value()) {
|
||||
ImGui::TextColored(YELLOW, "%s", this->status_message.value().c_str());
|
||||
} else if (this->texture) {
|
||||
ImGui::TextColored(WHITE, "Successfully acquired surface texture");
|
||||
} else {
|
||||
ImGui::TextColored(YELLOW, "Failed to acquire surface texture");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GenericSubScreen::build_texture(IDirect3DSurface9 *surface, UINT width, UINT height) {
|
||||
HRESULT hr;
|
||||
|
||||
D3DSURFACE_DESC desc {};
|
||||
hr = surface->GetDesc(&desc);
|
||||
if (FAILED(hr)) {
|
||||
this->status_message = fmt::format("Failed to get surface descriptor, hr={}", FMT_HRESULT(hr));
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = this->device->CreateTexture(width, height, 0, desc.Usage, desc.Format,
|
||||
desc.Pool, &this->texture, nullptr);
|
||||
if (FAILED(hr)) {
|
||||
this->status_message = fmt::format("Failed to create render target, hr={}", FMT_HRESULT(hr));
|
||||
return false;
|
||||
}
|
||||
|
||||
this->texture_width = width;
|
||||
this->texture_height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GenericSubScreen::draw_texture() {
|
||||
HRESULT hr;
|
||||
|
||||
auto surface = graphics_d3d9_ldj_get_sub_screen();
|
||||
if (surface == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->draws_window) {
|
||||
// calculate the **content** location and size.
|
||||
// GetContentRegionAvail returns the correct dimension, up to (and including) the resize handle
|
||||
// don't be tempted to change it to some other ImGui routine that accomplishes similar things!
|
||||
overlay_content_top_left = ImGui::GetCursorScreenPos();
|
||||
overlay_content_size = ImGui::GetContentRegionAvail();
|
||||
} else {
|
||||
// no window, full screen
|
||||
overlay_content_top_left = ImVec2(0, 0);
|
||||
overlay_content_size = ImGui::GetIO().DisplaySize;
|
||||
}
|
||||
|
||||
GENERIC_SUB_WINDOW_X = overlay_content_top_left.x;
|
||||
GENERIC_SUB_WINDOW_Y = overlay_content_top_left.y;
|
||||
GENERIC_SUB_WINDOW_WIDTH = overlay_content_size.x;
|
||||
GENERIC_SUB_WINDOW_HEIGHT = overlay_content_size.y;
|
||||
|
||||
if (this->draws_window &&
|
||||
this->texture &&
|
||||
((UINT)overlay_content_size.x != this->texture_width)) {
|
||||
|
||||
#if OVERLAYDBG
|
||||
log_info("sub::overlay", "resize {} != {} ", overlay_content_size.x, this->texture_width);
|
||||
#endif
|
||||
|
||||
// hack needed for SDVX; resizing the texture results in darker image, so allocate texture
|
||||
// again with the new size when the window is resized
|
||||
this->texture->Release();
|
||||
this->texture = nullptr;
|
||||
this->texture_width = 0;
|
||||
this->texture_height = 0;
|
||||
}
|
||||
|
||||
if (this->texture == nullptr) {
|
||||
if (!this->build_texture(surface, overlay_content_size.x, overlay_content_size.y)) {
|
||||
this->texture = nullptr;
|
||||
this->texture_width = 0;
|
||||
this->texture_height = 0;
|
||||
surface->Release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IDirect3DSurface9 *texture_surface = nullptr;
|
||||
hr = this->texture->GetSurfaceLevel(0, &texture_surface);
|
||||
if (FAILED(hr)) {
|
||||
this->status_message = fmt::format("Failed to get texture surface, hr={}", FMT_HRESULT(hr));
|
||||
surface->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
hr = this->device->StretchRect(surface, nullptr, texture_surface, nullptr, D3DTEXF_LINEAR);
|
||||
if (FAILED(hr)) {
|
||||
this->status_message = fmt::format("Failed to copy back buffer contents, hr={}", FMT_HRESULT(hr));
|
||||
surface->Release();
|
||||
texture_surface->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
surface->Release();
|
||||
texture_surface->Release();
|
||||
|
||||
// draw the subscreen (this draws *under* ImGui windows, over the game surface)
|
||||
auto bottom_right = overlay_content_size;
|
||||
bottom_right.x += overlay_content_top_left.x;
|
||||
bottom_right.y += overlay_content_top_left.y;
|
||||
ImGui::GetBackgroundDrawList()->AddImage(
|
||||
reinterpret_cast<void *>(this->texture),
|
||||
overlay_content_top_left,
|
||||
bottom_right);
|
||||
|
||||
if (this->draws_window) {
|
||||
// draw an invisible button so that it swallows mouse input
|
||||
// this is needed to prevent the window from being dragged around
|
||||
// (alternatively io.ConfigWindowsMoveFromTitleBarOnly can be set but that is global)
|
||||
ImGui::InvisibleButton(
|
||||
(this->title + "__InvisibleButton").c_str(),
|
||||
overlay_content_size,
|
||||
ImGuiButtonFlags_None);
|
||||
}
|
||||
|
||||
#if OVERLAYDBG
|
||||
log_info("sub::overlay", "{} / {} = {}", overlay_content_size.x, overlay_content_size.y, overlay_content_size.x / overlay_content_size.y);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user