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.
 
 
 

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