emu_window.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <cmath>
  6. #include "common/assert.h"
  7. #include "common/key_map.h"
  8. #include "emu_window.h"
  9. #include "video_core/video_core.h"
  10. void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) {
  11. pad_state.hex |= KeyMap::GetPadKey(key).hex;
  12. }
  13. void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) {
  14. pad_state.hex &= ~KeyMap::GetPadKey(key).hex;
  15. }
  16. /**
  17. * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout
  18. * @param layout FramebufferLayout object describing the framebuffer size and screen positions
  19. * @param framebuffer_x Framebuffer x-coordinate to check
  20. * @param framebuffer_y Framebuffer y-coordinate to check
  21. * @return True if the coordinates are within the touchpad, otherwise false
  22. */
  23. static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x,
  24. unsigned framebuffer_y) {
  25. return (framebuffer_y >= layout.bottom_screen.top &&
  26. framebuffer_y < layout.bottom_screen.bottom &&
  27. framebuffer_x >= layout.bottom_screen.left &&
  28. framebuffer_x < layout.bottom_screen.right);
  29. }
  30. std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
  31. new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
  32. new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
  33. new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
  34. new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
  35. return std::make_tuple(new_x, new_y);
  36. }
  37. void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
  38. if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
  39. return;
  40. touch_x = VideoCore::kScreenBottomWidth * (framebuffer_x - framebuffer_layout.bottom_screen.left) /
  41. (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left);
  42. touch_y = VideoCore::kScreenBottomHeight * (framebuffer_y - framebuffer_layout.bottom_screen.top) /
  43. (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
  44. touch_pressed = true;
  45. pad_state.touch = 1;
  46. }
  47. void EmuWindow::TouchReleased() {
  48. touch_pressed = false;
  49. touch_x = 0;
  50. touch_y = 0;
  51. pad_state.touch = 0;
  52. }
  53. void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
  54. if (!touch_pressed)
  55. return;
  56. if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
  57. std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
  58. TouchPressed(framebuffer_x, framebuffer_y);
  59. }
  60. EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) {
  61. ASSERT(width > 0);
  62. ASSERT(height > 0);
  63. EmuWindow::FramebufferLayout res = { width, height, {}, {} };
  64. float window_aspect_ratio = static_cast<float>(height) / width;
  65. float emulation_aspect_ratio = static_cast<float>(VideoCore::kScreenTopHeight * 2) /
  66. VideoCore::kScreenTopWidth;
  67. if (window_aspect_ratio > emulation_aspect_ratio) {
  68. // Window is narrower than the emulation content => apply borders to the top and bottom
  69. int viewport_height = static_cast<int>(std::round(emulation_aspect_ratio * width));
  70. res.top_screen.left = 0;
  71. res.top_screen.right = res.top_screen.left + width;
  72. res.top_screen.top = (height - viewport_height) / 2;
  73. res.top_screen.bottom = res.top_screen.top + viewport_height / 2;
  74. int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) /
  75. VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left));
  76. int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2;
  77. res.bottom_screen.left = bottom_border;
  78. res.bottom_screen.right = res.bottom_screen.left + bottom_width;
  79. res.bottom_screen.top = res.top_screen.bottom;
  80. res.bottom_screen.bottom = res.bottom_screen.top + viewport_height / 2;
  81. } else {
  82. // Otherwise, apply borders to the left and right sides of the window.
  83. int viewport_width = static_cast<int>(std::round(height / emulation_aspect_ratio));
  84. res.top_screen.left = (width - viewport_width) / 2;
  85. res.top_screen.right = res.top_screen.left + viewport_width;
  86. res.top_screen.top = 0;
  87. res.top_screen.bottom = res.top_screen.top + height / 2;
  88. int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) /
  89. VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left));
  90. int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2;
  91. res.bottom_screen.left = res.top_screen.left + bottom_border;
  92. res.bottom_screen.right = res.bottom_screen.left + bottom_width;
  93. res.bottom_screen.top = res.top_screen.bottom;
  94. res.bottom_screen.bottom = res.bottom_screen.top + height / 2;
  95. }
  96. return res;
  97. }