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.
 
 
 

1058 regels
30 KiB

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