/* * Copyright (C) 2022 Riyyi * * SPDX-License-Identifier: MIT */ #include // UINT_MAX #include // std::shared_ptr #include // std::move #include "glad/glad.h" #include "ruc/format/log.h" #include "ruc/meta/assert.h" #define STB_IMAGE_IMPLEMENTATION #include "stb/stb_image.h" #include "inferno/render/texture.h" namespace Inferno { Texture::Texture(const std::string& path) : m_path(std::move(path)) { int width; int height; int channels; // Load image data stbi_set_flip_vertically_on_load(1); unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, STBI_default); VERIFY(data, "Failed to load image: '{}'", path); m_width = width; m_height = height; if (channels == 4) { m_internalFormat = GL_RGBA8; m_dataFormat = GL_RGBA; } else if (channels == 3) { m_internalFormat = GL_RGB8; m_dataFormat = GL_RGB; } create(data); // Clean resources stbi_image_free(data); } Texture::~Texture() { glDeleteTextures(1, &m_id); } void Texture::bind(uint32_t unit) const { // Set active unit glActiveTexture(GL_TEXTURE0 + unit); glBindTexture(GL_TEXTURE_2D, m_id); // Reset unit glActiveTexture(GL_TEXTURE0); } void Texture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } void Texture::create(unsigned char* data) { m_id = UINT_MAX; // Create texture object glGenTextures(1, &m_id); // Bind texture object glBindTexture(GL_TEXTURE_2D, m_id); // Set unpacking of pixel data to byte-alignment, // this prevents alignment issues when using a single byte for color glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Generate texture glTexImage2D( GL_TEXTURE_2D, // Texture target 0, // Midmap level, base starts at level 0 m_internalFormat, // Texture format m_width, m_height, // Image width/height 0, // Always 0 (legacy) m_dataFormat, // Texture source format GL_UNSIGNED_BYTE, // Texture source datatype data); // Image data // Set the texture wrapping / filtering options glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // X glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Y glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Minify glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Magnify // Automatically generate all mipmap levels glGenerateMipmap(GL_TEXTURE_2D); // Unbind texture object glBindTexture(GL_TEXTURE_2D, 0); } // ----------------------------------------- TextureManager::TextureManager(s) { ruc::info("TextureManager initialized"); } TextureManager::~TextureManager() { } void TextureManager::add(const std::string& path, std::shared_ptr texture) { // Construct (key, value) pair and insert it into the unordered_map m_textureList.emplace(std::move(path), std::move(texture)); } std::shared_ptr TextureManager::load(const std::string& path) { if (exists(path)) { return get(path); } std::shared_ptr texture = std::make_shared(path); add(path, texture); return get(path); } std::shared_ptr TextureManager::get(const std::string& path) { return exists(path) ? m_textureList.at(path) : nullptr; } bool TextureManager::exists(const std::string& path) { return m_textureList.find(path) != m_textureList.end(); } void TextureManager::remove(const std::string& path) { if (exists(path)) { m_textureList.erase(path); } } void TextureManager::remove(std::shared_ptr texture) { if (exists(texture->path())) { m_textureList.erase(texture->path()); } } } // namespace Inferno