Open Source Tomb Raider Engine
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.

Shader.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /*!
  2. * \file src/system/Shader.cpp
  3. * \brief OpenGL Shader Implementation
  4. *
  5. * \author xythobuz
  6. */
  7. #include <sstream>
  8. #include "global.h"
  9. #include "Log.h"
  10. #include "system/Window.h"
  11. #include "system/Shader.h"
  12. #include <glbinding/gl/gl33.h>
  13. ShaderBuffer::~ShaderBuffer() {
  14. if (created)
  15. gl::glDeleteBuffers(1, &buffer);
  16. }
  17. void ShaderBuffer::bufferData(int elem, int size, void* data) {
  18. if (!created) {
  19. gl::glGenBuffers(1, &buffer);
  20. created = true;
  21. }
  22. boundSize = elem;
  23. gl::glBindBuffer(gl::GL_ARRAY_BUFFER, buffer);
  24. gl::glBufferData(gl::GL_ARRAY_BUFFER, elem * size, data, gl::GL_STATIC_DRAW);
  25. }
  26. void ShaderBuffer::bindBuffer() {
  27. if (!created) {
  28. gl::glGenBuffers(1, &buffer);
  29. created = true;
  30. }
  31. gl::glBindBuffer(gl::GL_ELEMENT_ARRAY_BUFFER, buffer);
  32. }
  33. void ShaderBuffer::bindBuffer(int location, int size) {
  34. if (!created) {
  35. gl::glGenBuffers(1, &buffer);
  36. created = true;
  37. }
  38. gl::glEnableVertexAttribArray(location);
  39. gl::glBindBuffer(gl::GL_ARRAY_BUFFER, buffer);
  40. gl::glVertexAttribPointer(location, size, gl::GL_FLOAT, gl::GL_FALSE, 0, nullptr);
  41. }
  42. void ShaderBuffer::unbind(int location) {
  43. orAssert(created == true);
  44. gl::glDisableVertexAttribArray(location);
  45. }
  46. // ----------------------------------------------------------------------------
  47. ShaderTexture::ShaderTexture(int w, int h) : width(w), height(h) {
  48. gl::glGenFramebuffers(1, &framebuffer);
  49. bind();
  50. texture = TextureManager::loadBufferSlot(nullptr, width, height, ColorMode::RGBA,
  51. 32, TextureStorage::SYSTEM, -1, false);
  52. gl::glGenRenderbuffers(1, &depth);
  53. gl::glBindRenderbuffer(gl::GL_RENDERBUFFER, depth);
  54. gl::glRenderbufferStorage(gl::GL_RENDERBUFFER, gl::GL_DEPTH_COMPONENT, width, height);
  55. gl::glFramebufferRenderbuffer(gl::GL_FRAMEBUFFER, gl::GL_DEPTH_ATTACHMENT, gl::GL_RENDERBUFFER, depth);
  56. gl::glFramebufferTexture(gl::GL_FRAMEBUFFER, gl::GL_COLOR_ATTACHMENT0,
  57. TextureManager::getTextureID(texture, TextureStorage::SYSTEM), 0);
  58. gl::GLenum drawBuffer = gl::GL_COLOR_ATTACHMENT0;
  59. gl::glDrawBuffers(1, &drawBuffer);
  60. orAssert(gl::glCheckFramebufferStatus(gl::GL_FRAMEBUFFER) == gl::GL_FRAMEBUFFER_COMPLETE);
  61. }
  62. ShaderTexture::~ShaderTexture() {
  63. gl::glDeleteRenderbuffers(1, &depth);
  64. gl::glDeleteFramebuffers(1, &framebuffer);
  65. //! \fixme free texture slot
  66. }
  67. void ShaderTexture::clear() {
  68. bind();
  69. gl::glClear(gl::GL_COLOR_BUFFER_BIT | gl::GL_DEPTH_BUFFER_BIT);
  70. }
  71. void ShaderTexture::bind() {
  72. gl::glBindFramebuffer(gl::GL_FRAMEBUFFER, framebuffer);
  73. gl::glViewport(0, 0, width, height);
  74. }
  75. // ----------------------------------------------------------------------------
  76. Shader::~Shader() {
  77. if (programID >= 0)
  78. gl::glDeleteProgram(programID);
  79. }
  80. int Shader::addUniform(const char* name) {
  81. orAssert(programID >= 0);
  82. int r = gl::glGetUniformLocation(programID, name);
  83. if (r < 0) {
  84. Log::get(LOG_ERROR) << "Can't find GLSL Uniform \"" << name << "\"!" << Log::endl;
  85. return -1;
  86. }
  87. uniforms.push_back(r);
  88. return uniforms.size() - 1;
  89. }
  90. unsigned int Shader::getUniform(int n) {
  91. orAssert(n >= 0);
  92. orAssert(n < uniforms.size());
  93. return uniforms.at(n);
  94. }
  95. void Shader::loadUniform(int uni, glm::vec2 vec) {
  96. gl::glUniform2f(getUniform(uni), vec.x, vec.y);
  97. }
  98. void Shader::loadUniform(int uni, glm::vec4 vec) {
  99. gl::glUniform4f(getUniform(uni), vec.r, vec.g, vec.b, vec.a);
  100. }
  101. void Shader::loadUniform(int uni, glm::mat4 mat) {
  102. gl::glUniformMatrix4fv(getUniform(uni), 1, gl::GL_FALSE, &mat[0][0]);
  103. }
  104. void Shader::loadUniform(int uni, int texture, TextureStorage store) {
  105. gl::glUniform1i(getUniform(uni), TextureManager::bindTexture(texture, store));
  106. }
  107. void Shader::use() {
  108. orAssert(programID >= 0);
  109. gl::glUseProgram(programID);
  110. }
  111. int Shader::compile(const char* vertex, const char* fragment) {
  112. orAssert(vertex != nullptr);
  113. orAssert(fragment != nullptr);
  114. gl::GLuint vertexID = gl::glCreateShader(gl::GL_VERTEX_SHADER);
  115. gl::GLuint fragmentID = gl::glCreateShader(gl::GL_FRAGMENT_SHADER);
  116. gl::GLint result = gl::GLint(gl::GL_FALSE);
  117. gl::GLint logLength = 0;
  118. // Compile vertex shader
  119. gl::glShaderSource(vertexID, 1, &vertex, nullptr);
  120. gl::glCompileShader(vertexID);
  121. // Check vertex shader
  122. gl::glGetShaderiv(vertexID, gl::GL_COMPILE_STATUS, &result);
  123. gl::glGetShaderiv(vertexID, gl::GL_INFO_LOG_LENGTH, &logLength);
  124. if ((logLength > 0) && (result != gl::GLint(gl::GL_TRUE))) {
  125. std::vector<char> message(logLength + 1);
  126. gl::glGetShaderInfoLog(vertexID, logLength, nullptr, &message[0]);
  127. Log::get(LOG_ERROR) << "Vertex Shader compilation error:" << Log::endl;
  128. Log::get(LOG_ERROR) << &message[0] << Log::endl;
  129. gl::glDeleteShader(vertexID);
  130. gl::glDeleteShader(fragmentID);
  131. return -1;
  132. }
  133. // Compile fragment shader
  134. gl::glShaderSource(fragmentID, 1, &fragment, nullptr);
  135. gl::glCompileShader(fragmentID);
  136. // Check fragment shader
  137. gl::glGetShaderiv(fragmentID, gl::GL_COMPILE_STATUS, &result);
  138. gl::glGetShaderiv(fragmentID, gl::GL_INFO_LOG_LENGTH, &logLength);
  139. if ((logLength > 0) && (result != gl::GLint(gl::GL_TRUE))) {
  140. std::vector<char> message(logLength + 1);
  141. gl::glGetShaderInfoLog(fragmentID, logLength, nullptr, &message[0]);
  142. Log::get(LOG_ERROR) << "Fragment Shader compilation error:" << Log::endl;
  143. Log::get(LOG_ERROR) << &message[0] << Log::endl;
  144. gl::glDeleteShader(vertexID);
  145. gl::glDeleteShader(fragmentID);
  146. return -2;
  147. }
  148. // Link both shaders
  149. programID = gl::glCreateProgram();
  150. gl::glAttachShader(programID, vertexID);
  151. gl::glAttachShader(programID, fragmentID);
  152. gl::glLinkProgram(programID);
  153. // Check resulting program
  154. gl::glGetProgramiv(programID, gl::GL_LINK_STATUS, &result);
  155. gl::glGetProgramiv(programID, gl::GL_INFO_LOG_LENGTH, &logLength);
  156. if ((logLength > 0) && (result != gl::GLint(gl::GL_TRUE))) {
  157. std::vector<char> message(logLength + 1);
  158. gl::glGetProgramInfoLog(programID, logLength, nullptr, &message[0]);
  159. Log::get(LOG_ERROR) << "Shader link error:" << Log::endl;
  160. Log::get(LOG_ERROR) << &message[0] << Log::endl;
  161. gl::glDeleteShader(vertexID);
  162. gl::glDeleteShader(fragmentID);
  163. gl::glDeleteProgram(programID);
  164. return -3;
  165. }
  166. gl::glDeleteShader(vertexID);
  167. gl::glDeleteShader(fragmentID);
  168. return programID;
  169. }
  170. // ----------------------------------------------------------------------------
  171. std::string Shader::getVersion(bool linked) {
  172. static std::string cache;
  173. static std::string cacheLinked;
  174. static bool cacheFilled = false;
  175. if (!cacheFilled) {
  176. std::ostringstream str;
  177. str << "OpenGL v" << gl::glGetString(gl::GL_VERSION);
  178. cache = str.str();
  179. str.str("");
  180. str << "OpenGL " << gl::glGetString(gl::GL_SHADING_LANGUAGE_VERSION) << " "
  181. << gl::glGetString(gl::GL_RENDERER) << " (" << gl::glGetString(gl::GL_VENDOR) << ")";
  182. cacheLinked = str.str();
  183. cacheFilled = true;
  184. }
  185. if (linked) {
  186. return cacheLinked;
  187. } else {
  188. return cache;
  189. }
  190. }
  191. Shader Shader::textShader;
  192. Shader Shader::textureShader;
  193. Shader Shader::colorShader;
  194. unsigned int Shader::vertexArrayID = 0;
  195. int Shader::initialize() {
  196. gl::glGenVertexArrays(1, &vertexArrayID);
  197. gl::glBindVertexArray(vertexArrayID);
  198. // Set background color
  199. gl::glClearColor(0.0f, 0.0f, 0.4f, 1.0f);
  200. set2DState(false);
  201. gl::glDepthFunc(gl::GL_LESS);
  202. gl::glEnable(gl::GL_BLEND);
  203. gl::glBlendFunc(gl::GL_SRC_ALPHA, gl::GL_ONE_MINUS_SRC_ALPHA);
  204. gl::glPointSize(5.0f);
  205. if (textShader.compile(textShaderVertex, textShaderFragment) < 0)
  206. return -1;
  207. if (textShader.addUniform("screen") < 0)
  208. return -2;
  209. if (textShader.addUniform("textureSampler") < 0)
  210. return -3;
  211. if (textShader.addUniform("colorVar") < 0)
  212. return -4;
  213. if (textureShader.compile(textureShaderVertex, textureShaderFragment) < 0)
  214. return -5;
  215. if (textureShader.addUniform("MVP") < 0)
  216. return -6;
  217. if (textureShader.addUniform("textureSampler") < 0)
  218. return -7;
  219. if (colorShader.compile(colorShaderVertex, colorShaderFragment) < 0)
  220. return -8;
  221. if (colorShader.addUniform("MVP") < 0)
  222. return -9;
  223. return 0;
  224. }
  225. void Shader::shutdown() {
  226. gl::glDeleteVertexArrays(1, &vertexArrayID);
  227. }
  228. void Shader::set2DState(bool on, bool depth) {
  229. if (on) {
  230. gl::glDisable(gl::GL_CULL_FACE);
  231. if (depth)
  232. gl::glDisable(gl::GL_DEPTH_TEST);
  233. } else {
  234. gl::glEnable(gl::GL_CULL_FACE);
  235. if (depth)
  236. gl::glEnable(gl::GL_DEPTH_TEST);
  237. }
  238. }
  239. void Shader::drawGL(ShaderBuffer& vertices, ShaderBuffer& uvs, glm::vec4 color,
  240. unsigned int texture, TextureStorage store, gl::GLenum mode,
  241. ShaderTexture* target, Shader& shader) {
  242. orAssert(vertices.getSize() == uvs.getSize());
  243. if (mode == gl::GL_TRIANGLES) {
  244. orAssert((vertices.getSize() % 3) == 0);
  245. }
  246. if (target == nullptr) {
  247. gl::glBindFramebuffer(gl::GL_FRAMEBUFFER, 0);
  248. gl::glViewport(0, 0, Window::getSize().x, Window::getSize().y);
  249. } else {
  250. target->bind();
  251. }
  252. shader.use();
  253. shader.loadUniform(0, glm::vec2(Window::getSize()));
  254. shader.loadUniform(1, texture, store);
  255. shader.loadUniform(2, color);
  256. vertices.bindBuffer(0, 2);
  257. uvs.bindBuffer(1, 2);
  258. set2DState(true);
  259. gl::glDrawArrays(mode, 0, vertices.getSize());
  260. set2DState(false);
  261. vertices.unbind(0);
  262. uvs.unbind(1);
  263. }
  264. void Shader::drawGL(ShaderBuffer& vertices, ShaderBuffer& uvs, unsigned int texture,
  265. glm::mat4 MVP, TextureStorage store, ShaderTexture* target,
  266. Shader& shader) {
  267. orAssert(vertices.getSize() == uvs.getSize());
  268. orAssert((vertices.getSize() % 3) == 0);
  269. if (target == nullptr) {
  270. gl::glBindFramebuffer(gl::GL_FRAMEBUFFER, 0);
  271. gl::glViewport(0, 0, Window::getSize().x, Window::getSize().y);
  272. } else {
  273. target->bind();
  274. }
  275. shader.use();
  276. shader.loadUniform(0, MVP);
  277. shader.loadUniform(1, texture, store);
  278. vertices.bindBuffer(0, 3);
  279. uvs.bindBuffer(1, 2);
  280. gl::glDrawArrays(gl::GL_TRIANGLES, 0, vertices.getSize());
  281. vertices.unbind(0);
  282. uvs.unbind(1);
  283. }
  284. void Shader::drawGL(ShaderBuffer& vertices, ShaderBuffer& uvs, ShaderBuffer& indices,
  285. unsigned int texture, glm::mat4 MVP, TextureStorage store,
  286. ShaderTexture* target, Shader& shader) {
  287. orAssert(vertices.getSize() == uvs.getSize());
  288. orAssert((indices.getSize() % 3) == 0);
  289. if (target == nullptr) {
  290. gl::glBindFramebuffer(gl::GL_FRAMEBUFFER, 0);
  291. gl::glViewport(0, 0, Window::getSize().x, Window::getSize().y);
  292. } else {
  293. target->bind();
  294. unsigned int sz = vertices.getSize();
  295. glm::vec3* buffer = new glm::vec3[sz];
  296. gl::glBindBuffer(gl::GL_ARRAY_BUFFER, vertices.getBuffer());
  297. gl::glGetBufferSubData(gl::GL_ARRAY_BUFFER, 0, sz * sizeof(glm::vec3), buffer);
  298. Log::get(LOG_DEBUG) << "drawGL Vertex dump:" << Log::endl;
  299. for (unsigned int i = 0; i < sz; i++) {
  300. glm::vec4 tmp(buffer[i], 1.0f);
  301. tmp = MVP * tmp;
  302. glm::vec3 res(tmp.x, tmp.y, tmp.z);
  303. Log::get(LOG_DEBUG) << buffer[i] << " -> " << res << Log::endl;
  304. }
  305. delete [] buffer;
  306. }
  307. shader.use();
  308. shader.loadUniform(0, MVP);
  309. shader.loadUniform(1, texture, store);
  310. vertices.bindBuffer(0, 3);
  311. uvs.bindBuffer(1, 2);
  312. indices.bindBuffer();
  313. gl::glDrawElements(gl::GL_TRIANGLES, indices.getSize(), gl::GL_UNSIGNED_SHORT, nullptr);
  314. vertices.unbind(0);
  315. uvs.unbind(1);
  316. }
  317. void Shader::drawGL(ShaderBuffer& vertices, ShaderBuffer& colors, glm::mat4 MVP,
  318. gl::GLenum mode, ShaderTexture* target, Shader& shader) {
  319. orAssert(vertices.getSize() == colors.getSize());
  320. if (mode == gl::GL_TRIANGLES) {
  321. orAssert((vertices.getSize() % 3) == 0);
  322. }
  323. if (target == nullptr) {
  324. gl::glBindFramebuffer(gl::GL_FRAMEBUFFER, 0);
  325. gl::glViewport(0, 0, Window::getSize().x, Window::getSize().y);
  326. } else {
  327. target->bind();
  328. }
  329. shader.use();
  330. shader.loadUniform(0, MVP);
  331. vertices.bindBuffer(0, 3);
  332. colors.bindBuffer(1, 3);
  333. gl::glDrawArrays(mode, 0, vertices.getSize());
  334. vertices.unbind(0);
  335. colors.unbind(1);
  336. }
  337. void Shader::drawGL(ShaderBuffer& vertices, ShaderBuffer& colors, ShaderBuffer& indices,
  338. glm::mat4 MVP, gl::GLenum mode, ShaderTexture* target, Shader& shader) {
  339. orAssert(vertices.getSize() == colors.getSize());
  340. if (mode == gl::GL_TRIANGLES) {
  341. orAssert((indices.getSize() % 3) == 0);
  342. }
  343. if (target == nullptr) {
  344. gl::glBindFramebuffer(gl::GL_FRAMEBUFFER, 0);
  345. gl::glViewport(0, 0, Window::getSize().x, Window::getSize().y);
  346. } else {
  347. target->bind();
  348. }
  349. shader.use();
  350. shader.loadUniform(0, MVP);
  351. vertices.bindBuffer(0, 3);
  352. colors.bindBuffer(1, 3);
  353. indices.bindBuffer();
  354. gl::glDrawElements(mode, indices.getSize(), gl::GL_UNSIGNED_SHORT, nullptr);
  355. vertices.unbind(0);
  356. colors.unbind(1);
  357. }
  358. // --------------------------------------
  359. // *INDENT-OFF*
  360. const char* Shader::textShaderVertex = R"!?!(
  361. #version 330 core
  362. layout(location = 0) in vec2 vertexPosition_screen;
  363. layout(location = 1) in vec2 vertexUV;
  364. out vec2 UV;
  365. uniform vec2 screen;
  366. void main() {
  367. vec2 halfScreen = screen / 2;
  368. vec2 vertexPosition_homogenous = (vertexPosition_screen - halfScreen) / halfScreen;
  369. gl_Position = vec4(vertexPosition_homogenous.x, -vertexPosition_homogenous.y, 0, 1);
  370. UV = vertexUV;
  371. }
  372. )!?!";
  373. const char* Shader::textShaderFragment = R"!?!(
  374. #version 330 core
  375. in vec2 UV;
  376. layout(location = 0) out vec4 color;
  377. uniform sampler2D textureSampler;
  378. uniform vec4 colorVar;
  379. void main() {
  380. color = texture(textureSampler, UV) * colorVar;
  381. }
  382. )!?!";
  383. // --------------------------------------
  384. const char* Shader::textureShaderVertex = R"!?!(
  385. #version 330 core
  386. layout(location = 0) in vec3 vertexPosition_modelspace;
  387. layout(location = 1) in vec2 vertexUV;
  388. out vec2 UV;
  389. uniform mat4 MVP;
  390. void main() {
  391. vec4 pos = MVP * vec4(vertexPosition_modelspace.x,
  392. -vertexPosition_modelspace.y,
  393. vertexPosition_modelspace.z,
  394. 1);
  395. gl_Position = vec4(-pos.x, pos.yzw);
  396. UV = vertexUV;
  397. }
  398. )!?!";
  399. const char* Shader::textureShaderFragment = R"!?!(
  400. #version 330 core
  401. in vec2 UV;
  402. layout(location = 0) out vec4 color;
  403. uniform sampler2D textureSampler;
  404. void main() {
  405. color = texture(textureSampler, UV);
  406. }
  407. )!?!";
  408. // --------------------------------------
  409. const char* Shader::colorShaderVertex = R"!?!(
  410. #version 330 core
  411. layout(location = 0) in vec3 vertexPosition_modelspace;
  412. layout(location = 1) in vec3 vertexColor;
  413. out vec3 color;
  414. uniform mat4 MVP;
  415. void main() {
  416. vec4 pos = MVP * vec4(vertexPosition_modelspace.x,
  417. -vertexPosition_modelspace.y,
  418. vertexPosition_modelspace.z,
  419. 1);
  420. gl_Position = vec4(-pos.x, pos.yzw);
  421. color = vertexColor;
  422. }
  423. )!?!";
  424. const char* Shader::colorShaderFragment = R"!?!(
  425. #version 330 core
  426. in vec3 color;
  427. layout(location = 0) out vec4 color_out;
  428. void main() {
  429. color_out = vec4(color, 1);
  430. }
  431. )!?!";
  432. // --------------------------------------
  433. // *INDENT-ON*