generate_program_permutations.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #!/usr/bin/python3
  2. # Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
  3. # All rights reserved.
  4. # Code licensed under the BSD License.
  5. # http://www.anki3d.org/LICENSE
  6. import os
  7. import argparse
  8. # Template
  9. template_xml = """<?xml version="1.0" encoding="UTF-8" ?>
  10. <!-- This file is auto generated by generate_program_permutations.py -->
  11. <shaderProgram>
  12. <shaders>
  13. <shader>
  14. <type>vert</type>
  15. <inputs>
  16. %vertInputs%
  17. </inputs>
  18. <source><![CDATA[#include "shaders/MsCommonVert.glsl"
  19. void main() {
  20. %vertSrc%
  21. }
  22. ]]></source>
  23. </shader>
  24. <shader>
  25. <type>frag</type>
  26. <inputs>
  27. %fragInputs%
  28. </inputs>
  29. <source><![CDATA[#include "shaders/MsCommonFrag.glsl"
  30. void main() {
  31. %fragSrc%
  32. }
  33. ]]></source>
  34. </shader>
  35. </shaders>
  36. </shaderProgram>
  37. """
  38. # Input type
  39. INPUT_NONE = 0
  40. INPUT_TEXTURE = 1
  41. INPUT_CONST = 2
  42. INPUT_VALUE = 3 # non-const
  43. INPUT_COUNT = 4
  44. # Variables
  45. DIFFUSE = 0
  46. SPECULAR = 1
  47. ROUGHNESS = 2
  48. METALLIC = 3
  49. NORMAL = 4
  50. EMISSION = 5
  51. SUBSURFACE = 6
  52. HEIGHT = 7
  53. VARIABLE_COUNT = 8
  54. allowed_permutations = [
  55. [INPUT_TEXTURE, INPUT_CONST],
  56. [INPUT_TEXTURE, INPUT_CONST],
  57. [INPUT_TEXTURE, INPUT_CONST],
  58. [INPUT_TEXTURE, INPUT_CONST],
  59. [INPUT_TEXTURE, INPUT_NONE],
  60. [INPUT_TEXTURE, INPUT_CONST],
  61. [INPUT_CONST],
  62. [INPUT_NONE, INPUT_TEXTURE]]
  63. def parse_commandline():
  64. """ Parse the command line arguments """
  65. parser = argparse.ArgumentParser(description = "Create shader program permutations",
  66. formatter_class = argparse.ArgumentDefaultsHelpFormatter)
  67. parser.add_argument("-o", "--output-dir", required = True, help = "specify the output directory")
  68. args = parser.parse_args()
  69. return args.output_dir
  70. def spin_wheel(wheel):
  71. """ Spin the wheel """
  72. done = False
  73. start = VARIABLE_COUNT - 1
  74. while True:
  75. if start == -1:
  76. done = True
  77. break
  78. wheel[start] += 1
  79. if wheel[start] >= INPUT_COUNT:
  80. wheel[start] = INPUT_NONE
  81. start = start - 1
  82. else:
  83. break
  84. return done
  85. def mutate(wheel):
  86. """ Create the mutation's source """
  87. parallax = wheel[HEIGHT] == INPUT_TEXTURE
  88. # Vert input & source
  89. if parallax:
  90. vert_inputs = """ <input><type>mat4</type><name>mvp</name></input>
  91. <input><type>mat3</type><name>normalMat</name><depth>0</depth></input>
  92. <input><type>mat4</type><name>modelViewMat</name><depth>0</depth></input>
  93. """
  94. vert_src = """#if COLOR
  95. positionUvNormalTangent(mvp, normalMat);
  96. parallax(vodelViewMat);
  97. #else
  98. ANKI_WRITE_POSITION(mvp * vec4(in_position, 1.0));
  99. #endif
  100. """
  101. else:
  102. vert_inputs = """ <input><type>mat4</type><name>mvp</name></input>
  103. <input><type>mat3</type><name>normalMat</name><depth>0</depth></input>
  104. """
  105. vert_src = """#if COLOR
  106. positionUvNormalTangent(mvp, normalMat);
  107. #else
  108. ANKI_WRITE_POSITION(mvp * vec4(in_position, 1.0));
  109. #endif
  110. """
  111. # Frag inputs & source & filename
  112. frag_ins = ""
  113. frag_src = "#if COLOR\n"
  114. fname = "ms_"
  115. if parallax:
  116. frag_ins += "\t\t\t\t<input><type>float</type><name>heightMapScale</name><const>1</const><depth>0</depth></input>\n"
  117. frag_src += "vec2 uv = computeTextureCoordParallax(heightTex, in_uv, heightMapScale);\n"
  118. else:
  119. frag_src += "vec2 uv = in_uv;\n"
  120. if wheel[DIFFUSE] == INPUT_TEXTURE:
  121. frag_ins += "\t\t\t\t<input><type>sampler2D</type><name>diffTex</name><depth>0</depth></input>\n"
  122. frag_src += "vec3 diffColor = texture(diffTex, uv).rgb;\n"
  123. fname += "difft_"
  124. elif wheel[DIFFUSE] == INPUT_CONST:
  125. frag_ins += "\t\t\t\t<input><type>vec3</type><name>diffColor</name><const>1</const><depth>0</depth></input>\n"
  126. fname += "diffc_"
  127. else:
  128. assert 0
  129. if wheel[SPECULAR] == INPUT_TEXTURE:
  130. frag_ins += "\t\t\t\t<input><type>sampler2D</type><name>specTex</name><depth>0</depth></input>\n"
  131. frag_src += "vec3 specColor = texture(specTex, uv).rgb;\n"
  132. fname += "spect_"
  133. elif wheel[SPECULAR] == INPUT_CONST:
  134. frag_ins += "\t\t\t\t<input><type>vec3</type><name>specColor</name><const>1</const><depth>0</depth></input>\n"
  135. fname += "specc_"
  136. else:
  137. assert 0
  138. if wheel[ROUGHNESS] == INPUT_TEXTURE:
  139. frag_ins += "\t\t\t\t<input><type>sampler2D</type><name>roughnessTex</name><depth>0</depth></input>\n"
  140. frag_src += "float roughness = texture(roughnessTex, uv).r;\n"
  141. fname += "rought_"
  142. elif wheel[ROUGHNESS] == INPUT_CONST:
  143. frag_ins += "\t\t\t\t<input><type>float</type><name>roughness</name><const>1</const><depth>0</depth></input>\n"
  144. fname += "roughc_"
  145. else:
  146. assert 0
  147. if wheel[METALLIC] == INPUT_TEXTURE:
  148. frag_ins += "\t\t\t\t<input><type>sampler2D</type><name>metallicTex</name><depth>0</depth></input>\n"
  149. frag_src += "float metallic = texture(metallicTex, uv).r;\n"
  150. fname += "metalt_"
  151. elif wheel[METALLIC] == INPUT_CONST:
  152. frag_ins += "\t\t\t\t<input><type>float</type><name>metallic</name><const>1</const><depth>0</depth></input>\n"
  153. fname += "metalc_"
  154. else:
  155. assert 0
  156. if wheel[NORMAL] == INPUT_TEXTURE:
  157. frag_ins += "\t\t\t\t<input><type>sampler2D</type><name>normalTex</name><depth>0</depth></input>\n"
  158. frag_src += "vec3 normal = readNormalFromTexture(normalTex, uv);\n"
  159. fname += "normalt_"
  160. elif wheel[NORMAL] == INPUT_NONE:
  161. frag_src += "vec3 normal = in_normal;\n"
  162. fname += "normal0_"
  163. else:
  164. assert 0
  165. if wheel[EMISSION] == INPUT_TEXTURE:
  166. frag_ins += "\t\t\t\t<input><type>sampler2D</type><name>emissionTex</name><depth>0</depth></input>\n"
  167. frag_src += "vec3 emission = texture(emissionTex, uv).rgb;\n"
  168. fname += "emist_"
  169. elif wheel[EMISSION] == INPUT_CONST:
  170. frag_ins += "\t\t\t\t<input><type>vec3</type><name>emission</name><const>1</const><depth>0</depth></input>\n"
  171. fname += "emisc_"
  172. else:
  173. assert 0
  174. if wheel[SUBSURFACE] == INPUT_CONST:
  175. frag_ins += "\t\t\t\t<input><type>float</type><name>subsurface</name><const>1</const><depth>0</depth></input>\n"
  176. fname += "subsc_"
  177. else:
  178. assert 0
  179. if wheel[HEIGHT] == INPUT_NONE:
  180. # nothing
  181. fname += "par0"
  182. elif wheel[HEIGHT] == INPUT_TEXTURE:
  183. frag_ins += "\t\t\t\t<input><type>sampler2D</type><name>heightTex</name><depth>0</depth></input>\n"
  184. fname += "par1"
  185. else:
  186. assert 0
  187. frag_src += "writeRts(diffColor, normal, specColor, roughness, subsurface, emission, metallic);\n"
  188. frag_src += "#endif\n"
  189. xml = template_xml
  190. xml = xml.replace("%vertInputs%", vert_inputs)
  191. xml = xml.replace("%vertSrc%", vert_src)
  192. xml = xml.replace("%fragInputs%", frag_ins)
  193. xml = xml.replace("%fragSrc%", frag_src)
  194. return (xml, fname)
  195. def main():
  196. """ Main function """
  197. out_dir = parse_commandline()
  198. wheel = [INPUT_NONE, INPUT_NONE, INPUT_NONE, INPUT_NONE, INPUT_NONE, INPUT_NONE, INPUT_NONE, INPUT_NONE]
  199. while(not spin_wheel(wheel)):
  200. if wheel[DIFFUSE] in allowed_permutations[DIFFUSE] \
  201. and wheel[SPECULAR] in allowed_permutations[SPECULAR] \
  202. and wheel[ROUGHNESS] in allowed_permutations[ROUGHNESS] \
  203. and wheel[METALLIC] in allowed_permutations[METALLIC] \
  204. and wheel[NORMAL] in allowed_permutations[NORMAL] \
  205. and wheel[EMISSION] in allowed_permutations[EMISSION] \
  206. and wheel[SUBSURFACE] in allowed_permutations[SUBSURFACE] \
  207. and wheel[HEIGHT] in allowed_permutations[HEIGHT]:
  208. (xml, fname) = mutate(wheel)
  209. file = open(fname + ".ankiprog", "w")
  210. file.write(xml)
  211. if __name__ == "__main__":
  212. main()