Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

787 řádky
22 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstring>
  14. #include <cstdio>
  15. #ifdef WIN32
  16. # define WIN32_LEAN_AND_MEAN
  17. # include <windows.h>
  18. # if defined USE_D3D9
  19. # include <algorithm>
  20. using std::min;
  21. using std::max;
  22. # include <d3d9.h>
  23. # include <d3dx9shader.h>
  24. # endif
  25. #endif
  26. #include "core.h"
  27. #include "lolgl.h"
  28. using namespace std;
  29. #if defined USE_D3D9
  30. extern IDirect3DDevice9 *g_d3ddevice;
  31. #elif defined _XBOX
  32. extern D3DDevice *g_d3ddevice;
  33. #endif
  34. namespace lol
  35. {
  36. /*
  37. * Shader implementation class
  38. */
  39. class ShaderData
  40. {
  41. friend class Shader;
  42. private:
  43. #if defined USE_D3D9
  44. IDirect3DVertexShader9 *vert_shader;
  45. IDirect3DPixelShader9 *frag_shader;
  46. ID3DXConstantTable *vert_table, *frag_table;
  47. #elif defined _XBOX
  48. D3DVertexShader *vert_shader;
  49. D3DPixelShader *frag_shader;
  50. ID3DXConstantTable *vert_table, *frag_table;
  51. #elif !defined __CELLOS_LV2__
  52. GLuint prog_id, vert_id, frag_id;
  53. #else
  54. CGprogram vert_id, frag_id;
  55. #endif
  56. uint32_t vert_crc, frag_crc;
  57. /* Shader patcher */
  58. static int GetVersion();
  59. static void Patch(char *dst, char const *vert, char const *frag);
  60. /* Global shader cache */
  61. static Shader *shaders[];
  62. static int nshaders;
  63. };
  64. Shader *ShaderData::shaders[256];
  65. int ShaderData::nshaders = 0;
  66. /*
  67. * Public Shader class
  68. */
  69. Shader *Shader::Create(char const *lolfx)
  70. {
  71. char *src = new char[strlen(lolfx) + 2];
  72. memcpy(src + 1, lolfx, strlen(lolfx) + 1);
  73. src[0] = '\n';
  74. /* Parse the crap */
  75. Array<char const *, char const *> sections;
  76. char *key = NULL;
  77. for (char *parser = src; *parser; )
  78. {
  79. if (key == NULL && (parser[0] == '\n' || parser[0] == '\r')
  80. && parser[1] == '-' && parser[2] == '-' && parser[3] == ' ')
  81. {
  82. *parser = '\0';
  83. parser += 4;
  84. key = parser;
  85. }
  86. else if (key && parser[0] == ' ')
  87. {
  88. *parser++ = '\0';
  89. }
  90. else if (key && (parser[0] == '\n' || parser[0] == '\r'))
  91. {
  92. sections.Push(key, parser);
  93. parser++;
  94. key = NULL;
  95. }
  96. else
  97. {
  98. parser++;
  99. }
  100. }
  101. char const *vert = NULL, *frag = NULL;
  102. for (int i = 0; i < sections.Count(); i++)
  103. {
  104. #if !defined __CELLOS_LV2__ && !defined _XBOX && !defined USE_D3D9
  105. if (!strcmp(sections[i].m1, "GLSL.Vert"))
  106. vert = sections[i].m2;
  107. if (!strcmp(sections[i].m1, "GLSL.Frag"))
  108. frag = sections[i].m2;
  109. #else
  110. if (!strcmp(sections[i].m1, "HLSL.Vert"))
  111. vert = sections[i].m2;
  112. if (!strcmp(sections[i].m1, "HLSL.Frag"))
  113. frag = sections[i].m2;
  114. #endif
  115. }
  116. Shader *ret = NULL;
  117. if (vert && frag)
  118. ret = Create(vert, frag);
  119. delete[] src;
  120. return ret;
  121. }
  122. Shader *Shader::Create(char const *vert, char const *frag)
  123. {
  124. uint32_t new_vert_crc = Hash::Crc32(vert);
  125. uint32_t new_frag_crc = Hash::Crc32(frag);
  126. for (int n = 0; n < ShaderData::nshaders; n++)
  127. {
  128. if (ShaderData::shaders[n]->data->vert_crc == new_vert_crc
  129. && ShaderData::shaders[n]->data->frag_crc == new_frag_crc)
  130. return ShaderData::shaders[n];
  131. }
  132. Shader *ret = new Shader(vert, frag);
  133. ShaderData::shaders[ShaderData::nshaders] = ret;
  134. ShaderData::nshaders++;
  135. return ret;
  136. }
  137. void Shader::Destroy(Shader *shader)
  138. {
  139. /* XXX: do nothing! the shader should remain in cache */
  140. (void)shader;
  141. }
  142. Shader::Shader(char const *vert, char const *frag)
  143. : data(new ShaderData())
  144. {
  145. #if defined USE_D3D9 || defined _XBOX
  146. ID3DXBuffer *shader_code, *error_msg;
  147. HRESULT hr;
  148. D3DXMACRO macros[] =
  149. {
  150. #if defined _XBOX
  151. { "_XBOX", "1" },
  152. #endif
  153. { NULL, NULL }
  154. };
  155. #elif !defined __CELLOS_LV2__
  156. char buf[4096], errbuf[4096];
  157. char const *shader = buf;
  158. GLint status;
  159. GLsizei len;
  160. #else
  161. /* Initialise the runtime shader compiler. FIXME: this needs only
  162. * to be done once. */
  163. cgRTCgcInit();
  164. #endif
  165. /* Compile vertex shader */
  166. data->vert_crc = Hash::Crc32(vert);
  167. #if defined USE_D3D9 || defined _XBOX
  168. hr = D3DXCompileShader(vert, (UINT)strlen(vert), macros, NULL, "main",
  169. "vs_2_0", 0, &shader_code, &error_msg,
  170. &data->vert_table);
  171. if (FAILED(hr))
  172. {
  173. Log::Error("failed to compile vertex shader: %s",
  174. error_msg ? error_msg->GetBufferPointer() : "error");
  175. Log::Error("shader source:\n%s\n", vert);
  176. }
  177. g_d3ddevice->CreateVertexShader((DWORD *)shader_code->GetBufferPointer(),
  178. &data->vert_shader);
  179. shader_code->Release();
  180. #elif !defined __CELLOS_LV2__
  181. ShaderData::Patch(buf, vert, NULL);
  182. data->vert_id = glCreateShader(GL_VERTEX_SHADER);
  183. glShaderSource(data->vert_id, 1, &shader, NULL);
  184. glCompileShader(data->vert_id);
  185. glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf);
  186. glGetShaderiv(data->vert_id, GL_COMPILE_STATUS, &status);
  187. if (status != GL_TRUE)
  188. {
  189. Log::Error("failed to compile vertex shader: %s", errbuf);
  190. Log::Error("shader source:\n%s\n", buf);
  191. }
  192. else if (len > 16)
  193. {
  194. Log::Debug("compile log for vertex shader: %s", errbuf);
  195. Log::Debug("shader source:\n%s\n", buf);
  196. }
  197. #else
  198. data->vert_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, vert,
  199. cgGLGetLatestProfile(CG_GL_VERTEX),
  200. NULL, NULL);
  201. if (data->vert_id == NULL)
  202. {
  203. Log::Error("failed to compile vertex shader");
  204. Log::Error("shader source:\n%s\n", vert);
  205. }
  206. #endif
  207. /* Compile fragment shader */
  208. data->frag_crc = Hash::Crc32(frag);
  209. #if defined USE_D3D9 || defined _XBOX
  210. hr = D3DXCompileShader(frag, (UINT)strlen(frag), macros, NULL, "main",
  211. "ps_2_0", 0, &shader_code, &error_msg,
  212. &data->frag_table);
  213. if (FAILED(hr))
  214. {
  215. Log::Error("failed to compile fragment shader: %s",
  216. error_msg ? error_msg->GetBufferPointer() : "error");
  217. Log::Error("shader source:\n%s\n", frag);
  218. }
  219. g_d3ddevice->CreatePixelShader((DWORD *)shader_code->GetBufferPointer(),
  220. &data->frag_shader);
  221. shader_code->Release();
  222. #elif !defined __CELLOS_LV2__
  223. ShaderData::Patch(buf, NULL, frag);
  224. data->frag_id = glCreateShader(GL_FRAGMENT_SHADER);
  225. glShaderSource(data->frag_id, 1, &shader, NULL);
  226. glCompileShader(data->frag_id);
  227. glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf);
  228. glGetShaderiv(data->frag_id, GL_COMPILE_STATUS, &status);
  229. if (status != GL_TRUE)
  230. {
  231. Log::Error("failed to compile fragment shader: %s", errbuf);
  232. Log::Error("shader source:\n%s\n", buf);
  233. }
  234. else if (len > 16)
  235. {
  236. Log::Debug("compile log for fragment shader: %s", errbuf);
  237. Log::Debug("shader source:\n%s\n", buf);
  238. }
  239. #else
  240. data->frag_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, frag,
  241. cgGLGetLatestProfile(CG_GL_FRAGMENT),
  242. NULL, NULL);
  243. if (data->frag_id == NULL)
  244. {
  245. Log::Error("failed to compile fragment shader");
  246. Log::Error("shader source:\n%s\n", frag);
  247. }
  248. #endif
  249. #if defined USE_D3D9 || defined _XBOX
  250. /* FIXME: this is only debug code, we don't need it. */
  251. D3DXCONSTANTTABLE_DESC desc;
  252. data->frag_table->GetDesc(&desc);
  253. for (int i = 0; i < desc.Constants; i++)
  254. {
  255. D3DXCONSTANT_DESC cdesc;
  256. UINT count = 1;
  257. D3DXHANDLE h = data->frag_table->GetConstant(NULL, i);
  258. data->frag_table->GetConstantDesc(h, &cdesc, &count);
  259. }
  260. data->vert_table->GetDesc(&desc);
  261. for (int i = 0; i < desc.Constants; i++)
  262. {
  263. D3DXCONSTANT_DESC cdesc;
  264. UINT count = 1;
  265. D3DXHANDLE h = data->vert_table->GetConstant(NULL, i);
  266. data->frag_table->GetConstantDesc(h, &cdesc, &count);
  267. }
  268. #elif !defined __CELLOS_LV2__
  269. /* Create program */
  270. data->prog_id = glCreateProgram();
  271. glAttachShader(data->prog_id, data->vert_id);
  272. glAttachShader(data->prog_id, data->frag_id);
  273. glLinkProgram(data->prog_id);
  274. glGetProgramInfoLog(data->prog_id, sizeof(errbuf), &len, errbuf);
  275. glGetProgramiv(data->prog_id, GL_LINK_STATUS, &status);
  276. if (status != GL_TRUE)
  277. {
  278. Log::Error("failed to link program: %s", errbuf);
  279. }
  280. else if (len > 16)
  281. {
  282. Log::Debug("link log for program: %s", errbuf);
  283. }
  284. glValidateProgram(data->prog_id);
  285. #endif
  286. }
  287. ShaderAttrib Shader::GetAttribLocation(char const *attr,
  288. VertexUsage usage, int index) const
  289. {
  290. ShaderAttrib ret;
  291. ret.m_flags = (uint64_t)(uint16_t)usage << 16;
  292. ret.m_flags |= (uint64_t)(uint16_t)index;
  293. #if defined USE_D3D9 || defined _XBOX
  294. #elif !defined __CELLOS_LV2__
  295. ret.m_flags |= (uint64_t)
  296. (uint32_t)glGetAttribLocation(data->prog_id, attr) << 32;
  297. #else
  298. /* FIXME: can we do this at all on the PS3? */
  299. #endif
  300. return ret;
  301. }
  302. ShaderUniform Shader::GetUniformLocation(char const *uni) const
  303. {
  304. ShaderUniform ret;
  305. #if defined USE_D3D9 || defined _XBOX
  306. /* Global variables are prefixed with "$" */
  307. char tmpname[128];
  308. sprintf(tmpname, "$%s", uni);
  309. D3DXCONSTANT_DESC cdesc;
  310. D3DXHANDLE hr;
  311. UINT count;
  312. count = 0;
  313. hr = data->frag_table->GetConstantByName(NULL, tmpname);
  314. if (hr)
  315. data->frag_table->GetConstantDesc(hr, &cdesc, &count);
  316. if (count)
  317. {
  318. ret.frag = cdesc.RegisterIndex;
  319. ret.flags |= 1;
  320. }
  321. count = 0;
  322. hr = data->vert_table->GetConstantByName(NULL, tmpname);
  323. if (hr)
  324. data->vert_table->GetConstantDesc(hr, &cdesc, &count);
  325. if (count)
  326. {
  327. ret.vert = cdesc.RegisterIndex;
  328. ret.flags |= 2;
  329. }
  330. #elif !defined __CELLOS_LV2__
  331. ret.frag = (uintptr_t)glGetUniformLocation(data->prog_id, uni);
  332. ret.vert = 0;
  333. #else
  334. ret.frag = (uintptr_t)cgGetNamedParameter(data->frag_id, uni);
  335. ret.vert = (uintptr_t)cgGetNamedParameter(data->vert_id, uni);
  336. #endif
  337. return ret;
  338. }
  339. void Shader::SetUniform(ShaderUniform const &uni, int i)
  340. {
  341. #if defined USE_D3D9 || defined _XBOX
  342. SetUniform(uni, ivec4(i, 0, 0, 0));
  343. #elif !defined __CELLOS_LV2__
  344. glUniform1i(uni.frag, i);
  345. #else
  346. /* FIXME: does this exist at all? cgGLSetParameter1i doesn't. */
  347. #endif
  348. }
  349. void Shader::SetUniform(ShaderUniform const &uni, ivec2 const &v)
  350. {
  351. #if defined USE_D3D9 || defined _XBOX
  352. SetUniform(uni, ivec4(v, 0, 0));
  353. #elif !defined __CELLOS_LV2__
  354. glUniform2i(uni.frag, v.x, v.y);
  355. #else
  356. /* FIXME: does this exist at all? */
  357. #endif
  358. }
  359. void Shader::SetUniform(ShaderUniform const &uni, ivec3 const &v)
  360. {
  361. #if defined USE_D3D9 || defined _XBOX
  362. SetUniform(uni, ivec4(v, 0));
  363. #elif !defined __CELLOS_LV2__
  364. glUniform3i(uni.frag, v.x, v.y, v.z);
  365. #else
  366. /* FIXME: does this exist at all? */
  367. #endif
  368. }
  369. void Shader::SetUniform(ShaderUniform const &uni, ivec4 const &v)
  370. {
  371. #if defined USE_D3D9 || defined _XBOX
  372. if (uni.flags & 1)
  373. g_d3ddevice->SetPixelShaderConstantI((UINT)uni.frag, &v[0], 1);
  374. if (uni.flags & 2)
  375. g_d3ddevice->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1);
  376. #elif !defined __CELLOS_LV2__
  377. glUniform4i(uni.frag, v.x, v.y, v.z, v.w);
  378. #else
  379. /* FIXME: does this exist at all? */
  380. #endif
  381. }
  382. void Shader::SetUniform(ShaderUniform const &uni, float f)
  383. {
  384. #if defined USE_D3D9 || defined _XBOX
  385. SetUniform(uni, vec4(f, 0, 0, 0));
  386. #elif !defined __CELLOS_LV2__
  387. glUniform1f(uni.frag, f);
  388. #else
  389. if (uni.frag)
  390. cgGLSetParameter1f((CGparameter)uni.frag, f);
  391. if (uni.vert)
  392. cgGLSetParameter1f((CGparameter)uni.vert, f);
  393. #endif
  394. }
  395. void Shader::SetUniform(ShaderUniform const &uni, vec2 const &v)
  396. {
  397. #if defined USE_D3D9 || defined _XBOX
  398. SetUniform(uni, vec4(v, 0, 0));
  399. #elif !defined __CELLOS_LV2__
  400. glUniform2fv(uni.frag, 1, &v[0]);
  401. #else
  402. if (uni.frag)
  403. cgGLSetParameter2fv((CGparameter)uni.frag, &v[0]);
  404. if (uni.vert)
  405. cgGLSetParameter2fv((CGparameter)uni.vert, &v[0]);
  406. #endif
  407. }
  408. void Shader::SetUniform(ShaderUniform const &uni, vec3 const &v)
  409. {
  410. #if defined USE_D3D9 || defined _XBOX
  411. SetUniform(uni, vec4(v, 0));
  412. #elif !defined __CELLOS_LV2__
  413. glUniform3fv(uni.frag, 1, &v[0]);
  414. #else
  415. if (uni.frag)
  416. cgGLSetParameter3fv((CGparameter)uni.frag, &v[0]);
  417. if (uni.vert)
  418. cgGLSetParameter3fv((CGparameter)uni.vert, &v[0]);
  419. #endif
  420. }
  421. void Shader::SetUniform(ShaderUniform const &uni, vec4 const &v)
  422. {
  423. #if defined USE_D3D9 || defined _XBOX
  424. if (uni.flags & 1)
  425. g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &v[0], 1);
  426. if (uni.flags & 2)
  427. g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1);
  428. #elif !defined __CELLOS_LV2__
  429. glUniform4fv(uni.frag, 1, &v[0]);
  430. #else
  431. if (uni.frag)
  432. cgGLSetParameter4fv((CGparameter)uni.frag, &v[0]);
  433. if (uni.vert)
  434. cgGLSetParameter4fv((CGparameter)uni.vert, &v[0]);
  435. #endif
  436. }
  437. void Shader::SetUniform(ShaderUniform const &uni, mat2 const &m)
  438. {
  439. #if defined USE_D3D9 || defined _XBOX
  440. /* FIXME: do we need padding here like for the mat3 version? */
  441. if (uni.flags & 1)
  442. g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 1);
  443. if (uni.flags & 2)
  444. g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1);
  445. #elif !defined __CELLOS_LV2__
  446. glUniformMatrix2fv(uni.frag, 1, GL_FALSE, &m[0][0]);
  447. #else
  448. mat4 tmp(m, 1.0f, 1.0f);
  449. if (uni.frag)
  450. cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
  451. if (uni.vert)
  452. cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
  453. #endif
  454. }
  455. void Shader::SetUniform(ShaderUniform const &uni, mat3 const &m)
  456. {
  457. #if defined USE_D3D9 || defined _XBOX
  458. /* Padding matrix columns is necessary on DirectX. We need to create
  459. * a new data structure; a 4×4 matrix will do. */
  460. mat4 tmp(m, 1.0f);
  461. if (uni.flags & 1)
  462. g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &tmp[0][0], 3);
  463. if (uni.flags & 2)
  464. g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3);
  465. #elif !defined __CELLOS_LV2__
  466. glUniformMatrix3fv(uni.frag, 1, GL_FALSE, &m[0][0]);
  467. #else
  468. /* FIXME: check it's the proper way to do this */
  469. mat4 tmp(m, 1.0f);
  470. if (uni.frag)
  471. cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
  472. if (uni.vert)
  473. cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
  474. #endif
  475. }
  476. void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m)
  477. {
  478. #if defined USE_D3D9 || defined _XBOX
  479. if (uni.flags & 1)
  480. g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 4);
  481. if (uni.flags & 2)
  482. g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4);
  483. #elif !defined __CELLOS_LV2__
  484. glUniformMatrix4fv(uni.frag, 1, GL_FALSE, &m[0][0]);
  485. #else
  486. if (uni.frag)
  487. cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
  488. if (uni.vert)
  489. cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
  490. #endif
  491. }
  492. void Shader::SetTexture(ShaderUniform const &uni, int id, int index)
  493. {
  494. #if defined USE_D3D9 || defined _XBOX
  495. /* FIXME: unimplemented */
  496. #elif !defined __CELLOS_LV2__
  497. glActiveTexture(GL_TEXTURE0 + index);
  498. //glEnable(GL_TEXTURE_2D);
  499. glBindTexture(GL_TEXTURE_2D, id);
  500. SetUniform(uni, index);
  501. #else
  502. /* FIXME: unimplemented */
  503. #endif
  504. }
  505. void Shader::Bind() const
  506. {
  507. #if defined USE_D3D9 || defined _XBOX
  508. HRESULT hr;
  509. hr = g_d3ddevice->SetVertexShader(data->vert_shader);
  510. hr = g_d3ddevice->SetPixelShader(data->frag_shader);
  511. #elif !defined __CELLOS_LV2__
  512. glUseProgram(data->prog_id);
  513. #else
  514. cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));
  515. cgGLBindProgram(data->vert_id);
  516. cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));
  517. cgGLBindProgram(data->frag_id);
  518. #endif
  519. }
  520. void Shader::Unbind() const
  521. {
  522. #if defined USE_D3D9 || defined _XBOX
  523. HRESULT hr;
  524. hr = g_d3ddevice->SetVertexShader(NULL);
  525. hr = g_d3ddevice->SetPixelShader(NULL);
  526. #elif !defined __CELLOS_LV2__
  527. /* FIXME: untested */
  528. glUseProgram(0);
  529. #else
  530. /* FIXME: untested */
  531. cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));
  532. cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));
  533. #endif
  534. }
  535. Shader::~Shader()
  536. {
  537. #if defined USE_D3D9 || defined _XBOX
  538. data->vert_shader->Release();
  539. data->vert_table->Release();
  540. data->frag_shader->Release();
  541. data->frag_table->Release();
  542. #elif !defined __CELLOS_LV2__
  543. glDetachShader(data->prog_id, data->vert_id);
  544. glDetachShader(data->prog_id, data->frag_id);
  545. glDeleteShader(data->vert_id);
  546. glDeleteShader(data->frag_id);
  547. glDeleteProgram(data->prog_id);
  548. #else
  549. cgDestroyProgram(data->vert_id);
  550. cgDestroyProgram(data->frag_id);
  551. #endif
  552. delete data;
  553. }
  554. /* Try to detect shader compiler features */
  555. int ShaderData::GetVersion()
  556. {
  557. static int version = 0;
  558. #if !defined USE_D3D9 && !defined _XBOX && !defined __CELLOS_LV2__
  559. if (!version)
  560. {
  561. #if defined HAVE_GLES_2X
  562. /* GLES 2.x supports #version 100, that's all. */
  563. return 100;
  564. #else
  565. char buf[4096];
  566. GLsizei len;
  567. int id = glCreateShader(GL_VERTEX_SHADER);
  568. /* Can we compile 1.30 shaders? */
  569. char const *test130 =
  570. "#version 130\n"
  571. "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
  572. glShaderSource(id, 1, &test130, NULL);
  573. glCompileShader(id);
  574. glGetShaderInfoLog(id, sizeof(buf), &len, buf);
  575. if (len <= 0)
  576. version = 130;
  577. /* If not, can we compile 1.20 shaders? */
  578. if (!version)
  579. {
  580. char const *test120 =
  581. "#version 120\n"
  582. "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
  583. glShaderSource(id, 1, &test120, NULL);
  584. glCompileShader(id);
  585. glGetShaderInfoLog(id, sizeof(buf), &len, buf);
  586. if (len <= 0)
  587. version = 120;
  588. }
  589. /* Otherwise, assume we can compile 1.10 shaders. */
  590. if (!version)
  591. version = 110;
  592. glDeleteShader(id);
  593. #endif
  594. }
  595. #endif
  596. return version;
  597. }
  598. /* Simple shader source patching for old GLSL versions.
  599. */
  600. void ShaderData::Patch(char *dst, char const *vert, char const *frag)
  601. {
  602. int ver_driver = GetVersion();
  603. strcpy(dst, vert ? vert : frag);
  604. if (ver_driver >= 130)
  605. return;
  606. int ver_shader = 110;
  607. char *parser = strstr(dst, "#version");
  608. if (parser)
  609. ver_shader = atoi(parser + strlen("#version"));
  610. /* This is GL ES, we only know version 100. */
  611. if (ver_shader > 100 && ver_driver == 100)
  612. {
  613. /* FIXME: this isn't elegant but honestly, we don't care, this
  614. * whole file is going to die soon. */
  615. char *p = strstr(dst, "#version");
  616. if (p)
  617. {
  618. p += 8;
  619. while (*p == ' ')
  620. p++;
  621. if (p[0] == '1' && p[1] && p[2])
  622. p[1] = p[2] = '0';
  623. }
  624. }
  625. if (ver_shader > 120 && ver_driver <= 120)
  626. {
  627. char const *end = dst + strlen(dst) + 1;
  628. /* Find main() */
  629. parser = strstr(dst, "main");
  630. if (!parser) return;
  631. parser = strstr(parser, "(");
  632. if (!parser) return;
  633. parser = strstr(parser, ")");
  634. if (!parser) return;
  635. parser = strstr(parser, "{");
  636. if (!parser) return;
  637. char *main = parser + 1;
  638. /* Perform main() replaces */
  639. char const * const main_replaces[] =
  640. {
  641. #if 0
  642. "in vec2 in_Vertex;", "vec2 in_Vertex = gl_Vertex.xy;",
  643. "in vec3 in_Vertex;", "vec3 in_Vertex = gl_Vertex.xyz;",
  644. "in vec4 in_Vertex;", "vec4 in_Vertex = gl_Vertex.xyzw;",
  645. "in vec2 in_Color;", "vec2 in_Color = gl_Color.xy;",
  646. "in vec3 in_Color;", "vec3 in_Color = gl_Color.xyz;",
  647. "in vec4 in_Color;", "vec4 in_Color = gl_Color.xyzw;",
  648. "in vec2 in_MultiTexCoord0;",
  649. "vec2 in_MultiTexCoord0 = gl_MultiTexCoord0.xy;",
  650. "in vec2 in_MultiTexCoord1;",
  651. "vec2 in_MultiTexCoord1 = gl_MultiTexCoord1.xy;",
  652. "in vec2 in_MultiTexCoord2;",
  653. "vec2 in_MultiTexCoord2 = gl_MultiTexCoord2.xy;",
  654. "in vec2 in_MultiTexCoord3;",
  655. "vec2 in_MultiTexCoord3 = gl_MultiTexCoord3.xy;",
  656. "in vec2 in_MultiTexCoord4;",
  657. "vec2 in_MultiTexCoord4 = gl_MultiTexCoord4.xy;",
  658. "in vec2 in_MultiTexCoord5;",
  659. "vec2 in_MultiTexCoord5 = gl_MultiTexCoord5.xy;",
  660. "in vec2 in_MultiTexCoord6;",
  661. "vec2 in_MultiTexCoord6 = gl_MultiTexCoord6.xy;",
  662. "in vec2 in_MultiTexCoord7;",
  663. "vec2 in_MultiTexCoord7 = gl_MultiTexCoord7.xy;",
  664. #endif
  665. NULL
  666. };
  667. for (char const * const *rep = main_replaces; rep[0]; rep += 2)
  668. {
  669. char *match = strstr(dst, rep[0]);
  670. if (match && match < main)
  671. {
  672. size_t l0 = strlen(rep[0]);
  673. size_t l1 = strlen(rep[1]);
  674. memmove(main + l1, main, end - main);
  675. memcpy(main, rep[1], l1);
  676. memset(match, ' ', l0);
  677. main += l1;
  678. end += l1;
  679. }
  680. }
  681. /* Perform small replaces */
  682. char const * const fast_replaces[] =
  683. {
  684. "#version 130", "#version 120",
  685. "in vec2", vert ? "attribute vec2" : "varying vec2",
  686. "in vec3", vert ? "attribute vec3" : "varying vec3",
  687. "in vec4", vert ? "attribute vec4" : "varying vec4",
  688. "in mat4", vert ? "attribute mat4" : "varying mat4",
  689. "out vec2", "varying vec2",
  690. "out vec3", "varying vec3",
  691. "out vec4", "varying vec4",
  692. "out mat4", "varying mat4",
  693. NULL
  694. };
  695. for (char const * const *rep = fast_replaces; rep[0]; rep += 2)
  696. {
  697. char *match;
  698. while ((match = strstr(dst, rep[0])))
  699. {
  700. size_t l0 = strlen(rep[0]);
  701. size_t l1 = strlen(rep[1]);
  702. if (l1 > l0)
  703. memmove(match + l1, match + l0, (end - match) - l0);
  704. memcpy(match, rep[1], l1);
  705. if (l1 < l0)
  706. memset(match + l0, ' ', l1 - l0);
  707. end += l1 - l0;
  708. }
  709. }
  710. }
  711. }
  712. } /* namespace lol */