opengl_manager.cxx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. //
  2. // helper.cxx
  3. // graphics
  4. //
  5. // Created by Sam Jaffe on 5/18/19.
  6. // Copyright © 2019 Sam Jaffe. All rights reserved.
  7. //
  8. #include "helper.hpp"
  9. #include "opengl_renderer.h"
  10. #include <iostream>
  11. #include <memory>
  12. #include <sstream>
  13. #ifdef __APPLE__
  14. #include <OpenGL/gl3.h>
  15. #endif
  16. #include "scope_guard/scope_guard.hpp"
  17. #include "vector/vector.hpp"
  18. #include "game/graphics/exception.h"
  19. #include "game/graphics/material.hpp"
  20. #include "game/graphics/shader.hpp"
  21. #include "game/graphics/shader_program.hpp"
  22. #include "game/graphics/texture.hpp"
  23. #include "game/util/env.hpp"
  24. #include "game/util/files.hpp"
  25. #include "game/util/time.hpp"
  26. namespace graphics {
  27. extern void print_shader_error(GLuint, std::string const &);
  28. extern void print_shader_program_error(GLuint, std::string const &,
  29. std::string const &);
  30. struct compilation_error : std::runtime_error {
  31. using std::runtime_error::runtime_error;
  32. };
  33. struct linker_error : std::runtime_error {
  34. using std::runtime_error::runtime_error;
  35. };
  36. }
  37. using namespace graphics;
  38. namespace {
  39. int glfmt(textures::format color_fmt) {
  40. switch (color_fmt) {
  41. case textures::format::RGB:
  42. return GL_RGB;
  43. case textures::format::RGBA:
  44. return GL_RGBA;
  45. }
  46. }
  47. int gltype(shaders::type tp) {
  48. switch (tp) {
  49. case shaders::type::FRAGMENT:
  50. return GL_FRAGMENT_SHADER;
  51. case shaders::type::VERTEX:
  52. return GL_VERTEX_SHADER;
  53. }
  54. }
  55. }
  56. texture opengl_manager::compile(textures::format color, math::vec2i size,
  57. void const * buffer) const {
  58. // textures::external_data data(env::resource_file(path));
  59. // unsigned int init(format color_fmt, math::vec2i dimension,
  60. // void const * data) {
  61. unsigned int id;
  62. // Enable texturings
  63. // glEnable( GL_TEXTURE_2D );
  64. // Tell OpenGL that our pixel data is single-byte aligned
  65. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  66. // Ask OpenGL for an unused texName (ID number) to use for this texture
  67. glGenTextures(1, &id);
  68. // Tell OpenGL to bind (set) this as the currently active texture
  69. glBindTexture(GL_TEXTURE_2D, id);
  70. // Set texture clamp vs. wrap (repeat)
  71. // one of: GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT,
  72. // GL_MIRROR_CLAMP_TO_EDGE, ...
  73. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  74. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  75. // the format our source pixel data is currently in; any of: GL_RGB,
  76. // GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, ...
  77. int bufferFormat = glfmt(color);
  78. // the format we want the texture to me on the card; allows us to translate
  79. // into a different texture format as we upload to OpenGL
  80. int internalFormat = bufferFormat;
  81. /* glTexImage2D: Load a 2d texture image
  82. * target: Creating this as a 2d texture.
  83. * level: Which mipmap level to use as the "root" (0 = the highest-quality,
  84. * full-res image), if mipmaps are enabled.
  85. * internalFormat: Type of texel format we want OpenGL to use for this
  86. * texture internally on the video card.
  87. * width: Texel-width of image; for maximum compatibility, use 2^N + 2^B,
  88. * where N is some integer in the range [3,10], and B is the border
  89. * thickness [0,1]
  90. * height: Texel-height of image; for maximum compatibility, use 2^M + 2^B,
  91. * where M is some integer in the range [3,10], and B is the border
  92. * thickness [0,1]
  93. * border: Border size, in texels (must be 0 or 1)
  94. * format: Pixel format describing the composition of the pixel data in
  95. * buffer
  96. * type: Pixel color components are unsigned bytes (one byte per color/alpha
  97. * channel)
  98. * pixels: Location of the actual pixel data bytes/buffer
  99. */
  100. glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size.x(), size.y(), 0,
  101. bufferFormat, GL_UNSIGNED_BYTE, buffer);
  102. glGenerateMipmap(GL_TEXTURE_2D);
  103. // Set magnification (texel > pixel) and minification (texel < pixel)
  104. // filters one of: GL_NEAREST, GL_LINEAR
  105. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  106. // one of: GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST,
  107. // GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST,
  108. // GL_LINEAR_MIPMAP_LINEAR
  109. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  110. GL_NEAREST_MIPMAP_LINEAR);
  111. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5);
  112. return texture{id, size};
  113. }
  114. shader opengl_manager::compile(shaders::type tp,
  115. std::string const & path) const {
  116. std::unique_ptr<char const[]> buffer;
  117. // 1. Load the vertex shader code (text file) to a new memory buffer
  118. std::string const abs_path = env::resource_file(path);
  119. if (!(buffer = files::load(abs_path))) {
  120. throw file_read_error("shader", abs_path);
  121. }
  122. // 2. Create a new shader ID
  123. // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
  124. unsigned int id = glCreateShader(gltype(tp));
  125. // 3. Associate the shader code with the new shader ID
  126. char const * buffer_ptr = buffer.get();
  127. glShaderSource(id, 1, &buffer_ptr, NULL);
  128. // 4. Compile the shader (the shader compiler is built in to your graphics
  129. // card driver)
  130. glCompileShader(id);
  131. // 5. Check for compile errors
  132. int return_code;
  133. glGetShaderiv(id, GL_COMPILE_STATUS, &return_code);
  134. if (return_code != GL_TRUE) {
  135. print_shader_error(id, abs_path);
  136. throw compilation_error("Could not compile the shader file");
  137. }
  138. return shader{id, tp, path};
  139. }
  140. shader_program opengl_manager::compile(identity<shader> fragmentShader,
  141. identity<shader> vertexShader) const {
  142. // 9. Create a new shader program ID
  143. unsigned int id = glCreateProgram();
  144. // 10. Attach the vertex and fragment shaders to the new shader program
  145. glAttachShader(id, vertexShader.id);
  146. glAttachShader(id, fragmentShader.id);
  147. // 11. Do some other advanced stuff we'll do later on (like setting generic
  148. // vertex attrib locations)
  149. glBindAttribLocation(id, 0, "a_position");
  150. glBindAttribLocation(id, 1, "a_color");
  151. glBindAttribLocation(id, 2, "a_texCoords");
  152. glBindAttribLocation(id, 3, "a_normal");
  153. // 12. Link the program
  154. glLinkProgram(id);
  155. // 13. Check for link errors
  156. int return_code;
  157. glGetProgramiv(id, GL_LINK_STATUS, &return_code);
  158. if (return_code != GL_TRUE) {
  159. // print_shader_program_error(id, fragmentShader.actual().path,
  160. // vertexShader.actual().path);
  161. throw linker_error("Could not link shader program");
  162. }
  163. return shader_program{id, fragmentShader, vertexShader};
  164. }
  165. opengl_uniform_data & opengl_manager::data(identity<shader_program> program) {
  166. auto & data = data_[program];
  167. // TODO: perform this in compile()
  168. if (data.uniform_id.empty()) {
  169. glUseProgram(program.id);
  170. using materials::uniform;
  171. data.uniform_id = {
  172. {uniform::NORMAL, glGetUniformLocation(program.id, "u_normalMap")},
  173. {uniform::DIFFUSE, glGetUniformLocation(program.id, "u_diffuseMap")},
  174. {uniform::SPECULAR, glGetUniformLocation(program.id, "u_specularMap")}};
  175. }
  176. return data;
  177. }