-
-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathimgui_cmap_picker.py
131 lines (90 loc) · 3.48 KB
/
imgui_cmap_picker.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
Imgui example that shows how to create a colormap picker menu
Uses the cmap library: https://github.com/tlambert03/cmap
pip install cmap
Instead of using the cmap library you can create 2D arrays in
the shape [2, 255, 3] that represent the LUT for the colormap
"""
# run_example = false
import ctypes
import numpy as np
import wgpu
from imgui_bundle import imgui
from wgpu.gui.auto import WgpuCanvas, run
from wgpu.utils.imgui import ImguiRenderer
from cmap import Colormap
# Create a canvas to render to
canvas = WgpuCanvas(title="imgui", size=(512, 256))
# Create a wgpu device
adapter = wgpu.gpu.request_adapter_sync(power_preference="high-performance")
device = adapter.request_device_sync()
imgui_renderer = ImguiRenderer(device, canvas)
def create_texture_and_upload(data: np.ndarray) -> int:
# crates a GPUTexture and uploads it
# create a GPUTexture
texture = device.create_texture(
size=(data.shape[1], data.shape[0], 4),
usage=wgpu.TextureUsage.COPY_DST | wgpu.TextureUsage.TEXTURE_BINDING,
dimension=wgpu.TextureDimension.d2,
format=wgpu.TextureFormat.rgba8unorm,
mip_level_count=1,
sample_count=1,
)
# upload to the GPU
device.queue.write_texture(
{"texture": texture, "mip_level": 0, "origin": (0, 0, 0)},
data,
{"offset": 0, "bytes_per_row": data.shape[1] * 4},
(data.shape[1], data.shape[0], 1),
)
# get a view
texture_view = texture.create_view()
# get the id so that imgui can display it
id_texture = ctypes.c_int32(id(texture_view)).value
# add texture view to the backend so that it can be retrieved for rendering
imgui_renderer.backend._texture_views[id_texture] = texture_view
return id_texture
# list of colormaps that we will display in the picker
cmaps = ["viridis", "plasma", "turbo", "spring", "winter", "bwr", "gnuplot2"]
cmap_data = dict()
# creates texture for each colormap, uploads to the GPU, stores ids so we can display them in imgui
for name in cmaps:
# creates LUT
data = Colormap(name)(np.linspace(0, 1)) * 255
# vstack it so we have 2 rows to make a Texture, an array of shape [2, 255, 3], [rows, cols, RGB]
tex_id = create_texture_and_upload(np.vstack([[data]] * 2).astype(np.uint8))
# store the texture id
cmap_data[name] = tex_id
current_cmap = cmaps[0]
def update_gui():
imgui.new_frame()
global current_cmap
imgui.set_next_window_size((175, 0), imgui.Cond_.appearing)
imgui.set_next_window_pos((0, 20), imgui.Cond_.appearing)
imgui.begin("window", None)
# make the cmap images display height similar to the text height so that it looks nice
texture_height = (
imgui_renderer.backend.io.font_global_scale * imgui.get_font().font_size
) - 2
# add the items for the picker
for cmap_name, tex_id in cmap_data.items():
# text part of each item
clicked, enabled = imgui.menu_item(
cmap_name, "", p_selected=current_cmap == cmap_name
)
imgui.same_line()
# the image part of each item, give it the texture id
imgui.image(tex_id, image_size=(50, texture_height), border_col=(1, 1, 1, 1))
if enabled:
current_cmap = cmap_name
imgui.end()
imgui.end_frame()
imgui.render()
return imgui.get_draw_data()
imgui_renderer.set_gui(update_gui)
def draw_frame():
imgui_renderer.render()
canvas.request_draw()
if __name__ == "__main__":
canvas.request_draw(draw_frame)
run()