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 14KB

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