123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- """Functions used to generate source files during build time
- All such functions are invoked in a subprocess on Windows to prevent build flakiness.
- """
- import os.path
- from typing import Optional, Iterable
- from platform_methods import subprocess_main
- def generate_inline_code(input_lines: Iterable[str], insert_newline: bool = True):
- """Take header data and generate inline code
- :param: input_lines: values for shared inline code
- :return: str - generated inline value
- """
- output = []
- for line in input_lines:
- if line:
- output.append(",".join(str(ord(c)) for c in line))
- if insert_newline:
- output.append("%s" % ord("\n"))
- output.append("0")
- return ",".join(output)
- class RDHeaderStruct:
- def __init__(self):
- self.vertex_lines = []
- self.fragment_lines = []
- self.compute_lines = []
- self.vertex_included_files = []
- self.fragment_included_files = []
- self.compute_included_files = []
- self.reading = ""
- self.line_offset = 0
- self.vertex_offset = 0
- self.fragment_offset = 0
- self.compute_offset = 0
- def include_file_in_rd_header(filename: str, header_data: RDHeaderStruct, depth: int) -> RDHeaderStruct:
- fs = open(filename, "r")
- line = fs.readline()
- while line:
- index = line.find("//")
- if index != -1:
- line = line[:index]
- if line.find("#[vertex]") != -1:
- header_data.reading = "vertex"
- line = fs.readline()
- header_data.line_offset += 1
- header_data.vertex_offset = header_data.line_offset
- continue
- if line.find("#[fragment]") != -1:
- header_data.reading = "fragment"
- line = fs.readline()
- header_data.line_offset += 1
- header_data.fragment_offset = header_data.line_offset
- continue
- if line.find("#[compute]") != -1:
- header_data.reading = "compute"
- line = fs.readline()
- header_data.line_offset += 1
- header_data.compute_offset = header_data.line_offset
- continue
- while line.find("#include ") != -1:
- includeline = line.replace("#include ", "").strip()[1:-1]
- if includeline.startswith("thirdparty/"):
- included_file = os.path.relpath(includeline)
- else:
- included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
- if not included_file in header_data.vertex_included_files and header_data.reading == "vertex":
- header_data.vertex_included_files += [included_file]
- if include_file_in_rd_header(included_file, header_data, depth + 1) is None:
- print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
- elif not included_file in header_data.fragment_included_files and header_data.reading == "fragment":
- header_data.fragment_included_files += [included_file]
- if include_file_in_rd_header(included_file, header_data, depth + 1) is None:
- print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
- elif not included_file in header_data.compute_included_files and header_data.reading == "compute":
- header_data.compute_included_files += [included_file]
- if include_file_in_rd_header(included_file, header_data, depth + 1) is None:
- print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
- line = fs.readline()
- line = line.replace("\r", "").replace("\n", "")
- if header_data.reading == "vertex":
- header_data.vertex_lines += [line]
- if header_data.reading == "fragment":
- header_data.fragment_lines += [line]
- if header_data.reading == "compute":
- header_data.compute_lines += [line]
- line = fs.readline()
- header_data.line_offset += 1
- fs.close()
- return header_data
- def build_rd_header(
- filename: str, optional_output_filename: str = None, header_data: Optional[RDHeaderStruct] = None
- ) -> None:
- header_data = header_data or RDHeaderStruct()
- include_file_in_rd_header(filename, header_data, 0)
- if optional_output_filename is None:
- out_file = filename + ".gen.h"
- else:
- out_file = optional_output_filename
- out_file_base = out_file
- out_file_base = out_file_base[out_file_base.rfind("/") + 1 :]
- out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :]
- out_file_ifdef = out_file_base.replace(".", "_").upper()
- out_file_class = out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "ShaderRD"
- if header_data.compute_lines:
- body_parts = [
- "static const char _compute_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.compute_lines),
- f'setup(nullptr, nullptr, _compute_code, "{out_file_class}");',
- ]
- else:
- body_parts = [
- "static const char _vertex_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.vertex_lines),
- "static const char _fragment_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.fragment_lines),
- f'setup(_vertex_code, _fragment_code, nullptr, "{out_file_class}");',
- ]
- body_content = "\n\t\t".join(body_parts)
- # Intended curly brackets are doubled so f-string doesn't eat them up.
- shader_template = f"""/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
- #ifndef {out_file_ifdef}_RD
- #define {out_file_ifdef}_RD
- #include "servers/rendering/renderer_rd/shader_rd.h"
- class {out_file_class} : public ShaderRD {{
- public:
- {out_file_class}() {{
- {body_content}
- }}
- }};
- #endif
- """
- with open(out_file, "w") as fd:
- fd.write(shader_template)
- def build_rd_headers(target, source, env):
- for x in source:
- build_rd_header(filename=str(x))
- class RAWHeaderStruct:
- def __init__(self):
- self.code = ""
- def include_file_in_raw_header(filename: str, header_data: RAWHeaderStruct, depth: int) -> None:
- fs = open(filename, "r")
- line = fs.readline()
- while line:
- while line.find("#include ") != -1:
- includeline = line.replace("#include ", "").strip()[1:-1]
- included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
- include_file_in_raw_header(included_file, header_data, depth + 1)
- line = fs.readline()
- header_data.code += line
- line = fs.readline()
- fs.close()
- def build_raw_header(
- filename: str, optional_output_filename: str = None, header_data: Optional[RAWHeaderStruct] = None
- ):
- header_data = header_data or RAWHeaderStruct()
- include_file_in_raw_header(filename, header_data, 0)
- if optional_output_filename is None:
- out_file = filename + ".gen.h"
- else:
- out_file = optional_output_filename
- out_file_base = out_file.replace(".glsl.gen.h", "_shader_glsl")
- out_file_base = out_file_base[out_file_base.rfind("/") + 1 :]
- out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :]
- out_file_ifdef = out_file_base.replace(".", "_").upper()
- shader_template = f"""/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
- #ifndef {out_file_ifdef}_RAW_H
- #define {out_file_ifdef}_RAW_H
- static const char {out_file_base}[] = {{
- {generate_inline_code(header_data.code, insert_newline=False)}
- }};
- #endif
- """
- with open(out_file, "w") as f:
- f.write(shader_template)
- def build_raw_headers(target, source, env):
- for x in source:
- build_raw_header(filename=str(x))
- if __name__ == "__main__":
- subprocess_main(globals())
|