|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +import collections |
| 3 | +import itertools |
| 4 | +import os |
| 5 | +import pathlib |
| 6 | +import sys |
| 7 | +import time |
| 8 | + |
| 9 | +import numpy as np |
| 10 | + |
| 11 | +# For Linux/Wayland users. |
| 12 | +if os.getenv("XDG_SESSION_TYPE") == "wayland": |
| 13 | + os.environ["XDG_SESSION_TYPE"] = "x11" |
| 14 | + |
| 15 | +import glfw |
| 16 | +import OpenGL.GL as gl |
| 17 | +import imgui |
| 18 | +from imgui.integrations.glfw import GlfwRenderer |
| 19 | + |
| 20 | +DRIFT_SPEED = 100 |
| 21 | +TAIL_LENGTH = 1000 |
| 22 | + |
| 23 | +frame_time = 0.0 |
| 24 | + |
| 25 | + |
| 26 | +def tick(): |
| 27 | + global frame_time |
| 28 | + frame_time = time.perf_counter() |
| 29 | + |
| 30 | + |
| 31 | +bm = collections.deque([np.array([0., 0.])] * 10, maxlen=TAIL_LENGTH) |
| 32 | + |
| 33 | +IS_DEBUG = (sys.gettrace() is not None) |
| 34 | + |
| 35 | + |
| 36 | +def frame_commands(): |
| 37 | + last_time = frame_time |
| 38 | + tick() |
| 39 | + curr_time = frame_time |
| 40 | + dt = curr_time - last_time |
| 41 | + try: |
| 42 | + fps = int(1 / dt) |
| 43 | + except ZeroDivisionError: |
| 44 | + fps = 0 |
| 45 | + |
| 46 | + io = imgui.get_io() |
| 47 | + |
| 48 | + if io.key_ctrl and io.keys_down[glfw.KEY_Q]: |
| 49 | + sys.exit(0) |
| 50 | + |
| 51 | + with imgui.begin_main_menu_bar() as main_menu_bar: |
| 52 | + if main_menu_bar.opened: |
| 53 | + with imgui.begin_menu("File", True) as file_menu: |
| 54 | + if file_menu.opened: |
| 55 | + clicked_quit, selected_quit = imgui.menu_item("Quit", "Ctrl+Q") |
| 56 | + if clicked_quit: |
| 57 | + sys.exit(0) |
| 58 | + |
| 59 | + with imgui.begin("FPS"): |
| 60 | + imgui.text(f"Debug: ") |
| 61 | + imgui.same_line() |
| 62 | + if IS_DEBUG: |
| 63 | + imgui.text_colored("ON", 0., 1., 0.) |
| 64 | + else: |
| 65 | + imgui.text_colored("OFF", 1., 0., 0.) |
| 66 | + imgui.text(f"FPS: {fps}") |
| 67 | + |
| 68 | + scale = np.sqrt(dt) * 200 |
| 69 | + dbm = np.random.multivariate_normal(mean=(0.0, 0.0), cov=scale * np.eye(2)) |
| 70 | + next_bm = bm[len(bm) - 1] + dbm |
| 71 | + next_bm = np.maximum(next_bm, 0.0) |
| 72 | + next_bm = np.minimum(next_bm, np.array(glfw.get_window_size(glfw.get_current_context()))) |
| 73 | + bm.append(next_bm) |
| 74 | + if tuple(io.mouse_pos) != (-1, -1): |
| 75 | + drift = (np.array(io.mouse_pos) - next_bm) / DRIFT_SPEED |
| 76 | + next_bm += drift |
| 77 | + draw_list = imgui.get_overlay_draw_list() |
| 78 | + for idx, ((x1, y1), (x2, y2)) in enumerate(itertools.pairwise(bm)): |
| 79 | + color = imgui.get_color_u32_rgba(1., 1., 1., idx / (len(bm) - 1)) |
| 80 | + draw_list.add_line(x1, y1, x2, y2, color, thickness=1.0) |
| 81 | + |
| 82 | + |
| 83 | +def render_frame(impl, window, font): |
| 84 | + glfw.poll_events() |
| 85 | + impl.process_inputs() |
| 86 | + imgui.new_frame() |
| 87 | + |
| 88 | + gl.glClearColor(0.1, 0.1, 0.1, 1) |
| 89 | + gl.glClear(gl.GL_COLOR_BUFFER_BIT) |
| 90 | + |
| 91 | + imgui.push_font(font) |
| 92 | + frame_commands() |
| 93 | + imgui.pop_font() |
| 94 | + |
| 95 | + imgui.render() |
| 96 | + impl.render(imgui.get_draw_data()) |
| 97 | + glfw.swap_buffers(window) |
| 98 | + |
| 99 | + |
| 100 | +def impl_glfw_init(): |
| 101 | + width, height = 600, 600 |
| 102 | + window_name = "Brownian motion demo" |
| 103 | + |
| 104 | + if not glfw.init(): |
| 105 | + print("Could not initialize OpenGL context") |
| 106 | + sys.exit(1) |
| 107 | + |
| 108 | + glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4) |
| 109 | + glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) |
| 110 | + glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) |
| 111 | + glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE) |
| 112 | + |
| 113 | + window = glfw.create_window(int(width), int(height), window_name, None, None) |
| 114 | + glfw.make_context_current(window) |
| 115 | + glfw.swap_interval(0) |
| 116 | + |
| 117 | + if not window: |
| 118 | + glfw.terminate() |
| 119 | + print("Could not initialize Window") |
| 120 | + sys.exit(1) |
| 121 | + |
| 122 | + return window |
| 123 | + |
| 124 | + |
| 125 | +def main(): |
| 126 | + imgui.create_context() |
| 127 | + window = impl_glfw_init() |
| 128 | + |
| 129 | + impl = GlfwRenderer(window) |
| 130 | + |
| 131 | + font_path = pathlib.Path(__file__).with_name("Montserrat-ExtraBold.ttf") |
| 132 | + try: |
| 133 | + font = imgui.get_io().fonts.add_font_from_file_ttf(str(font_path), 80) |
| 134 | + except imgui.ImGuiError: |
| 135 | + font = imgui.get_io().fonts.add_font_default() |
| 136 | + impl.refresh_font_texture() |
| 137 | + |
| 138 | + while not glfw.window_should_close(window): |
| 139 | + render_frame(impl, window, font) |
| 140 | + |
| 141 | + impl.shutdown() |
| 142 | + glfw.terminate() |
| 143 | + |
| 144 | + |
| 145 | +if __name__ == "__main__": |
| 146 | + main() |
0 commit comments