Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

911 wiersze
27 KiB

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