from __future__ import annotations import os import re from functools import lru_cache import moderngl from manimlib.utils.directories import get_shader_dir from manimlib.utils.file_ops import find_file from typing import TYPE_CHECKING if TYPE_CHECKING: from typing import Sequence, Optional @lru_cache() def get_shader_program( ctx: moderngl.context.Context, vertex_shader: str, fragment_shader: Optional[str] = None, geometry_shader: Optional[str] = None, ) -> moderngl.Program: return ctx.program( vertex_shader=vertex_shader, fragment_shader=fragment_shader, geometry_shader=geometry_shader, ) @lru_cache() def get_shader_code_from_file(filename: str) -> str | None: if not filename: return None try: filepath = find_file( filename, directories=[get_shader_dir(), "/"], extensions=[], ) except IOError: return None with open(filepath, "r") as f: result = f.read() # To share functionality between shaders, some functions are read in # from other files an inserted into the relevant strings before # passing to ctx.program for compiling # Replace "#INSERT " lines with relevant code insertions = re.findall(r"^#INSERT .*\.glsl$", result, flags=re.MULTILINE) for line in insertions: inserted_code = get_shader_code_from_file( os.path.join("inserts", line.replace("#INSERT ", "")) ) result = result.replace(line, inserted_code) return result def get_colormap_code(rgb_list: Sequence[float]) -> str: data = ",".join( "vec3({}, {}, {})".format(*rgb) for rgb in rgb_list ) return f"vec3[{len(rgb_list)}]({data})"