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.
163 lines
3.7 KiB
163 lines
3.7 KiB
#include <climits> // UINT_MAX |
|
#include <memory> // std::shared_ptr |
|
#include <utility> // std::move |
|
|
|
#include "glad/glad.h" |
|
#define STB_IMAGE_IMPLEMENTATION |
|
#include "stb/stb_image.h" |
|
|
|
#include "inferno/assert.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); |
|
|
|
ASSERT(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_instance = nullptr; |
|
|
|
void TextureManager::initialize() |
|
{ |
|
ASSERT(!s_instance, "TextureManager already exists!"); |
|
s_instance = this; |
|
|
|
info() << "TextureManager initialized"; |
|
} |
|
|
|
void TextureManager::destroy() |
|
{ |
|
delete s_instance; |
|
s_instance = nullptr; |
|
} |
|
|
|
void TextureManager::add(const std::string& path, const std::shared_ptr<Texture>& texture) |
|
{ |
|
// Construct (key, value) pair and insert it into the unordered_map |
|
m_textureList.emplace(path, texture); |
|
} |
|
|
|
std::shared_ptr<Texture> TextureManager::load(const std::string& path) |
|
{ |
|
if (exists(path)) { |
|
return get(path); |
|
} |
|
|
|
std::shared_ptr<Texture> texture = std::make_shared<Texture>(path); |
|
add(path, texture); |
|
return get(path); |
|
} |
|
|
|
std::shared_ptr<Texture> 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(const std::shared_ptr<Texture>& texture) |
|
{ |
|
if (exists(texture->path())) { |
|
m_textureList.erase(texture->path()); |
|
} |
|
} |
|
|
|
}
|
|
|