Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6d69cd3
Add dearpygui integration
eulertour May 22, 2021
7004574
Merge remote-tracking branch 'origin/master' into dearpygui-integration
eulertour May 22, 2021
937054c
Rename MobjectTest -> GuiTest
eulertour May 22, 2021
94efb35
flake8
eulertour May 22, 2021
0b9c8aa
Guard against dearpygui import
eulertour May 22, 2021
b0292f2
Add manim.gui
eulertour May 22, 2021
47da92b
Guard against dearpygui import in gui.py
eulertour May 22, 2021
07aa3d7
Add __init__.py
eulertour May 22, 2021
ecd1593
Add flag for GUI
eulertour May 27, 2021
4edade5
Default to boolean
eulertour May 28, 2021
4b003bf
Fix problem when scene isn't specified
eulertour May 28, 2021
853c892
Add gui_location flag
eulertour May 28, 2021
cd5a529
poetry lock
eulertour May 28, 2021
a8bc4c6
Merge branch 'master' into dearpygui-integration
eulertour May 28, 2021
8485ccd
Fix test
eulertour May 28, 2021
dc2a6bb
Merge branch 'dearpygui-integration' of github.com:eulertour/manim-1 …
eulertour May 28, 2021
83429ed
Update manim/gui/gui.py
eulertour May 31, 2021
42a12be
Update manim/_config/default.cfg
eulertour May 31, 2021
6d958ff
Update manim/cli/render/global_options.py
eulertour May 31, 2021
369e549
Merge branch 'master' into dearpygui-integration
eulertour May 31, 2021
2dcd28f
Merge branch 'main' into dearpygui-integration
Darylgolden Jun 2, 2021
3b989b3
Review comments
eulertour Jun 3, 2021
978989c
Update pyproject.toml
eulertour Jun 13, 2021
09a4b79
Add __all__ to shader.py
eulertour Jun 13, 2021
34aa29e
Merge branch 'dearpygui-integration' of github.com:eulertour/manim-1 …
eulertour Jun 13, 2021
9866318
Merge branch 'main' into dearpygui-integration
eulertour Jun 13, 2021
d7c4464
Add utils import to opengl/__init__.py
eulertour Jun 13, 2021
cfb8f71
Merge branch 'dearpygui-integration' of github.com:eulertour/manim-1 …
eulertour Jun 13, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions example_scenes/opengl.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import manim.utils.opengl as opengl
import manim.utils.space_ops as space_ops
from manim import *
from manim.cli.new.group import scene
from manim.opengl import *

# Copied from https://3b1b.github.io/manim/getting_started/example_scenes.html#surfaceexample.
Expand Down Expand Up @@ -72,6 +73,49 @@ def get_plane_mesh(context):
return Mesh(shader, attributes)


class GuiTest(Scene):
def construct(self):
mesh = get_plane_mesh(self.renderer.context)
# mesh.attributes["in_vert"][:, 0]
self.add(mesh)

def update_mesh(mesh, dt):
mesh.model_matrix = np.matmul(
opengl.rotation_matrix(z=dt), mesh.model_matrix
)

mesh.add_updater(update_mesh)

self.interactive_embed()


class GuiTest2(Scene):
def construct(self):
mesh = get_plane_mesh(self.renderer.context)
mesh.attributes["in_vert"][:, 0] -= 2
self.add(mesh)

mesh2 = get_plane_mesh(self.renderer.context)
mesh2.attributes["in_vert"][:, 0] += 2
self.add(mesh2)

def callback(sender, data):
mesh2.attributes["in_color"][:, 3] = dpg.get_value(sender)

self.widgets.append(
{
"name": "mesh2 opacity",
"widget": "slider_float",
"callback": callback,
"min_value": 0,
"max_value": 1,
"default_value": 1,
}
)

self.interactive_embed()


class ThreeDMobjectTest(Scene):
def construct(self):
# config["background_color"] = "#333333"
Expand All @@ -98,7 +142,9 @@ def update_mesh(mesh, dt):
class NamedFullScreenQuad(Scene):
def construct(self):
surface = FullScreenQuad(self.renderer.context, fragment_shader_name="design_3")
surface.shader.set_uniform("u_resolution", (854.0, 480.0, 0.0))
surface.shader.set_uniform(
"u_resolution", (config["pixel_width"], config["pixel_height"], 0.0)
)
surface.shader.set_uniform("u_time", 0)
self.add(surface)

