From 8dc57ce4445eb77ddac1843aa389dbce66f87fce Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Thu, 16 Apr 2020 22:33:03 +0800 Subject: [PATCH 01/21] [GUI] better GUI filter system (gui.get_event) --- examples/keyboard.py | 14 ++++----- examples/mpm99.py | 2 +- examples/nbody_oscillator.py | 2 +- python/taichi/misc/gui.py | 58 ++++++++++++++++++++++++++++-------- python/taichi/misc/image.py | 2 +- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/examples/keyboard.py b/examples/keyboard.py index 21533bfce4bff..194d18b193cbf 100644 --- a/examples/keyboard.py +++ b/examples/keyboard.py @@ -6,14 +6,11 @@ gui = ti.GUI("Keyboard", res=(400, 400)) while True: - while gui.has_key_event(): - e = gui.get_key_event() - if e.type == ti.GUI.RELEASE: - continue - if e.key == ti.GUI.ESCAPE: + while gui.get_event(ti.GUI.PRESS): + if gui.event.key == ti.GUI.ESCAPE: exit() - elif e.key == ti.GUI.RMB: - x, y = e.pos[0], e.pos[1] + elif gui.event.key == ti.GUI.RMB: + x, y = gui.event.pos if gui.is_pressed(ti.GUI.LEFT, 'a'): x -= delta @@ -24,8 +21,7 @@ if gui.is_pressed(ti.GUI.DOWN, 's'): y -= delta if gui.is_pressed(ti.GUI.LMB): - pos = gui.get_cursor_pos() - x, y = pos[0], pos[1] + x, y = gui.get_cursor_pos() gui.circle((x, y), 0xffffff, 8) gui.show() diff --git a/examples/mpm99.py b/examples/mpm99.py index f24c90b5d144c..ffec4860c59ca 100644 --- a/examples/mpm99.py +++ b/examples/mpm99.py @@ -91,7 +91,7 @@ def initialize(): Jp[i] = 1 initialize() gui = ti.GUI("Taichi MLS-MPM-99", res=512, background_color=0x112F41) -for frame in range(20000): +while not gui.get_event(ti.GUI.ESCAPE): for s in range(int(2e-3 // dt)): substep() colors = np.array([0x068587, 0xED553B, 0xEEEEF0], dtype=np.uint32) diff --git a/examples/nbody_oscillator.py b/examples/nbody_oscillator.py index 24ba33310ae10..90673fbb0f3c6 100644 --- a/examples/nbody_oscillator.py +++ b/examples/nbody_oscillator.py @@ -43,7 +43,7 @@ def advance(dt: ti.f32): gui = ti.GUI("n-body", res=(400, 400)) initialize() -while not gui.has_key_event() or gui.get_key_event().key == ti.GUI.MOTION: +while not gui.get_event(ti.GUI.ESCAPE): _pos = pos.to_numpy() gui.circles(_pos, radius=1, color=0x66ccff) gui.show() diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index ee2d17895b824..10fcf53acdb5b 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -123,30 +123,53 @@ def line(self, begin, end, radius, color): self.canvas.path_single(begin[0], begin[1], end[0], end[1], color, radius) - def show(self, file=None): + def show(self, file_or_image=None): self.core.update() - if file: - self.core.screenshot(file) + if isinstance(file_or_image, str): + self.core.screenshot(file_or_image) + elif file_or_image is not None: + self.set_image(file_or_image) self.clear(self.background_color) - def has_key_event(self): - return self.core.has_key_event() def get_event(self, *filter): + types = [] + keys = [] + combs = [] + for ent in filter: + if ent in [GUI.PRESS, GUI.RELEASE]: + types.append(ent) + elif isinstance(ent, tuple) or isinstance(ent, list): + type, key = ent + combs.append((type, key)) + else: + keys.append(ent) while True: if not self.has_key_event(): return False self.event = self.get_key_event() - if not len(filter) or self.event.type in filter: + if not len(combs): + if not len(types) or self.event.type in types: + if not len(keys) or self.event.key in keys: + break + elif (self.event.type, self.event.key) in combs: break return True - def get_key_event(self): + def get_cursor_pos(self): # ABi + pos = self.core.get_cursor_pos() + return pos[0], pos[1] + + def has_key_event(self): # ABi + return self.core.has_key_event() + + def get_key_event(self): # ABi self.core.wait_key_event() e = GUI.Event() e.key = self.core.get_key_event_head_key() e.type = self.core.get_key_event_head_type() e.pos = self.core.get_key_event_head_pos() + e.pos = (e.pos[0], e.pos[1]) e.modifier = [] for mod in ['Shift', 'Alt', 'Control']: if self.is_pressed(mod): @@ -158,6 +181,12 @@ def get_key_event(self): self.core.pop_key_event_head() return e + def peek_key_event(self): + e = None + if self.has_key_event(): + e = self.get_key_event() + return e + def is_pressed(self, *keys): for key in keys: if key in ['Shift', 'Alt', 'Control']: @@ -168,13 +197,16 @@ def is_pressed(self, *keys): else: return False - def get_cursor_pos(self): - return self.core.get_cursor_pos() + def peek_is_pressed(self, *keys): + self.peek_key_event() + return self.is_pressed(*keys) - def has_key_pressed(self): - if self.has_key_event(): - self.get_key_event() # pop to update self.key_pressed - return len(self.key_pressed) != 0 + def peek_key_pressed(self): + self.peek_key_event() + return self.key_pressed + + def has_key_pressed(self): # Deprecated + return len(self.peek_key_pressed()) def rgb_to_hex(c): diff --git a/python/taichi/misc/image.py b/python/taichi/misc/image.py index 704146b995d33..5c837390bd2a7 100644 --- a/python/taichi/misc/image.py +++ b/python/taichi/misc/image.py @@ -35,6 +35,6 @@ def imread(filename, channels=0): def imshow(img, winname='Taichi'): img = cook_image(img) gui = ti.GUI(winname, res=img.shape[:2]) - while not gui.is_pressed(ti.GUI.ESCAPE): + while not gui.get_event(ti.GUI.ESCAPE): gui.set_image(img) gui.show() From 22f05d7361acaf9b81532a44cc23a317c9a3bfc6 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sat, 18 Apr 2020 16:48:32 +0800 Subject: [PATCH 02/21] [skip ci] GUI.EventFilter --- python/taichi/misc/gui.py | 43 ++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index 10fcf53acdb5b..e47e0aea7984a 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -131,28 +131,39 @@ def show(self, file_or_image=None): self.set_image(file_or_image) self.clear(self.background_color) + class EventFilter: + + def __init__(self, *filter): + self.types = [] + self.keys = [] + self.combs = [] + for ent in filter: + if isinstance(ent, (tuple, list)): + self.combs.append(tuple(ent)) + elif ent in [GUI.PRESS, GUI.RELEASE]: + self.types.append(ent) + else: + self.keys.append(ent) + + def match(self, e): + if (e.type, e.key) in self.combs: + return True + if e.key in self.keys and e.key in self.combs: + return True + return False + def get_event(self, *filter): - types = [] - keys = [] - combs = [] - for ent in filter: - if ent in [GUI.PRESS, GUI.RELEASE]: - types.append(ent) - elif isinstance(ent, tuple) or isinstance(ent, list): - type, key = ent - combs.append((type, key)) - else: - keys.append(ent) + if not len(filter): + filter = None + elif not isinstance(filter[0], GUI.EventFilter): + filter = GUI.EventFilter(*filter) + while True: if not self.has_key_event(): return False self.event = self.get_key_event() - if not len(combs): - if not len(types) or self.event.type in types: - if not len(keys) or self.event.key in keys: - break - elif (self.event.type, self.event.key) in combs: + if filter is None or filter.match(self.event): break return True From b577d22ee98ebb2378b46628c35955e40266a0da Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sat, 18 Apr 2020 16:52:56 +0800 Subject: [PATCH 03/21] [skip ci] set() --- python/taichi/misc/gui.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index e47e0aea7984a..cfdb4f691af1e 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -134,16 +134,16 @@ def show(self, file_or_image=None): class EventFilter: def __init__(self, *filter): - self.types = [] - self.keys = [] - self.combs = [] + self.types = set() + self.keys = set() + self.combs = set() for ent in filter: if isinstance(ent, (tuple, list)): - self.combs.append(tuple(ent)) + self.combs.add(tuple(ent)) elif ent in [GUI.PRESS, GUI.RELEASE]: - self.types.append(ent) + self.types.add(ent) else: - self.keys.append(ent) + self.keys.add(ent) def match(self, e): if (e.type, e.key) in self.combs: From 4d648e54b806f8374ac5f5c89f297214872393cf Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sat, 18 Apr 2020 17:03:05 +0800 Subject: [PATCH 04/21] [skip ci] rename --- python/taichi/misc/gui.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index cfdb4f691af1e..dae4c8e83d31d 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -162,7 +162,7 @@ def get_event(self, *filter): while True: if not self.has_key_event(): return False - self.event = self.get_key_event() + self.event = self.pop_key_event() if filter is None or filter.match(self.event): break return True @@ -174,7 +174,7 @@ def get_cursor_pos(self): # ABi def has_key_event(self): # ABi return self.core.has_key_event() - def get_key_event(self): # ABi + def pop_key_event(self): # ABi self.core.wait_key_event() e = GUI.Event() e.key = self.core.get_key_event_head_key() @@ -192,10 +192,10 @@ def get_key_event(self): # ABi self.core.pop_key_event_head() return e - def peek_key_event(self): + def get_key_event(self): e = None if self.has_key_event(): - e = self.get_key_event() + e = self.pop_key_event() return e def is_pressed(self, *keys): @@ -208,16 +208,16 @@ def is_pressed(self, *keys): else: return False - def peek_is_pressed(self, *keys): - self.peek_key_event() + def get_is_pressed(self, *keys): + self.get_key_event() return self.is_pressed(*keys) - def peek_key_pressed(self): - self.peek_key_event() + def get_key_pressed(self): + self.get_key_event() return self.key_pressed def has_key_pressed(self): # Deprecated - return len(self.peek_key_pressed()) + return len(self.get_key_pressed()) def rgb_to_hex(c): From ec53b5105e1df13c71a684ba7d7949ddbb15424c Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sat, 18 Apr 2020 17:03:53 +0800 Subject: [PATCH 05/21] [skip ci] revert --- python/taichi/misc/gui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index dae4c8e83d31d..8940bccf3c4e1 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -139,7 +139,8 @@ def __init__(self, *filter): self.combs = set() for ent in filter: if isinstance(ent, (tuple, list)): - self.combs.add(tuple(ent)) + type, key = ent + self.combs.add((type, key)) elif ent in [GUI.PRESS, GUI.RELEASE]: self.types.add(ent) else: From 0ee5fdefd1350a715f6a8ffc93be022b1ea3c119 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sat, 18 Apr 2020 17:31:39 +0800 Subject: [PATCH 06/21] fix usage & add yield --- python/taichi/misc/gui.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index 8940bccf3c4e1..be4b7e5326e9c 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -149,24 +149,31 @@ def __init__(self, *filter): def match(self, e): if (e.type, e.key) in self.combs: return True - if e.key in self.keys and e.key in self.combs: - return True + if not self.keys or e.key in self.keys: + if not self.combs or e.key in self.combs: + return True return False - def get_event(self, *filter): - if not len(filter): + def get_events(self, *filter): + if not filter: filter = None elif not isinstance(filter[0], GUI.EventFilter): filter = GUI.EventFilter(*filter) while True: if not self.has_key_event(): - return False - self.event = self.pop_key_event() - if filter is None or filter.match(self.event): break - return True + e = self.pop_key_event() + print(e.key) + if filter is None or filter.match(e): + yield e + + def get_event(self, *filter): + for e in self.get_events(*filter): + self.event = e + return True + return False def get_cursor_pos(self): # ABi pos = self.core.get_cursor_pos() From f70050a0360965cb7f998a067bedfd10220b7b13 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sat, 18 Apr 2020 17:31:49 +0800 Subject: [PATCH 07/21] [skip ci] bette example --- examples/image_io.py | 2 +- examples/nbody_oscillator.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/image_io.py b/examples/image_io.py index 11b8aa440f01d..bcf7d18e6d0cd 100644 --- a/examples/image_io.py +++ b/examples/image_io.py @@ -14,7 +14,7 @@ def paint(): pixel = pixel.to_numpy() ti.imshow(pixel, 'Random Generated') for ext in ['bmp', 'png', 'jpg']: - fn = 'taichi-example-random-img.' + ext + fn = '/tmp/taichi-example-random-img.' + ext ti.imwrite(pixel, fn) pixel_r = ti.imread(fn) if ext != 'jpg': diff --git a/examples/nbody_oscillator.py b/examples/nbody_oscillator.py index 90673fbb0f3c6..123a751ee4ac2 100644 --- a/examples/nbody_oscillator.py +++ b/examples/nbody_oscillator.py @@ -1,7 +1,6 @@ import taichi as ti -ti.init( - arch=ti.opengl) # Try to run on GPU, use ti.opengl if you don't have CUDA +ti.init(arch=ti.opengl) N = 8000 pos = ti.Vector(2, dt=ti.f32, shape=N) From 164b424235459e5560b42e5f640cd357493a1567 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sun, 19 Apr 2020 21:00:58 +0800 Subject: [PATCH 08/21] [skip ci] refactor --- python/taichi/misc/gui.py | 47 ++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index be4b7e5326e9c..7906fba7dc757 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -155,7 +155,7 @@ def match(self, e): return False - def get_events(self, *filter): + def get_events(self, *filter): # APi if not filter: filter = None elif not isinstance(filter[0], GUI.EventFilter): @@ -164,12 +164,11 @@ def get_events(self, *filter): while True: if not self.has_key_event(): break - e = self.pop_key_event() - print(e.key) + e = self.get_key_event() if filter is None or filter.match(e): yield e - def get_event(self, *filter): + def get_event(self, *filter): # Deprecated APi for e in self.get_events(*filter): self.event = e return True @@ -182,8 +181,7 @@ def get_cursor_pos(self): # ABi def has_key_event(self): # ABi return self.core.has_key_event() - def pop_key_event(self): # ABi - self.core.wait_key_event() + def _peek_key_event(self): # ABi (assume has_key_event) e = GUI.Event() e.key = self.core.get_key_event_head_key() e.type = self.core.get_key_event_head_type() @@ -197,16 +195,33 @@ def pop_key_event(self): # ABi self.key_pressed.add(e.key) else: self.key_pressed.discard(e.key) + return e + + def _get_key_event(self): # ABi (assume has_key_event) + e = self._peek_key_event() self.core.pop_key_event_head() return e - def get_key_event(self): + def wait_key_event(self): # ABi + self.core.wait_key_event() + + def peek_key_event(self): # Unique APi + e = None + if self.has_key_event(): + e = self._peek_key_event() + return e + + def get_key_event(self): # Unique APi e = None if self.has_key_event(): - e = self.pop_key_event() + e = self._get_key_event() return e - def is_pressed(self, *keys): + def wait_get_key_event(self): # Shortcut APi = wait + get + self.wait_key_event() + return self._get_key_event() + + def is_pressed(self, *keys): # Shortcut APi = in key_pressed for key in keys: if key in ['Shift', 'Alt', 'Control']: if key + '_L' in self.key_pressed or key + '_R' in self.key_pressed: @@ -216,16 +231,18 @@ def is_pressed(self, *keys): else: return False - def get_is_pressed(self, *keys): - self.get_key_event() + def get_is_pressed(self, *keys): # Shortcut APi = pop all + is_pressed + while self.get_key_event() is not None: + pass return self.is_pressed(*keys) - def get_key_pressed(self): - self.get_key_event() + def get_key_pressed(self): # Shortcut APi = pop all + key_pressed + while self.get_key_event() is not None: + pass return self.key_pressed - def has_key_pressed(self): # Deprecated - return len(self.get_key_pressed()) + def has_key_pressed(self): # Deprecated APi, use get_key_pressed instead + return len(self.get_key_pressed()) != 0 def rgb_to_hex(c): From 63a74ee6265d46d31864653b01b2102dc25693c2 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sun, 19 Apr 2020 21:09:01 +0800 Subject: [PATCH 09/21] [skip ci] better rgb_to_hex --- python/taichi/misc/gui.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index 7906fba7dc757..d8f9161d0c6c7 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -245,6 +245,11 @@ def has_key_pressed(self): # Deprecated APi, use get_key_pressed instead return len(self.get_key_pressed()) != 0 -def rgb_to_hex(c): - to255 = lambda x: min(255, max(0, int(x * 255))) +def rgb_to_hex(c, g=None, b=None): + if g is not None: + c = (c, g, b) + if isinstance(x, int): + to255 = lambda x: min(255, max(0, x)) + else: + to255 = lambda x: min(255, max(0, int(x * 255))) return 65536 * to255(c[0]) + 256 * to255(c[1]) + to255(c[2]) From 33984853b8d31431198f19886673a3c77df362f7 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Tue, 21 Apr 2020 10:20:58 +0800 Subject: [PATCH 10/21] [skip ci] revert --- examples/image_io.py | 2 +- python/taichi/misc/gui.py | 16 ++++------------ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/examples/image_io.py b/examples/image_io.py index bcf7d18e6d0cd..11b8aa440f01d 100644 --- a/examples/image_io.py +++ b/examples/image_io.py @@ -14,7 +14,7 @@ def paint(): pixel = pixel.to_numpy() ti.imshow(pixel, 'Random Generated') for ext in ['bmp', 'png', 'jpg']: - fn = '/tmp/taichi-example-random-img.' + ext + fn = 'taichi-example-random-img.' + ext ti.imwrite(pixel, fn) pixel_r = ti.imread(fn) if ext != 'jpg': diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index d8f9161d0c6c7..a9435e11b1ed7 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -123,12 +123,9 @@ def line(self, begin, end, radius, color): self.canvas.path_single(begin[0], begin[1], end[0], end[1], color, radius) - def show(self, file_or_image=None): + def show(self, file=None): self.core.update() - if isinstance(file_or_image, str): - self.core.screenshot(file_or_image) - elif file_or_image is not None: - self.set_image(file_or_image) + self.core.screenshot(file_or_image) self.clear(self.background_color) class EventFilter: @@ -245,11 +242,6 @@ def has_key_pressed(self): # Deprecated APi, use get_key_pressed instead return len(self.get_key_pressed()) != 0 -def rgb_to_hex(c, g=None, b=None): - if g is not None: - c = (c, g, b) - if isinstance(x, int): - to255 = lambda x: min(255, max(0, x)) - else: - to255 = lambda x: min(255, max(0, int(x * 255))) +def rgb_to_hex(c): + to255 = lambda x: min(255, max(0, int(x * 255))) return 65536 * to255(c[0]) + 256 * to255(c[1]) + to255(c[2]) From 07ae7a8c39d77c9df21f878264511b7ec678547e Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Tue, 21 Apr 2020 10:25:41 +0800 Subject: [PATCH 11/21] [skip ci] fix revert typo --- python/taichi/misc/gui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index a9435e11b1ed7..014a24e9a4a68 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -125,7 +125,8 @@ def line(self, begin, end, radius, color): def show(self, file=None): self.core.update() - self.core.screenshot(file_or_image) + if file is not None: + self.core.screenshot(file) self.clear(self.background_color) class EventFilter: From c35841b152e48ec60f1f6da75aee06bb40b906f3 Mon Sep 17 00:00:00 2001 From: Taichi Gardener Date: Thu, 23 Apr 2020 01:10:26 -0400 Subject: [PATCH 12/21] [skip ci] enforce code format --- python/taichi/misc/gui.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index 014a24e9a4a68..d8ab879d99f4b 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -130,7 +130,6 @@ def show(self, file=None): self.clear(self.background_color) class EventFilter: - def __init__(self, *filter): self.types = set() self.keys = set() @@ -152,7 +151,6 @@ def match(self, e): return True return False - def get_events(self, *filter): # APi if not filter: filter = None From 47d361464d8edf97d83f0ac3d6e16cabc1adf3f8 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Thu, 23 Apr 2020 16:26:22 +0800 Subject: [PATCH 13/21] [skip ci] revert comp --- python/taichi/misc/gui.py | 48 ++++++++------------------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index d78f2366ce147..f3e2f9eecd62e 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -161,7 +161,7 @@ def match(self, e): return True return False - def get_events(self, *filter): # APi + def get_events(self, *filter): if not filter: filter = None elif not isinstance(filter[0], GUI.EventFilter): @@ -174,20 +174,21 @@ def get_events(self, *filter): # APi if filter is None or filter.match(e): yield e - def get_event(self, *filter): # Deprecated APi + def get_event(self, *filter): for e in self.get_events(*filter): self.event = e return True return False - def get_cursor_pos(self): # ABi + def get_cursor_pos(self): pos = self.core.get_cursor_pos() return pos[0], pos[1] - def has_key_event(self): # ABi + def has_key_event(self): return self.core.has_key_event() - def _peek_key_event(self): # ABi (assume has_key_event) + def get_key_event(self): + self.core.wait_key_event() e = GUI.Event() e.key = self.core.get_key_event_head_key() e.type = self.core.get_key_event_head_type() @@ -201,33 +202,10 @@ def _peek_key_event(self): # ABi (assume has_key_event) self.key_pressed.add(e.key) else: self.key_pressed.discard(e.key) - return e - - def _get_key_event(self): # ABi (assume has_key_event) - e = self._peek_key_event() self.core.pop_key_event_head() return e - def wait_key_event(self): # ABi - self.core.wait_key_event() - - def peek_key_event(self): # Unique APi - e = None - if self.has_key_event(): - e = self._peek_key_event() - return e - - def get_key_event(self): # Unique APi - e = None - if self.has_key_event(): - e = self._get_key_event() - return e - - def wait_get_key_event(self): # Shortcut APi = wait + get - self.wait_key_event() - return self._get_key_event() - - def is_pressed(self, *keys): # Shortcut APi = in key_pressed + def is_pressed(self, *keys): for key in keys: if key in ['Shift', 'Alt', 'Control']: if key + '_L' in self.key_pressed or key + '_R' in self.key_pressed: @@ -237,18 +215,10 @@ def is_pressed(self, *keys): # Shortcut APi = in key_pressed else: return False - def get_is_pressed(self, *keys): # Shortcut APi = pop all + is_pressed + def has_key_pressed(self): while self.get_key_event() is not None: pass - return self.is_pressed(*keys) - - def get_key_pressed(self): # Shortcut APi = pop all + key_pressed - while self.get_key_event() is not None: - pass - return self.key_pressed - - def has_key_pressed(self): # Deprecated APi, use get_key_pressed instead - return len(self.get_key_pressed()) != 0 + return len(self.key_pressed) != 0 def rgb_to_hex(c): From 9944ab990183ac72ba3067bb54480836ac88154c Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Thu, 23 Apr 2020 16:30:01 +0800 Subject: [PATCH 14/21] [skip ci] arrange --- python/taichi/misc/gui.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index f3e2f9eecd62e..95d044d91bcfd 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -135,7 +135,7 @@ def rect(self, topleft, bottomright, radius=1, color=0xFFFFFF): def show(self, file=None): self.core.update() - if file is not None: + if file: self.core.screenshot(file) self.clear(self.background_color) @@ -161,6 +161,15 @@ def match(self, e): return True return False + def has_key_event(self): + return self.core.has_key_event() + + def get_event(self, *filter): + for e in self.get_events(*filter): + self.event = e + return True + return False + def get_events(self, *filter): if not filter: filter = None @@ -174,19 +183,6 @@ def get_events(self, *filter): if filter is None or filter.match(e): yield e - def get_event(self, *filter): - for e in self.get_events(*filter): - self.event = e - return True - return False - - def get_cursor_pos(self): - pos = self.core.get_cursor_pos() - return pos[0], pos[1] - - def has_key_event(self): - return self.core.has_key_event() - def get_key_event(self): self.core.wait_key_event() e = GUI.Event() @@ -215,9 +211,13 @@ def is_pressed(self, *keys): else: return False + def get_cursor_pos(self): + pos = self.core.get_cursor_pos() + return pos[0], pos[1] + def has_key_pressed(self): - while self.get_key_event() is not None: - pass + if self.has_key_event(): + self.get_key_event() # pop to update self.key_pressed return len(self.key_pressed) != 0 From e2da02025a16d27748fb942f76948d92646eb402 Mon Sep 17 00:00:00 2001 From: Taichi Gardener Date: Thu, 23 Apr 2020 04:32:24 -0400 Subject: [PATCH 15/21] [skip ci] enforce code format --- examples/quadtree.py | 14 +++++++++----- taichi/program/program.cpp | 4 ++-- taichi/struct/struct_llvm.cpp | 1 - taichi/transforms/simplify.cpp | 3 +-- tests/python/test_optimization.py | 1 - 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/examples/quadtree.py b/examples/quadtree.py index 16aa398fa6218..ce617e8f0831b 100644 --- a/examples/quadtree.py +++ b/examples/quadtree.py @@ -6,7 +6,7 @@ RES = 1024 K = 2 R = 7 -N = K ** R +N = K**R Broot = ti.root B = ti.root @@ -18,12 +18,14 @@ img = ti.Vector(3, dt=ti.f32, shape=(RES, RES)) + @ti.kernel def action(p: ti.ext_arr()): a = ti.cast(p[0] * N, ti.i32) b = ti.cast(p[1] * N, ti.i32) qt[a, b] = 1 + @ti.func def draw_rect(b, i, j, s, k, dx, dy): x = i // s @@ -34,6 +36,7 @@ def draw_rect(b, i, j, s, k, dx, dy): a += ti.is_active(b, [x - dx, y - dy]) return a + @ti.kernel def paint(): for i, j in img: @@ -42,15 +45,16 @@ def paint(): for i, j in img: s = RES // N for r in ti.static(range(R)): - k = RES // K ** (R-r) - ia = draw_rect(qt.parent(r+1), i, j, s, k, 1, 0) - ja = draw_rect(qt.parent(r+1), i, j, s, k, 0, 1) - img[i, j][0] += (ia + ja) * ((R-r) / R) ** 2 + k = RES // K**(R - r) + ia = draw_rect(qt.parent(r + 1), i, j, s, k, 1, 0) + ja = draw_rect(qt.parent(r + 1), i, j, s, k, 0, 1) + img[i, j][0] += (ia + ja) * ((R - r) / R)**2 def vec2_npf32(m): return np.array([m[0], m[1]], dtype=np.float32) + gui = ti.GUI('Quadtree', (RES, RES)) while not gui.get_event(ti.GUI.PRESS): Broot.deactivate_all() diff --git a/taichi/program/program.cpp b/taichi/program/program.cpp index 176b1c5937a2d..757e543430aba 100644 --- a/taichi/program/program.cpp +++ b/taichi/program/program.cpp @@ -485,8 +485,8 @@ void Program::finalize() { std::string file_name = current_test; auto py_pos = file_name.find(".py::"); TI_ASSERT(py_pos != file_name.npos); - file_name = file_name.substr(0, py_pos) + "__" + - file_name.substr(py_pos + 5); + file_name = + file_name.substr(0, py_pos) + "__" + file_name.substr(py_pos + 5); auto first_space_pos = file_name.find_first_of(' '); TI_ASSERT(first_space_pos != file_name.npos); file_name = file_name.substr(0, first_space_pos); diff --git a/taichi/struct/struct_llvm.cpp b/taichi/struct/struct_llvm.cpp index beaaad9997cbc..3aa96659f7713 100644 --- a/taichi/struct/struct_llvm.cpp +++ b/taichi/struct/struct_llvm.cpp @@ -87,7 +87,6 @@ void StructCompilerLLVM::generate_types(SNode &snode) { ch_type}, type_stub_name(&snode)); - // Create a dummy function in the module with the type stub as return type // so that the type is referenced in the module auto ft = llvm::FunctionType::get(llvm::PointerType::get(stub, 0), false); diff --git a/taichi/transforms/simplify.cpp b/taichi/transforms/simplify.cpp index 0732efd94d1cd..033042ce12514 100644 --- a/taichi/transforms/simplify.cpp +++ b/taichi/transforms/simplify.cpp @@ -683,8 +683,7 @@ class BasicBlockSimplify : public IRVisitor { // step 2: eliminate useless extraction of another OffsetAndExtractBitsStmt if (advanced_optimization) { - if (stmt->offset == 0 && - stmt->bit_begin == 0 && + if (stmt->offset == 0 && stmt->bit_begin == 0 && stmt->input->is()) { auto bstmt = stmt->input->as(); if (stmt->bit_end == bstmt->bit_end - bstmt->bit_begin) { diff --git a/tests/python/test_optimization.py b/tests/python/test_optimization.py index d9b04a5851c89..6c2296adc526f 100644 --- a/tests/python/test_optimization.py +++ b/tests/python/test_optimization.py @@ -17,7 +17,6 @@ def func(): for j in range(1): val[None] = a - val[None] = 10 func() assert val[None] == 10 From 80ac2246fa18da26921fc51e07783b907bc5f430 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Thu, 23 Apr 2020 22:39:47 +0800 Subject: [PATCH 16/21] [skip ci] apply reviews --- python/taichi/misc/gui.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index 95d044d91bcfd..5e906476eb3e9 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -157,7 +157,7 @@ def match(self, e): if (e.type, e.key) in self.combs: return True if not self.keys or e.key in self.keys: - if not self.combs or e.key in self.combs: + if not self.types or e.type in self.types: return True return False @@ -171,10 +171,7 @@ def get_event(self, *filter): return False def get_events(self, *filter): - if not filter: - filter = None - elif not isinstance(filter[0], GUI.EventFilter): - filter = GUI.EventFilter(*filter) + filter = filter and GUI.EventFilter(*filter) or None while True: if not self.has_key_event(): From afe64ef7580aed4902a4cbafe2091a8c6de62a84 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Sat, 25 Apr 2020 15:17:53 +0800 Subject: [PATCH 17/21] better OR logic --- python/taichi/misc/gui.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index 5e906476eb3e9..c345a8cfec0b3 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -141,24 +141,15 @@ def show(self, file=None): class EventFilter: def __init__(self, *filter): - self.types = set() - self.keys = set() - self.combs = set() - for ent in filter: - if isinstance(ent, (tuple, list)): - type, key = ent - self.combs.add((type, key)) - elif ent in [GUI.PRESS, GUI.RELEASE]: - self.types.add(ent) - else: - self.keys.add(ent) + self.filter = set(filter) def match(self, e): - if (e.type, e.key) in self.combs: + if (e.type, e.key) in self.filter: + return True + if e.type in self.filter: + return True + if e.key in self.filter: return True - if not self.keys or e.key in self.keys: - if not self.types or e.type in self.types: - return True return False def has_key_event(self): From 2efeba33a4dd75f193eb3b1077b4109461a93568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=BA=8E=E6=96=8C?= <1931127624@qq.com> Date: Mon, 27 Apr 2020 16:48:02 +0800 Subject: [PATCH 18/21] assert len(combination entry) == 2 --- python/taichi/misc/gui.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index c345a8cfec0b3..2c3620c419190 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -141,7 +141,12 @@ def show(self, file=None): class EventFilter: def __init__(self, *filter): - self.filter = set(filter) + self.filter = set() + for ent in filter: + if isinstance(ent, (list, tuple)): + type, key = ent + ent = (type, key) + self.filter.add(ent) def match(self, e): if (e.type, e.key) in self.filter: From fce41a7255a531bb70e36a480bf5b645e31ab7a2 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Wed, 29 Apr 2020 16:00:22 +0800 Subject: [PATCH 19/21] [skip ci] fix doc --- docs/utilities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/utilities.rst b/docs/utilities.rst index 42efcf8758b65..346cf5a1c504b 100644 --- a/docs/utilities.rst +++ b/docs/utilities.rst @@ -9,7 +9,7 @@ GUI system .. code-block:: python gui = ti.GUI('Title', (640, 480)) - while not gui.is_pressed(ti.GUI.ESCAPE): + while not gui.get_event(ti.GUI.ESCAPE): # until ESC is pressed gui.set_image(img) gui.show() From 0b56be0ea0e02977babbcfa26c1c60a7a9c41f5a Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Wed, 29 Apr 2020 17:18:26 +0800 Subject: [PATCH 20/21] [skip ci] update doc for gui --- docs/gui.rst | 269 +++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + docs/utilities.rst | 25 ----- docs/vector.rst | 2 + 4 files changed, 272 insertions(+), 25 deletions(-) create mode 100644 docs/gui.rst diff --git a/docs/gui.rst b/docs/gui.rst new file mode 100644 index 0000000000000..79c2be15c1ff3 --- /dev/null +++ b/docs/gui.rst @@ -0,0 +1,269 @@ +.. _gui: + +GUI system +========== + +Taichi has a built-in GUI system to help users display graphic results easier. + + +Create a window +--------------- + + +.. function:: ti.GUI(title, res, bgcolor = 0x000000): + + :parameter title: (string) the window title + :parameter res: (scalar or tuple) resolution / size of the window + :parameter bgcolor: (optional, RGB hex) background color of the window + :return: (GUI) an object represents the window + + Create a window. + If ``res`` is scalar, then width will be equal to height. + + This creates a window whose width is 1024, height is 768: + + :: + + gui = ti.GUI('Window Title', (1024, 768)) + + +.. function:: gui.show(filename = None) + + :parameter gui: (GUI) the window object + :parameter filename: (optional, string) see notes below + + Show the window on the screen. + + .. note:: + If `filename` is specified, screenshot will be saved to the file specified by the name. For example, this screenshots each frame of the window, and save it in ``.png``'s: + + :: + + for frame in range(10000): + render(img) + gui.set_image(img) + gui.show(f'{frame:06d}.png') + + +Paint a window +-------------- + + +.. function:: gui.set_image(img) + + :parameter gui: (GUI) the window object + :parameter img: (np.array or Tensor) tensor containing the image, see notes below + + Set a image to display on the window. + + The pixel, ``i`` from bottom to up, ``j`` from left to right, is set to the value of ``img[i, j]``. + + + If the window size is ``(x, y)``, then the ``img`` must be one of: + + * ``ti.var(shape=(x, y))``, a grey-scale image + + * ``ti.var(shape=(x, y, 3))``, where `3` is for `(r, g, b)` channels + + * ``ti.Vector(3, shape=(x, y))`` (see :ref:`vector`) + + * ``np.ndarray(shape=(x, y))`` + + * ``np.ndarray(shape=(x, y, 3))`` + + + The data type of ``img`` must be one of: + + * float32, clamped into [0, 1] + + * float64, clamped into [0, 1] + + * uint8, range [0, 255] + + * uint16, range [0, 65535] + + * uint32, range [0, UINT_MAX] + + +.. function:: gui.circle(pos, color = 0xFFFFFF, radius = 1) + + :parameter gui: (GUI) the window object + :parameter pos: (tuple of 2) the position of circle + :parameter color: (optional, RGB hex) color to fill the circle + :parameter radius: (optional, scalar) the radius of circle + + Draw a solid circle. + + +.. function:: gui.circles(pos, color = 0xFFFFFF, radius = 1) + + :parameter gui: (GUI) the window object + :parameter pos: (np.array) the position of circles + :parameter color: (optional, RGB hex or np.array of uint32) color(s) to fill circles + :parameter radius: (optional, scalar) the radius of circle + + Draw solid circles. + +.. note:: + + If ``color`` is a numpy array, circle at ``pos[i]`` will be colored with ``color[i]``, therefore it must have the same size with ``pos``. + + +.. function:: gui.line(begin, end, color = 0xFFFFFF, radius = 1) + + :parameter gui: (GUI) the window object + :parameter begin: (tuple of 2) the first end point position of line + :parameter end: (tuple of 2) the second end point position of line + :parameter color: (optional, RGB hex) the color of line + :parameter radius: (optional, scalar) the width of line + + Draw a line. + + +.. function:: gui.triangle(a, b, c, color = 0xFFFFFF) + + :parameter gui: (GUI) the window object + :parameter a: (tuple of 2) the first end point position of triangle + :parameter b: (tuple of 2) the second end point position of triangle + :parameter c: (tuple of 2) the third end point position of triangle + :parameter color: (optional, RGB hex) the color to fill the triangle + + Draw a solid triangle. + + +.. function:: gui.rect(topleft, bottomright, radius = 1, color = 0xFFFFFF) + + :parameter gui: (GUI) the window object + :parameter topleft: (tuple of 2) the top-left point position of rectangle + :parameter bottomright: (tuple of 2) the bottom-right point position of rectangle + :parameter color: (optional, RGB hex) the color of stroke line + :parameter radius: (optional, scalar) the width of stroke line + + Draw a hollow rectangle. + + +Event processing +---------------- + +Every event have a key and type. +*Event key* is the key that you pressed on keyboard or mouse, can be one of: + +:: + + ti.GUI.ESCAPE + ti.GUI.SHIFT + ti.GUI.LEFT + 'a' + 'b' + ... + ti.GUI.LMB + ti.GUI.RMB + +*Event type* is the type of event, for now, there are just three type of event: + +:: + + ti.GUI.RELEASE # key up + ti.GUI.PRESS # key down + ti.GUI.MOTION # mouse moved + + +A *event filter* is a list combined of *key*, *type* and *(type, key)* tuple, e.g.: + +.. code-block:: + + # if ESC pressed or released: + gui.get_event(ti.GUI.ESCAPE) + + # if any key is pressed: + gui.get_event(ti.GUI.PRESS) + + # if ESC pressed or SPACE released: + gui.get_event((ti.GUI.PRESS, ti.GUI.ESCAPE), (ti.GUI.RELEASE, ti.GUI.SPACE)) + + +.. function:: gui.get_event(a, ...) + + :parameter gui: (GUI) + :parameter a: (optional, EventFilter) filter out matched events + :return: (bool) ``False`` if there is no pending event, vise versa + + Try to pop a event from the queue, and store it in ``gui.event``. + + For example: + + :: + + while gui.get_event(): + print('Event key', gui.event.key) + + + For example, loop until ESC is pressed: + + :: + + gui = ti.GUI('Title', (640, 480)) + while not gui.get_event(ti.GUI.ESCAPE): + gui.set_image(img) + gui.show() + +.. function:: gui.get_events(a, ...) + + :parameter gui: (GUI) + :parameter a: (optional, EventFilter) filter out matched events + :return: (generator) a python generator, see below + + Basically the same as ``gui.get_event``, except for this one returns a generator of events instead of storing into ``gui.event``: + + :: + + for e in gui.get_events(): + if e.key == ti.GUI.ESCAPE: + exit() + elif e.type == ti.GUI.SPACE: + do_something() + elif e.type in ['a', ti.GUI.LEFT]: + ... + +.. function:: gui.is_pressed(key, ...) + + :parameter gui: (GUI) + :parameter key: (EventKey) keys you want to detect + :return: (bool) ``True`` if one of the keys pressed, vice versa + + .. warning:: + + Must be used together with ``gui.get_event``, or it won't be updated! + For example: + + :: + + while True: + gui.get_event() # must be called before is_pressed + if gui.is_pressed('a', ti.GUI.LEFT): + print('Go left!') + elif gui.is_pressed('d', ti.GUI.RIGHT): + print('Go right!') + +.. function:: gui.get_cursor_pos() + + :parameter gui: (GUI) + :return: (tuple of 2) current cursor position within the window + + For example: + + :: + + mouse_x, mouse_y = gui.get_cursor_pos() + + +Image I/O +--------- + +.. code-block:: python + + img = ti.imread('hello.png') + ti.imshow(img, 'Window Title') + ti.imwrite(img, 'hello2.png') + +TODO: complete here diff --git a/docs/index.rst b/docs/index.rst index 0fa966f0785b1..76ed819d0ed1f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -57,6 +57,7 @@ The Taichi Programming Language :maxdepth: 3 utilities + gui global_settings performance acknowledgments diff --git a/docs/utilities.rst b/docs/utilities.rst index 346cf5a1c504b..9800905e384ab 100644 --- a/docs/utilities.rst +++ b/docs/utilities.rst @@ -1,31 +1,6 @@ Utilities ================================== -TODO: update - -GUI system ----------- - -.. code-block:: python - - gui = ti.GUI('Title', (640, 480)) - while not gui.get_event(ti.GUI.ESCAPE): # until ESC is pressed - gui.set_image(img) - gui.show() - - -Also checkout ``examples/keyboard.py`` for more advanced event processing. - - -Image I/O ---------- - -.. code-block:: python - - img = ti.imread('hello.png') - ti.imshow(img, 'Window Title') - ti.imwrite(img, 'hello2.png') - Logging ------- diff --git a/docs/vector.rst b/docs/vector.rst index fed835049d435..f0a5a049876c4 100644 --- a/docs/vector.rst +++ b/docs/vector.rst @@ -8,6 +8,8 @@ A vector in Taichi can have two forms: - as a temporary local variable. An ``n`` component vector consists of ``n`` scalar values. - as an element of a global tensor. In this case, the tensor is an N-dimensional array of ``n`` component vectors +See :ref:`tensor_matrix` for more details. + Declaration ----------- From 6a5a44d197a3cd2af8196b137b9cfd74d226bd0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=BA=8E=E6=96=8C?= <1931127624@qq.com> Date: Wed, 29 Apr 2020 17:30:38 +0800 Subject: [PATCH 21/21] [skip ci] Update docs/gui.rst --- docs/gui.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/gui.rst b/docs/gui.rst index 79c2be15c1ff3..2570d68b5e2a7 100644 --- a/docs/gui.rst +++ b/docs/gui.rst @@ -10,7 +10,7 @@ Create a window --------------- -.. function:: ti.GUI(title, res, bgcolor = 0x000000): +.. function:: ti.GUI(title, res, bgcolor = 0x000000) :parameter title: (string) the window title :parameter res: (scalar or tuple) resolution / size of the window