2302c7102f
Change GLES3 to not use a relative path Make the parameters more explicit and ensure the shaders generated are not using relative paths
239 lines
7.7 KiB
Python
239 lines
7.7 KiB
Python
"""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())
|