💿🐜 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.

228 lines
6.1 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 "gl/shader-program.hpp"
  20. #include "gl/shader-object.hpp"
  21. #include "gl/shader-variable-type.hpp"
  22. #include "gl/shader-input.hpp"
  23. #include <glad/glad.h>
  24. #include <stdexcept>
  25. namespace gl {
  26. shader_program::shader_program(const std::list<shader_object*>& shaders):
  27. gl_program_id(0)
  28. {
  29. gl_program_id = glCreateProgram();
  30. for (shader_object* shader: shaders)
  31. {
  32. glAttachShader(gl_program_id, shader->gl_shader_id);
  33. }
  34. glLinkProgram(gl_program_id);
  35. GLint status;
  36. glGetProgramiv(gl_program_id, GL_LINK_STATUS, &status);
  37. if (status == GL_FALSE)
  38. {
  39. throw std::runtime_error(get_info_log().c_str());
  40. }
  41. for (shader_object* shader: shaders)
  42. {
  43. glDetachShader(gl_program_id, shader->gl_shader_id);
  44. }
  45. // Find shader inputs
  46. find_inputs();
  47. }
  48. shader_program::~shader_program()
  49. {
  50. glDeleteProgram(gl_program_id);
  51. for (shader_input* input: inputs)
  52. {
  53. delete input;
  54. }
  55. }
  56. void shader_program::find_inputs()
  57. {
  58. // Get maximum uniform name length
  59. GLint max_uniform_name_length = 0;
  60. glGetProgramiv(gl_program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_length);
  61. // Allocate uniform name buffer
  62. GLchar* uniform_name = new GLchar[max_uniform_name_length];
  63. // Get number of active uniforms in the shader
  64. GLint active_uniform_count = 0;
  65. glGetProgramiv(gl_program_id, GL_ACTIVE_UNIFORMS, &active_uniform_count);
  66. // Set first available texture unit
  67. int available_texture_unit = 0;
  68. // For each active uniform
  69. for (GLuint uniform_index = 0; uniform_index < static_cast<GLuint>(active_uniform_count); ++uniform_index)
  70. {
  71. // Get information about uniform
  72. GLsizei uniform_name_length;
  73. GLint uniform_size;
  74. GLenum uniform_type;
  75. glGetActiveUniform(gl_program_id, uniform_index, static_cast<GLsizei>(max_uniform_name_length), &uniform_name_length, &uniform_size, &uniform_type, &uniform_name[0]);
  76. // Get name without array symbols
  77. std::string input_name = uniform_name;
  78. std::size_t bracketPos = input_name.find_first_of("[");
  79. if (bracketPos != std::string::npos)
  80. {
  81. input_name = input_name.substr(0, bracketPos);
  82. }
  83. // Determine corresponding shader variable data type
  84. shader_variable_type variable_type;
  85. int texture_unit = -1;
  86. bool unsupported = false;
  87. switch (uniform_type)
  88. {
  89. case GL_BOOL:
  90. variable_type = shader_variable_type::bool1;
  91. break;
  92. case GL_BOOL_VEC2:
  93. variable_type = shader_variable_type::bool2;
  94. break;
  95. case GL_BOOL_VEC3:
  96. variable_type = shader_variable_type::bool3;
  97. break;
  98. case GL_BOOL_VEC4:
  99. variable_type = shader_variable_type::bool4;
  100. break;
  101. case GL_INT:
  102. variable_type = shader_variable_type::int1;
  103. break;
  104. case GL_INT_VEC2:
  105. variable_type = shader_variable_type::int2;
  106. break;
  107. case GL_INT_VEC3:
  108. variable_type = shader_variable_type::int3;
  109. break;
  110. case GL_INT_VEC4:
  111. variable_type = shader_variable_type::int4;
  112. break;
  113. case GL_UNSIGNED_INT:
  114. variable_type = shader_variable_type::uint1;
  115. break;
  116. case GL_UNSIGNED_INT_VEC2:
  117. variable_type = shader_variable_type::uint2;
  118. break;
  119. case GL_UNSIGNED_INT_VEC3:
  120. variable_type = shader_variable_type::uint3;
  121. break;
  122. case GL_UNSIGNED_INT_VEC4:
  123. variable_type = shader_variable_type::uint4;
  124. break;
  125. case GL_FLOAT:
  126. variable_type = shader_variable_type::float1;
  127. break;
  128. case GL_FLOAT_VEC2:
  129. variable_type = shader_variable_type::float2;
  130. break;
  131. case GL_FLOAT_VEC3:
  132. variable_type = shader_variable_type::float3;
  133. break;
  134. case GL_FLOAT_VEC4:
  135. variable_type = shader_variable_type::float4;
  136. break;
  137. case GL_FLOAT_MAT2:
  138. variable_type = shader_variable_type::float2x2;
  139. break;
  140. case GL_FLOAT_MAT3:
  141. variable_type = shader_variable_type::float3x3;
  142. break;
  143. case GL_FLOAT_MAT4:
  144. variable_type = shader_variable_type::float4x4;
  145. break;
  146. case GL_SAMPLER_2D:
  147. case GL_SAMPLER_2D_SHADOW:
  148. variable_type = shader_variable_type::texture_2d;
  149. texture_unit = available_texture_unit;
  150. available_texture_unit += uniform_size;
  151. break;
  152. case GL_SAMPLER_CUBE:
  153. variable_type = shader_variable_type::texture_cube;
  154. texture_unit = available_texture_unit;
  155. available_texture_unit += uniform_size;
  156. break;
  157. default:
  158. unsupported = true;
  159. break;
  160. }
  161. // Check if data type is supported
  162. if (unsupported)
  163. {
  164. std::string message = std::string("Shader uniform \"") + std::string(uniform_name) + std::string("\" has unsupported data type.");
  165. throw std::runtime_error(message.c_str());
  166. }
  167. // Get uniform location
  168. GLint uniform_location = glGetUniformLocation(gl_program_id, uniform_name);
  169. if (uniform_location == -1)
  170. {
  171. //std::string message = std::string("Unable to get location for uniform \"") + std::string(uniform_name) + std::string("\"");
  172. //throw std::runtime_error(message.c_str());
  173. }
  174. else
  175. {
  176. // Create new shader input
  177. shader_input* input = new shader_input(this, inputs.size(), uniform_location, input_name, variable_type, uniform_size, texture_unit);
  178. input_map[input_name] = input;
  179. inputs.push_back(input);
  180. }
  181. }
  182. // Free uniform name buffer
  183. delete[] uniform_name;
  184. }
  185. std::string shader_program::get_info_log() const
  186. {
  187. GLint length;
  188. glGetProgramiv(gl_program_id, GL_INFO_LOG_LENGTH, &length);
  189. if (length > 0)
  190. {
  191. std::string log(length, '\0');
  192. glGetProgramInfoLog(gl_program_id, length, &length, &log[0]);
  193. return log;
  194. }
  195. return std::string();
  196. }
  197. } // namespace gl