From a60def7a02b37cc1ca1cfc976e15bf7ada61d355 Mon Sep 17 00:00:00 2001 From: Archie Hilton Date: Sun, 26 May 2024 20:46:09 +0100 Subject: [PATCH] texture: Use texture abstraction --- src/CMakeLists.txt | 1 + src/Quad.cc | 57 ++------------------- src/texture.cc | 120 +++++++++++++++++++++++++++++++++++++++++++++ src/texture.hh | 35 +++++++++++++ 4 files changed, 160 insertions(+), 53 deletions(-) create mode 100644 src/texture.cc create mode 100644 src/texture.hh diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 30a6531..afbf5a3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ add_executable(Exponent GLProgramLoader.cc Quad.cc Mesh.cc + texture.cc ) target_link_libraries(Exponent PUBLIC glfw glm::glm ${PNG_LIBRARY}) diff --git a/src/Quad.cc b/src/Quad.cc index c979db4..96375a0 100644 --- a/src/Quad.cc +++ b/src/Quad.cc @@ -3,6 +3,7 @@ #include "glm/ext/matrix_transform.hpp" #include "glm/gtc/type_ptr.hpp" #include "glm/trigonometric.hpp" +#include "src/texture.hh" #include #include #include @@ -23,59 +24,9 @@ Quad::Quad(std::span verts, const Uniform &uniform_data) color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); - png_uint_32 width = 0, height = 0; - int interlace_type = 0, bit_depth = 0, color_type = 0; - - FILE *fp = fopen("./res/tex/util/missing.png", "rb"); - png_const_bytep header[8] = {0}; - - if (fp == NULL) { - spdlog::error("Can't find texture file!"); - throw std::exception(); - } - - fread(header, 1, 8, fp); - - png_structp png_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - png_infop info_ptr = png_create_info_struct(png_ptr); - - setjmp(png_jmpbuf(png_ptr)); - - png_init_io(png_ptr, fp); - png_set_sig_bytes(png_ptr, 8); - - png_read_png(png_ptr, info_ptr, - PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | - PNG_TRANSFORM_EXPAND, - NULL); - - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_type, NULL, NULL); - - setjmp(png_jmpbuf(png_ptr)); - - png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); - size_t data_length = rowbytes * height; - - png_byte *data = (png_byte *)malloc(data_length); - - png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); - - for (int x = 0; x < height; x++) { - memcpy(data + (rowbytes * (height - x - 1)), row_pointers[x], rowbytes); - } - - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - fclose(fp); - - glGenTextures(1, &tex_id); - - glBindTexture(GL_TEXTURE_2D, tex_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, - GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); + tex_id = TextureLoader::get_instance() + ->load_texture("./res/tex/util/missing.png") + ->get_texture_id(); } glm::vec2 Quad::get_position_vector() { return glm::vec2(m_pos_x, m_pos_y); } diff --git a/src/texture.cc b/src/texture.cc new file mode 100644 index 0000000..1bda6df --- /dev/null +++ b/src/texture.cc @@ -0,0 +1,120 @@ +#include "texture.hh" + +#include +#include +#include +#include +#include +#include +#include +#include + +TextureLoader *TextureLoader::m_instance = NULL; + +TextureLoader *TextureLoader::get_instance() { + if (m_instance == NULL) { + m_instance = new TextureLoader(); + } + + return m_instance; +} + +TextureLoader::TextureLoader() { m_texture_cache.clear(); } + +TextureLoader::~TextureLoader() { + for (std::pair st : m_texture_cache) { + delete (st.second); + } +} + +Texture *TextureLoader::load_texture(const std::string &path) { + // Cache Hit + if (m_texture_cache.contains(path)) { + return m_texture_cache.at(path); + } + + // Cache miss - we have to load it and create it + m_texture_cache.emplace(std::make_pair(path, new Texture(path))); + + return m_texture_cache.at(path); +} + +Texture::Texture(const std::string &path) { + png_uint_32 width = 0, height = 0; + int interlace_type = 0, bit_depth = 0, color_type = 0; + + spdlog::trace("Creating texture with path {}"); + + // First - check the path actually exists + FILE *fp = fopen(path.c_str(), "rb"); + + if (fp == NULL) { + spdlog::error("Cant find texture at path {}", path); + // TODO Make my own exception for this and log it upstream + throw std::exception(); + } + + png_byte header[4] = {0}; + + fread(header, 1, 4, fp); + + // I'm not sure why this cast has to be there but clangd doesn't like it not + // being there... + // FIXME: for some reason, this fails. + /* + if (!png_sig_cmp(header, 0, 4)) { + spdlog::error("Texture file {} does not appear to be a png file.", path); + + throw std::exception(); + } + */ + + png_structp png_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + png_infop info_ptr = png_create_info_struct(png_ptr); + + setjmp(png_jmpbuf(png_ptr)); + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, 4); + + png_read_png(png_ptr, info_ptr, + PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | + PNG_TRANSFORM_EXPAND, + NULL); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, NULL, NULL); + + setjmp(png_jmpbuf(png_ptr)); + + png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + size_t data_length = rowbytes * height; + + png_byte *data = (png_byte *)malloc(data_length); + + png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); + + for (int x = 0; x < height; x++) { + memcpy(data + (rowbytes * (height - x - 1)), row_pointers[x], rowbytes); + } + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(fp); + + glGenTextures(1, &m_gl_texture_id); + + glBindTexture(GL_TEXTURE_2D, m_gl_texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, + GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); +} + +Texture::~Texture() { + spdlog::trace("Deleting texture id {}", m_gl_texture_id); + + glDeleteTextures(1, &m_gl_texture_id); +} + +GLuint Texture::get_texture_id() { return m_gl_texture_id; } diff --git a/src/texture.hh b/src/texture.hh new file mode 100644 index 0000000..3c66799 --- /dev/null +++ b/src/texture.hh @@ -0,0 +1,35 @@ +#pragma once + +#include + +#include +#include +#include + +class Texture { +private: + GLuint m_gl_texture_id; + +public: + Texture(const std::string &path); + ~Texture(); + Texture(const Texture &t) = delete; + + GLuint get_texture_id(); +}; + +class TextureLoader { +private: + static TextureLoader *m_instance; + + std::unordered_map m_texture_cache; + + TextureLoader(); + ~TextureLoader(); + +public: + Texture *load_texture(const std::string &path); + static TextureLoader *get_instance(); + + TextureLoader(const TextureLoader &tl) = delete; +};