texture_renderer.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #include "texture_renderer.h"
  2. #include <spdlog/spdlog.h>
  3. #include <cassert>
  4. #include <cstddef>
  5. static constexpr auto vertex_shader_source = R"(
  6. #version 460
  7. layout (location = 0) in vec2 pos_in;
  8. layout (location = 1) in vec2 tex_coord_in;
  9. out vec2 tex_coord;
  10. void main() {
  11. gl_Position = vec4(pos_in, 0, 1);
  12. tex_coord = tex_coord_in;
  13. }
  14. )";
  15. static constexpr auto fragment_shader_source = R"(
  16. #version 460
  17. layout (location = 0) out vec4 color_out;
  18. in vec2 tex_coord;
  19. uniform sampler2D tex_sampler;
  20. void main() {
  21. color_out = texture(tex_sampler, tex_coord);
  22. }
  23. )";
  24. static constexpr GLuint indices[] = {
  25. 0, 1, 3, // first triangle
  26. 1, 2, 3 // second triangle
  27. };
  28. struct texture_renderer::impl {
  29. GLuint vertex_array = 0;
  30. GLuint vertex_buffer = 0, element_buffer = 0;
  31. GLuint program = 0;
  32. impl() {
  33. // build program
  34. auto vertex_shader = glCreateShader(GL_VERTEX_SHADER);
  35. auto fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
  36. compile_shader(vertex_shader, vertex_shader_source, "vertex");
  37. compile_shader(fragment_shader, fragment_shader_source, "fragment");
  38. program = glCreateProgram();
  39. glAttachShader(program, vertex_shader);
  40. glAttachShader(program, fragment_shader);
  41. glLinkProgram(program);
  42. check_program();
  43. glDeleteShader(vertex_shader);
  44. glDeleteShader(fragment_shader);
  45. // create buffers
  46. static_assert(offsetof(impl, element_buffer) - offsetof(impl, vertex_buffer) == sizeof(GLuint));
  47. glGenBuffers(2, &vertex_buffer);
  48. // config vertex buffer
  49. glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
  50. glBufferStorage(GL_ARRAY_BUFFER, 16 * sizeof(GLfloat), nullptr, GL_DYNAMIC_STORAGE_BIT);
  51. // fill element buffer
  52. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer);
  53. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
  54. // config vertex array
  55. glGenVertexArrays(1, &vertex_array);
  56. glBindVertexArray(vertex_array);
  57. glEnableVertexAttribArray(0);
  58. glEnableVertexAttribArray(1);
  59. glVertexAttribPointer(0, 2, GL_FLOAT, false, 4 * sizeof(GLfloat), (void *) 0);
  60. glVertexAttribPointer(1, 2, GL_FLOAT, false, 4 * sizeof(GLfloat), (void *) (2 * sizeof(GLfloat)));
  61. }
  62. ~impl() {
  63. glDeleteBuffers(2, &vertex_buffer);
  64. glDeleteProgram(program);
  65. }
  66. static void compile_shader(GLuint shader, const char *source, const char *name) {
  67. glShaderSource(shader, 1, &source, nullptr);
  68. glCompileShader(shader);
  69. GLint status, log_length;
  70. glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
  71. glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
  72. auto info_log = (GLchar *) malloc(log_length);
  73. glGetShaderInfoLog(shader, log_length, nullptr, info_log);
  74. if (status == GL_TRUE) {
  75. SPDLOG_INFO("Compile {} shader succeeded: {}", name, info_log);
  76. } else {
  77. SPDLOG_ERROR("Compile {} shader failed: {}", name, info_log);
  78. assert(false);
  79. }
  80. free(info_log);
  81. }
  82. void check_program() {
  83. GLint status, log_length;
  84. glGetProgramiv(program, GL_LINK_STATUS, &status);
  85. glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
  86. auto info_log = (GLchar *) malloc(log_length);
  87. glGetProgramInfoLog(program, log_length, nullptr, info_log);
  88. if (status == GL_TRUE) {
  89. SPDLOG_INFO("Link program succeeded: {}", info_log);
  90. } else {
  91. SPDLOG_ERROR("Link program failed: {}", info_log);
  92. assert(false);
  93. }
  94. free(info_log);
  95. }
  96. void render(const texture_renderer::render_config *config) {
  97. auto x = config->x, y = config->y;
  98. auto width = config->width, height = config->height;
  99. // bindings
  100. glUseProgram(program);
  101. glBindVertexArray(vertex_array);
  102. glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
  103. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer);
  104. glBindTexture(GL_TEXTURE_2D, config->tex);
  105. // fill vertex buffer
  106. GLfloat vertices[] = {
  107. // 2 for position; 2 for texture
  108. x + width, y + height, 1, 1, // top right
  109. x + width, y, 1, 0, // bottom right
  110. x, y, 0, 0, // bottom left
  111. x, y + height, 0, 1 // top left
  112. };
  113. static_assert(sizeof(vertices) == 16 * sizeof(GLfloat));
  114. glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
  115. // draw texture
  116. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
  117. }
  118. };
  119. texture_renderer::texture_renderer()
  120. : pimpl(std::make_unique<impl>()) {}
  121. texture_renderer::~texture_renderer() = default;
  122. void texture_renderer::render(const texture_renderer::render_config *config) {
  123. pimpl->render(config);
  124. }