Expand Down Expand Up @@ -127,6 +173,7 @@ def construct(self):

uniform vec2 u_resolution;
uniform float u_time;
out vec4 frag_color;

// Function from Iñigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
Expand All @@ -153,12 +200,13 @@ def construct(self):
// and the Saturation to the radius
color = hsb2rgb(vec3((angle/TWO_PI)+0.5,radius,1.0));

gl_FragColor = vec4(color,1.0);
frag_color = vec4(color,1.0);
}
""",
output_color_variable="gl_FragColor",
)
surface.shader.set_uniform("u_resolution", (854.0, 480.0))
surface.shader.set_uniform(
"u_resolution", (config["pixel_width"], config["pixel_height"])
)
shader_time = 0

def update_surface(surface):
Expand All @@ -182,6 +230,7 @@ def construct(self):
uniform float v_red;
uniform float v_green;
uniform float v_blue;
out vec4 frag_color;

void main() {
frag_color = vec4(v_red, v_green, v_blue, 1);
Expand Down
6 changes: 6 additions & 0 deletions manim/_config/default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ webgl_renderer_path =
# --use_opengl_renderer
use_opengl_renderer = False

# --enable_gui
enable_gui = False

# --gui_location
gui_location = 40,800

# If the -t (--transparent) flag is used, these will be replaced with the
# values specified in the [TRANSPARENT] section later in this file.
png_mode = RGB
Expand Down
32 changes: 31 additions & 1 deletion manim/_config/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import errno
import logging
import os
import re
import sys
import typing
from collections.abc import Mapping, MutableMapping
Expand Down Expand Up @@ -282,6 +283,8 @@ class MyScene(Scene):
"renderer",
"use_opengl_renderer",
"use_webgl_renderer",
"enable_gui",
"gui_location",
"verbosity",
"video_dir",
"write_all",
Expand Down Expand Up @@ -407,6 +410,12 @@ def _set_boolean(self, key: typing.Union[str, int], val: typing.Any) -> None:
else:
raise ValueError(f"{key} must be boolean")

def _set_tuple(self, key: str, val: tuple) -> None:
if isinstance(val, tuple):
self._d[key] = val
else:
raise ValueError(f"{key} must be tuple")

def _set_str(self, key: str, val: typing.Any) -> None:
"""Set ``key`` to ``val`` if ``val`` is a string."""
if isinstance(val, str):
Expand Down Expand Up @@ -509,6 +518,7 @@ def digest_parser(self, parser: configparser.ConfigParser) -> "ManimConfig":
"custom_folders",
"use_opengl_renderer",
"use_webgl_renderer",
"enable_gui",
]:
setattr(self, key, parser["CLI"].getboolean(key, fallback=False))

Expand Down Expand Up @@ -553,6 +563,10 @@ def digest_parser(self, parser: configparser.ConfigParser) -> "ManimConfig":
# "frame_height",
]:
setattr(self, key, parser["CLI"].getfloat(key))

gui_location = tuple(map(int, re.split(";|,|-", parser["CLI"]["gui_location"])))
setattr(self, "gui_location", gui_location)

# plugins
self.plugins = parser["CLI"].get("plugins", fallback="", raw=True).split(",")
# the next two must be set AFTER digesting pixel_width and pixel_height
Expand Down Expand Up @@ -638,6 +652,7 @@ def digest_args(self, args: argparse.Namespace) -> "ManimConfig":
"background_color",
"use_opengl_renderer",
"use_webgl_renderer",
"enable_gui",
]:
if hasattr(args, key):
attr = getattr(args, key)
Expand Down Expand Up @@ -715,6 +730,9 @@ def digest_args(self, args: argparse.Namespace) -> "ManimConfig":
# --write_to_movie was not passed on the command line, so don't generate video.
self["write_to_movie"] = False

# Handle --gui_location flag.
self.gui_location = args.gui_location

return self

def digest_file(self, filename: str) -> "ManimConfig":
Expand Down Expand Up @@ -760,7 +778,7 @@ def digest_file(self, filename: str) -> "ManimConfig":

# config options are properties
preview = property(
lambda self: self._d["preview"],
lambda self: self._d["preview"] or self._d["enable_gui"],
lambda self, val: self._set_boolean("preview", val),
doc="Whether to play the rendered movie (-p).",
)
Expand Down Expand Up @@ -1129,6 +1147,18 @@ def use_webgl_renderer(self, val: bool) -> None:
doc="Main output directory. See :meth:`ManimConfig.get_dir`.",
)

enable_gui = property(
lambda self: self._d["enable_gui"],
lambda self, val: self._set_boolean("enable_gui", val),
doc="Enable GUI interaction.",
)

gui_location = property(
lambda self: self._d["gui_location"],
lambda self, val: self._set_tuple("gui_location", val),
doc="Enable GUI interaction.",
)

def get_dir(self, key: str, **kwargs: str) -> Path:
"""Resolve a config option that stores a directory.

