#include "touch_debug.h" #include #include #include #include #include "external/imgui/imgui.h" #include "games/rb/rb.h" #include "games/rb/touch_defs.h" namespace games::rb { struct TouchDebugState { std::array packet {}; bool is_landscape = false; }; std::atomic_bool TOUCH_DEBUG_OVERLAY = false; static std::atomic_bool TOUCH_ACTIVE = false; static std::mutex TOUCH_DEBUG_STATE_M; static TouchDebugState TOUCH_DEBUG_STATE; static float touch_scale_factor() { return TOUCH_SCALING / (float) TOUCH_SCALE_DEFAULT; } static void clear_touch_debug_state() { std::lock_guard lock(TOUCH_DEBUG_STATE_M); TOUCH_DEBUG_STATE = {}; } static TouchDebugState get_touch_debug_state() { std::lock_guard lock(TOUCH_DEBUG_STATE_M); return TOUCH_DEBUG_STATE; } static bool packet_bit_active( const std::array &packet, int bit) { return (packet[TOUCH_PACKET_DATA_OFFSET + bit / 8] & (1u << (bit % 8))) != 0; } static int sensor_center(int sensor, int sensor_count, int extent) { return ((sensor * 2 + 1) * extent) / (sensor_count * 2); } static float sensor_span_position(int sensor, int sensor_count, int extent) { return sensor * (extent - 1) / (float) (sensor_count - 1); } bool touch_debug_overlay_enabled() { return TOUCH_DEBUG_OVERLAY && TOUCH_ACTIVE.load(std::memory_order_acquire); } void touch_draw_debug_overlay() { if (!touch_debug_overlay_enabled()) { return; } const auto &io = ImGui::GetIO(); int width = static_cast(io.DisplaySize.x); int height = static_cast(io.DisplaySize.y); if (width <= 0 || height <= 0) { return; } const float scale_factor = touch_scale_factor(); const float left = width * (1.f - scale_factor) / 2.f; const float top = height * (1.f - scale_factor) / 2.f; const float right = width - left; const float bottom = height - top; TouchDebugState state = get_touch_debug_state(); ImDrawList *draw_list = ImGui::GetBackgroundDrawList(); auto draw_line = [&](float x1, float y1, float x2, float y2) { draw_list->AddLine( ImVec2(x1, y1), ImVec2(x2, y2), IM_COL32(0, 255, 64, 255), 2.f); }; // show the valid input area when touch scaling restricts it if (TOUCH_SCALING != TOUCH_SCALE_DEFAULT) { draw_list->AddRect( ImVec2(left, top), ImVec2(right, bottom), IM_COL32(255, 255, 255, 255), 0.f, 0, 2.f); } // spread the usable X sensors 2..45 from edge to edge for (int sensor = X_SENSOR_FIRST_ACTIVE; sensor <= X_SENSOR_LAST_ACTIVE; sensor++) { if (!packet_bit_active(state.packet, X_SENSOR_FIRST_BIT + sensor)) { continue; } float position = sensor_span_position( sensor - X_SENSOR_FIRST_ACTIVE, X_SENSOR_ACTIVE_COUNT, state.is_landscape ? height : width); if (state.is_landscape) { float y = top + position * scale_factor; draw_line(left, y, right, y); } else { float x = left + position * scale_factor; draw_line(x, top, x, bottom); } } for (int sensor = 0; sensor < Y_SENSOR_COUNT; sensor++) { if (!packet_bit_active(state.packet, Y_SENSOR_FIRST_BIT - sensor)) { continue; } int position = sensor_center( sensor, Y_SENSOR_COUNT, state.is_landscape ? width : height); if (state.is_landscape) { float x = right - position * scale_factor; draw_line(x, top, x, bottom); } else { float y = top + position * scale_factor; draw_line(left, y, right, y); } } } void touch_debug_attach() { clear_touch_debug_state(); TOUCH_ACTIVE.store(true, std::memory_order_release); } void touch_debug_detach() { TOUCH_ACTIVE.store(false, std::memory_order_release); clear_touch_debug_state(); } void touch_debug_publish(const unsigned char *data, bool is_landscape) { if (!TOUCH_DEBUG_OVERLAY) { return; } std::lock_guard lock(TOUCH_DEBUG_STATE_M); memcpy(TOUCH_DEBUG_STATE.packet.data(), data, TOUCH_PACKET_SIZE); TOUCH_DEBUG_STATE.is_landscape = is_landscape; } }