You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1061 line
30 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net>
  5. //
  6. // Lol Engine is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #include <lol/engine-internal.h>
  13. #include <lol/msg>
  14. #include <lol/pegtl>
  15. #include <../legacy/lol/base/assert.h>
  16. #include <string>
  17. #include <memory>
  18. #include <map>
  19. #include <set>
  20. #include <cstring>
  21. #include <cstdio>
  22. #if defined _WIN32
  23. # define WIN32_LEAN_AND_MEAN 1
  24. # include <windows.h>
  25. # undef WIN32_LEAN_AND_MEAN
  26. #endif
  27. #include "lolgl.h"
  28. // FIXME: fine-tune this define
  29. #if defined LOL_USE_GLEW || defined HAVE_GL_2X || defined HAVE_GLES_2X
  30. namespace lol
  31. {
  32. struct ShaderType
  33. {
  34. enum Value
  35. {
  36. Vertex = 1,
  37. Fragment,
  38. Geometry,
  39. TessControl,
  40. TessEval,
  41. }
  42. m_value;
  43. inline ShaderType(Value v) : m_value(v) {}
  44. inline ShaderType(int v) : m_value((Value)v) {}
  45. inline operator Value() { return m_value; }
  46. };
  47. static const char* attribute_names[] =
  48. {
  49. "in_Position",
  50. "in_BlendWeight",
  51. "in_BlendIndices",
  52. "in_Normal",
  53. "in_PointSize",
  54. "in_TexCoord",
  55. "in_TexCoordExt",
  56. "in_Tangent",
  57. "in_Binormal",
  58. "in_TessFactor",
  59. "in_PositionT",
  60. "in_Color",
  61. "in_Fog",
  62. "in_Depth",
  63. "in_Sample"
  64. };
  65. /*
  66. * Shader implementation class
  67. */
  68. class ShaderData
  69. {
  70. friend class Shader;
  71. private:
  72. std::string m_name;
  73. GLuint prog_id, vert_id, frag_id;
  74. // Benlitz: using a simple array could be faster since there is never more than a few attribute locations to store
  75. std::map<uint64_t, GLint> attrib_locations;
  76. std::map<uint64_t, bool> attrib_errors;
  77. size_t vert_crc, frag_crc;
  78. /* Shader patcher */
  79. static int GetVersion();
  80. static std::string Patch(std::string const &code, ShaderType type);
  81. };
  82. /* Global shader cache */
  83. static std::set<std::shared_ptr<Shader>> g_shaders;
  84. /*
  85. * LolFx parser
  86. */
  87. using namespace tao;
  88. using namespace pegtl;
  89. struct lolfx_parser
  90. {
  91. public:
  92. std::string m_section;
  93. std::map<std::string, std::string> m_programs;
  94. private:
  95. // title <- '[' (!']')+ ']' .{eol}
  96. struct do_title
  97. : plus<not_one<']'>> {};
  98. struct title
  99. : seq<one<'['>,
  100. do_title,
  101. one<']'>,
  102. until<eol, any>> {};
  103. // FIXME: I’m using this rule because the do_title above also
  104. // gets triggered when using at<> which is non-consuming.
  105. struct title_ignore
  106. : seq<one<'['>,
  107. plus<not_one<']'>>,
  108. one<']'>,
  109. until<eol, any>> {};
  110. // code_line <- .{eol}
  111. struct code_line
  112. : until<eol, any> {};
  113. // code_section < code_line{&(title / eof)}
  114. struct code_section
  115. : until<at<sor<title_ignore, pegtl::eof>>, code_line> {};
  116. // shader < title code_section
  117. struct shader
  118. : seq<title, code_section> {};
  119. // header < code_section
  120. struct header
  121. : code_section {};
  122. // lolfx < header code_section*
  123. struct lolfx
  124. : seq<header, star<shader>> {};
  125. // default action: nothing
  126. template<typename RULE>
  127. struct action : nothing<RULE> {};
  128. public:
  129. lolfx_parser(std::string const &code)
  130. : m_section("header")
  131. {
  132. string_input<> in(code, "shader");
  133. pegtl::parse<lolfx, action>(in, this);
  134. }
  135. };
  136. template<>
  137. struct lolfx_parser::action<lolfx_parser::do_title>
  138. {
  139. template<typename INPUT>
  140. static void apply(INPUT const &in, lolfx_parser *that)
  141. {
  142. that->m_section = in.string();
  143. }
  144. };
  145. template<>
  146. struct lolfx_parser::action<lolfx_parser::code_section>
  147. {
  148. template<typename INPUT>
  149. static void apply(INPUT const &in, lolfx_parser *that)
  150. {
  151. that->m_programs[that->m_section] = in.string();
  152. }
  153. };
  154. /*
  155. * Public Shader class
  156. */
  157. std::shared_ptr<Shader> Shader::Create(std::string const &name, std::string const &code)
  158. {
  159. lolfx_parser p(code);
  160. ASSERT(has_key(p.m_programs, "vert.glsl"),
  161. "no vertex shader in %s", name.c_str());
  162. ASSERT(has_key(p.m_programs, "frag.glsl"),
  163. "no fragment shader in %s", name.c_str());
  164. std::string vert = p.m_programs["vert.glsl"];
  165. std::string frag = p.m_programs["frag.glsl"];
  166. size_t new_vert_crc = std::hash<std::string>{}(vert);
  167. size_t new_frag_crc = std::hash<std::string>{}(frag);
  168. for (auto shader : g_shaders)
  169. {
  170. if (shader->data->vert_crc == new_vert_crc
  171. && shader->data->frag_crc == new_frag_crc)
  172. return shader;
  173. }
  174. // FIXME: the cache never expires!
  175. auto ret = std::make_shared<Shader>(name, vert, frag);
  176. g_shaders.insert(ret);
  177. return ret;
  178. }
  179. Shader::Shader(std::string const &name,
  180. std::string const &vert, std::string const &frag)
  181. : data(std::make_unique<ShaderData>())
  182. {
  183. data->m_name = name;
  184. char errbuf[4096];
  185. std::string shader_code;
  186. GLchar const *gl_code;
  187. GLint status;
  188. GLsizei len;
  189. /* Compile vertex shader */
  190. data->vert_crc = std::hash<std::string>{}(vert);
  191. shader_code = ShaderData::Patch(vert, ShaderType::Vertex);
  192. data->vert_id = glCreateShader(GL_VERTEX_SHADER);
  193. gl_code = shader_code.c_str();
  194. glShaderSource(data->vert_id, 1, &gl_code, nullptr);
  195. glCompileShader(data->vert_id);
  196. glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf);
  197. glGetShaderiv(data->vert_id, GL_COMPILE_STATUS, &status);
  198. if (status != GL_TRUE)
  199. {
  200. msg::error("failed to compile vertex shader %s: %s\n",
  201. name.c_str(), errbuf);
  202. msg::error("shader source:\n%s\n", shader_code.c_str());
  203. }
  204. else if (len > 16)
  205. {
  206. msg::debug("compile log for vertex shader %s: %s\n", name.c_str(), errbuf);
  207. msg::debug("shader source:\n%s\n", shader_code.c_str());
  208. }
  209. /* Compile fragment shader */
  210. data->frag_crc = std::hash<std::string>{}(frag);
  211. shader_code = ShaderData::Patch(frag, ShaderType::Fragment);
  212. data->frag_id = glCreateShader(GL_FRAGMENT_SHADER);
  213. gl_code = shader_code.c_str();
  214. glShaderSource(data->frag_id, 1, &gl_code, nullptr);
  215. glCompileShader(data->frag_id);
  216. glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf);
  217. glGetShaderiv(data->frag_id, GL_COMPILE_STATUS, &status);
  218. if (status != GL_TRUE)
  219. {
  220. msg::error("failed to compile fragment shader %s: %s\n",
  221. name.c_str(), errbuf);
  222. msg::error("shader source:\n%s\n", shader_code.c_str());
  223. }
  224. else if (len > 16)
  225. {
  226. msg::debug("compile log for fragment shader %s: %s\n",
  227. name.c_str(), errbuf);
  228. msg::debug("shader source:\n%s\n", shader_code.c_str());
  229. }
  230. /* Create program */
  231. data->prog_id = glCreateProgram();
  232. glAttachShader(data->prog_id, data->vert_id);
  233. glAttachShader(data->prog_id, data->frag_id);
  234. glLinkProgram(data->prog_id);
  235. glGetProgramInfoLog(data->prog_id, sizeof(errbuf), &len, errbuf);
  236. glGetProgramiv(data->prog_id, GL_LINK_STATUS, &status);
  237. if (status != GL_TRUE)
  238. {
  239. msg::error("failed to link program %s: %s\n", name.c_str(), errbuf);
  240. }
  241. else if (len > 16)
  242. {
  243. msg::debug("link log for program %s: %s\n", name.c_str(), errbuf);
  244. }
  245. GLint validated;
  246. glValidateProgram(data->prog_id);
  247. glGetProgramiv(data->prog_id, GL_VALIDATE_STATUS, &validated);
  248. if (validated != GL_TRUE)
  249. {
  250. msg::error("failed to validate program %s\n", name.c_str());
  251. }
  252. GLint num_attribs;
  253. glGetProgramiv(data->prog_id, GL_ACTIVE_ATTRIBUTES, &num_attribs);
  254. #if __EMSCRIPTEN__ // WebGL doesn't support GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, so chose a default size value.
  255. GLint max_len = 256;
  256. #else
  257. GLint max_len;
  258. glGetProgramiv(data->prog_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
  259. #endif
  260. char* name_buffer = new char[max_len];
  261. for (int i = 0; i < num_attribs; ++i)
  262. {
  263. int attrib_len;
  264. int attrib_size;
  265. int attrib_type;
  266. glGetActiveAttrib(data->prog_id, i, max_len, &attrib_len, (GLint*)&attrib_size, (GLenum*)&attrib_type, name_buffer);
  267. std::string attr_name(name_buffer);
  268. int index = -1;
  269. VertexUsage usage = VertexUsage::MAX;
  270. for (int j = 0; j < (int)VertexUsage::MAX; ++j)
  271. {
  272. if (starts_with(attr_name, attribute_names[j]) ||
  273. starts_with(attr_name, tolower(attribute_names[j])))
  274. {
  275. usage = VertexUsage(j);
  276. char* idx_ptr = &attr_name[0] + strlen(attribute_names[j]);
  277. index = strtol(idx_ptr, nullptr, 10);
  278. break;
  279. }
  280. }
  281. if (usage == VertexUsage::MAX || index == -1)
  282. {
  283. msg::error("unable to parse attribute semantic from name: %s\n",
  284. name_buffer);
  285. }
  286. else
  287. {
  288. GLint location = glGetAttribLocation(data->prog_id, name_buffer);
  289. uint64_t flags = (uint64_t)(uint16_t)usage.ToScalar() << 16;
  290. flags |= (uint64_t)(uint16_t)index;
  291. // TODO: this is here just in case. Remove this once everything has been correctly tested
  292. #if LOL_BUILD_DEBUG
  293. if (has_key(data->attrib_locations, flags))
  294. {
  295. msg::error("error while parsing attribute semantics in %s\n",
  296. attr_name.c_str());
  297. }
  298. #endif
  299. data->attrib_locations[flags] = location;
  300. }
  301. }
  302. delete[] name_buffer;
  303. }
  304. int Shader::GetAttribCount() const
  305. {
  306. return (int)data->attrib_locations.size();
  307. }
  308. ShaderAttrib Shader::GetAttribLocation(VertexUsage usage, int index) const
  309. {
  310. ShaderAttrib ret;
  311. ret.m_flags = (uint64_t)(uint16_t)usage.ToScalar() << 16;
  312. ret.m_flags |= (uint64_t)(uint16_t)index;
  313. GLint l = -1;
  314. if (!try_get(data->attrib_locations, ret.m_flags, l))
  315. {
  316. /* Only spit an error once, we don’t need to flood the console. */
  317. if (!has_key(data->attrib_errors, ret.m_flags))
  318. {
  319. msg::error("attribute %s not found in shader %s\n",
  320. usage.tostring().c_str(), data->m_name.c_str());
  321. data->attrib_errors[ret.m_flags] = true;
  322. }
  323. }
  324. ret.m_flags |= (uint64_t)(uint32_t)l << 32;
  325. return ret;
  326. }
  327. ShaderUniform Shader::GetUniformLocation(std::string const& uni) const
  328. {
  329. return GetUniformLocation(uni.c_str());
  330. }
  331. ShaderUniform Shader::GetUniformLocation(char const *uni) const
  332. {
  333. ShaderUniform ret;
  334. ret.frag = (uintptr_t)glGetUniformLocation(data->prog_id, uni);
  335. ret.vert = 0;
  336. return ret;
  337. }
  338. /*
  339. * Uniform setters for scalars
  340. */
  341. void Shader::SetUniform(ShaderUniform const &uni, int i)
  342. {
  343. glUniform1i((GLint)uni.frag, i);
  344. }
  345. void Shader::SetUniform(ShaderUniform const &uni, ivec2 const &v)
  346. {
  347. glUniform2i((GLint)uni.frag, v.x, v.y);
  348. }
  349. void Shader::SetUniform(ShaderUniform const &uni, ivec3 const &v)
  350. {
  351. glUniform3i((GLint)uni.frag, v.x, v.y, v.z);
  352. }
  353. void Shader::SetUniform(ShaderUniform const &uni, ivec4 const &v)
  354. {
  355. glUniform4i((GLint)uni.frag, v.x, v.y, v.z, v.w);
  356. }
  357. void Shader::SetUniform(ShaderUniform const &uni, float f)
  358. {
  359. glUniform1f((GLint)uni.frag, f);
  360. }
  361. void Shader::SetUniform(ShaderUniform const &uni, vec2 const &v)
  362. {
  363. glUniform2fv((GLint)uni.frag, 1, &v[0]);
  364. }
  365. void Shader::SetUniform(ShaderUniform const &uni, vec3 const &v)
  366. {
  367. glUniform3fv((GLint)uni.frag, 1, &v[0]);
  368. }
  369. void Shader::SetUniform(ShaderUniform const &uni, vec4 const &v)
  370. {
  371. glUniform4fv((GLint)uni.frag, 1, &v[0]);
  372. }
  373. void Shader::SetUniform(ShaderUniform const &uni, mat2 const &m)
  374. {
  375. glUniformMatrix2fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]);
  376. }
  377. void Shader::SetUniform(ShaderUniform const &uni, mat3 const &m)
  378. {
  379. glUniformMatrix3fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]);
  380. }
  381. void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m)
  382. {
  383. glUniformMatrix4fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]);
  384. }
  385. void Shader::SetUniform(ShaderUniform const &uni, TextureUniform tex, int index)
  386. {
  387. glActiveTexture(GL_TEXTURE0 + index);
  388. glBindTexture(GL_TEXTURE_2D, (int)tex.m_flags);
  389. SetUniform(uni, index);
  390. }
  391. /*
  392. * Uniform setters for arrays
  393. */
  394. void Shader::SetUniform(ShaderUniform const &uni, std::vector<float> const &v)
  395. {
  396. glUniform1fv((GLint)uni.frag, (GLsizei)v.size(), &v[0]);
  397. }
  398. void Shader::SetUniform(ShaderUniform const &uni, std::vector<vec2> const &v)
  399. {
  400. glUniform2fv((GLint)uni.frag, (GLsizei)v.size(), &v[0][0]);
  401. }
  402. void Shader::SetUniform(ShaderUniform const &uni, std::vector<vec3> const &v)
  403. {
  404. glUniform3fv((GLint)uni.frag, (GLsizei)v.size(), &v[0][0]);
  405. }
  406. void Shader::SetUniform(ShaderUniform const &uni, std::vector<vec4> const &v)
  407. {
  408. glUniform4fv((GLint)uni.frag, (GLsizei)v.size(), &v[0][0]);
  409. }
  410. void Shader::Bind() const
  411. {
  412. glUseProgram(data->prog_id);
  413. }
  414. void Shader::Unbind() const
  415. {
  416. /* FIXME: untested */
  417. glUseProgram(0);
  418. }
  419. Shader::~Shader()
  420. {
  421. glDetachShader(data->prog_id, data->vert_id);
  422. glDetachShader(data->prog_id, data->frag_id);
  423. glDeleteShader(data->vert_id);
  424. glDeleteShader(data->frag_id);
  425. glDeleteProgram(data->prog_id);
  426. }
  427. /* Try to detect shader compiler features */
  428. int ShaderData::GetVersion()
  429. {
  430. static int version = 0;
  431. if (!version)
  432. {
  433. #if defined HAVE_GLES_2X
  434. /* GLES 2.x supports #version 100, that's all. */
  435. return 100;
  436. #else
  437. char buf[4096];
  438. GLsizei len;
  439. int id = glCreateShader(GL_VERTEX_SHADER);
  440. /* Can we compile 1.30 shaders? */
  441. char const *test130 =
  442. "#version 130\n"
  443. "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
  444. glShaderSource(id, 1, &test130, nullptr);
  445. glCompileShader(id);
  446. glGetShaderInfoLog(id, sizeof(buf), &len, buf);
  447. if (len <= 0)
  448. version = 130;
  449. /* If not, can we compile 1.20 shaders? */
  450. if (!version)
  451. {
  452. char const *test120 =
  453. "#version 120\n"
  454. "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
  455. glShaderSource(id, 1, &test120, nullptr);
  456. glCompileShader(id);
  457. glGetShaderInfoLog(id, sizeof(buf), &len, buf);
  458. if (len <= 0)
  459. version = 120;
  460. }
  461. /* Otherwise, assume we can compile 1.10 shaders. */
  462. if (!version)
  463. version = 110;
  464. glDeleteShader(id);
  465. #endif
  466. }
  467. return version;
  468. }
  469. /*
  470. * Simple shader source patching for old GLSL versions.
  471. */
  472. std::string ShaderData::Patch(std::string const &code, ShaderType type)
  473. {
  474. int ver_driver = GetVersion();
  475. std::string patched_code = code;
  476. if (ver_driver >= 130)
  477. return patched_code;
  478. /* FIXME: use std::string instead of char * for parsing? */
  479. int ver_shader = 110;
  480. char *parser = strstr(&patched_code[0], "#version");
  481. if (parser)
  482. ver_shader = atoi(parser + strlen("#version"));
  483. /* This is GL ES, we only know version 100. */
  484. if (ver_shader > 100 && ver_driver == 100)
  485. {
  486. /* FIXME: this isn't elegant but honestly, we don't care, this
  487. * whole file is going to die soon. */
  488. char *p = strstr(&patched_code[0], "#version");
  489. if (p)
  490. {
  491. p += 8;
  492. while (*p == ' ')
  493. p++;
  494. if (p[0] == '1' && p[1] && p[2])
  495. p[1] = p[2] = '0';
  496. }
  497. }
  498. if (ver_shader > 120 && ver_driver <= 120)
  499. {
  500. char const *end = patched_code.c_str() + patched_code.length() + 1;
  501. /* Find main() */
  502. parser = strstr(&patched_code[0], "main");
  503. if (!parser) return patched_code;
  504. parser = strstr(parser, "(");
  505. if (!parser) return patched_code;
  506. parser = strstr(parser, ")");
  507. if (!parser) return patched_code;
  508. parser = strstr(parser, "{");
  509. if (!parser) return patched_code;
  510. char *main = parser + 1;
  511. /* Perform main() replaces */
  512. char const * const main_replaces[] =
  513. {
  514. #if 0
  515. "in vec2 in_Vertex;", "vec2 in_Vertex = gl_Vertex.xy;",
  516. "in vec3 in_Vertex;", "vec3 in_Vertex = gl_Vertex.xyz;",
  517. "in vec4 in_Vertex;", "vec4 in_Vertex = gl_Vertex.xyzw;",
  518. "in vec2 in_Color;", "vec2 in_Color = gl_Color.xy;",
  519. "in vec3 in_Color;", "vec3 in_Color = gl_Color.xyz;",
  520. "in vec4 in_Color;", "vec4 in_Color = gl_Color.xyzw;",
  521. "in vec2 in_MultiTexCoord0;",
  522. "vec2 in_MultiTexCoord0 = gl_MultiTexCoord0.xy;",
  523. "in vec2 in_MultiTexCoord1;",
  524. "vec2 in_MultiTexCoord1 = gl_MultiTexCoord1.xy;",
  525. "in vec2 in_MultiTexCoord2;",
  526. "vec2 in_MultiTexCoord2 = gl_MultiTexCoord2.xy;",
  527. "in vec2 in_MultiTexCoord3;",
  528. "vec2 in_MultiTexCoord3 = gl_MultiTexCoord3.xy;",
  529. "in vec2 in_MultiTexCoord4;",
  530. "vec2 in_MultiTexCoord4 = gl_MultiTexCoord4.xy;",
  531. "in vec2 in_MultiTexCoord5;",
  532. "vec2 in_MultiTexCoord5 = gl_MultiTexCoord5.xy;",
  533. "in vec2 in_MultiTexCoord6;",
  534. "vec2 in_MultiTexCoord6 = gl_MultiTexCoord6.xy;",
  535. "in vec2 in_MultiTexCoord7;",
  536. "vec2 in_MultiTexCoord7 = gl_MultiTexCoord7.xy;",
  537. #endif
  538. nullptr
  539. };
  540. for (char const * const *rep = main_replaces; rep[0]; rep += 2)
  541. {
  542. char *match = strstr(&patched_code[0], rep[0]);
  543. if (match && match < main)
  544. {
  545. size_t l0 = strlen(rep[0]);
  546. size_t l1 = strlen(rep[1]);
  547. memmove(main + l1, main, end - main);
  548. memcpy(main, rep[1], l1);
  549. memset(match, ' ', l0);
  550. main += l1;
  551. end += l1;
  552. }
  553. }
  554. /* Perform small replaces */
  555. char const * const fast_replaces[] =
  556. {
  557. #if __APPLE__
  558. "#version 130", "#version 150",
  559. "texture2D", "texture",
  560. #else
  561. "#version 130", "#version 120",
  562. "out vec4 out_color;", " ",
  563. "out_color =", "gl_FragColor =",
  564. "in vec2", type == ShaderType::Vertex ? "attribute vec2" : "varying vec2",
  565. "in vec3", type == ShaderType::Vertex ? "attribute vec3" : "varying vec3",
  566. "in vec4", type == ShaderType::Vertex ? "attribute vec4" : "varying vec4",
  567. "in mat4", type == ShaderType::Vertex ? "attribute mat4" : "varying mat4",
  568. "out vec2", "varying vec2",
  569. "out vec3", "varying vec3",
  570. "out vec4", "varying vec4",
  571. "out mat4", "varying mat4",
  572. #endif
  573. nullptr
  574. };
  575. for (char const * const *rep = fast_replaces; rep[0]; rep += 2)
  576. {
  577. while (true)
  578. {
  579. size_t index = patched_code.find(rep[0]);
  580. if (index == std::string::npos)
  581. break;
  582. size_t l0 = strlen(rep[0]);
  583. size_t l1 = strlen(rep[1]);
  584. UNUSED(l1);
  585. std::string left = patched_code.substr(0, index);
  586. std::string right = patched_code.substr(index + l0, patched_code.length() - (index + l0));
  587. patched_code = left + std::string(rep[1]) + right;
  588. }
  589. }
  590. }
  591. return patched_code;
  592. }
  593. //----
  594. std::string Shader::GetVariablePrefix(const ShaderVariable variable)
  595. {
  596. switch (variable.ToScalar())
  597. {
  598. case ShaderVariable::Attribute: return "in_";
  599. case ShaderVariable::Uniform: return "u_";
  600. case ShaderVariable::Varying: return "pass_";
  601. case ShaderVariable::InOut:
  602. default: return "";
  603. }
  604. }
  605. //----
  606. std::string Shader::GetVariableQualifier(const ShaderVariable variable)
  607. {
  608. switch (variable.ToScalar())
  609. {
  610. case ShaderVariable::Attribute: return "attribute";
  611. case ShaderVariable::Uniform: return "uniform";
  612. case ShaderVariable::Varying: return "varying";
  613. case ShaderVariable::InOut:
  614. default: return "";
  615. }
  616. }
  617. //----
  618. std::string Shader::GetFunctionQualifier(const ShaderVariable variable, const ShaderProgram program)
  619. {
  620. switch (program.ToScalar())
  621. {
  622. case ShaderProgram::Geometry:
  623. {
  624. //TODO : L O L ----------------
  625. return "";
  626. }
  627. case ShaderProgram::Vertex:
  628. {
  629. switch (variable.ToScalar())
  630. {
  631. case ShaderVariable::Attribute: return "in";
  632. case ShaderVariable::Uniform: return "in";
  633. case ShaderVariable::Varying: return "inout";
  634. case ShaderVariable::InOut: return "inout";
  635. default: return "";
  636. }
  637. return "";
  638. }
  639. case ShaderProgram::Pixel:
  640. {
  641. switch (variable.ToScalar())
  642. {
  643. case ShaderVariable::Attribute: return "in";
  644. case ShaderVariable::Uniform: return "in";
  645. case ShaderVariable::Varying: return "in";
  646. case ShaderVariable::InOut: return "inout";
  647. default: return "";
  648. }
  649. return "";
  650. }
  651. default:
  652. {
  653. return "";
  654. }
  655. }
  656. }
  657. //----
  658. std::string Shader::GetProgramQualifier(const ShaderProgram program)
  659. {
  660. switch (program.ToScalar())
  661. {
  662. case ShaderProgram::Geometry: return ""; //TODO : L O L ---------
  663. case ShaderProgram::Vertex: return "[vert.glsl]";
  664. case ShaderProgram::Pixel: return "[frag.glsl]";
  665. default: return "";
  666. }
  667. }
  668. //----
  669. std::string Shader::GetProgramOutVariable(const ShaderProgram program)
  670. {
  671. switch (program.ToScalar())
  672. {
  673. case ShaderProgram::Geometry: return ""; //TODO : L O L ---------
  674. case ShaderProgram::Vertex: return "gl_Position";
  675. case ShaderProgram::Pixel: return "gl_FragColor";
  676. default: return "";
  677. }
  678. }
  679. //----
  680. std::string Shader::GetProgramOutVariableLocal(const ShaderProgram program)
  681. {
  682. switch (program.ToScalar())
  683. {
  684. case ShaderProgram::Geometry: return ""; //TODO : L O L ---------
  685. case ShaderProgram::Vertex: return "out_position";
  686. case ShaderProgram::Pixel: return "out_frag_color";
  687. default: return "";
  688. }
  689. }
  690. //ShaderVar -------------------------------------------------------------------
  691. ShaderVar ShaderVar::GetShaderOut(ShaderProgram program)
  692. {
  693. switch (program.ToScalar())
  694. {
  695. case ShaderProgram::Geometry: //TODO : L O L ------------------------------
  696. default: ASSERT(false); return ShaderVar();
  697. case ShaderProgram::Vertex: return ShaderVar(ShaderVariable::InOut, ShaderVariableType::Vec4, Shader::GetProgramOutVariableLocal(program));
  698. case ShaderProgram::Pixel: return ShaderVar(ShaderVariable::InOut, ShaderVariableType::Vec4, Shader::GetProgramOutVariableLocal(program));
  699. }
  700. }
  701. //Shader Block implementation class -------------------------------------------
  702. void ShaderBlock::AddVar(ShaderVar const& var)
  703. {
  704. ShaderVariable qualifier = var.GetQualifier();
  705. std::string type = var.GetType();
  706. std::string name = Shader::GetVariablePrefix(qualifier) + var.m_name;
  707. ASSERT(!has_key(m_parameters[qualifier.ToScalar()], name));
  708. m_parameters[qualifier.ToScalar()][name] = type;
  709. }
  710. //----
  711. void ShaderBlock::AddCallParameters(std::map<std::string, std::string> const& variables, std::string& result)
  712. {
  713. for (auto const &key : variables)
  714. {
  715. if (result.length() > 0)
  716. result += ", ";
  717. result += key.first;
  718. }
  719. }
  720. //----
  721. void ShaderBlock::AddDefinitionParameters(const ShaderVariable type, const ShaderProgram program, std::map<std::string, std::string>& variables, std::string& result)
  722. {
  723. for (auto const &key : variables)
  724. {
  725. if (result.length() > 0)
  726. result += ", ";
  727. result += Shader::GetFunctionQualifier(type, program) + " ";
  728. result += key.second;
  729. result += " ";
  730. result += key.first;
  731. }
  732. }
  733. //----
  734. void ShaderBlock::Build(const ShaderProgram program, std::string& call, std::string& function)
  735. {
  736. ASSERT(m_name.length());
  737. ASSERT(m_parameters[ShaderVariable::InOut].size());
  738. //Build call in main
  739. std::string call_name = std::string("Call_") + m_name;
  740. call = call_name + "(";
  741. std::string call_parameters;
  742. for (int i = 0; i < ShaderVariable::MAX; i++)
  743. AddCallParameters(/*(ShaderVariable)i, */m_parameters[i], call_parameters);
  744. call += call_parameters + ");";
  745. //Build function declaration
  746. function = std::string("void ") + call_name + "(";
  747. std::string def_parameters;
  748. for (int i = 0; i < ShaderVariable::MAX; i++)
  749. AddDefinitionParameters((ShaderVariable)i, program, m_parameters[i], def_parameters);
  750. function += def_parameters + ")\n{\n"
  751. + m_code_main + (ends_with(m_code_main, "\n") ? std::string() : "\n") +
  752. "}";
  753. }
  754. //Shader Builder implementation class -----------------------------------------
  755. ShaderBuilder::ShaderBuilder(std::string const& name, std::string const& version)
  756. : m_name(name), m_version(version)
  757. {
  758. ASSERT(name.length());
  759. ASSERT(version.length());
  760. }
  761. //----
  762. ShaderBuilder::~ShaderBuilder()
  763. {
  764. }
  765. //----
  766. std::string const& ShaderBuilder::GetName()
  767. {
  768. return m_name;
  769. }
  770. //----
  771. ShaderBuilder& ShaderBuilder::operator<<(const ShaderProgram program)
  772. {
  773. m_current_program = program;
  774. return *this;
  775. }
  776. //----
  777. ShaderBuilder& ShaderBuilder::operator<<(ShaderBlock* new_block)
  778. {
  779. ASSERT(m_current_program != ShaderProgram::MAX);
  780. for (auto const block : m_blocks[m_current_program.ToScalar()])
  781. if (block == new_block)
  782. return *this;
  783. m_blocks[m_current_program.ToScalar()].push_back(new_block);
  784. return *this;
  785. }
  786. //----
  787. ShaderBuilder& ShaderBuilder::operator<<(ShaderBlock const& block)
  788. {
  789. ASSERT(m_current_program != ShaderProgram::MAX);
  790. m_blocks[m_current_program.ToScalar()].push_back(new ShaderBlock(block));
  791. return *this;
  792. }
  793. //----
  794. std::string ShaderBuilder::AddSlotOutVariableLocal(const ShaderProgram program)
  795. {
  796. ShaderVariable var = ShaderVariable::InOut;
  797. std::string result = Shader::GetProgramOutVariableLocal(program);
  798. switch (program.ToScalar())
  799. {
  800. case ShaderProgram::Geometry:
  801. {
  802. //TODO : L O L ----------------
  803. break;
  804. }
  805. case ShaderProgram::Vertex:
  806. {
  807. m_parameters[program.ToScalar()][var.ToScalar()][result] = "vec4";
  808. break;
  809. }
  810. case ShaderProgram::Pixel:
  811. {
  812. m_parameters[program.ToScalar()][var.ToScalar()][result] = "vec4";
  813. break;
  814. }
  815. default:
  816. {
  817. break;
  818. }
  819. }
  820. return result;
  821. }
  822. //----
  823. void ShaderBuilder::MergeParameters(std::map<std::string, std::string>& variables, std::map<std::string, std::string>& merged)
  824. {
  825. for (auto const &key : variables)
  826. {
  827. bool has_param = has_key(merged, key.first);
  828. //Key exists, check the type to make sure it's the same
  829. ASSERT(!has_param || (has_param && merged[key.first] == variables[key.first]),
  830. "has_param=%d, key=%s merged[key]=%s, variables[key]=%s\n",
  831. (int)has_param, key.first.c_str(), merged[key.first].c_str(), key.second.c_str());
  832. //does not exist, had it
  833. if (!has_param)
  834. merged[key.first] = key.second;
  835. }
  836. }
  837. //----
  838. std::string ShaderBuilder::Build()
  839. {
  840. std::string code;
  841. //Cleanup first
  842. for (int prog = 0; prog < ShaderProgram::MAX; prog++)
  843. for (int var = 0; var < ShaderVariable::MAX; var++)
  844. m_parameters[prog][var].clear();
  845. //Start building
  846. for (int prog = 0; prog < ShaderProgram::MAX; prog++)
  847. {
  848. //Add default local out in merged variables
  849. std::string out_local_var = AddSlotOutVariableLocal((ShaderProgram)prog);
  850. if (!out_local_var.length())
  851. continue;
  852. //Merge all variables
  853. for (int var = 0; var < ShaderVariable::MAX; var++)
  854. for (auto *block : m_blocks[prog])
  855. MergeParameters(block->m_parameters[var], m_parameters[prog][var]);
  856. //Actually write code
  857. code += Shader::GetProgramQualifier((ShaderProgram)prog) + "\n";
  858. //Add actual code
  859. code += std::string("#version ") + m_version + "\n\n";
  860. // Safety for GLES
  861. code += "#if defined GL_ES\nprecision mediump float;\n#endif\n";
  862. //Added shader variables
  863. for (int var = 0; var < ShaderVariable::InOut; var++)
  864. {
  865. auto all_keys = keys(m_parameters[prog][var]);
  866. if (all_keys.size())
  867. {
  868. code += std::string("//- ") + Shader::GetVariableQualifier((ShaderVariable)var) + " ----\n";
  869. for (auto const &key : all_keys)
  870. {
  871. code += Shader::GetVariableQualifier((ShaderVariable)var) + " ";
  872. code += m_parameters[prog][var][key] + " " + key + ";\n";
  873. }
  874. if (var + 1 < ShaderVariable::InOut)
  875. code += "\n";
  876. }
  877. }
  878. code += "\n";
  879. //Build Blocks code and add it
  880. std::vector<std::string> calls;
  881. for (auto *block : m_blocks[prog])
  882. {
  883. std::string call;
  884. std::string function;
  885. block->Build(ShaderProgram(prog), call, function);
  886. calls.push_back(call);
  887. if (block->m_code_custom.length())
  888. {
  889. code += std::string("//- ") + block->GetName() + " custom code ----\n";
  890. code += block->m_code_custom + "\n\n";
  891. }
  892. code += std::string("//- ") + block->GetName() + " main code ----\n";
  893. code += function + "\n\n";
  894. }
  895. //Added main definition
  896. code += "//- Main ----\nvoid main(void)\n{\n";
  897. //Add local variables
  898. int var = ShaderVariable::InOut;
  899. auto all_keys = keys(m_parameters[prog][var]);
  900. for (auto const &key : all_keys)
  901. code += " " + m_parameters[prog][var][key] + " " + key + ";\n";
  902. code += "\n";
  903. //Add calls
  904. code += "//- Calls ----\n";
  905. for (auto const &call : calls)
  906. code += " " + call + "\n";
  907. code += "\n";
  908. code += " " + Shader::GetProgramOutVariable((ShaderProgram)prog) + " = " + out_local_var + ";\n}\n\n";
  909. }
  910. return code;
  911. }
  912. } /* namespace lol */
  913. #endif