pygame_backend.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. from __future__ import absolute_import
  2. from imgui_bundle import imgui
  3. from imgui_bundle.python_backends.opengl_backend_programmable import ProgrammablePipelineRenderer
  4. from typing import Dict
  5. import pygame
  6. import pygame.event
  7. import pygame.time
  8. PygameKey = int
  9. class PygameRenderer(ProgrammablePipelineRenderer):
  10. key_map: Dict[PygameKey, imgui.Key]
  11. modifier_map: Dict[PygameKey, imgui.Key]
  12. def __init__(self):
  13. super(PygameRenderer, self).__init__()
  14. self._gui_time = None
  15. self._map_keys()
  16. def _map_keys(self):
  17. self.key_map = {
  18. pygame.K_LEFT: imgui.Key.left_arrow,
  19. pygame.K_RIGHT: imgui.Key.right_arrow,
  20. pygame.K_UP: imgui.Key.up_arrow,
  21. pygame.K_DOWN: imgui.Key.down_arrow,
  22. pygame.K_PAGEUP: imgui.Key.page_up,
  23. pygame.K_PAGEDOWN: imgui.Key.page_down,
  24. pygame.K_HOME: imgui.Key.home,
  25. pygame.K_END: imgui.Key.end,
  26. pygame.K_INSERT: imgui.Key.insert,
  27. pygame.K_DELETE: imgui.Key.delete,
  28. pygame.K_BACKSPACE: imgui.Key.backspace,
  29. pygame.K_RETURN: imgui.Key.enter,
  30. pygame.K_ESCAPE: imgui.Key.escape,
  31. pygame.K_KP_ENTER: imgui.Key.keypad_enter,
  32. pygame.K_TAB: imgui.Key.tab,
  33. pygame.K_LCTRL: imgui.Key.left_ctrl,
  34. pygame.K_RCTRL: imgui.Key.right_ctrl,
  35. pygame.K_LALT: imgui.Key.left_alt,
  36. pygame.K_RALT: imgui.Key.right_alt,
  37. pygame.K_RSHIFT: imgui.Key.right_shift,
  38. pygame.K_LSHIFT: imgui.Key.left_shift,
  39. pygame.K_LSUPER: imgui.Key.left_super,
  40. pygame.K_RSUPER: imgui.Key.right_super,
  41. # pygame.K_a: imgui.Key.a,
  42. # pygame.K_c: imgui.Key.c,
  43. # pygame.K_v: imgui.Key.v,
  44. # pygame.K_x: imgui.Key.x,
  45. # pygame.K_y: imgui.Key.y,
  46. # pygame.K_z: imgui.Key.z,
  47. }
  48. self.modifier_map = {
  49. pygame.K_LCTRL: imgui.Key.mod_ctrl,
  50. pygame.K_RCTRL: imgui.Key.mod_ctrl,
  51. pygame.K_LSHIFT: imgui.Key.mod_shift,
  52. pygame.K_RSHIFT: imgui.Key.mod_shift,
  53. pygame.K_LALT: imgui.Key.mod_alt,
  54. pygame.K_RALT: imgui.Key.mod_alt,
  55. pygame.K_LSUPER: imgui.Key.mod_super,
  56. pygame.K_RSUPER: imgui.Key.mod_super,
  57. }
  58. self.mouse_map = {
  59. 2: imgui.MouseButton_.middle,
  60. 3: imgui.MouseButton_.right
  61. }
  62. def process_event(self, event):
  63. # perf: local for faster access
  64. io = self.io
  65. if event.type == pygame.MOUSEMOTION:
  66. io.add_mouse_pos_event(event.pos[0], event.pos[1])
  67. return True
  68. if event.type == pygame.MOUSEBUTTONDOWN or event.type == pygame.MOUSEBUTTONUP:
  69. down = event.type == pygame.MOUSEBUTTONDOWN
  70. imgui_button = self.mouse_map.get(event.button, event.button - 1)
  71. io.add_mouse_button_event(imgui_button, down)
  72. return True
  73. if event.type == pygame.MOUSEWHEEL:
  74. k = 0.5
  75. io.add_mouse_wheel_event(event.x * k, event.y * k)
  76. return True
  77. processed_special_key = False
  78. if event.type in (pygame.KEYDOWN, pygame.KEYUP):
  79. is_down = event.type == pygame.KEYDOWN
  80. if event.key in self.key_map.keys():
  81. io.add_key_event(self.key_map[event.key], down=is_down)
  82. processed_special_key = True
  83. if event.key in self.modifier_map.keys():
  84. io.add_key_event(self.modifier_map[event.key], down=is_down)
  85. processed_special_key = True
  86. if event.type == pygame.KEYDOWN and not processed_special_key:
  87. for char in event.unicode:
  88. code = ord(char)
  89. if 0 < code < 0x10000:
  90. io.add_input_character(code)
  91. return True
  92. if event.type == pygame.VIDEORESIZE:
  93. surface = pygame.display.get_surface()
  94. # note: pygame does not modify existing surface upon resize,
  95. # we need to do it ourselves.
  96. pygame.display.set_mode(
  97. (event.w, event.h),
  98. flags=surface.get_flags(),
  99. )
  100. # existing font texure is no longer valid, so we need to refresh it
  101. self._update_textures()
  102. # notify imgui about new window size
  103. io.display_size = event.size
  104. # delete old surface, it is no longer needed
  105. del surface
  106. return True
  107. def process_inputs(self):
  108. io = imgui.get_io()
  109. current_time = pygame.time.get_ticks() / 1000.0
  110. if self._gui_time:
  111. io.delta_time = current_time - self._gui_time
  112. else:
  113. io.delta_time = 1.0 / 60.0
  114. if io.delta_time <= 0.0:
  115. io.delta_time = 1.0 / 1000.0
  116. self._gui_time = current_time