| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- # -*- coding: utf-8 -*-
- #type: ignore
- from __future__ import absolute_import
- from imgui_bundle import imgui
- from pyglet.window import key, mouse, Window
- import pyglet
- import pyglet.clock
- from imgui_bundle.python_backends import compute_fb_scale
- from imgui_bundle.python_backends.opengl_backend_programmable import ProgrammablePipelineRenderer
- class PygletMixin(object):
- _gui_time = None
- MOUSE_CURSORS = {
- imgui.MouseCursor_.arrow.value: Window.CURSOR_DEFAULT,
- imgui.MouseCursor_.text_input.value: Window.CURSOR_TEXT,
- imgui.MouseCursor_.resize_all.value: Window.CURSOR_SIZE,
- imgui.MouseCursor_.resize_ns.value: Window.CURSOR_SIZE_UP_DOWN,
- imgui.MouseCursor_.resize_ew.value: Window.CURSOR_SIZE_LEFT_RIGHT,
- imgui.MouseCursor_.resize_nesw.value: Window.CURSOR_SIZE_DOWN_LEFT,
- imgui.MouseCursor_.resize_nwse.value: Window.CURSOR_SIZE_DOWN_RIGHT,
- imgui.MouseCursor_.hand.value: Window.CURSOR_HAND,
- }
- def __init__(self):
- super(PygletMixin, self).__init__()
- self._cursor = -2
- self._window = None
- # Let Dear imgui know we have mouse cursor support
- self.io = imgui.get_io()
- self.io.backend_flags |= imgui.BackendFlags_.has_mouse_cursors
- self._map_keys()
- def _map_keys(self):
- self.key_map = {}
- key_map = self.key_map
- # Control Keys
- key_map[key.TAB] = imgui.Key.tab
- key_map[key.BACKSPACE] = imgui.Key.backspace
- key_map[key.RETURN] = imgui.Key.enter
- key_map[key.ESCAPE] = imgui.Key.escape
- key_map[key.INSERT] = imgui.Key.insert
- key_map[key.DELETE] = imgui.Key.delete
- key_map[key.SPACE] = imgui.Key.space
- # Function Keys
- key_map[key.F1] = imgui.Key.f1
- key_map[key.F2] = imgui.Key.f2
- key_map[key.F3] = imgui.Key.f3
- key_map[key.F4] = imgui.Key.f4
- key_map[key.F5] = imgui.Key.f5
- key_map[key.F6] = imgui.Key.f6
- key_map[key.F7] = imgui.Key.f7
- key_map[key.F8] = imgui.Key.f8
- key_map[key.F9] = imgui.Key.f9
- key_map[key.F10] = imgui.Key.f10
- key_map[key.F11] = imgui.Key.f11
- key_map[key.F12] = imgui.Key.f12
- # Navigation Keys
- key_map[key.LEFT] = imgui.Key.left_arrow
- key_map[key.RIGHT] = imgui.Key.right_arrow
- key_map[key.UP] = imgui.Key.up_arrow
- key_map[key.DOWN] = imgui.Key.down_arrow
- key_map[key.PAGEUP] = imgui.Key.page_up
- key_map[key.PAGEDOWN] = imgui.Key.page_down
- key_map[key.HOME] = imgui.Key.home
- key_map[key.END] = imgui.Key.end
- # Numeric Keys
- key_map[key._0] = imgui.Key._0
- key_map[key._1] = imgui.Key._1
- key_map[key._2] = imgui.Key._2
- key_map[key._3] = imgui.Key._3
- key_map[key._4] = imgui.Key._4
- key_map[key._5] = imgui.Key._5
- key_map[key._6] = imgui.Key._6
- key_map[key._7] = imgui.Key._7
- key_map[key._8] = imgui.Key._8
- key_map[key._9] = imgui.Key._9
- # Keypad Keys
- key_map[key.NUM_ENTER] = imgui.Key.keypad_enter
- key_map[key.NUM_0] = imgui.Key.keypad0
- key_map[key.NUM_1] = imgui.Key.keypad1
- key_map[key.NUM_2] = imgui.Key.keypad2
- key_map[key.NUM_3] = imgui.Key.keypad3
- key_map[key.NUM_4] = imgui.Key.keypad4
- key_map[key.NUM_5] = imgui.Key.keypad5
- key_map[key.NUM_6] = imgui.Key.keypad6
- key_map[key.NUM_7] = imgui.Key.keypad7
- key_map[key.NUM_8] = imgui.Key.keypad8
- key_map[key.NUM_9] = imgui.Key.keypad9
- key_map[key.NUM_DECIMAL] = imgui.Key.keypad_decimal
- key_map[key.NUM_DIVIDE] = imgui.Key.keypad_divide
- key_map[key.NUM_MULTIPLY] = imgui.Key.keypad_multiply
- key_map[key.NUM_SUBTRACT] = imgui.Key.keypad_subtract
- key_map[key.NUM_ADD] = imgui.Key.keypad_add
- # Alphabetic Keys
- key_map[key.A] = imgui.Key.a
- key_map[key.B] = imgui.Key.b
- key_map[key.C] = imgui.Key.c
- key_map[key.D] = imgui.Key.d
- key_map[key.E] = imgui.Key.e
- key_map[key.F] = imgui.Key.f
- key_map[key.G] = imgui.Key.g
- key_map[key.H] = imgui.Key.h
- key_map[key.I] = imgui.Key.i
- key_map[key.J] = imgui.Key.j
- key_map[key.K] = imgui.Key.k
- key_map[key.L] = imgui.Key.l
- key_map[key.M] = imgui.Key.m
- key_map[key.N] = imgui.Key.n
- key_map[key.O] = imgui.Key.o
- key_map[key.P] = imgui.Key.p
- key_map[key.Q] = imgui.Key.q
- key_map[key.R] = imgui.Key.r
- key_map[key.S] = imgui.Key.s
- key_map[key.T] = imgui.Key.t
- key_map[key.U] = imgui.Key.u
- key_map[key.V] = imgui.Key.v
- key_map[key.W] = imgui.Key.w
- key_map[key.X] = imgui.Key.x
- key_map[key.Y] = imgui.Key.y
- key_map[key.Z] = imgui.Key.z
- # Modifier Keys
- key_map[key.LCTRL] = imgui.Key.left_ctrl
- key_map[key.RCTRL] = imgui.Key.right_ctrl
- key_map[key.LSHIFT] = imgui.Key.left_shift
- key_map[key.RSHIFT] = imgui.Key.right_shift
- key_map[key.LALT] = imgui.Key.left_alt
- key_map[key.RALT] = imgui.Key.right_alt
- key_map[key.LCOMMAND] = imgui.Key.left_super
- key_map[key.RCOMMAND] = imgui.Key.right_super
- # Symbol Keys
- key_map[key.GRAVE] = imgui.Key.grave_accent # `
- key_map[key.MINUS] = imgui.Key.minus # -
- key_map[key.EQUAL] = imgui.Key.equal # =
- key_map[key.BRACKETLEFT] = imgui.Key.left_bracket # [
- key_map[key.BRACKETRIGHT] = imgui.Key.right_bracket # ]
- key_map[key.BACKSLASH] = imgui.Key.backslash # \
- key_map[key.SEMICOLON] = imgui.Key.semicolon # ;
- key_map[key.APOSTROPHE] = imgui.Key.apostrophe # '
- key_map[key.COMMA] = imgui.Key.comma # ,
- key_map[key.PERIOD] = imgui.Key.period # .
- key_map[key.SLASH] = imgui.Key.slash # /
- # Miscellaneous Keys
- key_map[key.PRINT] = imgui.Key.print_screen
- key_map[key.PAUSE] = imgui.Key.pause
- # Lock Keys
- key_map[key.CAPSLOCK] = imgui.Key.caps_lock
- key_map[key.NUMLOCK] = imgui.Key.num_lock
- key_map[key.SCROLLLOCK] = imgui.Key.scroll_lock
- def _set_pixel_ratio(self, window):
- window_size = window.get_size()
- self.io.display_size = window_size
- # It is conceivable that the pyglet version will not be solely
- # determinant of whether we use the fixed or programmable, so do some
- # minor introspection here to check.
- if hasattr(window, "get_viewport_size"):
- viewport_size = window.get_viewport_size()
- self.io.display_framebuffer_scale = compute_fb_scale(
- window_size, viewport_size
- )
- elif hasattr(window, "get_pixel_ratio"):
- self.io.display_framebuffer_scale = (
- window.get_pixel_ratio(),
- window.get_pixel_ratio(),
- )
- else:
- # Default to 1.0 in this unlikely circumstance
- self.io.display_fb_scale = (1.0, 1.0)
- def _attach_callbacks(self, window):
- self._window = window
- window.push_handlers(
- self.on_mouse_motion,
- self.on_key_press,
- self.on_key_release,
- self.on_text,
- self.on_mouse_drag,
- self.on_mouse_press,
- self.on_mouse_release,
- self.on_mouse_scroll,
- self.on_resize,
- )
- def _handle_mouse_cursor(self):
- if self.io.config_flags & imgui.ConfigFlags_.no_mouse_cursor_change.value:
- return
- mouse_cursor = imgui.get_mouse_cursor()
- window = self._window
- if self._cursor != mouse_cursor:
- self._cursor = mouse_cursor
- if mouse_cursor == imgui.MouseCursor_.none:
- window.set_mouse_visible(False)
- else:
- cursor = self.MOUSE_CURSORS.get(mouse_cursor)
- window.set_mouse_cursor(window.get_system_mouse_cursor(cursor))
- def _on_key(self, key_pressed, down):
- if key_pressed in self.key_map:
- imgui_key = self.key_map[key_pressed]
- self.io.add_key_event(imgui_key, down=down)
- # Handle modifiers, since ImGui has an additional mod_ctrl / shift / etc
- if imgui_key == imgui.Key.left_ctrl or imgui_key == imgui.Key.right_ctrl:
- self.io.add_key_event(imgui.Key.mod_ctrl, down)
- if imgui_key == imgui.Key.left_shift or imgui_key == imgui.Key.right_shift:
- self.io.add_key_event(imgui.Key.mod_shift, down)
- if imgui_key == imgui.Key.left_alt or imgui_key == imgui.Key.right_alt:
- self.io.add_key_event(imgui.Key.mod_alt, down)
- if imgui_key == imgui.Key.left_super or imgui_key == imgui.Key.right_super:
- self.io.add_key_event(imgui.Key.mod_super, down)
- def on_key_press(self, key_pressed, mods):
- self._on_key(key_pressed, True)
- def on_key_release(self, key_released, mods):
- self._on_key(key_released, False)
- def on_text(self, text):
- io = imgui.get_io()
- for char in text:
- io.add_input_character(ord(char))
- def on_mouse_motion(self, x, y, dx, dy):
- self.io.add_mouse_pos_event(x, self.io.display_size.y - y)
- def _on_mouse_button(self, pyglet_button, down):
- imgui_button = 0
- if pyglet_button == mouse.LEFT:
- imgui_button = 0
- elif pyglet_button == mouse.RIGHT:
- imgui_button = 1
- elif pyglet_button == mouse.MIDDLE:
- imgui_button = 2
- self.io.add_mouse_button_event(imgui_button, down)
- def on_mouse_press(self, x, y, button, modifiers):
- self._on_mouse_button(button, True)
- def on_mouse_release(self, x, y, button, modifiers):
- self._on_mouse_button(button, False)
- def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
- self._on_mouse_button(button, True)
- self.on_mouse_motion(x, y, dx, dy)
- def on_mouse_scroll(self, x, y, mods, scroll):
- self.io.add_mouse_wheel_event(0, -scroll)
- def on_resize(self, width, height):
- self.io.display_size = width, height
- def process_inputs(self):
- io = imgui.get_io()
- current_time = pyglet.clock.tick()
- if self._gui_time:
- io.delta_time = current_time - self._gui_time
- else:
- io.delta_time = 1.0 / 60.0
- if io.delta_time <= 0.0:
- io.delta_time = 1.0 / 1000.0
- self._gui_time = current_time
- class PygletProgrammablePipelineRenderer(PygletMixin, ProgrammablePipelineRenderer):
- def __init__(self, window, attach_callbacks=True):
- super(PygletProgrammablePipelineRenderer, self).__init__()
- self._set_pixel_ratio(window)
- if attach_callbacks:
- self._attach_callbacks(window)
- def render(self, draw_data):
- super(PygletProgrammablePipelineRenderer, self).render(draw_data)
- self._handle_mouse_cursor()
- def create_renderer(window, attach_callbacks=True):
- """
- This is a helper function that wraps the appropriate version of the Pyglet
- renderer class, based on the version of pyglet being used.
- """
- # Determine the context version
- # Pyglet < 2.0 has issues with ProgrammablePipeline even when the context
- # is OpenGL 3, so we need to check the pyglet version rather than looking
- # at window.config.major_version to see if we want to use programmable.
- assert int(pyglet.version.split('.')[0]) >= 2
- return PygletProgrammablePipelineRenderer(window, attach_callbacks)
|