diff --git a/src/core/graphics/gl_rectangle.rs b/src/core/graphics/gl_rectangle.rs new file mode 100644 index 00000000..5202b670 --- /dev/null +++ b/src/core/graphics/gl_rectangle.rs @@ -0,0 +1,145 @@ +use crate::core::graphics::gl_utils::{create_program, create_shader, shader_source}; +use gl::types::GLuint; +use std::ptr; + +pub struct GlRectangle { + rect_vertices: Vec<[f32; 8]>, // [x, y, r, g, b, a, unused1, unused2] for each vertex + rect_indices: Vec<[u16; 6]>, + rect_program: GLuint, +} + +impl GlRectangle { + pub fn new() -> Self { + let rect_program = unsafe { + let vert_shader = create_shader("rect", shader_source!("rect_vert"), gl::VERTEX_SHADER).unwrap(); + let frag_shader = create_shader("rect", shader_source!("rect_frag"), gl::FRAGMENT_SHADER).unwrap(); + let program = create_program(&[vert_shader, frag_shader]).unwrap(); + gl::DeleteShader(vert_shader); + gl::DeleteShader(frag_shader); + + gl::UseProgram(program); + + gl::BindAttribLocation(program, 0, "position\0".as_ptr() as _); + gl::BindAttribLocation(program, 1, "color\0".as_ptr() as _); + + gl::UseProgram(0); + + program + }; + + GlRectangle { + rect_vertices: Vec::new(), + rect_indices: Vec::new(), + rect_program, + } + } + + // Helper method to render vertices + unsafe fn render_vertices(&mut self) { + gl::UseProgram(self.rect_program); + + gl::Enable(gl::BLEND); + gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + + gl::EnableVertexAttribArray(0); + gl::EnableVertexAttribArray(1); + + // Position attribute (x, y) + gl::VertexAttribPointer(0, 2, gl::FLOAT, gl::FALSE, 8 * std::mem::size_of::() as i32, self.rect_vertices.as_ptr() as _); + + // Color attribute (r, g, b, a) - offset by 2 floats + gl::VertexAttribPointer(1, 4, gl::FLOAT, gl::FALSE, 8 * std::mem::size_of::() as i32, + (self.rect_vertices.as_ptr() as *const u8).add(2 * std::mem::size_of::()) as _); + + gl::DrawElements(gl::TRIANGLES, (6 * self.rect_indices.len()) as i32, gl::UNSIGNED_SHORT, self.rect_indices.as_ptr() as _); + + gl::DisableVertexAttribArray(0); + gl::DisableVertexAttribArray(1); + gl::Disable(gl::BLEND); + gl::UseProgram(0); + } + + // Draw a filled rectangle + pub unsafe fn draw_filled(&mut self, x: f32, y: f32, width: f32, height: f32, fill_color: (f32, f32, f32, f32)) { + // Clear previous vertices and indices + self.rect_vertices.clear(); + self.rect_indices.clear(); + + // Create vertices for the filled rectangle (4 corners) + let (r, g, b, a) = fill_color; + let vertices = [ + // Top left + [x, y + height, r, g, b, a, 0.0, 0.0], + // Top right + [x + width, y + height, r, g, b, a, 0.0, 0.0], + // Bottom right + [x + width, y, r, g, b, a, 0.0, 0.0], + // Bottom left + [x, y, r, g, b, a, 0.0, 0.0], + ]; + + self.rect_vertices.extend_from_slice(&vertices); + + // Create indices for two triangles forming the rectangle + let indices = [0, 1, 2, 0, 2, 3]; // Two triangles: (0,1,2) and (0,2,3) + self.rect_indices.push(indices); + + self.render_vertices(); + } + + // Draw a stroke-only rectangle (unfilled) + pub unsafe fn draw_stroke(&mut self, x: f32, y: f32, width: f32, height: f32, stroke_color: (f32, f32, f32, f32), stroke_width: f32) { + // Clear previous vertices and indices + self.rect_vertices.clear(); + self.rect_indices.clear(); + + let (r, g, b, a) = stroke_color; + let half_stroke = stroke_width / 2.0; + + // Create vertices for 4 stroke rectangles (top, right, bottom, left) + let vertices = [ + // Top stroke + [x - half_stroke, y + height + half_stroke, r, g, b, a, 0.0, 0.0], + [x + width + half_stroke, y + height + half_stroke, r, g, b, a, 0.0, 0.0], + [x + width + half_stroke, y + height - half_stroke, r, g, b, a, 0.0, 0.0], + [x - half_stroke, y + height - half_stroke, r, g, b, a, 0.0, 0.0], + + // Right stroke + [x + width - half_stroke, y + height + half_stroke, r, g, b, a, 0.0, 0.0], + [x + width + half_stroke, y + height + half_stroke, r, g, b, a, 0.0, 0.0], + [x + width + half_stroke, y - half_stroke, r, g, b, a, 0.0, 0.0], + [x + width - half_stroke, y - half_stroke, r, g, b, a, 0.0, 0.0], + + // Bottom stroke + [x - half_stroke, y + half_stroke, r, g, b, a, 0.0, 0.0], + [x + width + half_stroke, y + half_stroke, r, g, b, a, 0.0, 0.0], + [x + width + half_stroke, y - half_stroke, r, g, b, a, 0.0, 0.0], + [x - half_stroke, y - half_stroke, r, g, b, a, 0.0, 0.0], + + // Left stroke + [x - half_stroke, y + height + half_stroke, r, g, b, a, 0.0, 0.0], + [x + half_stroke, y + height + half_stroke, r, g, b, a, 0.0, 0.0], + [x + half_stroke, y - half_stroke, r, g, b, a, 0.0, 0.0], + [x - half_stroke, y - half_stroke, r, g, b, a, 0.0, 0.0], + ]; + + self.rect_vertices.extend_from_slice(&vertices); + + // Create indices for 4 rectangles (16 vertices = 4 rectangles * 4 vertices each) + for i in 0..4 { + let base = i * 4; + let indices = [base, base + 1, base + 2, base, base + 2, base + 3]; + self.rect_indices.push(indices); + } + + self.render_vertices(); + } + + // Draw a rectangle with both fill and stroke + pub unsafe fn draw_filled_stroke(&mut self, x: f32, y: f32, width: f32, height: f32, fill_color: (f32, f32, f32, f32), stroke_color: (f32, f32, f32, f32), stroke_width: f32) { + // First draw the fill + self.draw_filled(x, y, width, height, fill_color); + // Then draw the stroke + self.draw_stroke(x, y, width, height, stroke_color, stroke_width); + } +} diff --git a/src/core/graphics/gpu_renderer.rs b/src/core/graphics/gpu_renderer.rs index c23a188a..4db337fb 100644 --- a/src/core/graphics/gpu_renderer.rs +++ b/src/core/graphics/gpu_renderer.rs @@ -1,4 +1,5 @@ use crate::core::graphics::gl_glyph::GlGlyph; +use crate::core::graphics::gl_rectangle:: GlRectangle; use crate::core::graphics::gpu::{PowCnt1, DISPLAY_HEIGHT, DISPLAY_WIDTH}; use crate::core::graphics::gpu_2d::registers_2d::Gpu2DRegisters; use crate::core::graphics::gpu_2d::renderer_2d::Gpu2DRenderer; @@ -7,7 +8,7 @@ use crate::core::graphics::gpu_3d::registers_3d::Gpu3DRegisters; use crate::core::graphics::gpu_3d::renderer_3d::Gpu3DRenderer; use crate::core::graphics::gpu_mem_buf::GpuMemBuf; use crate::core::memory::mem::Memory; -use crate::presenter::{Presenter, PresenterScreen, PRESENTER_SCREEN_HEIGHT, PRESENTER_SCREEN_WIDTH, PRESENTER_SUB_REGULAR, PRESENTER_SUB_RESIZED, PRESENTER_SUB_ROTATED}; +use crate::presenter::{Presenter, PresenterScreen, PRESENTER_SCREEN_HEIGHT, PRESENTER_SCREEN_WIDTH, PRESENTER_SUB_REGULAR, PRESENTER_SUB_RESIZED, PRESENTER_SUB_RESIZED_INV, PRESENTER_SUB_ROTATED, SWAP_ZONE_WIDTH, SWAP_ZONE_HEIGHT}; use crate::settings::{ScreenMode, Settings}; use gl::types::GLuint; use std::intrinsics::unlikely; @@ -41,6 +42,7 @@ pub struct GpuRenderer { common: GpuRendererCommon, gl_glyph: GlGlyph, + gl_rectangle: GlRectangle, rendering: Mutex, rendering_condvar: Condvar, @@ -66,6 +68,7 @@ impl GpuRenderer { common: GpuRendererCommon::new(), gl_glyph: GlGlyph::new(), + gl_rectangle: GlRectangle::new(), rendering: Mutex::new(false), rendering_condvar: Condvar::new(), @@ -128,7 +131,7 @@ impl GpuRenderer { } } - pub fn render_loop(&mut self, presenter: &mut Presenter, fps: &Arc, last_save_time: &Arc>>, settings: &Settings) { + pub fn render_loop(&mut self, presenter: &mut Presenter, fps: &Arc, last_save_time: &Arc>>, settings: &Settings, swap_sizes: bool) { { let rendering = self.rendering.lock().unwrap(); let _drawing = self.rendering_condvar.wait_while(rendering, |rendering| !*rendering).unwrap(); @@ -177,7 +180,7 @@ impl GpuRenderer { let screen_topology = match settings.screenmode() { ScreenMode::Regular => PRESENTER_SUB_REGULAR, ScreenMode::Rotated => PRESENTER_SUB_ROTATED, - ScreenMode::Resized => PRESENTER_SUB_RESIZED, + ScreenMode::Resized => if swap_sizes { PRESENTER_SUB_RESIZED } else { PRESENTER_SUB_RESIZED_INV }, }; let used_fbo = match screen_topology.mode { ScreenMode::Regular | ScreenMode::Resized => self.renderer_2d.common.blend_fbo.fbo, @@ -232,6 +235,15 @@ impl GpuRenderer { let arm7_emu: &str = settings.arm7_hle().into(); self.gl_glyph.draw(format!("{}ms {arm7_emu}\n{per}% ({fps}fps)\n{info_text}", self.average_render_time)); + + // Draw a UI element to represent the touch-region to swap screen sizes in resized screen mode + if settings.screenmode() == ScreenMode::Resized + { + let swap_zone_x = (PRESENTER_SCREEN_WIDTH - SWAP_ZONE_WIDTH - 4) as f32; + let swap_zone_y = 5 as f32; + self.gl_rectangle.draw_filled_stroke(swap_zone_x, swap_zone_y, (SWAP_ZONE_WIDTH) as f32, SWAP_ZONE_HEIGHT as f32, + (0.31, 0.31, 0.31, 1.0), (0.66, 0.66, 0.66, 1.0), 1.0); + } #[cfg(feature = "profiling")] gl::ReadPixels( diff --git a/src/core/graphics/mod.rs b/src/core/graphics/mod.rs index e0caa32b..37e55528 100644 --- a/src/core/graphics/mod.rs +++ b/src/core/graphics/mod.rs @@ -1,4 +1,5 @@ mod gl_glyph; +mod gl_rectangle; mod gl_utils; pub mod gpu; pub mod gpu_2d; diff --git a/src/core/graphics/shaders/cg/rect_frag.cg b/src/core/graphics/shaders/cg/rect_frag.cg new file mode 100644 index 00000000..e66210b5 --- /dev/null +++ b/src/core/graphics/shaders/cg/rect_frag.cg @@ -0,0 +1,5 @@ +float4 in fragColor : COLOR0; + +void main(out float4 color : COLOR) { + color = fragColor; +} diff --git a/src/core/graphics/shaders/cg/rect_vert.cg b/src/core/graphics/shaders/cg/rect_vert.cg new file mode 100644 index 00000000..642547ea --- /dev/null +++ b/src/core/graphics/shaders/cg/rect_vert.cg @@ -0,0 +1,7 @@ +float4 out gl_Position : POSITION; +float4 out fragColor : COLOR0; + +void main(float4 position, float4 color) { + fragColor = color; + gl_Position = float4(position.x / 480.0 - 1.0, -position.y / 272.0 + 1.0, 0.0, 1.0); +} diff --git a/src/core/graphics/shaders/glsl/rect_frag.glsl b/src/core/graphics/shaders/glsl/rect_frag.glsl new file mode 100644 index 00000000..22a5b5c0 --- /dev/null +++ b/src/core/graphics/shaders/glsl/rect_frag.glsl @@ -0,0 +1,11 @@ +#version 300 es + +precision mediump float; + +layout(location = 0) out vec4 color; + +in vec4 fragColor; + +void main() { + color = fragColor; +} diff --git a/src/core/graphics/shaders/glsl/rect_vert.glsl b/src/core/graphics/shaders/glsl/rect_vert.glsl new file mode 100644 index 00000000..07a73f33 --- /dev/null +++ b/src/core/graphics/shaders/glsl/rect_vert.glsl @@ -0,0 +1,10 @@ +#version 300 es + +in vec4 position; +in vec4 color; +out vec4 fragColor; + +void main() { + fragColor = color; + gl_Position = vec4(position.x / 480.0 - 1.0, -position.y / 272.0 + 1.0, 0.0, 1.0); +} diff --git a/src/main.rs b/src/main.rs index 3edff716..568b84bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,9 +27,9 @@ use crate::jit::jit_asm::{JitAsm, MAX_STACK_DEPTH_SIZE}; use crate::jit::jit_memory::JitMemory; use crate::logging::{debug_println, info_println}; use crate::mmap::{register_abort_handler, ArmContext, Mmap, PAGE_SIZE}; -use crate::presenter::{PresentEvent, Presenter, PRESENTER_AUDIO_BUF_SIZE}; +use crate::presenter::{PresentEvent, Presenter, PRESENTER_AUDIO_BUF_SIZE, PRESENTER_SUB_RESIZED, PRESENTER_SCREEN_WIDTH, SWAP_ZONE_WIDTH, SWAP_ZONE_HEIGHT}; use crate::profiling::{profiling_init, profiling_set_thread_name}; -use crate::settings::{Arm7Emu, Settings}; +use crate::settings::{Arm7Emu, ScreenMode, Settings}; use crate::utils::{const_str_equal, set_thread_prio_affinity, HeapMemU32, ThreadAffinity, ThreadPriority}; use std::cell::UnsafeCell; use std::cmp::min; @@ -299,6 +299,25 @@ fn execute_jit(emu: &mut UnsafeCell) { } } +fn handle_touch_swap( + swap_sizes: &mut bool, + raw_touch: Option<(u16, u16)>, + prev_swap_touch: &mut bool, +) { + if let Some((tx, ty)) = raw_touch { + let (x, y) = (tx as u32, ty as u32); + let in_zone = x >= (PRESENTER_SCREEN_WIDTH as u32).saturating_sub(SWAP_ZONE_WIDTH) && y < SWAP_ZONE_HEIGHT; + + if in_zone && !*prev_swap_touch { + *swap_sizes = !*swap_sizes; + } + + *prev_swap_touch = in_zone; + } else { + *prev_swap_touch = false; + } +} + #[used] #[export_name = "_newlib_heap_size_user"] pub static _NEWLIB_HEAP_SIZE_USER: u32 = 256 * 1024 * 1024; // 256 MiB @@ -468,13 +487,22 @@ pub fn actual_main() { .unwrap(); let gpu_renderer = unsafe { gpu_renderer.get().as_mut().unwrap() }; - while let PresentEvent::Inputs { keymap, touch } = presenter.poll_event(settings.screenmode()) { + + // Bottom screen on the right bigger by default + let mut swap_sizes = true; + let mut prev_swap_touch = false; + + while let PresentEvent::Inputs { keymap, touch, raw_touch } = presenter.poll_event(settings.screenmode(), swap_sizes) { if let Some((x, y)) = touch { touch_points.store(((y as u16) << 8) | (x as u16), Ordering::Relaxed); } key_map.store(keymap, Ordering::Relaxed); - gpu_renderer.render_loop(&mut presenter, &fps, &last_save_time, &settings); + if settings.screenmode() == ScreenMode::Resized { + handle_touch_swap(&mut swap_sizes, raw_touch, &mut prev_swap_touch); + } + + gpu_renderer.render_loop(&mut presenter, &fps, &last_save_time, &settings, swap_sizes); } audio_thread.join().unwrap(); diff --git a/src/presenter/mod.rs b/src/presenter/mod.rs index 49695fbd..20decf2b 100644 --- a/src/presenter/mod.rs +++ b/src/presenter/mod.rs @@ -13,9 +13,11 @@ mod platform; pub const PRESENTER_SCREEN_WIDTH: u32 = 960; pub const PRESENTER_SCREEN_HEIGHT: u32 = 544; +pub const SWAP_ZONE_WIDTH: u32 = 87; +pub const SWAP_ZONE_HEIGHT: u32 = 71; pub enum PresentEvent { - Inputs { keymap: u32, touch: Option<(u8, u8)> }, + Inputs { keymap: u32, touch: Option<(u8, u8)>, raw_touch: Option<(u16, u16)> }, Quit, } @@ -85,6 +87,23 @@ pub const PRESENTER_SUB_RESIZED_BOTTOM_SCREEN: PresenterScreen = PresenterScreen PRESENTER_SUB_RESIZED_SCREEN_HEIGHT_BOT, ); +pub const PRESENTER_SUB_RESIZED_INV_SCREEN_WIDTH_TOP: u32 = DISPLAY_WIDTH as u32 * 2; +pub const PRESENTER_SUB_RESIZED_INV_SCREEN_WIDTH_BOT: u32 = DISPLAY_WIDTH as u32; +pub const PRESENTER_SUB_RESIZED_INV_SCREEN_HEIGHT_TOP: u32 = DISPLAY_HEIGHT as u32 * 2; +pub const PRESENTER_SUB_RESIZED_INV_SCREEN_HEIGHT_BOT: u32 = DISPLAY_HEIGHT as u32; +pub const PRESENTER_SUB_RESIZED_INV_TOP_SCREEN: PresenterScreen = PresenterScreen::new( + (PRESENTER_SCREEN_WIDTH - PRESENTER_SUB_RESIZED_INV_SCREEN_WIDTH_TOP - PRESENTER_SUB_RESIZED_INV_SCREEN_WIDTH_BOT) / 2, + (PRESENTER_SCREEN_HEIGHT - PRESENTER_SUB_RESIZED_INV_SCREEN_HEIGHT_TOP) / 2, + PRESENTER_SUB_RESIZED_INV_SCREEN_WIDTH_TOP, + PRESENTER_SUB_RESIZED_INV_SCREEN_HEIGHT_TOP, +); +pub const PRESENTER_SUB_RESIZED_INV_BOTTOM_SCREEN: PresenterScreen = PresenterScreen::new( + PRESENTER_SUB_RESIZED_INV_TOP_SCREEN.x + PRESENTER_SUB_RESIZED_INV_TOP_SCREEN.width, + (PRESENTER_SCREEN_HEIGHT - PRESENTER_SUB_RESIZED_INV_SCREEN_HEIGHT_BOT) / 2, + PRESENTER_SUB_RESIZED_INV_SCREEN_WIDTH_BOT, + PRESENTER_SUB_RESIZED_INV_SCREEN_HEIGHT_BOT, +); + pub const PRESENTER_SUB_REGULAR: ScreenTopology = ScreenTopology { top: PRESENTER_SUB_TOP_SCREEN, bottom: PRESENTER_SUB_BOTTOM_SCREEN, @@ -102,3 +121,9 @@ pub const PRESENTER_SUB_RESIZED: ScreenTopology = ScreenTopology { bottom: PRESENTER_SUB_RESIZED_BOTTOM_SCREEN, mode: ScreenMode::Resized, }; + +pub const PRESENTER_SUB_RESIZED_INV: ScreenTopology = ScreenTopology { + top: PRESENTER_SUB_RESIZED_INV_TOP_SCREEN, + bottom: PRESENTER_SUB_RESIZED_INV_BOTTOM_SCREEN, + mode: ScreenMode::Resized, +}; \ No newline at end of file diff --git a/src/presenter/vita.rs b/src/presenter/vita.rs index 873ba49a..843afb53 100644 --- a/src/presenter/vita.rs +++ b/src/presenter/vita.rs @@ -14,8 +14,9 @@ use crate::presenter::platform::imgui::{ ImGui_SetItemDefaultFocus, ImGui_SetNextWindowPos, ImGui_SetNextWindowSize, ImGui_SetWindowFocus, ImGui_StyleColorsDark, ImGui_Text, ImVec2, ImVec4, }; use crate::presenter::{ - PresentEvent, PRESENTER_AUDIO_BUF_SIZE, PRESENTER_AUDIO_SAMPLE_RATE, PRESENTER_SCREEN_HEIGHT, PRESENTER_SCREEN_WIDTH, PRESENTER_SUB_BOTTOM_SCREEN, PRESENTER_SUB_RESIZED_BOTTOM_SCREEN, - PRESENTER_SUB_ROTATED_BOTTOM_SCREEN, + PresentEvent, PRESENTER_AUDIO_BUF_SIZE, PRESENTER_AUDIO_SAMPLE_RATE, PRESENTER_SCREEN_HEIGHT, PRESENTER_SCREEN_WIDTH, + PRESENTER_SUB_BOTTOM_SCREEN, PRESENTER_SUB_RESIZED_BOTTOM_SCREEN, PRESENTER_SUB_RESIZED_INV_BOTTOM_SCREEN, PRESENTER_SUB_ROTATED_BOTTOM_SCREEN, + SWAP_ZONE_WIDTH, SWAP_ZONE_HEIGHT }; use crate::settings::{Arm7Emu, ScreenMode, SettingValue, Settings, SettingsConfig}; use gl::types::{GLboolean, GLenum, GLuint}; @@ -160,8 +161,9 @@ impl Presenter { } } - pub fn poll_event(&mut self, screenmode: ScreenMode) -> PresentEvent { - let mut touch = None; + pub fn poll_event(&mut self, screenmode: ScreenMode, swap_sizes: bool) -> PresentEvent { + let mut raw_touch: Option<(u16, u16)> = None; + let mut touch: Option<(u8, u8)> = None; unsafe { let pressed = MaybeUninit::::uninit(); @@ -184,39 +186,43 @@ impl Presenter { let report = touch_report.report.first().unwrap(); let x = report.x as u32 * PRESENTER_SCREEN_WIDTH / 1920; let y = report.y as u32 * PRESENTER_SCREEN_HEIGHT / 1080; - - match screenmode { - ScreenMode::Regular => { - if PRESENTER_SUB_BOTTOM_SCREEN.is_within(x, y) { - let (x, y) = PRESENTER_SUB_BOTTOM_SCREEN.normalize(x, y); - let screen_x = (DISPLAY_WIDTH as u32 * x / PRESENTER_SUB_BOTTOM_SCREEN.width) as u8; - let screen_y = (DISPLAY_HEIGHT as u32 * y / PRESENTER_SUB_BOTTOM_SCREEN.height) as u8; - touch = Some((screen_x, screen_y)); - } - } - ScreenMode::Rotated => { - if PRESENTER_SUB_ROTATED_BOTTOM_SCREEN.is_within(x, y) { - let (x, y) = PRESENTER_SUB_ROTATED_BOTTOM_SCREEN.normalize(x, y); - let screen_x = (DISPLAY_WIDTH as u32 - (DISPLAY_WIDTH as u32 * y / PRESENTER_SUB_ROTATED_BOTTOM_SCREEN.height)) as u8; - let screen_y = (DISPLAY_HEIGHT as u32 * x / PRESENTER_SUB_ROTATED_BOTTOM_SCREEN.width) as u8; - touch = Some((screen_x, screen_y)); + raw_touch = Some((x as u16, y as u16)); + let in_swap_zone = x >= PRESENTER_SCREEN_WIDTH - SWAP_ZONE_WIDTH && y < SWAP_ZONE_HEIGHT; + + if !in_swap_zone || screenmode != ScreenMode::Resized { + match screenmode { + ScreenMode::Regular | ScreenMode::Resized => { + let rect = if screenmode == ScreenMode::Regular { + PRESENTER_SUB_BOTTOM_SCREEN + } else if swap_sizes { + PRESENTER_SUB_RESIZED_BOTTOM_SCREEN + } else { + PRESENTER_SUB_RESIZED_INV_BOTTOM_SCREEN + }; + if rect.is_within(x, y) { + let (x, y) = rect.normalize(x, y); + let screen_x = (DISPLAY_WIDTH as u32 * x / rect.width) as u8; + let screen_y = (DISPLAY_HEIGHT as u32 * y / rect.height) as u8; + touch = Some((screen_x, screen_y)); + } } - } - ScreenMode::Resized => { - if PRESENTER_SUB_RESIZED_BOTTOM_SCREEN.is_within(x, y) { - let (x, y) = PRESENTER_SUB_RESIZED_BOTTOM_SCREEN.normalize(x, y); - let screen_x = (DISPLAY_WIDTH as u32 * x / PRESENTER_SUB_RESIZED_BOTTOM_SCREEN.width) as u8; - let screen_y = (DISPLAY_HEIGHT as u32 * y / PRESENTER_SUB_RESIZED_BOTTOM_SCREEN.height) as u8; - touch = Some((screen_x, screen_y)); + ScreenMode::Rotated => { + let rect = PRESENTER_SUB_ROTATED_BOTTOM_SCREEN; + if rect.is_within(x, y) { + let (x, y) = rect.normalize(x, y); + let screen_x = (DISPLAY_WIDTH as u32 - (DISPLAY_WIDTH as u32 * y / rect.height)) as u8; + let screen_y = (DISPLAY_HEIGHT as u32 * x / rect.width) as u8; + touch = Some((screen_x, screen_y)); + } } } + self.keymap &= !(1 << 16); } - self.keymap &= !(1 << 16); } else { self.keymap |= 1 << 16; } } - PresentEvent::Inputs { keymap: self.keymap, touch } + PresentEvent::Inputs { keymap: self.keymap, touch, raw_touch } } pub fn present_ui(&self) -> (CartridgeIo, Settings) {