💿🐜 Antkeeper source code https://antkeeper.com
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.

223 lines
6.0 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "rasterizer/shader-program.hpp"
  20. #include "rasterizer/shader.hpp"
  21. #include "rasterizer/shader-variable-type.hpp"
  22. #include "rasterizer/shader-input.hpp"
  23. #include <glad/glad.h>
  24. #include <stdexcept>
  25. shader_program::shader_program(const std::list<shader*>& shaders):
  26. gl_program_id(0)
  27. {
  28. gl_program_id = glCreateProgram();
  29. for (shader* shader: shaders)
  30. {
  31. glAttachShader(gl_program_id, shader->gl_shader_id);
  32. }
  33. glLinkProgram(gl_program_id);
  34. GLint status;
  35. glGetProgramiv(gl_program_id, GL_LINK_STATUS, &status);
  36. if (status == GL_FALSE)
  37. {
  38. throw std::runtime_error(get_info_log().c_str());
  39. }
  40. for (shader* shader: shaders)
  41. {
  42. glDetachShader(gl_program_id, shader->gl_shader_id);
  43. }
  44. // Find shader inputs
  45. find_inputs();
  46. }
  47. shader_program::~shader_program()
  48. {
  49. glDeleteProgram(gl_program_id);
  50. for (shader_input* input: inputs)
  51. {
  52. delete input;
  53. }
  54. }
  55. void shader_program::find_inputs()
  56. {
  57. // Get maximum uniform name length
  58. GLint max_uniform_name_length = 0;
  59. glGetProgramiv(gl_program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_length);
  60. // Allocate uniform name buffer
  61. GLchar* uniform_name = new GLchar[max_uniform_name_length];
  62. // Get number of active uniforms in the shader
  63. GLint active_uniform_count = 0;
  64. glGetProgramiv(gl_program_id, GL_ACTIVE_UNIFORMS, &active_uniform_count);
  65. // Set first available texture unit
  66. int available_texture_unit = 0;
  67. // For each active uniform
  68. for (GLuint uniform_index = 0; uniform_index < static_cast<GLuint>(active_uniform_count); ++uniform_index)
  69. {
  70. // Get information about uniform
  71. GLsizei uniform_name_length;
  72. GLint uniform_size;
  73. GLenum uniform_type;
  74. glGetActiveUniform(gl_program_id, uniform_index, static_cast<GLsizei>(max_uniform_name_length), &uniform_name_length, &uniform_size, &uniform_type, &uniform_name[0]);
  75. // Get name without array symbols
  76. std::string input_name = uniform_name;
  77. std::size_t bracketPos = input_name.find_first_of("[");
  78. if (bracketPos != std::string::npos)
  79. {
  80. input_name = input_name.substr(0, bracketPos);
  81. }
  82. // Determine corresponding shader variable data type
  83. shader_variable_type variable_type;
  84. int texture_unit = -1;
  85. bool unsupported = false;
  86. switch (uniform_type)
  87. {
  88. case GL_BOOL:
  89. variable_type = shader_variable_type::bool1;
  90. break;
  91. case GL_BOOL_VEC2:
  92. variable_type = shader_variable_type::bool2;
  93. break;
  94. case GL_BOOL_VEC3:
  95. variable_type = shader_variable_type::bool3;
  96. break;
  97. case GL_BOOL_VEC4:
  98. variable_type = shader_variable_type::bool4;
  99. break;
  100. case GL_INT:
  101. variable_type = shader_variable_type::int1;
  102. break;
  103. case GL_INT_VEC2:
  104. variable_type = shader_variable_type::int2;
  105. break;
  106. case GL_INT_VEC3:
  107. variable_type = shader_variable_type::int3;
  108. break;
  109. case GL_INT_VEC4:
  110. variable_type = shader_variable_type::int4;
  111. break;
  112. case GL_UNSIGNED_INT:
  113. variable_type = shader_variable_type::uint1;
  114. break;
  115. case GL_UNSIGNED_INT_VEC2:
  116. variable_type = shader_variable_type::uint2;
  117. break;
  118. case GL_UNSIGNED_INT_VEC3:
  119. variable_type = shader_variable_type::uint3;
  120. break;
  121. case GL_UNSIGNED_INT_VEC4:
  122. variable_type = shader_variable_type::uint4;
  123. break;
  124. case GL_FLOAT:
  125. variable_type = shader_variable_type::float1;
  126. break;
  127. case GL_FLOAT_VEC2:
  128. variable_type = shader_variable_type::float2;
  129. break;
  130. case GL_FLOAT_VEC3:
  131. variable_type = shader_variable_type::float3;
  132. break;
  133. case GL_FLOAT_VEC4:
  134. variable_type = shader_variable_type::float4;
  135. break;
  136. case GL_FLOAT_MAT2:
  137. variable_type = shader_variable_type::float2x2;
  138. break;
  139. case GL_FLOAT_MAT3:
  140. variable_type = shader_variable_type::float3x3;
  141. break;
  142. case GL_FLOAT_MAT4:
  143. variable_type = shader_variable_type::float4x4;
  144. break;
  145. case GL_SAMPLER_2D:
  146. case GL_SAMPLER_2D_SHADOW:
  147. variable_type = shader_variable_type::texture_2d;
  148. texture_unit = available_texture_unit;
  149. available_texture_unit += uniform_size;
  150. break;
  151. case GL_SAMPLER_CUBE:
  152. variable_type = shader_variable_type::texture_cube;
  153. texture_unit = available_texture_unit;
  154. available_texture_unit += uniform_size;
  155. break;
  156. default:
  157. unsupported = true;
  158. break;
  159. }
  160. // Check if data type is supported
  161. if (unsupported)
  162. {
  163. std::string message = std::string("Shader uniform \"") + std::string(uniform_name) + std::string("\" has unsupported data type.");
  164. throw std::runtime_error(message.c_str());
  165. }
  166. // Get uniform location
  167. GLint uniform_location = glGetUniformLocation(gl_program_id, uniform_name);
  168. if (uniform_location == -1)
  169. {
  170. std::string message = std::string("Unable to get location for uniform \"") + std::string(uniform_name) + std::string("\"");
  171. throw std::runtime_error(message.c_str());
  172. }
  173. // Create new shader input
  174. shader_input* input = new shader_input(this, inputs.size(), uniform_location, input_name, variable_type, uniform_size, texture_unit);
  175. input_map[input_name] = input;
  176. inputs.push_back(input);
  177. }
  178. // Free uniform name buffer
  179. delete[] uniform_name;
  180. }
  181. std::string shader_program::get_info_log() const
  182. {
  183. GLint length;
  184. glGetProgramiv(gl_program_id, GL_INFO_LOG_LENGTH, &length);
  185. if (length > 0)
  186. {
  187. std::string log(length, '\0');
  188. glGetProgramInfoLog(gl_program_id, length, &length, &log[0]);
  189. return log;
  190. }
  191. return std::string();
  192. }