Expand Down
26 changes: 26 additions & 0 deletions manim/cli/render/global_options.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import re

import click
from cloup import option, option_group

from ... import logger


def validate_gui_location(ctx, param, value):
if value:
try:
x_offset, y_offset = map(int, re.split(";|,|-", value))
return (x_offset, y_offset)
except Exception:
logger.error("GUI location option is invalid.")
exit()


global_options = option_group(
"Global options",
option(
Expand Down Expand Up @@ -36,4 +51,15 @@
default=None,
help="Display warnings for outdated installation.",
),
option(
"--enable_gui",
is_flag=True,
help="Enable GUI interaction.",
),
option(
"--gui_location",
default="40,800",
callback=validate_gui_location,
help="Starting location for the GUI.",
),
)
5 changes: 1 addition & 4 deletions manim/cli/render/render_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ def validate_resolution(ctx, param, value):
if value:
try:
start, end = map(int, re.split(";|,|-", value))
return (
start,
end,
)
return (start, end)
except Exception:
logger.error("Resolution option is invalid.")
exit()
Expand Down
Empty file added manim/gui/__init__.py
Empty file.
71 changes: 71 additions & 0 deletions manim/gui/gui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from pathlib import Path

try:
import dearpygui.core
import dearpygui.demo
import dearpygui.simple

dearpygui_imported = True
except ImportError:
dearpygui_imported = False


from .. import config
from ..utils.module_ops import scene_classes_from_file


def configure_pygui(renderer, widgets, update=True):
if not dearpygui_imported:
raise RuntimeError("Attempted to use DearPyGUI when it isn't imported.")
if update:
dearpygui.core.delete_item("Manim GUI")

def rerun_callback(sender, data):
renderer.scene.queue.put(("rerun_gui", [], {}))

def continue_callback(sender, data):
renderer.scene.queue.put(("exit_gui", [], {}))

def scene_selection_callback(sender, data):
config["scene_names"] = (dearpygui.core.get_value(sender),)
renderer.scene.queue.put(("rerun_gui", [], {}))

scene_classes = scene_classes_from_file(Path(config["input_file"]), full_list=True)
scene_names = [scene_class.__name__ for scene_class in scene_classes]

with dearpygui.simple.window(
"Manim GUI",
x_pos=config["gui_location"][0],
y_pos=config["gui_location"][1],
width=1000,
height=500,
):
dearpygui.core.set_global_font_scale(2)
dearpygui.core.add_button("Rerun", callback=rerun_callback)
dearpygui.core.add_button("Continue", callback=continue_callback)
dearpygui.core.add_combo(
"Selected scene",
items=scene_names,
callback=scene_selection_callback,
default_value=config["scene_names"][0],
)
dearpygui.core.add_separator()
if len(widgets) != 0:
with dearpygui.simple.collapsing_header(
f"{config['scene_names'][0]} widgets", default_open=True
):
for widget_config in widgets:
widget_config_copy = widget_config.copy()
name = widget_config_copy["name"]
widget = widget_config_copy["widget"]
if widget != "separator":
del widget_config_copy["name"]
del widget_config_copy["widget"]
getattr(dearpygui.core, f"add_{widget}")(
name, **widget_config_copy
)
else:
dearpygui.core.add_separator()
# dearpygui.demo.show_demo()
if not update:
dearpygui.core.start_dearpygui()
2 changes: 2 additions & 0 deletions manim/mobject/opengl_three_dimensions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import math

import numpy as np

from ..constants import *
from ..mobject.types.opengl_surface import OpenGLSurface
from ..mobject.types.opengl_vectorized_mobject import OpenGLVGroup, OpenGLVMobject
Expand Down
2 changes: 2 additions & 0 deletions manim/opengl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from dearpygui import core as dpg

from ..mobject.opengl_geometry import *
from ..mobject.opengl_mobject import *
from ..mobject.opengl_three_dimensions import *
Expand Down
Loading