Add keyboard controls

This commit is contained in:
Devin Neal 2021-03-15 19:53:17 -07:00
commit 05a50ebdfa
5 changed files with 76 additions and 20 deletions

View file

@ -8,14 +8,6 @@ from pathlib import Path
# Lines that do not yet work with the Community Version are commented.
class Test(Scene):
def construct(self):
circle = OpenGLCircle()
self.play(circle.animate.shift(RIGHT))
circle.add_updater(lambda s: s.move_to(self.mouse_point))
self.interact()
class InteractiveDevelopment(Scene):
def construct(self):
circle = OpenGLCircle()

View file

@ -177,3 +177,5 @@ QUALITIES: typing.Dict[str, typing.Dict[str, typing.Union[str, int, None]]] = {
DEFAULT_QUALITY: str = "high_quality"
DEFAULT_QUALITY_SHORT = QUALITIES[DEFAULT_QUALITY]["flag"]
SHIFT_VALUE = 65505
CTRL_VALUE = 65507

View file

@ -91,12 +91,10 @@ class OpenGLCamera(OpenGLMobject):
quaternion_from_angle_axis(phi, RIGHT, axis_normalized=True),
quaternion_from_angle_axis(gamma, OUT, axis_normalized=True),
)
self.inverse_camera_rotation_matrix = rotation_matrix_transpose_from_quaternion(
quat
)
self.inverse_rotation_matrix = rotation_matrix_transpose_from_quaternion(quat)
def rotate(self, angle, axis=OUT, **kwargs):
curr_rot_T = self.inverse_camera_rotation_matrix
curr_rot_T = self.inverse_rotation_matrix
added_rot_T = rotation_matrix_transpose(angle, axis)
new_rot_T = np.dot(curr_rot_T, added_rot_T)
Fz = new_rot_T[2]
@ -197,6 +195,7 @@ class OpenGLRenderer:
self.context = moderngl.create_standalone_context()
self.frame_buffer_object = self.get_frame_buffer_object(self.context, 0)
self.frame_buffer_object.use()
self.pressed_keys = set()
self.context.enable(moderngl.BLEND)
self.context.blend_func = (
@ -223,24 +222,24 @@ class OpenGLRenderer:
def get_pixel_shape(self):
return self.frame_buffer_object.viewport[2:4]
def refresh_perspective_uniforms(self, camera_frame):
def refresh_perspective_uniforms(self, camera):
pw, ph = self.get_pixel_shape()
fw, fh = camera_frame.get_shape()
fw, fh = camera.get_shape()
# TODO, this should probably be a mobject uniform, with
# the camera taking care of the conversion factor
anti_alias_width = self.anti_alias_width / (ph / fh)
# Orient light
rotation = camera_frame.inverse_camera_rotation_matrix
light_pos = camera_frame.light_source.get_location()
rotation = camera.inverse_rotation_matrix
light_pos = camera.light_source.get_location()
light_pos = np.dot(rotation, light_pos)
self.perspective_uniforms = {
"frame_shape": camera_frame.get_shape(),
"frame_shape": camera.get_shape(),
"anti_alias_width": anti_alias_width,
"camera_center": tuple(camera_frame.get_center()),
"camera_center": tuple(camera.get_center()),
"camera_rotation": tuple(np.array(rotation).T.flatten()),
"light_source_position": tuple(light_pos),
"focal_distance": camera_frame.get_focal_distance(),
"focal_distance": camera.get_focal_distance(),
}
def render_mobjects(self, mobs):

View file

@ -29,9 +29,33 @@ class Window(PygletWindow):
self.swap_buffers()
# Delegate event handling to scene
# Delegate event handling to scene.
def on_mouse_motion(self, x, y, dx, dy):
super().on_mouse_motion(x, y, dx, dy)
point = self.renderer.pixel_coords_to_space_coords(x, y)
d_point = self.renderer.pixel_coords_to_space_coords(dx, dy, relative=True)
self.renderer.scene.on_mouse_motion(point, d_point)
def on_mouse_scroll(self, x, y, x_offset: float, y_offset: float):
super().on_mouse_scroll(x, y, x_offset, y_offset)
point = self.renderer.pixel_coords_to_space_coords(x, y)
offset = self.renderer.pixel_coords_to_space_coords(
x_offset, y_offset, relative=True
)
self.renderer.scene.on_mouse_scroll(point, offset)
def on_key_press(self, symbol, modifiers):
self.renderer.pressed_keys.add(symbol)
super().on_key_press(symbol, modifiers)
self.renderer.scene.on_key_press(symbol, modifiers)
def on_key_release(self, symbol, modifiers):
self.renderer.pressed_keys.remove(symbol)
super().on_key_release(symbol, modifiers)
self.renderer.scene.on_key_release(symbol, modifiers)
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
super().on_mouse_drag(x, y, dx, dy, buttons, modifiers)
point = self.renderer.pixel_coords_to_space_coords(x, y)
d_point = self.renderer.pixel_coords_to_space_coords(dx, dy, relative=True)
self.renderer.scene.on_mouse_drag(point, d_point, buttons, modifiers)

View file

@ -28,6 +28,7 @@ from ..utils.family import extract_mobject_family_members
from ..renderer.cairo_renderer import CairoRenderer
from ..utils.exceptions import EndSceneEarlyException
from ..utils.family_ops import restructure_list_to_exclude_certain_family_members
from ..utils.space_ops import rotate_vector
class Scene(Container):
@ -969,3 +970,41 @@ class Scene(Container):
def on_mouse_motion(self, point, d_point):
self.mouse_point.move_to(point)
if SHIFT_VALUE in self.renderer.pressed_keys:
shift = -d_point
shift[0] *= self.camera.get_width() / 2
shift[1] *= self.camera.get_height() / 2
transform = self.camera.inverse_rotation_matrix
shift = np.dot(np.transpose(transform), shift)
self.camera.shift(shift)
def on_mouse_scroll(self, point, offset):
if CTRL_VALUE in self.renderer.pressed_keys:
factor = 1 + np.arctan(-20 * offset[1])
self.camera.scale(factor, about_point=point)
transform = self.camera.inverse_rotation_matrix
shift = np.dot(np.transpose(transform), offset)
if SHIFT_VALUE in self.renderer.pressed_keys:
self.camera.shift(20.0 * np.array(rotate_vector(shift, PI / 2)))
else:
self.camera.shift(20.0 * shift)
def on_key_press(self, symbol, modifiers):
try:
char = chr(symbol)
except OverflowError:
logger.warning("The value of the pressed key is too large.")
return
if char == "r":
self.camera.to_default_state()
elif char == "q":
self.quit_interaction = True
def on_key_release(self, symbol, modifiers):
pass
def on_mouse_drag(self, point, d_point, buttons, modifiers):
self.camera.increment_theta(-d_point[0])
self.camera.increment_phi(d_point[1])