diff --git a/example_scenes.py b/example_scenes.py index e89ed8aa..8178fad0 100644 --- a/example_scenes.py +++ b/example_scenes.py @@ -202,17 +202,17 @@ class SurfaceExample(Scene): torus1 = Torus(r1=1, r2=1) torus2 = Torus(r1=3, r2=1) sphere = Sphere(radius=3, resolution=torus1.resolution) - surfaces = [sphere, torus1, torus2] - # If you want these to be textured with pictures of, say, earth, - # find images for the texture maps you want, perhaps - # https://en.wikipedia.org/wiki/File:Blue_Marble_2002.png and - # https://commons.wikimedia.org/wiki/File:The_earth_at_night.jpg - # and make sure they are available in whatever folder manim - # looks for images, then uncomment the lines below - # surfaces = [ - # TexturedSurface(surface, "EarthTextureMap", "NightEarthTextureMap") - # for surface in [sphere, torus1, torus2] - # ] + # You can texture a surface with up to two images, which will + # be interpreted as the side towards the light, and away from + # the light. These can be either urls, or paths to a local file + # in whatever you've set as the iamge directory in + # the custom_defaults.yml file + day_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/2/23/Blue_Marble_2002.png/1280px-Blue_Marble_2002.png" + night_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/The_earth_at_night.jpg/1280px-The_earth_at_night.jpg" + surfaces = [ + TexturedSurface(surface, day_texture, night_texture) + for surface in [sphere, torus1, torus2] + ] for mob in surfaces: mob.mesh = SurfaceMesh(mob) diff --git a/manimlib/shader_wrapper.py b/manimlib/shader_wrapper.py index e47874ea..0775c5f4 100644 --- a/manimlib/shader_wrapper.py +++ b/manimlib/shader_wrapper.py @@ -1,12 +1,11 @@ import os -import logging import re import moderngl import numpy as np import copy from manimlib.utils.directories import get_shader_dir -from manimlib.utils.file_ops import seek_full_path_from_defaults +from manimlib.utils.file_ops import find_file # Mobjects that should be rendered with # the same shader will be organized and @@ -111,7 +110,7 @@ def get_shader_code_from_file(filename): return None try: - filepath = seek_full_path_from_defaults( + filepath = find_file( filename, directories=[get_shader_dir(), "/"], extensions=[], diff --git a/manimlib/utils/directories.py b/manimlib/utils/directories.py index cac924bf..cd70af57 100644 --- a/manimlib/utils/directories.py +++ b/manimlib/utils/directories.py @@ -25,12 +25,16 @@ def get_directories(): return PRE_COMPUTED_DIRS +def get_temp_dir(): + return get_directories()["temporary_storage"] + + def get_tex_dir(): - return guarantee_existence(os.path.join(get_directories()["temporary_storage"], "Tex")) + return guarantee_existence(os.path.join(get_temp_dir(), "Tex")) def get_mobject_data_dir(): - return guarantee_existence(os.path.join(get_directories()["temporary_storage"], "mobject_data")) + return guarantee_existence(os.path.join(get_temp_dir(), "mobject_data")) def get_output_dir(): diff --git a/manimlib/utils/file_ops.py b/manimlib/utils/file_ops.py index 90466f8c..761bf039 100644 --- a/manimlib/utils/file_ops.py +++ b/manimlib/utils/file_ops.py @@ -1,6 +1,10 @@ import os import numpy as np +import validators +import urllib.request +import tempfile + def add_extension_if_not_present(file_name, extension): # This could conceivably be smarter about handling existing differing extensions @@ -16,17 +20,34 @@ def guarantee_existence(path): return os.path.abspath(path) -def seek_full_path_from_defaults(file_name, directories, extensions): - possible_paths = [file_name] - possible_paths += [ +def find_file(file_name, directories=None, extensions=None): + # Check if this is a file online first, and if so, download + # it to a temporary directory + if validators.url(file_name): + stem, name = os.path.split(file_name) + folder = guarantee_existence( + os.path.join(tempfile.gettempdir(), "manim_downloads") + ) + path = os.path.join(folder, name) + urllib.request.urlretrieve(file_name, path) + return path + + # Check if what was passed in is already a valid path to a file + if os.path.exists(file_name): + return file_name + + # Otherwise look in local file system + directories = directories or [""] + extensions = extensions or [""] + possible_paths = ( os.path.join(directory, file_name + extension) for directory in directories - for extension in ["", *extensions] - ] + for extension in extensions + ) for path in possible_paths: if os.path.exists(path): return path - raise IOError("File {} not Found".format(file_name)) + raise IOError(f"{file_name} not Found") def get_sorted_integer_files(directory, diff --git a/manimlib/utils/images.py b/manimlib/utils/images.py index 761d6c6b..f9d3a718 100644 --- a/manimlib/utils/images.py +++ b/manimlib/utils/images.py @@ -1,14 +1,13 @@ import numpy as np - from PIL import Image -from manimlib.utils.file_ops import seek_full_path_from_defaults +from manimlib.utils.file_ops import find_file from manimlib.utils.directories import get_raster_image_dir from manimlib.utils.directories import get_vector_image_dir def get_full_raster_image_path(image_file_name): - return seek_full_path_from_defaults( + return find_file( image_file_name, directories=[get_raster_image_dir()], extensions=[".jpg", ".png", ".gif"] @@ -16,7 +15,7 @@ def get_full_raster_image_path(image_file_name): def get_full_vector_image_path(image_file_name): - return seek_full_path_from_defaults( + return find_file( image_file_name, directories=[get_vector_image_dir()], extensions=[".svg", ".xdv"], diff --git a/manimlib/utils/sounds.py b/manimlib/utils/sounds.py index 284ef360..9b349a7c 100644 --- a/manimlib/utils/sounds.py +++ b/manimlib/utils/sounds.py @@ -1,5 +1,5 @@ import os -from manimlib.utils.file_ops import seek_full_path_from_defaults +from manimlib.utils.file_ops import find_file def play_chord(*nums): @@ -32,7 +32,7 @@ def play_finish_sound(): def get_full_sound_file_path(sound_file_name): - return seek_full_path_from_defaults( + return find_file( sound_file_name, directories=[os.path.join("assets", "sounds")], extensions=[".wav", ".mp3"] diff --git a/requirements.txt b/requirements.txt index a5a83b17..0d116339 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,4 +14,6 @@ pydub PyOpenGL pyyaml screeninfo -pyreadline; sys_platform == 'win32' \ No newline at end of file +pyreadline; sys_platform == 'win32' +tempfile +validators \ No newline at end of file